@rolatech/angular-platform 20.3.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +3 -0
  2. package/fesm2022/rolatech-angular-platform-application-create-DqPMquaO.mjs +129 -0
  3. package/fesm2022/rolatech-angular-platform-application-create-DqPMquaO.mjs.map +1 -0
  4. package/fesm2022/rolatech-angular-platform-application-detail-BoITs_yE.mjs +54 -0
  5. package/fesm2022/rolatech-angular-platform-application-detail-BoITs_yE.mjs.map +1 -0
  6. package/fesm2022/rolatech-angular-platform-application-index-BlCbJVDc.mjs +82 -0
  7. package/fesm2022/rolatech-angular-platform-application-index-BlCbJVDc.mjs.map +1 -0
  8. package/fesm2022/rolatech-angular-platform-application-organization-index-D7TJ8CID.mjs +54 -0
  9. package/fesm2022/rolatech-angular-platform-application-organization-index-D7TJ8CID.mjs.map +1 -0
  10. package/fesm2022/rolatech-angular-platform-application-role-index-9_XVRBgD.mjs +66 -0
  11. package/fesm2022/rolatech-angular-platform-application-role-index-9_XVRBgD.mjs.map +1 -0
  12. package/fesm2022/rolatech-angular-platform-application-routes-DE5CJMgn.mjs +38 -0
  13. package/fesm2022/rolatech-angular-platform-application-routes-DE5CJMgn.mjs.map +1 -0
  14. package/fesm2022/rolatech-angular-platform-platform-auth-client-detail-BMvM7PvP.mjs +137 -0
  15. package/fesm2022/rolatech-angular-platform-platform-auth-client-detail-BMvM7PvP.mjs.map +1 -0
  16. package/fesm2022/rolatech-angular-platform-platform-auth-client-editor-75GPRUsF.mjs +281 -0
  17. package/fesm2022/rolatech-angular-platform-platform-auth-client-editor-75GPRUsF.mjs.map +1 -0
  18. package/fesm2022/rolatech-angular-platform-platform-auth-client-index-DilT3UzO.mjs +95 -0
  19. package/fesm2022/rolatech-angular-platform-platform-auth-client-index-DilT3UzO.mjs.map +1 -0
  20. package/fesm2022/rolatech-angular-platform-platform-auth-client.routes-D_VFpAgu.mjs +21 -0
  21. package/fesm2022/rolatech-angular-platform-platform-auth-client.routes-D_VFpAgu.mjs.map +1 -0
  22. package/fesm2022/rolatech-angular-platform-platform-endpoint-detail-CEaO9MFQ.mjs +57 -0
  23. package/fesm2022/rolatech-angular-platform-platform-endpoint-detail-CEaO9MFQ.mjs.map +1 -0
  24. package/fesm2022/rolatech-angular-platform-platform-endpoint-index-69W62bRP.mjs +92 -0
  25. package/fesm2022/rolatech-angular-platform-platform-endpoint-index-69W62bRP.mjs.map +1 -0
  26. package/fesm2022/rolatech-angular-platform-platform-endpoint.routes-Cj66S7N-.mjs +13 -0
  27. package/fesm2022/rolatech-angular-platform-platform-endpoint.routes-Cj66S7N-.mjs.map +1 -0
  28. package/fesm2022/rolatech-angular-platform-platform-role-index-8kRxDJiW.mjs +35 -0
  29. package/fesm2022/rolatech-angular-platform-platform-role-index-8kRxDJiW.mjs.map +1 -0
  30. package/fesm2022/rolatech-angular-platform-platform-service-registry-detail-CQ4Wk1R8.mjs +89 -0
  31. package/fesm2022/rolatech-angular-platform-platform-service-registry-detail-CQ4Wk1R8.mjs.map +1 -0
  32. package/fesm2022/rolatech-angular-platform-platform-service-registry-editor-Bd3nIfxd.mjs +246 -0
  33. package/fesm2022/rolatech-angular-platform-platform-service-registry-editor-Bd3nIfxd.mjs.map +1 -0
  34. package/fesm2022/rolatech-angular-platform-platform-service-registry-index-D4470pau.mjs +95 -0
  35. package/fesm2022/rolatech-angular-platform-platform-service-registry-index-D4470pau.mjs.map +1 -0
  36. package/fesm2022/rolatech-angular-platform-platform-service-registry.routes-DlWUwwws.mjs +21 -0
  37. package/fesm2022/rolatech-angular-platform-platform-service-registry.routes-DlWUwwws.mjs.map +1 -0
  38. package/fesm2022/rolatech-angular-platform-platform-user-detail-fzo89PHV.mjs +81 -0
  39. package/fesm2022/rolatech-angular-platform-platform-user-detail-fzo89PHV.mjs.map +1 -0
  40. package/fesm2022/rolatech-angular-platform-platform-user-index-DBT4N0zi.mjs +89 -0
  41. package/fesm2022/rolatech-angular-platform-platform-user-index-DBT4N0zi.mjs.map +1 -0
  42. package/fesm2022/rolatech-angular-platform-platform-user.routes-C6OoAsWU.mjs +13 -0
  43. package/fesm2022/rolatech-angular-platform-platform-user.routes-C6OoAsWU.mjs.map +1 -0
  44. package/fesm2022/rolatech-angular-platform-role-permission-page-DslhArZQ.mjs +527 -0
  45. package/fesm2022/rolatech-angular-platform-role-permission-page-DslhArZQ.mjs.map +1 -0
  46. package/fesm2022/rolatech-angular-platform-role-permission-page.routes-IiX17wDW.mjs +11 -0
  47. package/fesm2022/rolatech-angular-platform-role-permission-page.routes-IiX17wDW.mjs.map +1 -0
  48. package/fesm2022/rolatech-angular-platform.mjs +293 -0
  49. package/fesm2022/rolatech-angular-platform.mjs.map +1 -0
  50. package/package.json +33 -0
  51. package/types/rolatech-angular-platform.d.ts +70 -0
