Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
310 changes: 185 additions & 125 deletions bun.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion e2e/src/pages/admin.page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export class AdminPage extends BasePage {
*/
async selectApiKeyDomain(domain = 'Place Technology'): Promise<void> {
await this.page
.locator('admin-api-keys mat-select[name="type"]')
.locator('admin-api-keys admin-domain-select mat-select')
.click();
await this.page
.locator('mat-option')
Expand Down
14 changes: 3 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
},
"private": true,
"dependencies": {
"@angular/animations": "22.2.3",
"@angular/common": "22.2.3",
"@angular/compiler": "22.2.3",
"@angular/core": "22.2.3",
Expand All @@ -40,10 +39,8 @@
"@angular/compiler-cli": "22.2.3",
"@angular/language-service": "22.2.3",
"@angular/material": "22.2.4",
"@angular/pwa": "22.2.3",
"@eslint/js": "^9.8.0",
"@fontsource-variable/roboto": "^5.3.0",
"@ngneat/spectator": "^22.1.0",
"@nx/angular": "23.3.0",
"@nx/devkit": "23.3.0",
"@nx/eslint": "23.3.0",
Expand All @@ -63,26 +60,24 @@
"@swc/core": "~1.5.7",
"@swc/helpers": "~0.5.11",
"@tailwindcss/postcss": "^4.1.17",
"@types/js-yaml": "^4.0.9",
"@types/node": "20.19.9",
"@typescript-eslint/utils": "8.65.0",
"@vitest/coverage-v8": "^4.0.8",
"@vitest/ui": "^4.0.8",
"@xterm/xterm": "^5.5.0",
"angular-eslint": "22.6.0",
"autoprefixer": "^10.4.16",
"date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"eslint": "^9.8.0",
"eslint-config-prettier": "^10.0.0",
"eslint-plugin-playwright": "^1.6.2",
"firacode": "^6.2.0",
"git-describe": "^4.1.1",
"jiti": "2.4.2",
"js-yaml": "^4.1.1",
"jsdom": "~22.1.0",
"marked": "^17.0.0",
"material-symbols": "^0.39.3",
"monaco-editor": "^0.54.0",
"mqtt": "^5.14.1",
"ng-mocks": "^14.14.0",
"nx": "23.3.0",
"postcss-import": "^16.1.1",
Expand All @@ -91,16 +86,13 @@
"prettier": "^3.6.2",
"prettier-plugin-organize-imports": "^4.3.0",
"prettier-plugin-tailwindcss": "^0.7.1",
"qr": "^0.5.2",
"rxjs": "^7.8.2",
"suneditor": "^2.47.8",
"ts-md5": "^2.0.1",
"tslib": "^2.3.0",
"typescript": "~6.0.3",
"typescript-eslint": "8.65.0",
"vite": "8.3.5",
"vitest": "^4.0.8",
"yaml": "^2.8.1"
"vitest": "^4.0.8"
},
"nx": {
"includedScripts": []
Expand Down
156 changes: 0 additions & 156 deletions public/assets/not-supported.html

This file was deleted.

32 changes: 6 additions & 26 deletions src/app/admin/admin-data.service.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,19 @@
import { Service, WritableSignal, signal } from '@angular/core';
import { PlaceDomain, authority, queryDomains } from '@placeos/ts-client';

export type AdminSortState = [string, boolean];
import { TableSort } from '../ui/simple-table.component';

@Service()
export class AdminDataService {
private readonly _domain_list = signal<PlaceDomain[]>([]);
private readonly _loading_domains = signal(false);
private readonly _domain_error = signal<unknown>(null);
private readonly _selected_domains = new Map<
string,
WritableSignal<PlaceDomain | null>
>();
private readonly _filters = new Map<string, WritableSignal<string>>();
private readonly _sorts = new Map<string, WritableSignal<AdminSortState>>();
private readonly _sorts = new Map<string, WritableSignal<TableSort>>();
private _domain_request: Promise<PlaceDomain[]> | null = null;

public readonly domain_list = this._domain_list.asReadonly();
public readonly loading_domains = this._loading_domains.asReadonly();
public readonly domain_error = this._domain_error.asReadonly();

public selectedDomain(key: string): WritableSignal<PlaceDomain | null> {
let selected = this._selected_domains.get(key);
Expand All @@ -38,42 +33,27 @@ export class AdminDataService {
return filter;
}

public sort(key: string): WritableSignal<AdminSortState> {
/** Table sort of an admin page, kept while the app is open */
public sort(key: string): WritableSignal<TableSort> {
let sort = this._sorts.get(key);
if (!sort) {
sort = signal<AdminSortState>(['', false]);
sort = signal<TableSort>(null);
this._sorts.set(key, sort);
}
return sort;
}

public sortBy(key: string, new_field: string) {
const sort = this.sort(key);
const [field, asc] = sort();
if (field === new_field) {
sort.set(asc ? ['', false] : [new_field, true]);
} else {
sort.set([new_field, false]);
}
}

public async loadDomains(limit = 500): Promise<PlaceDomain[]> {
if (this._domain_list().length) return this._domain_list();
if (this._domain_request) return this._domain_request;
this._loading_domains.set(true);
this._domain_error.set(null);
this._domain_request = queryDomains({ limit })
.then((response) => response.data || [])
.catch((error) => {
this._domain_error.set(error);
return [] as PlaceDomain[];
})
.catch(() => [] as PlaceDomain[])
.then((domains) => {
this._domain_list.set(domains);
return domains;
})
.finally(() => {
this._loading_domains.set(false);
this._domain_request = null;
});
return this._domain_request;
Expand Down
63 changes: 63 additions & 0 deletions src/app/admin/admin-domain-select.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {
booleanAttribute,
Component,
computed,
inject,
input,
output,
} from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatSelectModule } from '@angular/material/select';
import { PlaceDomain } from '@placeos/ts-client';
import { TranslatePipe } from '../ui/translate.pipe';
import { AdminDataService } from './admin-data.service';

/** Domain picker for admin pages. AdminDataService keeps the choice per `key`. */
@Component({
selector: 'admin-domain-select',
template: `
<mat-form-field appearance="outline" [class]="field_class()">
<mat-select
name="domain"
[ngModel]="domain()"
(ngModelChange)="select($event)"
[placeholder]="
(all() ? 'ADMIN.ALL_DOMAINS' : 'ADMIN.SELECT_DOMAIN')
| translate
"
>
@if (all()) {
<mat-option [value]="{}">
{{ 'ADMIN.ALL_DOMAINS' | translate }}
</mat-option>
}
@for (domain of domain_list(); track domain.id) {
<mat-option [value]="domain">{{ domain.name }}</mat-option>
}
</mat-select>
</mat-form-field>
`,
imports: [FormsModule, MatFormFieldModule, MatSelectModule, TranslatePipe],
})
export class AdminDomainSelectComponent {
private _data = inject(AdminDataService);

/** Admin page that owns the selection */
public readonly key = input.required<string>();
/** Add an "All domains" option */
public readonly all = input(false, { transform: booleanAttribute });
public readonly field_class = input('no-subscript w-56');
/** Emits after the user picks a domain */
public readonly changed = output<PlaceDomain>();

public readonly domain_list = this._data.domain_list;
public readonly domain = computed(() =>
this._data.selectedDomain(this.key())(),
);

public select(domain: PlaceDomain) {
this._data.setDomain(this.key(), domain);
this.changed.emit(domain);
}
}
9 changes: 1 addition & 8 deletions src/app/admin/admin.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Component, OnInit, computed, inject } from '@angular/core';
import { MatRippleModule } from '@angular/material/core';
import { RouterModule } from '@angular/router';
import { extensionsForItem } from '../common/api';
import { AsyncHandler } from '../common/async-handler.class';
import { PlaceDebugService } from '../common/debug.service';
import { ActiveItemService } from '../common/item.service';
import { i18n } from '../common/locale.service';
Expand Down Expand Up @@ -80,12 +79,6 @@ import { TranslatePipe } from '../ui/translate.pipe';
width: 100%;
height: 100%;
}

.active {
background-color: var(--secondary) !important;
color: var(--secondary-content);
margin-right: -1px;
}
`,
],
imports: [
Expand All @@ -97,7 +90,7 @@ import { TranslatePipe } from '../ui/translate.pipe';
RouterModule,
],
})
export class PlaceComponent extends AsyncHandler implements OnInit {
export class PlaceComponent implements OnInit {
private _settings = inject(SettingsService);
private _service = inject(ActiveItemService);
private _debug = inject(PlaceDebugService);
Expand Down
Loading
Loading