@@ -0,0 +1,95 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, signal, computed, Injectable, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { Router } from '@angular/router';
4
+ import { PlatformPageHeader, PlatformStatCard, PlatformFilterPanel, PlatformDataTable } from './rolatech-angular-platform.mjs';
5
+ import { firstValueFrom } from 'rxjs';
6
+ import { PlatformServiceRegistryService } from '@rolatech/angular-services';
7
+
8
+ class PlatformServiceRegistryIndexFacade {
9
+ serviceRegistryService = inject(PlatformServiceRegistryService);
10
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
11
+ error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
12
+ items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : []));
13
+ keyword = signal('', ...(ngDevMode ? [{ debugName: "keyword" }] : []));
14
+ status = signal('ALL', ...(ngDevMode ? [{ debugName: "status" }] : []));
15
+ filteredItems = computed(() => {
16
+ const keyword = this.keyword().trim().toLowerCase();
17
+ const status = this.status();
18
+ return this.items().filter((item) => {
19
+ const haystack = [item.name, item.code, item.namespace, item.serviceType, item.version, item.baseUrl, item.healthStatus]
20
+ .filter(Boolean)
21
+ .join(' ')
22
+ .toLowerCase();
23
+ const matchesKeyword = !keyword || haystack.includes(keyword);
24
+ const itemStatus = item.enabled ? 'ENABLED' : 'DISABLED';
25
+ const matchesStatus = status === 'ALL' || itemStatus === status;
26
+ return matchesKeyword && matchesStatus;
27
+ });
28
+ }, ...(ngDevMode ? [{ debugName: "filteredItems" }] : []));
29
+ total = computed(() => this.items().length, ...(ngDevMode ? [{ debugName: "total" }] : []));
30
+ enabledCount = computed(() => this.items().filter((item) => item.enabled).length, ...(ngDevMode ? [{ debugName: "enabledCount" }] : []));
31
+ healthyCount = computed(() => this.items().filter((item) => (item.healthStatus ?? '').toUpperCase() === 'HEALTHY' || (item.healthStatus ?? '').toUpperCase() === 'UP').length, ...(ngDevMode ? [{ debugName: "healthyCount" }] : []));
32
+ endpointCount = computed(() => this.items().reduce((sum, item) => sum + item.endpointCount, 0), ...(ngDevMode ? [{ debugName: "endpointCount" }] : []));
33
+ async load() {
34
+ this.loading.set(true);
35
+ this.error.set(null);
36
+ try {
37
+ const page = await firstValueFrom(this.serviceRegistryService.findServices({
38
+ limit: 100,
39
+ sort: ['updatedAt desc'],
40
+ }));
41
+ this.items.set(page.items ?? []);
42
+ }
43
+ catch (error) {
44
+ console.error(error);
45
+ this.items.set([]);
46
+ this.error.set('Unable to load platform services.');
47
+ }
48
+ finally {
49
+ this.loading.set(false);
50
+ }
51
+ }
52
+ setKeyword(value) {
53
+ this.keyword.set(value);
54
+ }
55
+ setStatus(value) {
56
+ this.status.set(value);
57
+ }
58
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformServiceRegistryIndexFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
59
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformServiceRegistryIndexFacade });
60
+ }
61
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformServiceRegistryIndexFacade, decorators: [{
62
+ type: Injectable
63
+ }] });
64
+
65
+ class PlatformServiceRegistryIndexPage {
66
+ facade = inject(PlatformServiceRegistryIndexFacade);
67
+ router = inject(Router);
68
+ ngOnInit() {
69
+ void this.facade.load();
70
+ }
71
+ onKeywordInput(event) {
72
+ this.facade.setKeyword(event.target.value);
73
+ }
74
+ onStatusChange(event) {
75
+ this.facade.setStatus(event.target.value);
76
+ }
77
+ openService(serviceId) {
78
+ void this.router.navigate(['/platform/service-registry', serviceId]);
79
+ }
80
+ createService() {
81
+ void this.router.navigate(['/platform/service-registry/create']);
82
+ }
83
+ editService(serviceId) {
84
+ void this.router.navigate(['/platform/service-registry', serviceId, 'edit']);
85
+ }
86
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformServiceRegistryIndexPage, deps: [], target: i0.ɵɵFactoryTarget.Component });
87
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: PlatformServiceRegistryIndexPage, isStandalone: true, selector: "rolatech-platform-service-registry-index-page", providers: [PlatformServiceRegistryIndexFacade], ngImport: i0, template: "<section class=\"rt-platform-theme flex flex-col gap-6 bg-(--rt-base-background) p-6 text-(--rt-text-primary)\">\n <rolatech-platform-page-header>\n <div header-left class=\"space-y-1\">\n <h1 class=\"text-2xl font-semibold tracking-tight\">Service Registry</h1>\n <p class=\"text-sm text-muted-foreground\">Inspect registered services, runtime health, and exposed endpoint counts.</p>\n </div>\n <div header-actions>\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl bg-(--rt-accent) px-4 py-2 text-sm font-medium text-(--rt-accent-foreground)\"\n (click)=\"createService()\"\n >\n Register Service\n </button>\n </div>\n </rolatech-platform-page-header>\n\n <section class=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <rolatech-platform-stat-card>\n <div stat-label>Total Services</div>\n <div stat-value>{{ facade.total() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Enabled</div>\n <div stat-value>{{ facade.enabledCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Healthy</div>\n <div stat-value>{{ facade.healthyCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Total Endpoints</div>\n <div stat-value>{{ facade.endpointCount() }}</div>\n </rolatech-platform-stat-card>\n </section>\n\n <section class=\"grid gap-6 xl:grid-cols-[320px_minmax(0,1fr)]\">\n <rolatech-platform-filter-panel>\n <div filter-title>Filters</div>\n <div filter-description>Refine registered services.</div>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Search</span>\n <input\n type=\"text\"\n [value]=\"facade.keyword()\"\n (input)=\"onKeywordInput($event)\"\n placeholder=\"Search service, namespace, base URL\"\n class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\"\n />\n </label>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Status</span>\n <select class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\" (change)=\"onStatusChange($event)\">\n <option value=\"ALL\">All</option>\n <option value=\"ENABLED\">Enabled</option>\n <option value=\"DISABLED\">Disabled</option>\n </select>\n </label>\n </rolatech-platform-filter-panel>\n\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Registered Services</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.filteredItems().length }} items</div>\n </div>\n\n @if (facade.error()) {\n <p class=\"mb-4 rounded-2xl border border-rose-300/40 bg-rose-500/10 px-4 py-3 text-sm text-(--rt-text-primary)\">\n {{ facade.error() }}\n </p>\n }\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">Service</th>\n <th class=\"px-4 py-3 font-medium\">Namespace</th>\n <th class=\"px-4 py-3 font-medium\">Base URL</th>\n <th class=\"px-4 py-3 font-medium\">Health</th>\n <th class=\"px-4 py-3 font-medium\">Endpoints</th>\n <th class=\"px-4 py-3 font-medium\">Actions</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.loading()) {\n <tr>\n <td colspan=\"6\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading services...</td>\n </tr>\n } @else if (facade.filteredItems().length === 0) {\n <tr>\n <td colspan=\"6\" class=\"px-4 py-10 text-center text-muted-foreground\">No services matched your filters.</td>\n </tr>\n } @else { @for (item of facade.filteredItems(); track item.id) {\n <tr class=\"border-t border-(--rt-border-color)\">\n <td class=\"px-4 py-3\">\n <div class=\"font-medium\">{{ item.name }}</div>\n <div class=\"text-sm text-muted-foreground\">{{ item.code || item.id }}</div>\n </td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.namespace || '\u2014' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground break-all\">{{ item.baseUrl || '\u2014' }}</td>\n <td class=\"px-4 py-3\">\n <div class=\"font-medium\">{{ item.healthStatus || 'UNKNOWN' }}</div>\n <div class=\"text-sm text-muted-foreground\">{{ item.instanceCount }} instances</div>\n </td>\n <td class=\"px-4 py-3\">\n <div class=\"font-medium\">{{ item.endpointCount }}</div>\n <div class=\"text-sm text-muted-foreground\">{{ item.version || 'No version' }}</div>\n </td>\n <td class=\"px-4 py-3\">\n <div class=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-3 py-2 text-sm font-medium\"\n (click)=\"openService(item.id)\"\n >\n View\n </button>\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-3 py-2 text-sm font-medium\"\n (click)=\"editService(item.id)\"\n >\n Edit\n </button>\n </div>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n </section>\n</section>\n", styles: [":host{display:block}\n"], dependencies: [{ kind: "component", type: PlatformPageHeader, selector: "rolatech-platform-page-header" }, { kind: "component", type: PlatformStatCard, selector: "rolatech-platform-stat-card" }, { kind: "component", type: PlatformFilterPanel, selector: "rolatech-platform-filter-panel" }, { kind: "component", type: PlatformDataTable, selector: "rolatech-platform-data-table" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
88
+ }
89
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformServiceRegistryIndexPage, decorators: [{
90
+ type: Component,
91
+ args: [{ selector: 'rolatech-platform-service-registry-index-page', standalone: true, imports: [PlatformPageHeader, PlatformStatCard, PlatformFilterPanel, PlatformDataTable], changeDetection: ChangeDetectionStrategy.OnPush, providers: [PlatformServiceRegistryIndexFacade], template: "<section class=\"rt-platform-theme flex flex-col gap-6 bg-(--rt-base-background) p-6 text-(--rt-text-primary)\">\n <rolatech-platform-page-header>\n <div header-left class=\"space-y-1\">\n <h1 class=\"text-2xl font-semibold tracking-tight\">Service Registry</h1>\n <p class=\"text-sm text-muted-foreground\">Inspect registered services, runtime health, and exposed endpoint counts.</p>\n </div>\n <div header-actions>\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl bg-(--rt-accent) px-4 py-2 text-sm font-medium text-(--rt-accent-foreground)\"\n (click)=\"createService()\"\n >\n Register Service\n </button>\n </div>\n </rolatech-platform-page-header>\n\n <section class=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <rolatech-platform-stat-card>\n <div stat-label>Total Services</div>\n <div stat-value>{{ facade.total() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Enabled</div>\n <div stat-value>{{ facade.enabledCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Healthy</div>\n <div stat-value>{{ facade.healthyCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Total Endpoints</div>\n <div stat-value>{{ facade.endpointCount() }}</div>\n </rolatech-platform-stat-card>\n </section>\n\n <section class=\"grid gap-6 xl:grid-cols-[320px_minmax(0,1fr)]\">\n <rolatech-platform-filter-panel>\n <div filter-title>Filters</div>\n <div filter-description>Refine registered services.</div>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Search</span>\n <input\n type=\"text\"\n [value]=\"facade.keyword()\"\n (input)=\"onKeywordInput($event)\"\n placeholder=\"Search service, namespace, base URL\"\n class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\"\n />\n </label>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Status</span>\n <select class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\" (change)=\"onStatusChange($event)\">\n <option value=\"ALL\">All</option>\n <option value=\"ENABLED\">Enabled</option>\n <option value=\"DISABLED\">Disabled</option>\n </select>\n </label>\n </rolatech-platform-filter-panel>\n\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Registered Services</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.filteredItems().length }} items</div>\n </div>\n\n @if (facade.error()) {\n <p class=\"mb-4 rounded-2xl border border-rose-300/40 bg-rose-500/10 px-4 py-3 text-sm text-(--rt-text-primary)\">\n {{ facade.error() }}\n </p>\n }\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">Service</th>\n <th class=\"px-4 py-3 font-medium\">Namespace</th>\n <th class=\"px-4 py-3 font-medium\">Base URL</th>\n <th class=\"px-4 py-3 font-medium\">Health</th>\n <th class=\"px-4 py-3 font-medium\">Endpoints</th>\n <th class=\"px-4 py-3 font-medium\">Actions</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.loading()) {\n <tr>\n <td colspan=\"6\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading services...</td>\n </tr>\n } @else if (facade.filteredItems().length === 0) {\n <tr>\n <td colspan=\"6\" class=\"px-4 py-10 text-center text-muted-foreground\">No services matched your filters.</td>\n </tr>\n } @else { @for (item of facade.filteredItems(); track item.id) {\n <tr class=\"border-t border-(--rt-border-color)\">\n <td class=\"px-4 py-3\">\n <div class=\"font-medium\">{{ item.name }}</div>\n <div class=\"text-sm text-muted-foreground\">{{ item.code || item.id }}</div>\n </td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.namespace || '\u2014' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground break-all\">{{ item.baseUrl || '\u2014' }}</td>\n <td class=\"px-4 py-3\">\n <div class=\"font-medium\">{{ item.healthStatus || 'UNKNOWN' }}</div>\n <div class=\"text-sm text-muted-foreground\">{{ item.instanceCount }} instances</div>\n </td>\n <td class=\"px-4 py-3\">\n <div class=\"font-medium\">{{ item.endpointCount }}</div>\n <div class=\"text-sm text-muted-foreground\">{{ item.version || 'No version' }}</div>\n </td>\n <td class=\"px-4 py-3\">\n <div class=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-3 py-2 text-sm font-medium\"\n (click)=\"openService(item.id)\"\n >\n View\n </button>\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-3 py-2 text-sm font-medium\"\n (click)=\"editService(item.id)\"\n >\n Edit\n </button>\n </div>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n </section>\n</section>\n", styles: [":host{display:block}\n"] }]
92
+ }] });
93
+
94
+ export { PlatformServiceRegistryIndexPage };
95
+ //# sourceMappingURL=rolatech-angular-platform-platform-service-registry-index-D4470pau.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rolatech-angular-platform-platform-service-registry-index-D4470pau.mjs","sources":["../../../../packages/angular-platform/src/lib/store/platform-service-registry-index.facade.ts","../../../../packages/angular-platform/src/lib/pages/service-registry/platform-service-registry-index/platform-service-registry-index.ts","../../../../packages/angular-platform/src/lib/pages/service-registry/platform-service-registry-index/platform-service-registry-index.html"],"sourcesContent":["import { Injectable, computed, inject, signal } from '@angular/core';\nimport { firstValueFrom } from 'rxjs';\nimport { PlatformServiceRegistryService, PlatformServiceRegistrySummaryResponse } from '@rolatech/angular-services';\n\n@Injectable()\nexport class PlatformServiceRegistryIndexFacade {\n private readonly serviceRegistryService = inject(PlatformServiceRegistryService);\n\n readonly loading = signal(false);\n readonly error = signal<string | null>(null);\n readonly items = signal<PlatformServiceRegistrySummaryResponse[]>([]);\n\n readonly keyword = signal('');\n readonly status = signal<'ALL' | 'ENABLED' | 'DISABLED'>('ALL');\n\n readonly filteredItems = computed(() => {\n const keyword = this.keyword().trim().toLowerCase();\n const status = this.status();\n\n return this.items().filter((item) => {\n const haystack = [item.name, item.code, item.namespace, item.serviceType, item.version, item.baseUrl, item.healthStatus]\n .filter(Boolean)\n .join(' ')\n .toLowerCase();\n const matchesKeyword = !keyword || haystack.includes(keyword);\n const itemStatus = item.enabled ? 'ENABLED' : 'DISABLED';\n const matchesStatus = status === 'ALL' || itemStatus === status;\n return matchesKeyword && matchesStatus;\n });\n });\n\n readonly total = computed(() => this.items().length);\n readonly enabledCount = computed(() => this.items().filter((item) => item.enabled).length);\n readonly healthyCount = computed(() =>\n this.items().filter((item) => (item.healthStatus ?? '').toUpperCase() === 'HEALTHY' || (item.healthStatus ?? '').toUpperCase() === 'UP').length,\n );\n readonly endpointCount = computed(() => this.items().reduce((sum, item) => sum + item.endpointCount, 0));\n\n async load(): Promise<void> {\n this.loading.set(true);\n this.error.set(null);\n\n try {\n const page = await firstValueFrom(\n this.serviceRegistryService.findServices({\n limit: 100,\n sort: ['updatedAt desc'],\n }),\n );\n this.items.set(page.items ?? []);\n } catch (error) {\n console.error(error);\n this.items.set([]);\n this.error.set('Unable to load platform services.');\n } finally {\n this.loading.set(false);\n }\n }\n\n setKeyword(value: string): void {\n this.keyword.set(value);\n }\n\n setStatus(value: 'ALL' | 'ENABLED' | 'DISABLED'): void {\n this.status.set(value);\n }\n}\n","import { ChangeDetectionStrategy, Component, OnInit, inject } from '@angular/core';\nimport { Router } from '@angular/router';\nimport { PlatformDataTable, PlatformFilterPanel, PlatformPageHeader, PlatformStatCard } from '../../../shared';\nimport { PlatformServiceRegistryIndexFacade } from '../../../store/platform-service-registry-index.facade';\n\n@Component({\n selector: 'rolatech-platform-service-registry-index-page',\n standalone: true,\n imports: [PlatformPageHeader, PlatformStatCard, PlatformFilterPanel, PlatformDataTable],\n templateUrl: './platform-service-registry-index.html',\n styleUrl: './platform-service-registry-index.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [PlatformServiceRegistryIndexFacade],\n})\nexport class PlatformServiceRegistryIndexPage implements OnInit {\n readonly facade = inject(PlatformServiceRegistryIndexFacade);\n private readonly router = inject(Router);\n\n ngOnInit(): void {\n void this.facade.load();\n }\n\n onKeywordInput(event: Event): void {\n this.facade.setKeyword((event.target as HTMLInputElement).value);\n }\n\n onStatusChange(event: Event): void {\n this.facade.setStatus((event.target as HTMLSelectElement).value as 'ALL' | 'ENABLED' | 'DISABLED');\n }\n\n openService(serviceId: string): void {\n void this.router.navigate(['/platform/service-registry', serviceId]);\n }\n\n createService(): void {\n void this.router.navigate(['/platform/service-registry/create']);\n }\n\n editService(serviceId: string): void {\n void this.router.navigate(['/platform/service-registry', serviceId, 'edit']);\n }\n}\n","<section class=\"rt-platform-theme flex flex-col gap-6 bg-(--rt-base-background) p-6 text-(--rt-text-primary)\">\n <rolatech-platform-page-header>\n <div header-left class=\"space-y-1\">\n <h1 class=\"text-2xl font-semibold tracking-tight\">Service Registry</h1>\n <p class=\"text-sm text-muted-foreground\">Inspect registered services, runtime health, and exposed endpoint counts.</p>\n </div>\n <div header-actions>\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl bg-(--rt-accent) px-4 py-2 text-sm font-medium text-(--rt-accent-foreground)\"\n (click)=\"createService()\"\n >\n Register Service\n </button>\n </div>\n </rolatech-platform-page-header>\n\n <section class=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <rolatech-platform-stat-card>\n <div stat-label>Total Services</div>\n <div stat-value>{{ facade.total() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Enabled</div>\n <div stat-value>{{ facade.enabledCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Healthy</div>\n <div stat-value>{{ facade.healthyCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Total Endpoints</div>\n <div stat-value>{{ facade.endpointCount() }}</div>\n </rolatech-platform-stat-card>\n </section>\n\n <section class=\"grid gap-6 xl:grid-cols-[320px_minmax(0,1fr)]\">\n <rolatech-platform-filter-panel>\n <div filter-title>Filters</div>\n <div filter-description>Refine registered services.</div>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Search</span>\n <input\n type=\"text\"\n [value]=\"facade.keyword()\"\n (input)=\"onKeywordInput($event)\"\n placeholder=\"Search service, namespace, base URL\"\n class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\"\n />\n </label>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Status</span>\n <select class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\" (change)=\"onStatusChange($event)\">\n <option value=\"ALL\">All</option>\n <option value=\"ENABLED\">Enabled</option>\n <option value=\"DISABLED\">Disabled</option>\n </select>\n </label>\n </rolatech-platform-filter-panel>\n\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Registered Services</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.filteredItems().length }} items</div>\n </div>\n\n @if (facade.error()) {\n <p class=\"mb-4 rounded-2xl border border-rose-300/40 bg-rose-500/10 px-4 py-3 text-sm text-(--rt-text-primary)\">\n {{ facade.error() }}\n </p>\n }\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">Service</th>\n <th class=\"px-4 py-3 font-medium\">Namespace</th>\n <th class=\"px-4 py-3 font-medium\">Base URL</th>\n <th class=\"px-4 py-3 font-medium\">Health</th>\n <th class=\"px-4 py-3 font-medium\">Endpoints</th>\n <th class=\"px-4 py-3 font-medium\">Actions</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.loading()) {\n <tr>\n <td colspan=\"6\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading services...</td>\n </tr>\n } @else if (facade.filteredItems().length === 0) {\n <tr>\n <td colspan=\"6\" class=\"px-4 py-10 text-center text-muted-foreground\">No services matched your filters.</td>\n </tr>\n } @else { @for (item of facade.filteredItems(); track item.id) {\n <tr class=\"border-t border-(--rt-border-color)\">\n <td class=\"px-4 py-3\">\n <div class=\"font-medium\">{{ item.name }}</div>\n <div class=\"text-sm text-muted-foreground\">{{ item.code || item.id }}</div>\n </td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.namespace || '—' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground break-all\">{{ item.baseUrl || '—' }}</td>\n <td class=\"px-4 py-3\">\n <div class=\"font-medium\">{{ item.healthStatus || 'UNKNOWN' }}</div>\n <div class=\"text-sm text-muted-foreground\">{{ item.instanceCount }} instances</div>\n </td>\n <td class=\"px-4 py-3\">\n <div class=\"font-medium\">{{ item.endpointCount }}</div>\n <div class=\"text-sm text-muted-foreground\">{{ item.version || 'No version' }}</div>\n </td>\n <td class=\"px-4 py-3\">\n <div class=\"flex flex-wrap gap-2\">\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-3 py-2 text-sm font-medium\"\n (click)=\"openService(item.id)\"\n >\n View\n </button>\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-3 py-2 text-sm font-medium\"\n (click)=\"editService(item.id)\"\n >\n Edit\n </button>\n </div>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n </section>\n</section>\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ const PLATFORM_SERVICE_REGISTRY_ROUTES = [
2
+ {
3
+ path: '',
4
+ loadComponent: () => import('./rolatech-angular-platform-platform-service-registry-index-D4470pau.mjs').then((m) => m.PlatformServiceRegistryIndexPage),
5
+ },
6
+ {
7
+ path: 'create',
8
+ loadComponent: () => import('./rolatech-angular-platform-platform-service-registry-editor-Bd3nIfxd.mjs').then((m) => m.PlatformServiceRegistryEditorPage),
9
+ },
10
+ {
11
+ path: ':serviceId/edit',
12
+ loadComponent: () => import('./rolatech-angular-platform-platform-service-registry-editor-Bd3nIfxd.mjs').then((m) => m.PlatformServiceRegistryEditorPage),
13
+ },
14
+ {
15
+ path: ':serviceId',
16
+ loadComponent: () => import('./rolatech-angular-platform-platform-service-registry-detail-CQ4Wk1R8.mjs').then((m) => m.PlatformServiceRegistryDetailPage),
17
+ },
18
+ ];
19
+
20
+ export { PLATFORM_SERVICE_REGISTRY_ROUTES };
21
+ //# sourceMappingURL=rolatech-angular-platform-platform-service-registry.routes-DlWUwwws.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rolatech-angular-platform-platform-service-registry.routes-DlWUwwws.mjs","sources":["../../../../packages/angular-platform/src/lib/pages/service-registry/platform-service-registry.routes.ts"],"sourcesContent":["import { Routes } from '@angular/router';\n\nexport const PLATFORM_SERVICE_REGISTRY_ROUTES: Routes = [\n {\n path: '',\n loadComponent: () =>\n import('./platform-service-registry-index/platform-service-registry-index').then((m) => m.PlatformServiceRegistryIndexPage),\n },\n {\n path: 'create',\n loadComponent: () =>\n import('./platform-service-registry-editor/platform-service-registry-editor').then((m) => m.PlatformServiceRegistryEditorPage),\n },\n {\n path: ':serviceId/edit',\n loadComponent: () =>\n import('./platform-service-registry-editor/platform-service-registry-editor').then((m) => m.PlatformServiceRegistryEditorPage),\n },\n {\n path: ':serviceId',\n loadComponent: () =>\n import('./platform-service-registry-detail/platform-service-registry-detail').then((m) => m.PlatformServiceRegistryDetailPage),\n },\n];\n"],"names":[],"mappings":"AAEO,MAAM,gCAAgC,GAAW;AACtD,IAAA;AACE,QAAA,IAAI,EAAE,EAAE;AACR,QAAA,aAAa,EAAE,MACb,OAAO,0EAAmE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,gCAAgC,CAAC;AAC9H,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,QAAQ;AACd,QAAA,aAAa,EAAE,MACb,OAAO,2EAAqE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,iCAAiC,CAAC;AACjI,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,iBAAiB;AACvB,QAAA,aAAa,EAAE,MACb,OAAO,2EAAqE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,iCAAiC,CAAC;AACjI,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,YAAY;AAClB,QAAA,aAAa,EAAE,MACb,OAAO,2EAAqE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,iCAAiC,CAAC;AACjI,KAAA;;;;;"}
@@ -0,0 +1,81 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, signal, computed, Injectable, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { ActivatedRoute, RouterLink } from '@angular/router';
4
+ import { PlatformPageHeader, PlatformStatCard, PlatformDetailPanel } from './rolatech-angular-platform.mjs';
5
+ import { firstValueFrom } from 'rxjs';
6
+ import { PlatformUserService } from '@rolatech/angular-services';
7
+
8
+ class PlatformUserDetailFacade {
9
+ platformUserService = inject(PlatformUserService);
10
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
11
+ error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
12
+ item = signal(null, ...(ngDevMode ? [{ debugName: "item" }] : []));
13
+ displayName = computed(() => {
14
+ const item = this.item();
15
+ if (!item) {
16
+ return '';
17
+ }
18
+ return item.name || [item.firstName, item.lastName].filter(Boolean).join(' ').trim() || item.username || item.email || item.id;
19
+ }, ...(ngDevMode ? [{ debugName: "displayName" }] : []));
20
+ applicationCount = computed(() => this.item()?.applications?.length ?? 0, ...(ngDevMode ? [{ debugName: "applicationCount" }] : []));
21
+ organizationCount = computed(() => this.item()?.organizations?.length ?? 0, ...(ngDevMode ? [{ debugName: "organizationCount" }] : []));
22
+ platformRoleCount = computed(() => this.item()?.platformRoles?.length ?? 0, ...(ngDevMode ? [{ debugName: "platformRoleCount" }] : []));
23
+ permissionCount = computed(() => this.item()?.permissions?.length ?? 0, ...(ngDevMode ? [{ debugName: "permissionCount" }] : []));
24
+ async load(userId) {
25
+ this.loading.set(true);
26
+ this.error.set(null);
27
+ try {
28
+ const [detail, context] = await Promise.all([
29
+ firstValueFrom(this.platformUserService.findUserById(userId)),
30
+ firstValueFrom(this.platformUserService.findUserContext(userId)),
31
+ ]);
32
+ this.item.set(this.mergeContext(detail, context));
33
+ }
34
+ catch (error) {
35
+ console.error(error);
36
+ this.item.set(null);
37
+ this.error.set('Unable to load platform user details.');
38
+ }
39
+ finally {
40
+ this.loading.set(false);
41
+ }
42
+ }
43
+ mergeContext(detail, context) {
44
+ if (!context) {
45
+ return detail;
46
+ }
47
+ return {
48
+ ...detail,
49
+ platformRoles: detail.platformRoles?.length ? detail.platformRoles : context.platformRoles,
50
+ applications: detail.applications?.length ? detail.applications : context.applications,
51
+ organizations: detail.organizations?.length ? detail.organizations : context.organizations,
52
+ permissions: detail.permissions?.length ? detail.permissions : (context.permissions ?? null),
53
+ };
54
+ }
55
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformUserDetailFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
56
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformUserDetailFacade });
57
+ }
58
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformUserDetailFacade, decorators: [{
59
+ type: Injectable
60
+ }] });
61
+
62
+ class PlatformUserDetailPage {
63
+ facade = inject(PlatformUserDetailFacade);
64
+ route = inject(ActivatedRoute);
65
+ userId = this.route.snapshot.paramMap.get('userId') ?? '';
66
+ ngOnInit() {
67
+ if (!this.userId) {
68
+ return;
69
+ }
70
+ void this.facade.load(this.userId);
71
+ }
72
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformUserDetailPage, deps: [], target: i0.ɵɵFactoryTarget.Component });
73
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: PlatformUserDetailPage, isStandalone: true, selector: "rolatech-platform-user-detail-page", providers: [PlatformUserDetailFacade], ngImport: i0, template: "<section class=\"rt-platform-theme flex flex-col gap-6 bg-(--rt-base-background) p-6 text-(--rt-text-primary)\">\n @if (facade.loading()) {\n <section class=\"rounded-2xl border border-(--rt-border-color) bg-card p-10 text-center text-muted-foreground shadow-sm\">Loading user...</section>\n } @else if (facade.item(); as item) {\n <rolatech-platform-page-header>\n <div header-left class=\"space-y-2\">\n <div class=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <a routerLink=\"../\" class=\"hover:underline cursor-pointer\">Users</a>\n <span>/</span>\n <span>{{ facade.displayName() }}</span>\n </div>\n\n <div>\n <h1 class=\"text-2xl font-semibold tracking-tight\">{{ facade.displayName() }}</h1>\n <div class=\"mt-1 text-sm text-muted-foreground\">@if (item.username) { &#64;{{ item.username }} } @else { {{ item.id }} }</div>\n </div>\n\n <div class=\"flex flex-wrap gap-2\">\n <span class=\"rt-platform-chip rt-platform-chip--status\">{{ item.status || 'UNKNOWN' }}</span>\n @for (role of item.platformRoles ?? []; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n }\n </div>\n </div>\n </rolatech-platform-page-header>\n\n <section class=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <rolatech-platform-stat-card>\n <div stat-label>Platform Roles</div>\n <div stat-value>{{ facade.platformRoleCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Applications</div>\n <div stat-value>{{ facade.applicationCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Organizations</div>\n <div stat-value>{{ facade.organizationCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Permissions</div>\n <div stat-value>{{ facade.permissionCount() }}</div>\n </rolatech-platform-stat-card>\n </section>\n\n <section class=\"grid gap-6 xl:grid-cols-2\">\n <rolatech-platform-detail-panel>\n <div panel-title>Basic Information</div>\n <div panel-description>Primary identity and contact data.</div>\n\n <div class=\"grid gap-4 md:grid-cols-2\">\n <div>\n <div class=\"text-xs text-muted-foreground\">User ID</div>\n <div class=\"font-medium break-all\">{{ item.id }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Username</div>\n <div class=\"font-medium\">{{ item.username || '\u2014' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Email</div>\n <div class=\"font-medium\">{{ item.email || '\u2014' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Phone</div>\n <div class=\"font-medium\">{{ item.phone || '\u2014' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Created At</div>\n <div class=\"font-medium\">{{ item.createdAt || '\u2014' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Status</div>\n <div class=\"font-medium\">{{ item.status || 'UNKNOWN' }}</div>\n </div>\n </div>\n </rolatech-platform-detail-panel>\n\n <rolatech-platform-detail-panel>\n <div panel-title>Platform Access</div>\n <div panel-description>Platform-level roles and permission footprint.</div>\n\n <div class=\"space-y-4\">\n <div>\n <div class=\"text-xs text-muted-foreground\">Platform Roles</div>\n <div class=\"mt-2 flex flex-wrap gap-2\">\n @for (role of item.platformRoles ?? []; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n } @if (!(item.platformRoles?.length)) {\n <span class=\"text-sm text-muted-foreground\">No platform roles returned.</span>\n }\n </div>\n </div>\n\n <div>\n <div class=\"text-xs text-muted-foreground\">Permissions</div>\n <div class=\"mt-2 flex flex-wrap gap-2\">\n @for (permission of (item.permissions ?? []).slice(0, 12); track permission) {\n <span class=\"rt-platform-chip\">{{ permission }}</span>\n } @if (!(item.permissions?.length)) {\n <span class=\"text-sm text-muted-foreground\">No permission details returned.</span>\n } @if ((item.permissions?.length ?? 0) > 12) {\n <span class=\"text-sm text-muted-foreground\">+{{ (item.permissions?.length ?? 0) - 12 }} more</span>\n }\n </div>\n </div>\n </div>\n </rolatech-platform-detail-panel>\n </section>\n\n <section class=\"grid gap-6 xl:grid-cols-2\">\n <rolatech-platform-detail-panel>\n <div panel-title>Application Memberships</div>\n <div panel-description>Applications this user belongs to.</div>\n\n <div class=\"space-y-3\">\n @for (membership of item.applications ?? []; track membership.appId) {\n <a class=\"rt-platform-link-block cursor-pointer\" [routerLink]=\"['/platform/applications', membership.appId]\">\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"min-w-0\">\n <div class=\"font-medium\">{{ membership.appName || membership.appCode || membership.appId }}</div>\n <div class=\"text-sm text-muted-foreground break-all\">{{ membership.appId }}</div>\n </div>\n <div class=\"text-sm text-muted-foreground\">{{ membership.roles.length }} roles</div>\n </div>\n\n <div class=\"mt-3 flex flex-wrap gap-2\">\n @for (role of membership.roles; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n }\n </div>\n </a>\n } @if (!(item.applications?.length)) {\n <div class=\"rounded-2xl border border-(--rt-border-color) border-dashed p-4 text-sm text-muted-foreground\">No application memberships returned.</div>\n }\n </div>\n </rolatech-platform-detail-panel>\n\n <rolatech-platform-detail-panel>\n <div panel-title>Organization Memberships</div>\n <div panel-description>Organizations this user belongs to under those applications.</div>\n\n <div class=\"space-y-3\">\n @for (membership of item.organizations ?? []; track membership.orgId) {\n <div class=\"rt-platform-link-block\">\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"min-w-0\">\n <div class=\"font-medium\">{{ membership.orgName || membership.orgCode || membership.orgId }}</div>\n <div class=\"text-sm text-muted-foreground break-all\">{{ membership.orgId }}</div>\n </div>\n <div class=\"text-sm text-muted-foreground break-all\">{{ membership.appId }}</div>\n </div>\n\n <div class=\"mt-3 flex flex-wrap gap-2\">\n @for (role of membership.roles; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n }\n </div>\n </div>\n } @if (!(item.organizations?.length)) {\n <div class=\"rounded-2xl border border-(--rt-border-color) border-dashed p-4 text-sm text-muted-foreground\">\n No organization memberships returned.\n </div>\n }\n </div>\n </rolatech-platform-detail-panel>\n </section>\n } @else {\n <section class=\"rounded-2xl border border-(--rt-border-color) bg-card p-10 text-center text-muted-foreground shadow-sm\">User not found.</section>\n }\n</section>\n", styles: [":host{display:block}.rt-platform-chip{display:inline-flex;align-items:center;border:1px solid var(--rt-outline);border-radius:9999px;padding:.25rem .75rem;font-size:.75rem;font-weight:600;background-color:color-mix(in srgb,var(--rt-brand-color) 10%,transparent);color:var(--rt-text-primary)}.rt-platform-chip--status{background-color:color-mix(in srgb,var(--rt-brand-color) 12%,var(--rt-base-background))}.rt-platform-link-block{display:block;border:1px solid var(--rt-outline);border-radius:1rem;background-color:var(--rt-raised-background);padding:1rem}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: PlatformPageHeader, selector: "rolatech-platform-page-header" }, { kind: "component", type: PlatformStatCard, selector: "rolatech-platform-stat-card" }, { kind: "component", type: PlatformDetailPanel, selector: "rolatech-platform-detail-panel" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
74
+ }
75
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformUserDetailPage, decorators: [{
76
+ type: Component,
77
+ args: [{ selector: 'rolatech-platform-user-detail-page', standalone: true, imports: [RouterLink, PlatformPageHeader, PlatformStatCard, PlatformDetailPanel], changeDetection: ChangeDetectionStrategy.OnPush, providers: [PlatformUserDetailFacade], template: "<section class=\"rt-platform-theme flex flex-col gap-6 bg-(--rt-base-background) p-6 text-(--rt-text-primary)\">\n @if (facade.loading()) {\n <section class=\"rounded-2xl border border-(--rt-border-color) bg-card p-10 text-center text-muted-foreground shadow-sm\">Loading user...</section>\n } @else if (facade.item(); as item) {\n <rolatech-platform-page-header>\n <div header-left class=\"space-y-2\">\n <div class=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <a routerLink=\"../\" class=\"hover:underline cursor-pointer\">Users</a>\n <span>/</span>\n <span>{{ facade.displayName() }}</span>\n </div>\n\n <div>\n <h1 class=\"text-2xl font-semibold tracking-tight\">{{ facade.displayName() }}</h1>\n <div class=\"mt-1 text-sm text-muted-foreground\">@if (item.username) { &#64;{{ item.username }} } @else { {{ item.id }} }</div>\n </div>\n\n <div class=\"flex flex-wrap gap-2\">\n <span class=\"rt-platform-chip rt-platform-chip--status\">{{ item.status || 'UNKNOWN' }}</span>\n @for (role of item.platformRoles ?? []; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n }\n </div>\n </div>\n </rolatech-platform-page-header>\n\n <section class=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <rolatech-platform-stat-card>\n <div stat-label>Platform Roles</div>\n <div stat-value>{{ facade.platformRoleCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Applications</div>\n <div stat-value>{{ facade.applicationCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Organizations</div>\n <div stat-value>{{ facade.organizationCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Permissions</div>\n <div stat-value>{{ facade.permissionCount() }}</div>\n </rolatech-platform-stat-card>\n </section>\n\n <section class=\"grid gap-6 xl:grid-cols-2\">\n <rolatech-platform-detail-panel>\n <div panel-title>Basic Information</div>\n <div panel-description>Primary identity and contact data.</div>\n\n <div class=\"grid gap-4 md:grid-cols-2\">\n <div>\n <div class=\"text-xs text-muted-foreground\">User ID</div>\n <div class=\"font-medium break-all\">{{ item.id }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Username</div>\n <div class=\"font-medium\">{{ item.username || '\u2014' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Email</div>\n <div class=\"font-medium\">{{ item.email || '\u2014' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Phone</div>\n <div class=\"font-medium\">{{ item.phone || '\u2014' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Created At</div>\n <div class=\"font-medium\">{{ item.createdAt || '\u2014' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Status</div>\n <div class=\"font-medium\">{{ item.status || 'UNKNOWN' }}</div>\n </div>\n </div>\n </rolatech-platform-detail-panel>\n\n <rolatech-platform-detail-panel>\n <div panel-title>Platform Access</div>\n <div panel-description>Platform-level roles and permission footprint.</div>\n\n <div class=\"space-y-4\">\n <div>\n <div class=\"text-xs text-muted-foreground\">Platform Roles</div>\n <div class=\"mt-2 flex flex-wrap gap-2\">\n @for (role of item.platformRoles ?? []; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n } @if (!(item.platformRoles?.length)) {\n <span class=\"text-sm text-muted-foreground\">No platform roles returned.</span>\n }\n </div>\n </div>\n\n <div>\n <div class=\"text-xs text-muted-foreground\">Permissions</div>\n <div class=\"mt-2 flex flex-wrap gap-2\">\n @for (permission of (item.permissions ?? []).slice(0, 12); track permission) {\n <span class=\"rt-platform-chip\">{{ permission }}</span>\n } @if (!(item.permissions?.length)) {\n <span class=\"text-sm text-muted-foreground\">No permission details returned.</span>\n } @if ((item.permissions?.length ?? 0) > 12) {\n <span class=\"text-sm text-muted-foreground\">+{{ (item.permissions?.length ?? 0) - 12 }} more</span>\n }\n </div>\n </div>\n </div>\n </rolatech-platform-detail-panel>\n </section>\n\n <section class=\"grid gap-6 xl:grid-cols-2\">\n <rolatech-platform-detail-panel>\n <div panel-title>Application Memberships</div>\n <div panel-description>Applications this user belongs to.</div>\n\n <div class=\"space-y-3\">\n @for (membership of item.applications ?? []; track membership.appId) {\n <a class=\"rt-platform-link-block cursor-pointer\" [routerLink]=\"['/platform/applications', membership.appId]\">\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"min-w-0\">\n <div class=\"font-medium\">{{ membership.appName || membership.appCode || membership.appId }}</div>\n <div class=\"text-sm text-muted-foreground break-all\">{{ membership.appId }}</div>\n </div>\n <div class=\"text-sm text-muted-foreground\">{{ membership.roles.length }} roles</div>\n </div>\n\n <div class=\"mt-3 flex flex-wrap gap-2\">\n @for (role of membership.roles; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n }\n </div>\n </a>\n } @if (!(item.applications?.length)) {\n <div class=\"rounded-2xl border border-(--rt-border-color) border-dashed p-4 text-sm text-muted-foreground\">No application memberships returned.</div>\n }\n </div>\n </rolatech-platform-detail-panel>\n\n <rolatech-platform-detail-panel>\n <div panel-title>Organization Memberships</div>\n <div panel-description>Organizations this user belongs to under those applications.</div>\n\n <div class=\"space-y-3\">\n @for (membership of item.organizations ?? []; track membership.orgId) {\n <div class=\"rt-platform-link-block\">\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"min-w-0\">\n <div class=\"font-medium\">{{ membership.orgName || membership.orgCode || membership.orgId }}</div>\n <div class=\"text-sm text-muted-foreground break-all\">{{ membership.orgId }}</div>\n </div>\n <div class=\"text-sm text-muted-foreground break-all\">{{ membership.appId }}</div>\n </div>\n\n <div class=\"mt-3 flex flex-wrap gap-2\">\n @for (role of membership.roles; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n }\n </div>\n </div>\n } @if (!(item.organizations?.length)) {\n <div class=\"rounded-2xl border border-(--rt-border-color) border-dashed p-4 text-sm text-muted-foreground\">\n No organization memberships returned.\n </div>\n }\n </div>\n </rolatech-platform-detail-panel>\n </section>\n } @else {\n <section class=\"rounded-2xl border border-(--rt-border-color) bg-card p-10 text-center text-muted-foreground shadow-sm\">User not found.</section>\n }\n</section>\n", styles: [":host{display:block}.rt-platform-chip{display:inline-flex;align-items:center;border:1px solid var(--rt-outline);border-radius:9999px;padding:.25rem .75rem;font-size:.75rem;font-weight:600;background-color:color-mix(in srgb,var(--rt-brand-color) 10%,transparent);color:var(--rt-text-primary)}.rt-platform-chip--status{background-color:color-mix(in srgb,var(--rt-brand-color) 12%,var(--rt-base-background))}.rt-platform-link-block{display:block;border:1px solid var(--rt-outline);border-radius:1rem;background-color:var(--rt-raised-background);padding:1rem}\n"] }]
78
+ }] });
79
+
80
+ export { PlatformUserDetailPage };
81
+ //# sourceMappingURL=rolatech-angular-platform-platform-user-detail-fzo89PHV.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rolatech-angular-platform-platform-user-detail-fzo89PHV.mjs","sources":["../../../../packages/angular-platform/src/lib/store/platform-user-detail.facade.ts","../../../../packages/angular-platform/src/lib/pages/user/platform-user-detail/platform-user-detail.ts","../../../../packages/angular-platform/src/lib/pages/user/platform-user-detail/platform-user-detail.html"],"sourcesContent":["import { Injectable, computed, inject, signal } from '@angular/core';\nimport { firstValueFrom } from 'rxjs';\nimport {\n PlatformUserContextResponse,\n PlatformUserDetailResponse,\n PlatformUserService,\n} from '@rolatech/angular-services';\n\n@Injectable()\nexport class PlatformUserDetailFacade {\n private readonly platformUserService = inject(PlatformUserService);\n\n readonly loading = signal(false);\n readonly error = signal<string | null>(null);\n readonly item = signal<PlatformUserDetailResponse | null>(null);\n\n readonly displayName = computed(() => {\n const item = this.item();\n if (!item) {\n return '';\n }\n\n return item.name || [item.firstName, item.lastName].filter(Boolean).join(' ').trim() || item.username || item.email || item.id;\n });\n\n readonly applicationCount = computed(() => this.item()?.applications?.length ?? 0);\n readonly organizationCount = computed(() => this.item()?.organizations?.length ?? 0);\n readonly platformRoleCount = computed(() => this.item()?.platformRoles?.length ?? 0);\n readonly permissionCount = computed(() => this.item()?.permissions?.length ?? 0);\n\n async load(userId: string): Promise<void> {\n this.loading.set(true);\n this.error.set(null);\n\n try {\n const [detail, context] = await Promise.all([\n firstValueFrom(this.platformUserService.findUserById(userId)),\n firstValueFrom(this.platformUserService.findUserContext(userId)),\n ]);\n\n this.item.set(this.mergeContext(detail, context));\n } catch (error) {\n console.error(error);\n this.item.set(null);\n this.error.set('Unable to load platform user details.');\n } finally {\n this.loading.set(false);\n }\n }\n\n private mergeContext(\n detail: PlatformUserDetailResponse,\n context: PlatformUserContextResponse | null,\n ): PlatformUserDetailResponse {\n if (!context) {\n return detail;\n }\n\n return {\n ...detail,\n platformRoles: detail.platformRoles?.length ? detail.platformRoles : context.platformRoles,\n applications: detail.applications?.length ? detail.applications : context.applications,\n organizations: detail.organizations?.length ? detail.organizations : context.organizations,\n permissions: detail.permissions?.length ? detail.permissions : (context.permissions ?? null),\n };\n }\n}\n","import { ChangeDetectionStrategy, Component, OnInit, inject } from '@angular/core';\nimport { ActivatedRoute, RouterLink } from '@angular/router';\nimport {\n PlatformDetailPanel,\n PlatformPageHeader,\n PlatformStatCard,\n} from '../../../shared';\nimport { PlatformUserDetailFacade } from '../../../store/platform-user-detail.facade';\n\n@Component({\n selector: 'rolatech-platform-user-detail-page',\n standalone: true,\n imports: [RouterLink, PlatformPageHeader, PlatformStatCard, PlatformDetailPanel],\n templateUrl: './platform-user-detail.html',\n styleUrl: './platform-user-detail.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [PlatformUserDetailFacade],\n})\nexport class PlatformUserDetailPage implements OnInit {\n readonly facade = inject(PlatformUserDetailFacade);\n private readonly route = inject(ActivatedRoute);\n\n readonly userId = this.route.snapshot.paramMap.get('userId') ?? '';\n\n ngOnInit(): void {\n if (!this.userId) {\n return;\n }\n\n void this.facade.load(this.userId);\n }\n}\n","<section class=\"rt-platform-theme flex flex-col gap-6 bg-(--rt-base-background) p-6 text-(--rt-text-primary)\">\n @if (facade.loading()) {\n <section class=\"rounded-2xl border border-(--rt-border-color) bg-card p-10 text-center text-muted-foreground shadow-sm\">Loading user...</section>\n } @else if (facade.item(); as item) {\n <rolatech-platform-page-header>\n <div header-left class=\"space-y-2\">\n <div class=\"flex items-center gap-2 text-sm text-muted-foreground\">\n <a routerLink=\"../\" class=\"hover:underline cursor-pointer\">Users</a>\n <span>/</span>\n <span>{{ facade.displayName() }}</span>\n </div>\n\n <div>\n <h1 class=\"text-2xl font-semibold tracking-tight\">{{ facade.displayName() }}</h1>\n <div class=\"mt-1 text-sm text-muted-foreground\">@if (item.username) { &#64;{{ item.username }} } @else { {{ item.id }} }</div>\n </div>\n\n <div class=\"flex flex-wrap gap-2\">\n <span class=\"rt-platform-chip rt-platform-chip--status\">{{ item.status || 'UNKNOWN' }}</span>\n @for (role of item.platformRoles ?? []; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n }\n </div>\n </div>\n </rolatech-platform-page-header>\n\n <section class=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <rolatech-platform-stat-card>\n <div stat-label>Platform Roles</div>\n <div stat-value>{{ facade.platformRoleCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Applications</div>\n <div stat-value>{{ facade.applicationCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Organizations</div>\n <div stat-value>{{ facade.organizationCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Permissions</div>\n <div stat-value>{{ facade.permissionCount() }}</div>\n </rolatech-platform-stat-card>\n </section>\n\n <section class=\"grid gap-6 xl:grid-cols-2\">\n <rolatech-platform-detail-panel>\n <div panel-title>Basic Information</div>\n <div panel-description>Primary identity and contact data.</div>\n\n <div class=\"grid gap-4 md:grid-cols-2\">\n <div>\n <div class=\"text-xs text-muted-foreground\">User ID</div>\n <div class=\"font-medium break-all\">{{ item.id }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Username</div>\n <div class=\"font-medium\">{{ item.username || '—' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Email</div>\n <div class=\"font-medium\">{{ item.email || '—' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Phone</div>\n <div class=\"font-medium\">{{ item.phone || '—' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Created At</div>\n <div class=\"font-medium\">{{ item.createdAt || '—' }}</div>\n </div>\n <div>\n <div class=\"text-xs text-muted-foreground\">Status</div>\n <div class=\"font-medium\">{{ item.status || 'UNKNOWN' }}</div>\n </div>\n </div>\n </rolatech-platform-detail-panel>\n\n <rolatech-platform-detail-panel>\n <div panel-title>Platform Access</div>\n <div panel-description>Platform-level roles and permission footprint.</div>\n\n <div class=\"space-y-4\">\n <div>\n <div class=\"text-xs text-muted-foreground\">Platform Roles</div>\n <div class=\"mt-2 flex flex-wrap gap-2\">\n @for (role of item.platformRoles ?? []; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n } @if (!(item.platformRoles?.length)) {\n <span class=\"text-sm text-muted-foreground\">No platform roles returned.</span>\n }\n </div>\n </div>\n\n <div>\n <div class=\"text-xs text-muted-foreground\">Permissions</div>\n <div class=\"mt-2 flex flex-wrap gap-2\">\n @for (permission of (item.permissions ?? []).slice(0, 12); track permission) {\n <span class=\"rt-platform-chip\">{{ permission }}</span>\n } @if (!(item.permissions?.length)) {\n <span class=\"text-sm text-muted-foreground\">No permission details returned.</span>\n } @if ((item.permissions?.length ?? 0) > 12) {\n <span class=\"text-sm text-muted-foreground\">+{{ (item.permissions?.length ?? 0) - 12 }} more</span>\n }\n </div>\n </div>\n </div>\n </rolatech-platform-detail-panel>\n </section>\n\n <section class=\"grid gap-6 xl:grid-cols-2\">\n <rolatech-platform-detail-panel>\n <div panel-title>Application Memberships</div>\n <div panel-description>Applications this user belongs to.</div>\n\n <div class=\"space-y-3\">\n @for (membership of item.applications ?? []; track membership.appId) {\n <a class=\"rt-platform-link-block cursor-pointer\" [routerLink]=\"['/platform/applications', membership.appId]\">\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"min-w-0\">\n <div class=\"font-medium\">{{ membership.appName || membership.appCode || membership.appId }}</div>\n <div class=\"text-sm text-muted-foreground break-all\">{{ membership.appId }}</div>\n </div>\n <div class=\"text-sm text-muted-foreground\">{{ membership.roles.length }} roles</div>\n </div>\n\n <div class=\"mt-3 flex flex-wrap gap-2\">\n @for (role of membership.roles; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n }\n </div>\n </a>\n } @if (!(item.applications?.length)) {\n <div class=\"rounded-2xl border border-(--rt-border-color) border-dashed p-4 text-sm text-muted-foreground\">No application memberships returned.</div>\n }\n </div>\n </rolatech-platform-detail-panel>\n\n <rolatech-platform-detail-panel>\n <div panel-title>Organization Memberships</div>\n <div panel-description>Organizations this user belongs to under those applications.</div>\n\n <div class=\"space-y-3\">\n @for (membership of item.organizations ?? []; track membership.orgId) {\n <div class=\"rt-platform-link-block\">\n <div class=\"flex items-center justify-between gap-3\">\n <div class=\"min-w-0\">\n <div class=\"font-medium\">{{ membership.orgName || membership.orgCode || membership.orgId }}</div>\n <div class=\"text-sm text-muted-foreground break-all\">{{ membership.orgId }}</div>\n </div>\n <div class=\"text-sm text-muted-foreground break-all\">{{ membership.appId }}</div>\n </div>\n\n <div class=\"mt-3 flex flex-wrap gap-2\">\n @for (role of membership.roles; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n }\n </div>\n </div>\n } @if (!(item.organizations?.length)) {\n <div class=\"rounded-2xl border border-(--rt-border-color) border-dashed p-4 text-sm text-muted-foreground\">\n No organization memberships returned.\n </div>\n }\n </div>\n </rolatech-platform-detail-panel>\n </section>\n } @else {\n <section class=\"rounded-2xl border border-(--rt-border-color) bg-card p-10 text-center text-muted-foreground shadow-sm\">User not found.</section>\n }\n</section>\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, signal, computed, Injectable, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { Router } from '@angular/router';
4
+ import { PlatformPageHeader, PlatformStatCard, PlatformFilterPanel, PlatformDataTable } from './rolatech-angular-platform.mjs';
5
+ import { firstValueFrom } from 'rxjs';
6
+ import { PlatformUserService } from '@rolatech/angular-services';
7
+
8
+ class PlatformUserIndexFacade {
9
+ platformUserService = inject(PlatformUserService);
10
+ loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
11
+ error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
12
+ items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : []));
13
+ keyword = signal('', ...(ngDevMode ? [{ debugName: "keyword" }] : []));
14
+ status = signal('ALL', ...(ngDevMode ? [{ debugName: "status" }] : []));
15
+ filteredItems = computed(() => {
16
+ const keyword = this.keyword().trim().toLowerCase();
17
+ const status = this.status();
18
+ return this.items().filter((item) => {
19
+ const haystack = [item.name, item.username, item.email, ...item.roles].filter(Boolean).join(' ').toLowerCase();
20
+ const matchesKeyword = !keyword || haystack.includes(keyword);
21
+ const matchesStatus = status === 'ALL' || (item.status ?? '').toUpperCase() === status;
22
+ return matchesKeyword && matchesStatus;
23
+ });
24
+ }, ...(ngDevMode ? [{ debugName: "filteredItems" }] : []));
25
+ total = computed(() => this.items().length, ...(ngDevMode ? [{ debugName: "total" }] : []));
26
+ activeCount = computed(() => this.items().filter((item) => (item.status ?? '').toUpperCase() === 'ACTIVE').length, ...(ngDevMode ? [{ debugName: "activeCount" }] : []));
27
+ adminCount = computed(() => this.items().filter((item) => item.roles.some((role) => role.includes('ADMIN') || role.includes('OWNER'))).length, ...(ngDevMode ? [{ debugName: "adminCount" }] : []));
28
+ verifiedEmailCount = computed(() => this.items().filter((item) => !!item.email).length, ...(ngDevMode ? [{ debugName: "verifiedEmailCount" }] : []));
29
+ async load() {
30
+ this.loading.set(true);
31
+ this.error.set(null);
32
+ try {
33
+ const page = await firstValueFrom(this.platformUserService.findUsers({
34
+ limit: 100,
35
+ sort: ['createdAt desc'],
36
+ }));
37
+ this.items.set(page.items ?? []);
38
+ }
39
+ catch (error) {
40
+ console.error(error);
41
+ this.items.set([]);
42
+ this.error.set('Unable to load platform users.');
43
+ }
44
+ finally {
45
+ this.loading.set(false);
46
+ }
47
+ }
48
+ setKeyword(value) {
49
+ this.keyword.set(value);
50
+ }
51
+ setStatus(value) {
52
+ this.status.set(value);
53
+ }
54
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformUserIndexFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
55
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformUserIndexFacade });
56
+ }
57
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformUserIndexFacade, decorators: [{
58
+ type: Injectable
59
+ }] });
60
+
61
+ class PlatformUserIndexPage {
62
+ facade = inject(PlatformUserIndexFacade);
63
+ router = inject(Router);
64
+ ngOnInit() {
65
+ void this.facade.load();
66
+ }
67
+ onKeywordInput(event) {
68
+ this.facade.setKeyword(event.target.value);
69
+ }
70
+ onStatusChange(event) {
71
+ this.facade.setStatus(event.target.value);
72
+ }
73
+ openUser(userId) {
74
+ void this.router.navigate(['/platform/users', userId]);
75
+ }
76
+ displayName(user) {
77
+ const fullName = [user.firstName, user.lastName].filter((value) => Boolean(value?.trim())).join(' ');
78
+ return user.name || fullName || user.username || user.id;
79
+ }
80
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformUserIndexPage, deps: [], target: i0.ɵɵFactoryTarget.Component });
81
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: PlatformUserIndexPage, isStandalone: true, selector: "rolatech-platform-user-index-page", providers: [PlatformUserIndexFacade], ngImport: i0, template: "<section class=\"rt-platform-theme flex flex-col gap-6 bg-(--rt-base-background) p-6 text-(--rt-text-primary)\">\n <rolatech-platform-page-header>\n <div header-left class=\"space-y-1\">\n <h1 class=\"text-2xl font-semibold tracking-tight\">Platform Users</h1>\n <p class=\"text-sm text-muted-foreground\">Inspect platform users and their cross-application access.</p>\n </div>\n </rolatech-platform-page-header>\n\n <section class=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <rolatech-platform-stat-card>\n <div stat-label>Total Users</div>\n <div stat-value>{{ facade.total() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Active Users</div>\n <div stat-value>{{ facade.activeCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Admins / Owners</div>\n <div stat-value>{{ facade.adminCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>With Email</div>\n <div stat-value>{{ facade.verifiedEmailCount() }}</div>\n </rolatech-platform-stat-card>\n </section>\n\n <section class=\"grid gap-6 xl:grid-cols-[320px_minmax(0,1fr)]\">\n <rolatech-platform-filter-panel>\n <div filter-title>Filters</div>\n <div filter-description>Refine visible users.</div>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Search</span>\n <input\n type=\"text\"\n [value]=\"facade.keyword()\"\n (input)=\"onKeywordInput($event)\"\n placeholder=\"Search name, username, email, role\"\n class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\"\n />\n </label>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Status</span>\n <select class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\" (change)=\"onStatusChange($event)\">\n <option value=\"ALL\">All</option>\n <option value=\"ACTIVE\">Active</option>\n <option value=\"LOCKED\">Locked</option>\n <option value=\"DISABLED\">Disabled</option>\n <option value=\"PENDING\">Pending</option>\n </select>\n </label>\n </rolatech-platform-filter-panel>\n\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Users</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.filteredItems().length }} items</div>\n </div>\n\n @if (facade.error()) {\n <p class=\"mb-4 rounded-2xl border border-rose-300/40 bg-rose-500/10 px-4 py-3 text-sm text-(--rt-text-primary)\">\n {{ facade.error() }}\n </p>\n }\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">User</th>\n <th class=\"px-4 py-3 font-medium\">Email</th>\n <th class=\"px-4 py-3 font-medium\">Roles</th>\n <th class=\"px-4 py-3 font-medium\">Status</th>\n <th class=\"px-4 py-3 font-medium\">Joined</th>\n <th class=\"px-4 py-3 font-medium\">Actions</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.loading()) {\n <tr>\n <td colspan=\"6\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading users...</td>\n </tr>\n } @else if (facade.filteredItems().length === 0) {\n <tr>\n <td colspan=\"6\" class=\"px-4 py-10 text-center text-muted-foreground\">No users matched your filters.</td>\n </tr>\n } @else { @for (item of facade.filteredItems(); track item.id) {\n <tr class=\"border-t border-(--rt-border-color)\">\n <td class=\"px-4 py-3\">\n <div class=\"font-medium\">{{ displayName(item) }}</div>\n <div class=\"text-sm text-muted-foreground\">@if (item.username) { &#64;{{ item.username }} } @else { {{ item.id }} }</div>\n </td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.email || '\u2014' }}</td>\n <td class=\"px-4 py-3\">\n <div class=\"flex flex-wrap gap-2\">\n @for (role of item.roles; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n } @if (item.roles.length === 0) {\n <span class=\"text-sm text-muted-foreground\">No direct roles</span>\n }\n </div>\n </td>\n <td class=\"px-4 py-3\">\n <span class=\"rt-platform-chip rt-platform-chip--status\">{{ item.status || 'UNKNOWN' }}</span>\n </td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.createdAt || '\u2014' }}</td>\n <td class=\"px-4 py-3\">\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-3 py-2 text-sm font-medium\"\n (click)=\"openUser(item.id)\"\n >\n View User\n </button>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n </section>\n</section>\n", styles: [":host{display:block}.rt-platform-chip{display:inline-flex;align-items:center;border:1px solid var(--rt-outline);border-radius:9999px;padding:.25rem .75rem;font-size:.75rem;font-weight:600;background-color:color-mix(in srgb,var(--rt-brand-color) 10%,transparent);color:var(--rt-text-primary)}.rt-platform-chip--status{background-color:color-mix(in srgb,var(--rt-brand-color) 12%,var(--rt-base-background))}\n"], dependencies: [{ kind: "component", type: PlatformPageHeader, selector: "rolatech-platform-page-header" }, { kind: "component", type: PlatformStatCard, selector: "rolatech-platform-stat-card" }, { kind: "component", type: PlatformFilterPanel, selector: "rolatech-platform-filter-panel" }, { kind: "component", type: PlatformDataTable, selector: "rolatech-platform-data-table" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
82
+ }
83
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: PlatformUserIndexPage, decorators: [{
84
+ type: Component,
85
+ args: [{ selector: 'rolatech-platform-user-index-page', standalone: true, imports: [PlatformPageHeader, PlatformStatCard, PlatformFilterPanel, PlatformDataTable], changeDetection: ChangeDetectionStrategy.OnPush, providers: [PlatformUserIndexFacade], template: "<section class=\"rt-platform-theme flex flex-col gap-6 bg-(--rt-base-background) p-6 text-(--rt-text-primary)\">\n <rolatech-platform-page-header>\n <div header-left class=\"space-y-1\">\n <h1 class=\"text-2xl font-semibold tracking-tight\">Platform Users</h1>\n <p class=\"text-sm text-muted-foreground\">Inspect platform users and their cross-application access.</p>\n </div>\n </rolatech-platform-page-header>\n\n <section class=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <rolatech-platform-stat-card>\n <div stat-label>Total Users</div>\n <div stat-value>{{ facade.total() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Active Users</div>\n <div stat-value>{{ facade.activeCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Admins / Owners</div>\n <div stat-value>{{ facade.adminCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>With Email</div>\n <div stat-value>{{ facade.verifiedEmailCount() }}</div>\n </rolatech-platform-stat-card>\n </section>\n\n <section class=\"grid gap-6 xl:grid-cols-[320px_minmax(0,1fr)]\">\n <rolatech-platform-filter-panel>\n <div filter-title>Filters</div>\n <div filter-description>Refine visible users.</div>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Search</span>\n <input\n type=\"text\"\n [value]=\"facade.keyword()\"\n (input)=\"onKeywordInput($event)\"\n placeholder=\"Search name, username, email, role\"\n class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\"\n />\n </label>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Status</span>\n <select class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\" (change)=\"onStatusChange($event)\">\n <option value=\"ALL\">All</option>\n <option value=\"ACTIVE\">Active</option>\n <option value=\"LOCKED\">Locked</option>\n <option value=\"DISABLED\">Disabled</option>\n <option value=\"PENDING\">Pending</option>\n </select>\n </label>\n </rolatech-platform-filter-panel>\n\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Users</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.filteredItems().length }} items</div>\n </div>\n\n @if (facade.error()) {\n <p class=\"mb-4 rounded-2xl border border-rose-300/40 bg-rose-500/10 px-4 py-3 text-sm text-(--rt-text-primary)\">\n {{ facade.error() }}\n </p>\n }\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">User</th>\n <th class=\"px-4 py-3 font-medium\">Email</th>\n <th class=\"px-4 py-3 font-medium\">Roles</th>\n <th class=\"px-4 py-3 font-medium\">Status</th>\n <th class=\"px-4 py-3 font-medium\">Joined</th>\n <th class=\"px-4 py-3 font-medium\">Actions</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.loading()) {\n <tr>\n <td colspan=\"6\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading users...</td>\n </tr>\n } @else if (facade.filteredItems().length === 0) {\n <tr>\n <td colspan=\"6\" class=\"px-4 py-10 text-center text-muted-foreground\">No users matched your filters.</td>\n </tr>\n } @else { @for (item of facade.filteredItems(); track item.id) {\n <tr class=\"border-t border-(--rt-border-color)\">\n <td class=\"px-4 py-3\">\n <div class=\"font-medium\">{{ displayName(item) }}</div>\n <div class=\"text-sm text-muted-foreground\">@if (item.username) { &#64;{{ item.username }} } @else { {{ item.id }} }</div>\n </td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.email || '\u2014' }}</td>\n <td class=\"px-4 py-3\">\n <div class=\"flex flex-wrap gap-2\">\n @for (role of item.roles; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n } @if (item.roles.length === 0) {\n <span class=\"text-sm text-muted-foreground\">No direct roles</span>\n }\n </div>\n </td>\n <td class=\"px-4 py-3\">\n <span class=\"rt-platform-chip rt-platform-chip--status\">{{ item.status || 'UNKNOWN' }}</span>\n </td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.createdAt || '\u2014' }}</td>\n <td class=\"px-4 py-3\">\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-3 py-2 text-sm font-medium\"\n (click)=\"openUser(item.id)\"\n >\n View User\n </button>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n </section>\n</section>\n", styles: [":host{display:block}.rt-platform-chip{display:inline-flex;align-items:center;border:1px solid var(--rt-outline);border-radius:9999px;padding:.25rem .75rem;font-size:.75rem;font-weight:600;background-color:color-mix(in srgb,var(--rt-brand-color) 10%,transparent);color:var(--rt-text-primary)}.rt-platform-chip--status{background-color:color-mix(in srgb,var(--rt-brand-color) 12%,var(--rt-base-background))}\n"] }]
86
+ }] });
87
+
88
+ export { PlatformUserIndexPage };
89
+ //# sourceMappingURL=rolatech-angular-platform-platform-user-index-DBT4N0zi.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rolatech-angular-platform-platform-user-index-DBT4N0zi.mjs","sources":["../../../../packages/angular-platform/src/lib/store/platform-user-index.facade.ts","../../../../packages/angular-platform/src/lib/pages/user/platform-user-index/platform-user-index.ts","../../../../packages/angular-platform/src/lib/pages/user/platform-user-index/platform-user-index.html"],"sourcesContent":["import { Injectable, computed, inject, signal } from '@angular/core';\nimport { firstValueFrom } from 'rxjs';\nimport { PlatformUserService, PlatformUserSummaryResponse } from '@rolatech/angular-services';\n\n@Injectable()\nexport class PlatformUserIndexFacade {\n private readonly platformUserService = inject(PlatformUserService);\n\n readonly loading = signal(false);\n readonly error = signal<string | null>(null);\n readonly items = signal<PlatformUserSummaryResponse[]>([]);\n\n readonly keyword = signal('');\n readonly status = signal<'ALL' | 'ACTIVE' | 'LOCKED' | 'DISABLED' | 'PENDING'>('ALL');\n\n readonly filteredItems = computed(() => {\n const keyword = this.keyword().trim().toLowerCase();\n const status = this.status();\n\n return this.items().filter((item) => {\n const haystack = [item.name, item.username, item.email, ...item.roles].filter(Boolean).join(' ').toLowerCase();\n const matchesKeyword = !keyword || haystack.includes(keyword);\n const matchesStatus = status === 'ALL' || (item.status ?? '').toUpperCase() === status;\n\n return matchesKeyword && matchesStatus;\n });\n });\n\n readonly total = computed(() => this.items().length);\n readonly activeCount = computed(() => this.items().filter((item) => (item.status ?? '').toUpperCase() === 'ACTIVE').length);\n readonly adminCount = computed(() =>\n this.items().filter((item) => item.roles.some((role) => role.includes('ADMIN') || role.includes('OWNER'))).length,\n );\n readonly verifiedEmailCount = computed(() => this.items().filter((item) => !!item.email).length);\n\n async load(): Promise<void> {\n this.loading.set(true);\n this.error.set(null);\n\n try {\n const page = await firstValueFrom(\n this.platformUserService.findUsers({\n limit: 100,\n sort: ['createdAt desc'],\n }),\n );\n this.items.set(page.items ?? []);\n } catch (error) {\n console.error(error);\n this.items.set([]);\n this.error.set('Unable to load platform users.');\n } finally {\n this.loading.set(false);\n }\n }\n\n setKeyword(value: string): void {\n this.keyword.set(value);\n }\n\n setStatus(value: 'ALL' | 'ACTIVE' | 'LOCKED' | 'DISABLED' | 'PENDING'): void {\n this.status.set(value);\n }\n}\n","import { ChangeDetectionStrategy, Component, OnInit, inject } from '@angular/core';\nimport { Router } from '@angular/router';\nimport {\n PlatformDataTable,\n PlatformFilterPanel,\n PlatformPageHeader,\n PlatformStatCard,\n} from '../../../shared';\nimport { PlatformUserIndexFacade } from '../../../store/platform-user-index.facade';\nimport { PlatformUserSummaryResponse } from '@rolatech/angular-services';\n\n@Component({\n selector: 'rolatech-platform-user-index-page',\n standalone: true,\n imports: [PlatformPageHeader, PlatformStatCard, PlatformFilterPanel, PlatformDataTable],\n templateUrl: './platform-user-index.html',\n styleUrl: './platform-user-index.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [PlatformUserIndexFacade],\n})\nexport class PlatformUserIndexPage implements OnInit {\n readonly facade = inject(PlatformUserIndexFacade);\n private readonly router = inject(Router);\n\n ngOnInit(): void {\n void this.facade.load();\n }\n\n onKeywordInput(event: Event): void {\n this.facade.setKeyword((event.target as HTMLInputElement).value);\n }\n\n onStatusChange(event: Event): void {\n this.facade.setStatus((event.target as HTMLSelectElement).value as 'ALL' | 'ACTIVE' | 'LOCKED' | 'DISABLED' | 'PENDING');\n }\n\n openUser(userId: string): void {\n void this.router.navigate(['/platform/users', userId]);\n }\n\n displayName(user: PlatformUserSummaryResponse): string {\n const fullName = [user.firstName, user.lastName].filter((value) => Boolean(value?.trim())).join(' ');\n return user.name || fullName || user.username || user.id;\n }\n}\n","<section class=\"rt-platform-theme flex flex-col gap-6 bg-(--rt-base-background) p-6 text-(--rt-text-primary)\">\n <rolatech-platform-page-header>\n <div header-left class=\"space-y-1\">\n <h1 class=\"text-2xl font-semibold tracking-tight\">Platform Users</h1>\n <p class=\"text-sm text-muted-foreground\">Inspect platform users and their cross-application access.</p>\n </div>\n </rolatech-platform-page-header>\n\n <section class=\"grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <rolatech-platform-stat-card>\n <div stat-label>Total Users</div>\n <div stat-value>{{ facade.total() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Active Users</div>\n <div stat-value>{{ facade.activeCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Admins / Owners</div>\n <div stat-value>{{ facade.adminCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>With Email</div>\n <div stat-value>{{ facade.verifiedEmailCount() }}</div>\n </rolatech-platform-stat-card>\n </section>\n\n <section class=\"grid gap-6 xl:grid-cols-[320px_minmax(0,1fr)]\">\n <rolatech-platform-filter-panel>\n <div filter-title>Filters</div>\n <div filter-description>Refine visible users.</div>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Search</span>\n <input\n type=\"text\"\n [value]=\"facade.keyword()\"\n (input)=\"onKeywordInput($event)\"\n placeholder=\"Search name, username, email, role\"\n class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\"\n />\n </label>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Status</span>\n <select class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\" (change)=\"onStatusChange($event)\">\n <option value=\"ALL\">All</option>\n <option value=\"ACTIVE\">Active</option>\n <option value=\"LOCKED\">Locked</option>\n <option value=\"DISABLED\">Disabled</option>\n <option value=\"PENDING\">Pending</option>\n </select>\n </label>\n </rolatech-platform-filter-panel>\n\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Users</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.filteredItems().length }} items</div>\n </div>\n\n @if (facade.error()) {\n <p class=\"mb-4 rounded-2xl border border-rose-300/40 bg-rose-500/10 px-4 py-3 text-sm text-(--rt-text-primary)\">\n {{ facade.error() }}\n </p>\n }\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">User</th>\n <th class=\"px-4 py-3 font-medium\">Email</th>\n <th class=\"px-4 py-3 font-medium\">Roles</th>\n <th class=\"px-4 py-3 font-medium\">Status</th>\n <th class=\"px-4 py-3 font-medium\">Joined</th>\n <th class=\"px-4 py-3 font-medium\">Actions</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.loading()) {\n <tr>\n <td colspan=\"6\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading users...</td>\n </tr>\n } @else if (facade.filteredItems().length === 0) {\n <tr>\n <td colspan=\"6\" class=\"px-4 py-10 text-center text-muted-foreground\">No users matched your filters.</td>\n </tr>\n } @else { @for (item of facade.filteredItems(); track item.id) {\n <tr class=\"border-t border-(--rt-border-color)\">\n <td class=\"px-4 py-3\">\n <div class=\"font-medium\">{{ displayName(item) }}</div>\n <div class=\"text-sm text-muted-foreground\">@if (item.username) { &#64;{{ item.username }} } @else { {{ item.id }} }</div>\n </td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.email || '—' }}</td>\n <td class=\"px-4 py-3\">\n <div class=\"flex flex-wrap gap-2\">\n @for (role of item.roles; track role) {\n <span class=\"rt-platform-chip\">{{ role }}</span>\n } @if (item.roles.length === 0) {\n <span class=\"text-sm text-muted-foreground\">No direct roles</span>\n }\n </div>\n </td>\n <td class=\"px-4 py-3\">\n <span class=\"rt-platform-chip rt-platform-chip--status\">{{ item.status || 'UNKNOWN' }}</span>\n </td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.createdAt || '—' }}</td>\n <td class=\"px-4 py-3\">\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-3 py-2 text-sm font-medium\"\n (click)=\"openUser(item.id)\"\n >\n View User\n </button>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n </section>\n</section>\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ const PLATFORM_USER_ROUTES = [
2
+ {
3
+ path: '',
4
+ loadComponent: () => import('./rolatech-angular-platform-platform-user-index-DBT4N0zi.mjs').then((m) => m.PlatformUserIndexPage),
5
+ },
6
+ {
7
+ path: ':userId',
8
+ loadComponent: () => import('./rolatech-angular-platform-platform-user-detail-fzo89PHV.mjs').then((m) => m.PlatformUserDetailPage),
9
+ },
10
+ ];
11
+
12
+ export { PLATFORM_USER_ROUTES };
13
+ //# sourceMappingURL=rolatech-angular-platform-platform-user.routes-C6OoAsWU.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rolatech-angular-platform-platform-user.routes-C6OoAsWU.mjs","sources":["../../../../packages/angular-platform/src/lib/pages/user/platform-user.routes.ts"],"sourcesContent":["import { Routes } from '@angular/router';\n\nexport const PLATFORM_USER_ROUTES: Routes = [\n {\n path: '',\n loadComponent: () => import('./platform-user-index/platform-user-index').then((m) => m.PlatformUserIndexPage),\n },\n {\n path: ':userId',\n loadComponent: () => import('./platform-user-detail/platform-user-detail').then((m) => m.PlatformUserDetailPage),\n },\n];\n"],"names":[],"mappings":"AAEO,MAAM,oBAAoB,GAAW;AAC1C,IAAA;AACE,QAAA,IAAI,EAAE,EAAE;AACR,QAAA,aAAa,EAAE,MAAM,OAAO,8DAA2C,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,qBAAqB,CAAC;AAC9G,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,SAAS;AACf,QAAA,aAAa,EAAE,MAAM,OAAO,+DAA6C,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,sBAAsB,CAAC;AACjH,KAAA;;;;;"}