@rolatech/angular-platform 20.3.0-beta.2 → 20.3.0-beta.4
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.
- package/fesm2022/rolatech-angular-platform-application-create-CwJeutMN.mjs +138 -0
- package/fesm2022/rolatech-angular-platform-application-create-CwJeutMN.mjs.map +1 -0
- package/fesm2022/rolatech-angular-platform-application-detail-Bzgydts3.mjs +54 -0
- package/fesm2022/rolatech-angular-platform-application-detail-Bzgydts3.mjs.map +1 -0
- package/fesm2022/rolatech-angular-platform-application-member-detail-D3ESzMBX.mjs +72 -0
- package/fesm2022/rolatech-angular-platform-application-member-detail-D3ESzMBX.mjs.map +1 -0
- package/fesm2022/rolatech-angular-platform-application-member-index-D7po13YP.mjs +135 -0
- package/fesm2022/rolatech-angular-platform-application-member-index-D7po13YP.mjs.map +1 -0
- package/fesm2022/rolatech-angular-platform-application-organization-index-CX4KNdF7.mjs +55 -0
- package/fesm2022/rolatech-angular-platform-application-organization-index-CX4KNdF7.mjs.map +1 -0
- package/fesm2022/rolatech-angular-platform-application-role-index-BymGtx1Z.mjs +67 -0
- package/fesm2022/rolatech-angular-platform-application-role-index-BymGtx1Z.mjs.map +1 -0
- package/fesm2022/{rolatech-angular-platform-application-routes-DE5CJMgn.mjs → rolatech-angular-platform-application-routes-kbstcOg1.mjs} +16 -8
- package/fesm2022/rolatech-angular-platform-application-routes-kbstcOg1.mjs.map +1 -0
- package/fesm2022/rolatech-angular-platform-application-workspace-shell-MPkdKJ2X.mjs +73 -0
- package/fesm2022/rolatech-angular-platform-application-workspace-shell-MPkdKJ2X.mjs.map +1 -0
- package/fesm2022/rolatech-angular-platform-role-permission-index-B4-9h-mZ.mjs +157 -0
- package/fesm2022/rolatech-angular-platform-role-permission-index-B4-9h-mZ.mjs.map +1 -0
- package/fesm2022/{rolatech-angular-platform-role-permission-page-DslhArZQ.mjs → rolatech-angular-platform-role-permission-page-CgRpVi8e.mjs} +12 -3
- package/fesm2022/rolatech-angular-platform-role-permission-page-CgRpVi8e.mjs.map +1 -0
- package/fesm2022/{rolatech-angular-platform-role-permission-page.routes-IiX17wDW.mjs → rolatech-angular-platform-role-permission-page.routes-D8wuIMCR.mjs} +2 -2
- package/fesm2022/{rolatech-angular-platform-role-permission-page.routes-IiX17wDW.mjs.map → rolatech-angular-platform-role-permission-page.routes-D8wuIMCR.mjs.map} +1 -1
- package/fesm2022/rolatech-angular-platform.mjs +19 -3
- package/fesm2022/rolatech-angular-platform.mjs.map +1 -1
- package/package.json +1 -1
- package/fesm2022/rolatech-angular-platform-application-create-DqPMquaO.mjs +0 -129
- package/fesm2022/rolatech-angular-platform-application-create-DqPMquaO.mjs.map +0 -1
- package/fesm2022/rolatech-angular-platform-application-detail-BoITs_yE.mjs +0 -54
- package/fesm2022/rolatech-angular-platform-application-detail-BoITs_yE.mjs.map +0 -1
- package/fesm2022/rolatech-angular-platform-application-organization-index-D7TJ8CID.mjs +0 -54
- package/fesm2022/rolatech-angular-platform-application-organization-index-D7TJ8CID.mjs.map +0 -1
- package/fesm2022/rolatech-angular-platform-application-role-index-9_XVRBgD.mjs +0 -66
- package/fesm2022/rolatech-angular-platform-application-role-index-9_XVRBgD.mjs.map +0 -1
- package/fesm2022/rolatech-angular-platform-application-routes-DE5CJMgn.mjs.map +0 -1
- package/fesm2022/rolatech-angular-platform-platform-role-index-8kRxDJiW.mjs +0 -35
- package/fesm2022/rolatech-angular-platform-platform-role-index-8kRxDJiW.mjs.map +0 -1
- package/fesm2022/rolatech-angular-platform-role-permission-page-DslhArZQ.mjs.map +0 -1
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, signal, computed, Injectable, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { ActivatedRoute, Router, RouterLink } from '@angular/router';
|
|
4
|
+
import { PlatformStatCard, PlatformFilterPanel, PlatformDataTable } from './rolatech-angular-platform.mjs';
|
|
5
|
+
import { firstValueFrom } from 'rxjs';
|
|
6
|
+
import { ApplicationService } from '@rolatech/angular-services';
|
|
7
|
+
import { A as ApplicationWorkspaceShell } from './rolatech-angular-platform-application-workspace-shell-MPkdKJ2X.mjs';
|
|
8
|
+
|
|
9
|
+
class ApplicationMemberIndexFacade {
|
|
10
|
+
applicationService = inject(ApplicationService);
|
|
11
|
+
loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
12
|
+
error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
13
|
+
items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
14
|
+
keyword = signal('', ...(ngDevMode ? [{ debugName: "keyword" }] : []));
|
|
15
|
+
status = signal('ALL', ...(ngDevMode ? [{ debugName: "status" }] : []));
|
|
16
|
+
filteredItems = computed(() => {
|
|
17
|
+
const keyword = this.keyword().trim().toLowerCase();
|
|
18
|
+
const status = this.status();
|
|
19
|
+
return this.items().filter((item) => {
|
|
20
|
+
const haystack = [
|
|
21
|
+
item.name,
|
|
22
|
+
item.fullName,
|
|
23
|
+
item.firstName,
|
|
24
|
+
item.lastName,
|
|
25
|
+
item.username,
|
|
26
|
+
item.email,
|
|
27
|
+
item.phone,
|
|
28
|
+
...item.roles,
|
|
29
|
+
]
|
|
30
|
+
.filter(Boolean)
|
|
31
|
+
.join(' ')
|
|
32
|
+
.toLowerCase();
|
|
33
|
+
const matchesKeyword = !keyword || haystack.includes(keyword);
|
|
34
|
+
const matchesStatus = status === 'ALL' || (item.status ?? '').toUpperCase() === status;
|
|
35
|
+
return matchesKeyword && matchesStatus;
|
|
36
|
+
});
|
|
37
|
+
}, ...(ngDevMode ? [{ debugName: "filteredItems" }] : []));
|
|
38
|
+
total = computed(() => this.items().length, ...(ngDevMode ? [{ debugName: "total" }] : []));
|
|
39
|
+
activeCount = computed(() => this.items().filter((item) => (item.status ?? '').toUpperCase() === 'ACTIVE').length, ...(ngDevMode ? [{ debugName: "activeCount" }] : []));
|
|
40
|
+
verifiedCount = computed(() => this.items().filter((item) => {
|
|
41
|
+
const verification = item.verification;
|
|
42
|
+
return !!verification && (verification.emailVerified || verification.phoneVerified || verification.identityVerified);
|
|
43
|
+
}).length, ...(ngDevMode ? [{ debugName: "verifiedCount" }] : []));
|
|
44
|
+
totalOrganizations = computed(() => this.items().reduce((sum, item) => sum + (item.organizationCount ?? 0), 0), ...(ngDevMode ? [{ debugName: "totalOrganizations" }] : []));
|
|
45
|
+
async load(appId) {
|
|
46
|
+
if (!appId) {
|
|
47
|
+
this.items.set([]);
|
|
48
|
+
this.error.set('Application context is missing.');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
this.loading.set(true);
|
|
52
|
+
this.error.set(null);
|
|
53
|
+
try {
|
|
54
|
+
const page = await firstValueFrom(this.applicationService.findApplicationMembers(appId, {
|
|
55
|
+
limit: 100,
|
|
56
|
+
sort: ['joinedAt desc'],
|
|
57
|
+
}));
|
|
58
|
+
this.items.set(page.items ?? []);
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
console.error(error);
|
|
62
|
+
this.items.set([]);
|
|
63
|
+
this.error.set('Unable to load application members.');
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
this.loading.set(false);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
setKeyword(value) {
|
|
70
|
+
this.keyword.set(value);
|
|
71
|
+
}
|
|
72
|
+
setStatus(value) {
|
|
73
|
+
this.status.set(value);
|
|
74
|
+
}
|
|
75
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationMemberIndexFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
76
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationMemberIndexFacade });
|
|
77
|
+
}
|
|
78
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationMemberIndexFacade, decorators: [{
|
|
79
|
+
type: Injectable
|
|
80
|
+
}] });
|
|
81
|
+
|
|
82
|
+
class ApplicationMemberIndex {
|
|
83
|
+
facade = inject(ApplicationMemberIndexFacade);
|
|
84
|
+
route = inject(ActivatedRoute);
|
|
85
|
+
router = inject(Router);
|
|
86
|
+
appId = this.route.snapshot.paramMap.get('appId') ?? '';
|
|
87
|
+
ngOnInit() {
|
|
88
|
+
void this.facade.load(this.appId);
|
|
89
|
+
}
|
|
90
|
+
onKeywordInput(event) {
|
|
91
|
+
this.facade.setKeyword(event.target.value);
|
|
92
|
+
}
|
|
93
|
+
onStatusChange(event) {
|
|
94
|
+
this.facade.setStatus(event.target.value);
|
|
95
|
+
}
|
|
96
|
+
openMember(member) {
|
|
97
|
+
const memberId = member.memberId || member.userId;
|
|
98
|
+
if (!memberId) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
void this.router.navigate([memberId], { relativeTo: this.route });
|
|
102
|
+
}
|
|
103
|
+
displayName(member) {
|
|
104
|
+
return (member.name ||
|
|
105
|
+
member.fullName ||
|
|
106
|
+
[member.firstName, member.lastName].filter((value) => Boolean(value?.trim())).join(' ') ||
|
|
107
|
+
member.username ||
|
|
108
|
+
member.email ||
|
|
109
|
+
member.memberId);
|
|
110
|
+
}
|
|
111
|
+
verificationSummary(member) {
|
|
112
|
+
const verification = member.verification;
|
|
113
|
+
if (!verification) {
|
|
114
|
+
return 'Pending';
|
|
115
|
+
}
|
|
116
|
+
const labels = [
|
|
117
|
+
verification.emailVerified ? 'Email' : null,
|
|
118
|
+
verification.phoneVerified ? 'Phone' : null,
|
|
119
|
+
verification.identityVerified ? 'Identity' : null,
|
|
120
|
+
].filter((item) => !!item);
|
|
121
|
+
if (labels.length > 0) {
|
|
122
|
+
return labels.join(', ');
|
|
123
|
+
}
|
|
124
|
+
return verification.status || 'Pending';
|
|
125
|
+
}
|
|
126
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationMemberIndex, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
127
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: ApplicationMemberIndex, isStandalone: true, selector: "rolatech-application-member-index", providers: [ApplicationMemberIndexFacade], ngImport: i0, template: "<rolatech-application-workspace-shell\n [appId]=\"appId\"\n activeTab=\"members\"\n sectionTitle=\"Members\"\n sectionDescription=\"Inspect everyone who belongs to this application workspace.\"\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 Members</div>\n <div stat-value>{{ facade.total() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Active Members</div>\n <div stat-value>{{ facade.activeCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>With Verification</div>\n <div stat-value>{{ facade.verifiedCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Organization Links</div>\n <div stat-value>{{ facade.totalOrganizations() }}</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 the visible member list.</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 member, email, phone, 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=\"PENDING\">Pending</option>\n <option value=\"LOCKED\">Locked</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\">Members</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\">Member</th>\n <th class=\"px-4 py-3 font-medium\">Email</th>\n <th class=\"px-4 py-3 font-medium\">Phone</th>\n <th class=\"px-4 py-3 font-medium\">Verification</th>\n <th class=\"px-4 py-3 font-medium\">Organizations</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\">Actions</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.loading()) {\n <tr>\n <td colspan=\"8\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading application members...</td>\n </tr>\n } @else if (facade.filteredItems().length === 0) {\n <tr>\n <td colspan=\"8\" class=\"px-4 py-10 text-center text-muted-foreground\">No members matched your filters.</td>\n </tr>\n } @else { @for (item of facade.filteredItems(); track item.memberId) {\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) { @{{ item.username }} } @else { {{ item.userId || item.memberId }} }</div>\n </td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.email || '\u2014' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.phone || '\u2014' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ verificationSummary(item) }}</td>\n <td class=\"px-4 py-3\">{{ item.organizationCount ?? 0 }}</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 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\">\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)=\"openMember(item)\"\n >\n View Member\n </button>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n </section>\n</rolatech-application-workspace-shell>\n", styles: [""], dependencies: [{ kind: "component", type: ApplicationWorkspaceShell, selector: "rolatech-application-workspace-shell", inputs: ["appId", "activeTab", "sectionTitle", "sectionDescription", "showEditButton"] }, { 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 });
|
|
128
|
+
}
|
|
129
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationMemberIndex, decorators: [{
|
|
130
|
+
type: Component,
|
|
131
|
+
args: [{ selector: 'rolatech-application-member-index', standalone: true, imports: [RouterLink, ApplicationWorkspaceShell, PlatformStatCard, PlatformFilterPanel, PlatformDataTable], changeDetection: ChangeDetectionStrategy.OnPush, providers: [ApplicationMemberIndexFacade], template: "<rolatech-application-workspace-shell\n [appId]=\"appId\"\n activeTab=\"members\"\n sectionTitle=\"Members\"\n sectionDescription=\"Inspect everyone who belongs to this application workspace.\"\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 Members</div>\n <div stat-value>{{ facade.total() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Active Members</div>\n <div stat-value>{{ facade.activeCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>With Verification</div>\n <div stat-value>{{ facade.verifiedCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Organization Links</div>\n <div stat-value>{{ facade.totalOrganizations() }}</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 the visible member list.</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 member, email, phone, 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=\"PENDING\">Pending</option>\n <option value=\"LOCKED\">Locked</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\">Members</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\">Member</th>\n <th class=\"px-4 py-3 font-medium\">Email</th>\n <th class=\"px-4 py-3 font-medium\">Phone</th>\n <th class=\"px-4 py-3 font-medium\">Verification</th>\n <th class=\"px-4 py-3 font-medium\">Organizations</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\">Actions</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.loading()) {\n <tr>\n <td colspan=\"8\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading application members...</td>\n </tr>\n } @else if (facade.filteredItems().length === 0) {\n <tr>\n <td colspan=\"8\" class=\"px-4 py-10 text-center text-muted-foreground\">No members matched your filters.</td>\n </tr>\n } @else { @for (item of facade.filteredItems(); track item.memberId) {\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) { @{{ item.username }} } @else { {{ item.userId || item.memberId }} }</div>\n </td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.email || '\u2014' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.phone || '\u2014' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ verificationSummary(item) }}</td>\n <td class=\"px-4 py-3\">{{ item.organizationCount ?? 0 }}</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 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\">\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)=\"openMember(item)\"\n >\n View Member\n </button>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n </section>\n</rolatech-application-workspace-shell>\n" }]
|
|
132
|
+
}] });
|
|
133
|
+
|
|
134
|
+
export { ApplicationMemberIndex };
|
|
135
|
+
//# sourceMappingURL=rolatech-angular-platform-application-member-index-D7po13YP.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rolatech-angular-platform-application-member-index-D7po13YP.mjs","sources":["../../../../packages/angular-platform/src/lib/store/application-member-index.facade.ts","../../../../packages/angular-platform/src/lib/pages/application/application-member-index/application-member-index.ts","../../../../packages/angular-platform/src/lib/pages/application/application-member-index/application-member-index.html"],"sourcesContent":["import { Injectable, computed, inject, signal } from '@angular/core';\nimport { firstValueFrom } from 'rxjs';\nimport { ApplicationMemberSummaryResponse, ApplicationService } from '@rolatech/angular-services';\n\n@Injectable()\nexport class ApplicationMemberIndexFacade {\n private readonly applicationService = inject(ApplicationService);\n\n readonly loading = signal(false);\n readonly error = signal<string | null>(null);\n readonly items = signal<ApplicationMemberSummaryResponse[]>([]);\n\n readonly keyword = signal('');\n readonly status = signal<'ALL' | 'ACTIVE' | 'PENDING' | 'LOCKED' | '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 = [\n item.name,\n item.fullName,\n item.firstName,\n item.lastName,\n item.username,\n item.email,\n item.phone,\n ...item.roles,\n ]\n .filter(Boolean)\n .join(' ')\n .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 verifiedCount = computed(() =>\n this.items().filter((item) => {\n const verification = item.verification;\n return !!verification && (verification.emailVerified || verification.phoneVerified || verification.identityVerified);\n }).length,\n );\n readonly totalOrganizations = computed(() =>\n this.items().reduce((sum, item) => sum + (item.organizationCount ?? 0), 0),\n );\n\n async load(appId: string): Promise<void> {\n if (!appId) {\n this.items.set([]);\n this.error.set('Application context is missing.');\n return;\n }\n\n this.loading.set(true);\n this.error.set(null);\n\n try {\n const page = await firstValueFrom(\n this.applicationService.findApplicationMembers(appId, {\n limit: 100,\n sort: ['joinedAt desc'],\n }),\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 application members.');\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' | 'PENDING' | 'LOCKED' | 'DISABLED'): void {\n this.status.set(value);\n }\n}\n","import { ChangeDetectionStrategy, Component, OnInit, inject } from '@angular/core';\nimport { ActivatedRoute, Router, RouterLink } from '@angular/router';\nimport { ApplicationMemberSummaryResponse } from '@rolatech/angular-services';\nimport {\n PlatformDataTable,\n PlatformFilterPanel,\n PlatformStatCard,\n} from '../../../shared';\nimport { ApplicationMemberIndexFacade } from '../../../store/application-member-index.facade';\nimport { ApplicationWorkspaceShell } from '../application-workspace-shell/application-workspace-shell';\n\n@Component({\n selector: 'rolatech-application-member-index',\n standalone: true,\n imports: [RouterLink, ApplicationWorkspaceShell, PlatformStatCard, PlatformFilterPanel, PlatformDataTable],\n templateUrl: './application-member-index.html',\n styleUrl: './application-member-index.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [ApplicationMemberIndexFacade],\n})\nexport class ApplicationMemberIndex implements OnInit {\n readonly facade = inject(ApplicationMemberIndexFacade);\n private readonly route = inject(ActivatedRoute);\n private readonly router = inject(Router);\n\n readonly appId = this.route.snapshot.paramMap.get('appId') ?? '';\n\n ngOnInit(): void {\n void this.facade.load(this.appId);\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' | 'PENDING' | 'LOCKED' | 'DISABLED');\n }\n\n openMember(member: ApplicationMemberSummaryResponse): void {\n const memberId = member.memberId || member.userId;\n if (!memberId) {\n return;\n }\n\n void this.router.navigate([memberId], { relativeTo: this.route });\n }\n\n displayName(member: ApplicationMemberSummaryResponse): string {\n return (\n member.name ||\n member.fullName ||\n [member.firstName, member.lastName].filter((value) => Boolean(value?.trim())).join(' ') ||\n member.username ||\n member.email ||\n member.memberId\n );\n }\n\n verificationSummary(member: ApplicationMemberSummaryResponse): string {\n const verification = member.verification;\n if (!verification) {\n return 'Pending';\n }\n\n const labels = [\n verification.emailVerified ? 'Email' : null,\n verification.phoneVerified ? 'Phone' : null,\n verification.identityVerified ? 'Identity' : null,\n ].filter((item): item is string => !!item);\n\n if (labels.length > 0) {\n return labels.join(', ');\n }\n\n return verification.status || 'Pending';\n }\n}\n","<rolatech-application-workspace-shell\n [appId]=\"appId\"\n activeTab=\"members\"\n sectionTitle=\"Members\"\n sectionDescription=\"Inspect everyone who belongs to this application workspace.\"\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 Members</div>\n <div stat-value>{{ facade.total() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Active Members</div>\n <div stat-value>{{ facade.activeCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>With Verification</div>\n <div stat-value>{{ facade.verifiedCount() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Organization Links</div>\n <div stat-value>{{ facade.totalOrganizations() }}</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 the visible member list.</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 member, email, phone, 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=\"PENDING\">Pending</option>\n <option value=\"LOCKED\">Locked</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\">Members</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\">Member</th>\n <th class=\"px-4 py-3 font-medium\">Email</th>\n <th class=\"px-4 py-3 font-medium\">Phone</th>\n <th class=\"px-4 py-3 font-medium\">Verification</th>\n <th class=\"px-4 py-3 font-medium\">Organizations</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\">Actions</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.loading()) {\n <tr>\n <td colspan=\"8\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading application members...</td>\n </tr>\n } @else if (facade.filteredItems().length === 0) {\n <tr>\n <td colspan=\"8\" class=\"px-4 py-10 text-center text-muted-foreground\">No members matched your filters.</td>\n </tr>\n } @else { @for (item of facade.filteredItems(); track item.memberId) {\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) { @{{ item.username }} } @else { {{ item.userId || item.memberId }} }</div>\n </td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.email || '—' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.phone || '—' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ verificationSummary(item) }}</td>\n <td class=\"px-4 py-3\">{{ item.organizationCount ?? 0 }}</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 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\">\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)=\"openMember(item)\"\n >\n View Member\n </button>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n </section>\n</rolatech-application-workspace-shell>\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, signal, Injectable, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { ActivatedRoute } from '@angular/router';
|
|
4
|
+
import { PlatformDataTable, PlatformStatusBadge } from './rolatech-angular-platform.mjs';
|
|
5
|
+
import { A as ApplicationWorkspaceShell } from './rolatech-angular-platform-application-workspace-shell-MPkdKJ2X.mjs';
|
|
6
|
+
import { firstValueFrom } from 'rxjs';
|
|
7
|
+
import { ApplicationService } from '@rolatech/angular-services';
|
|
8
|
+
|
|
9
|
+
class ApplicationOrganizationIndexFacade {
|
|
10
|
+
applicationService = inject(ApplicationService);
|
|
11
|
+
loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
12
|
+
items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
13
|
+
error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
14
|
+
async load(applicationId) {
|
|
15
|
+
this.loading.set(true);
|
|
16
|
+
this.error.set(null);
|
|
17
|
+
try {
|
|
18
|
+
const page = await firstValueFrom(this.applicationService.findApplicationOrganizations(applicationId));
|
|
19
|
+
this.items.set(page.items ?? []);
|
|
20
|
+
}
|
|
21
|
+
catch (error) {
|
|
22
|
+
console.error(error);
|
|
23
|
+
this.items.set([]);
|
|
24
|
+
this.error.set('Unable to load application organizations.');
|
|
25
|
+
}
|
|
26
|
+
finally {
|
|
27
|
+
this.loading.set(false);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationOrganizationIndexFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
31
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationOrganizationIndexFacade });
|
|
32
|
+
}
|
|
33
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationOrganizationIndexFacade, decorators: [{
|
|
34
|
+
type: Injectable
|
|
35
|
+
}] });
|
|
36
|
+
|
|
37
|
+
class ApplicationOrganizationIndex {
|
|
38
|
+
facade = inject(ApplicationOrganizationIndexFacade);
|
|
39
|
+
route = inject(ActivatedRoute);
|
|
40
|
+
applicationId = this.route.snapshot.paramMap.get('appId') ?? this.route.snapshot.paramMap.get('id') ?? '';
|
|
41
|
+
ngOnInit() {
|
|
42
|
+
if (this.applicationId) {
|
|
43
|
+
void this.facade.load(this.applicationId);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationOrganizationIndex, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
47
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: ApplicationOrganizationIndex, isStandalone: true, selector: "rolatech-application-organization-index", providers: [ApplicationOrganizationIndexFacade], ngImport: i0, template: "<rolatech-application-workspace-shell\n [appId]=\"applicationId\"\n activeTab=\"organizations\"\n sectionTitle=\"Organizations\"\n sectionDescription=\"Organizations that belong to this application.\"\n>\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\">\n Loading organizations...\n </section>\n } @else {\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Organizations</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.items().length }} items</div>\n </div>\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">Name</th>\n <th class=\"px-4 py-3 font-medium\">Code</th>\n <th class=\"px-4 py-3 font-medium\">Status</th>\n <th class=\"px-4 py-3 font-medium\">Members</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.items().length === 0) {\n <tr>\n <td colspan=\"4\" class=\"px-4 py-10 text-center text-muted-foreground\">No organizations found.</td>\n </tr>\n } @else { @for (item of facade.items(); track item.id) {\n <tr class=\"border-t border-(--rt-border-color)\">\n <td class=\"px-4 py-3 font-medium\">{{ item.name }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.code }}</td>\n <td class=\"px-4 py-3\">\n <rolatech-platform-status-badge [status]=\"item.status\" />\n </td>\n <td class=\"px-4 py-3\">{{ item.memberCount }}</td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n }\n</rolatech-application-workspace-shell>\n", dependencies: [{ kind: "component", type: ApplicationWorkspaceShell, selector: "rolatech-application-workspace-shell", inputs: ["appId", "activeTab", "sectionTitle", "sectionDescription", "showEditButton"] }, { kind: "component", type: PlatformDataTable, selector: "rolatech-platform-data-table" }, { kind: "component", type: PlatformStatusBadge, selector: "rolatech-platform-status-badge", inputs: ["status"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
48
|
+
}
|
|
49
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationOrganizationIndex, decorators: [{
|
|
50
|
+
type: Component,
|
|
51
|
+
args: [{ selector: 'rolatech-application-organization-index', standalone: true, imports: [ApplicationWorkspaceShell, PlatformDataTable, PlatformStatusBadge], changeDetection: ChangeDetectionStrategy.OnPush, providers: [ApplicationOrganizationIndexFacade], template: "<rolatech-application-workspace-shell\n [appId]=\"applicationId\"\n activeTab=\"organizations\"\n sectionTitle=\"Organizations\"\n sectionDescription=\"Organizations that belong to this application.\"\n>\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\">\n Loading organizations...\n </section>\n } @else {\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Organizations</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.items().length }} items</div>\n </div>\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">Name</th>\n <th class=\"px-4 py-3 font-medium\">Code</th>\n <th class=\"px-4 py-3 font-medium\">Status</th>\n <th class=\"px-4 py-3 font-medium\">Members</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.items().length === 0) {\n <tr>\n <td colspan=\"4\" class=\"px-4 py-10 text-center text-muted-foreground\">No organizations found.</td>\n </tr>\n } @else { @for (item of facade.items(); track item.id) {\n <tr class=\"border-t border-(--rt-border-color)\">\n <td class=\"px-4 py-3 font-medium\">{{ item.name }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.code }}</td>\n <td class=\"px-4 py-3\">\n <rolatech-platform-status-badge [status]=\"item.status\" />\n </td>\n <td class=\"px-4 py-3\">{{ item.memberCount }}</td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n }\n</rolatech-application-workspace-shell>\n" }]
|
|
52
|
+
}] });
|
|
53
|
+
|
|
54
|
+
export { ApplicationOrganizationIndex };
|
|
55
|
+
//# sourceMappingURL=rolatech-angular-platform-application-organization-index-CX4KNdF7.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rolatech-angular-platform-application-organization-index-CX4KNdF7.mjs","sources":["../../../../packages/angular-platform/src/lib/store/application-organization-index.facade.ts","../../../../packages/angular-platform/src/lib/pages/application/application-organization-index/application-organization-index.ts","../../../../packages/angular-platform/src/lib/pages/application/application-organization-index/application-organization-index.html"],"sourcesContent":["import { Injectable, inject, signal } from '@angular/core';\nimport { firstValueFrom } from 'rxjs';\nimport { ApplicationOrganizationResponse, ApplicationService } from '@rolatech/angular-services';\n\nexport type ApplicationOrganizationItem = ApplicationOrganizationResponse;\n\n@Injectable()\nexport class ApplicationOrganizationIndexFacade {\n private readonly applicationService = inject(ApplicationService);\n\n readonly loading = signal(false);\n readonly items = signal<ApplicationOrganizationItem[]>([]);\n readonly error = signal<string | null>(null);\n\n async load(applicationId: string): Promise<void> {\n this.loading.set(true);\n this.error.set(null);\n try {\n const page = await firstValueFrom(this.applicationService.findApplicationOrganizations(applicationId));\n this.items.set(page.items ?? []);\n } catch (error) {\n console.error(error);\n this.items.set([]);\n this.error.set('Unable to load application organizations.');\n } finally {\n this.loading.set(false);\n }\n }\n}\n","import { ChangeDetectionStrategy, Component, OnInit, inject } from '@angular/core';\nimport { ActivatedRoute } from '@angular/router';\nimport { PlatformDataTable, PlatformStatusBadge } from '../../../shared';\nimport { ApplicationWorkspaceShell } from '../application-workspace-shell/application-workspace-shell';\nimport { ApplicationOrganizationIndexFacade } from '../../../store/application-organization-index.facade';\n\n@Component({\n selector: 'rolatech-application-organization-index',\n standalone: true,\n imports: [ApplicationWorkspaceShell, PlatformDataTable, PlatformStatusBadge],\n templateUrl: './application-organization-index.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [ApplicationOrganizationIndexFacade],\n})\nexport class ApplicationOrganizationIndex implements OnInit {\n readonly facade = inject(ApplicationOrganizationIndexFacade);\n private readonly route = inject(ActivatedRoute);\n\n readonly applicationId = this.route.snapshot.paramMap.get('appId') ?? this.route.snapshot.paramMap.get('id') ?? '';\n\n ngOnInit(): void {\n if (this.applicationId) {\n void this.facade.load(this.applicationId);\n }\n }\n}\n","<rolatech-application-workspace-shell\n [appId]=\"applicationId\"\n activeTab=\"organizations\"\n sectionTitle=\"Organizations\"\n sectionDescription=\"Organizations that belong to this application.\"\n>\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\">\n Loading organizations...\n </section>\n } @else {\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Organizations</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.items().length }} items</div>\n </div>\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">Name</th>\n <th class=\"px-4 py-3 font-medium\">Code</th>\n <th class=\"px-4 py-3 font-medium\">Status</th>\n <th class=\"px-4 py-3 font-medium\">Members</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.items().length === 0) {\n <tr>\n <td colspan=\"4\" class=\"px-4 py-10 text-center text-muted-foreground\">No organizations found.</td>\n </tr>\n } @else { @for (item of facade.items(); track item.id) {\n <tr class=\"border-t border-(--rt-border-color)\">\n <td class=\"px-4 py-3 font-medium\">{{ item.name }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.code }}</td>\n <td class=\"px-4 py-3\">\n <rolatech-platform-status-badge [status]=\"item.status\" />\n </td>\n <td class=\"px-4 py-3\">{{ item.memberCount }}</td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n }\n</rolatech-application-workspace-shell>\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, signal, Injectable, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { ActivatedRoute, Router } from '@angular/router';
|
|
4
|
+
import { PlatformDataTable, PlatformScopeBadge, PlatformStatusBadge } from './rolatech-angular-platform.mjs';
|
|
5
|
+
import { A as ApplicationWorkspaceShell } from './rolatech-angular-platform-application-workspace-shell-MPkdKJ2X.mjs';
|
|
6
|
+
import { firstValueFrom } from 'rxjs';
|
|
7
|
+
import { RoleService } from '@rolatech/angular-services';
|
|
8
|
+
|
|
9
|
+
class ApplicationRoleIndexFacade {
|
|
10
|
+
roleService = inject(RoleService);
|
|
11
|
+
loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
12
|
+
items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
13
|
+
async load(applicationId) {
|
|
14
|
+
if (!applicationId) {
|
|
15
|
+
this.items.set([]);
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
this.loading.set(true);
|
|
19
|
+
try {
|
|
20
|
+
const roles = await firstValueFrom(this.roleService.findApplicationRoles(applicationId));
|
|
21
|
+
this.items.set((roles ?? []).map((role) => this.toRoleItem(role)));
|
|
22
|
+
}
|
|
23
|
+
finally {
|
|
24
|
+
this.loading.set(false);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
toRoleItem(role) {
|
|
28
|
+
return {
|
|
29
|
+
id: role.id,
|
|
30
|
+
name: role.name,
|
|
31
|
+
code: role.code,
|
|
32
|
+
scope: role.scope === 'ORG' ? 'ORG' : 'APP',
|
|
33
|
+
permissionCount: role.permissionIds.length,
|
|
34
|
+
memberCount: 0,
|
|
35
|
+
status: role.enabled ? 'ACTIVE' : 'INACTIVE',
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationRoleIndexFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
39
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationRoleIndexFacade });
|
|
40
|
+
}
|
|
41
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationRoleIndexFacade, decorators: [{
|
|
42
|
+
type: Injectable
|
|
43
|
+
}] });
|
|
44
|
+
|
|
45
|
+
class ApplicationRoleIndex {
|
|
46
|
+
facade = inject(ApplicationRoleIndexFacade);
|
|
47
|
+
route = inject(ActivatedRoute);
|
|
48
|
+
router = inject(Router);
|
|
49
|
+
applicationId = this.route.snapshot.paramMap.get('appId') ?? this.route.snapshot.paramMap.get('id') ?? '';
|
|
50
|
+
ngOnInit() {
|
|
51
|
+
if (this.applicationId) {
|
|
52
|
+
void this.facade.load(this.applicationId);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
openRole(id) {
|
|
56
|
+
void this.router.navigate([id, 'permissions'], { relativeTo: this.route });
|
|
57
|
+
}
|
|
58
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationRoleIndex, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
59
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: ApplicationRoleIndex, isStandalone: true, selector: "rolatech-application-role-index", providers: [ApplicationRoleIndexFacade], ngImport: i0, template: "<rolatech-application-workspace-shell\n [appId]=\"applicationId\"\n activeTab=\"roles\"\n sectionTitle=\"Roles\"\n sectionDescription=\"Roles defined within this application.\"\n>\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 roles...</section>\n } @else {\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Roles</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.items().length }} items</div>\n </div>\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">Name</th>\n <th class=\"px-4 py-3 font-medium\">Code</th>\n <th class=\"px-4 py-3 font-medium\">Scope</th>\n <th class=\"px-4 py-3 font-medium\">Permissions</th>\n <th class=\"px-4 py-3 font-medium\">Members</th>\n <th class=\"px-4 py-3 font-medium\">Status</th>\n <th class=\"px-4 py-3 font-medium\">Actions</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.items().length === 0) {\n <tr>\n <td colspan=\"7\" class=\"px-4 py-10 text-center text-muted-foreground\">No roles found.</td>\n </tr>\n } @else { @for (item of facade.items(); track item.id) {\n <tr class=\"border-t border-(--rt-border-color)\">\n <td class=\"px-4 py-3 font-medium\">{{ item.name }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.code }}</td>\n <td class=\"px-4 py-3\">\n <rolatech-platform-scope-badge [scope]=\"item.scope\" />\n </td>\n <td class=\"px-4 py-3\">{{ item.permissionCount }}</td>\n <td class=\"px-4 py-3\">{{ item.memberCount }}</td>\n <td class=\"px-4 py-3\">\n <rolatech-platform-status-badge [status]=\"item.status\" />\n </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)=\"openRole(item.id)\"\n >\n View Role\n </button>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n }\n</rolatech-application-workspace-shell>\n", dependencies: [{ kind: "component", type: ApplicationWorkspaceShell, selector: "rolatech-application-workspace-shell", inputs: ["appId", "activeTab", "sectionTitle", "sectionDescription", "showEditButton"] }, { kind: "component", type: PlatformDataTable, selector: "rolatech-platform-data-table" }, { kind: "component", type: PlatformScopeBadge, selector: "rolatech-platform-scope-badge", inputs: ["scope"] }, { kind: "component", type: PlatformStatusBadge, selector: "rolatech-platform-status-badge", inputs: ["status"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
60
|
+
}
|
|
61
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationRoleIndex, decorators: [{
|
|
62
|
+
type: Component,
|
|
63
|
+
args: [{ selector: 'rolatech-application-role-index', standalone: true, imports: [ApplicationWorkspaceShell, PlatformDataTable, PlatformScopeBadge, PlatformStatusBadge], changeDetection: ChangeDetectionStrategy.OnPush, providers: [ApplicationRoleIndexFacade], template: "<rolatech-application-workspace-shell\n [appId]=\"applicationId\"\n activeTab=\"roles\"\n sectionTitle=\"Roles\"\n sectionDescription=\"Roles defined within this application.\"\n>\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 roles...</section>\n } @else {\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Roles</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.items().length }} items</div>\n </div>\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">Name</th>\n <th class=\"px-4 py-3 font-medium\">Code</th>\n <th class=\"px-4 py-3 font-medium\">Scope</th>\n <th class=\"px-4 py-3 font-medium\">Permissions</th>\n <th class=\"px-4 py-3 font-medium\">Members</th>\n <th class=\"px-4 py-3 font-medium\">Status</th>\n <th class=\"px-4 py-3 font-medium\">Actions</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.items().length === 0) {\n <tr>\n <td colspan=\"7\" class=\"px-4 py-10 text-center text-muted-foreground\">No roles found.</td>\n </tr>\n } @else { @for (item of facade.items(); track item.id) {\n <tr class=\"border-t border-(--rt-border-color)\">\n <td class=\"px-4 py-3 font-medium\">{{ item.name }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.code }}</td>\n <td class=\"px-4 py-3\">\n <rolatech-platform-scope-badge [scope]=\"item.scope\" />\n </td>\n <td class=\"px-4 py-3\">{{ item.permissionCount }}</td>\n <td class=\"px-4 py-3\">{{ item.memberCount }}</td>\n <td class=\"px-4 py-3\">\n <rolatech-platform-status-badge [status]=\"item.status\" />\n </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)=\"openRole(item.id)\"\n >\n View Role\n </button>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n }\n</rolatech-application-workspace-shell>\n" }]
|
|
64
|
+
}] });
|
|
65
|
+
|
|
66
|
+
export { ApplicationRoleIndex };
|
|
67
|
+
//# sourceMappingURL=rolatech-angular-platform-application-role-index-BymGtx1Z.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rolatech-angular-platform-application-role-index-BymGtx1Z.mjs","sources":["../../../../packages/angular-platform/src/lib/store/application-role-index.facade.ts","../../../../packages/angular-platform/src/lib/pages/application/application-role-index/application-role-index.ts","../../../../packages/angular-platform/src/lib/pages/application/application-role-index/application-role-index.html"],"sourcesContent":["import { Injectable, inject, signal } from '@angular/core';\nimport { firstValueFrom } from 'rxjs';\nimport { RoleResponse, RoleService } from '@rolatech/angular-services';\n\nexport interface ApplicationRoleItem {\n id: string;\n name: string;\n code: string;\n scope: 'APP' | 'ORG';\n permissionCount: number;\n memberCount: number;\n status: 'ACTIVE' | 'INACTIVE' | 'DRAFT';\n}\n\n@Injectable()\nexport class ApplicationRoleIndexFacade {\n private readonly roleService = inject(RoleService);\n\n readonly loading = signal(false);\n readonly items = signal<ApplicationRoleItem[]>([]);\n\n async load(applicationId: string): Promise<void> {\n if (!applicationId) {\n this.items.set([]);\n return;\n }\n\n this.loading.set(true);\n try {\n const roles = await firstValueFrom(this.roleService.findApplicationRoles(applicationId));\n this.items.set((roles ?? []).map((role) => this.toRoleItem(role)));\n } finally {\n this.loading.set(false);\n }\n }\n\n private toRoleItem(role: RoleResponse): ApplicationRoleItem {\n return {\n id: role.id,\n name: role.name,\n code: role.code,\n scope: role.scope === 'ORG' ? 'ORG' : 'APP',\n permissionCount: role.permissionIds.length,\n memberCount: 0,\n status: role.enabled ? 'ACTIVE' : 'INACTIVE',\n };\n }\n}\n","import { ChangeDetectionStrategy, Component, OnInit, inject } from '@angular/core';\nimport { ActivatedRoute, Router } from '@angular/router';\nimport { PlatformDataTable, PlatformScopeBadge, PlatformStatusBadge } from '../../../shared';\nimport { ApplicationWorkspaceShell } from '../application-workspace-shell/application-workspace-shell';\nimport { ApplicationRoleIndexFacade } from '../../../store/application-role-index.facade';\n\n@Component({\n selector: 'rolatech-application-role-index',\n standalone: true,\n imports: [ApplicationWorkspaceShell, PlatformDataTable, PlatformScopeBadge, PlatformStatusBadge],\n templateUrl: './application-role-index.html',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [ApplicationRoleIndexFacade],\n})\nexport class ApplicationRoleIndex implements OnInit {\n readonly facade = inject(ApplicationRoleIndexFacade);\n private readonly route = inject(ActivatedRoute);\n private readonly router = inject(Router);\n\n readonly applicationId = this.route.snapshot.paramMap.get('appId') ?? this.route.snapshot.paramMap.get('id') ?? '';\n\n ngOnInit(): void {\n if (this.applicationId) {\n void this.facade.load(this.applicationId);\n }\n }\n\n openRole(id: string): void {\n void this.router.navigate([id, 'permissions'], { relativeTo: this.route });\n }\n}\n","<rolatech-application-workspace-shell\n [appId]=\"applicationId\"\n activeTab=\"roles\"\n sectionTitle=\"Roles\"\n sectionDescription=\"Roles defined within this application.\"\n>\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 roles...</section>\n } @else {\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Roles</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.items().length }} items</div>\n </div>\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">Name</th>\n <th class=\"px-4 py-3 font-medium\">Code</th>\n <th class=\"px-4 py-3 font-medium\">Scope</th>\n <th class=\"px-4 py-3 font-medium\">Permissions</th>\n <th class=\"px-4 py-3 font-medium\">Members</th>\n <th class=\"px-4 py-3 font-medium\">Status</th>\n <th class=\"px-4 py-3 font-medium\">Actions</th>\n </tr>\n </thead>\n\n <tbody>\n @if (facade.items().length === 0) {\n <tr>\n <td colspan=\"7\" class=\"px-4 py-10 text-center text-muted-foreground\">No roles found.</td>\n </tr>\n } @else { @for (item of facade.items(); track item.id) {\n <tr class=\"border-t border-(--rt-border-color)\">\n <td class=\"px-4 py-3 font-medium\">{{ item.name }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.code }}</td>\n <td class=\"px-4 py-3\">\n <rolatech-platform-scope-badge [scope]=\"item.scope\" />\n </td>\n <td class=\"px-4 py-3\">{{ item.permissionCount }}</td>\n <td class=\"px-4 py-3\">{{ item.memberCount }}</td>\n <td class=\"px-4 py-3\">\n <rolatech-platform-status-badge [status]=\"item.status\" />\n </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)=\"openRole(item.id)\"\n >\n View Role\n </button>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n }\n</rolatech-application-workspace-shell>\n"],"names":[],"mappings":"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"}
|
|
@@ -5,34 +5,42 @@ const APPLICATION_ROUTES = [
|
|
|
5
5
|
},
|
|
6
6
|
{
|
|
7
7
|
path: 'new',
|
|
8
|
-
loadComponent: () => import('./rolatech-angular-platform-application-create-
|
|
8
|
+
loadComponent: () => import('./rolatech-angular-platform-application-create-CwJeutMN.mjs').then((m) => m.ApplicationCreate),
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
path: ':appId',
|
|
12
|
-
loadComponent: () => import('./rolatech-angular-platform-application-detail-
|
|
12
|
+
loadComponent: () => import('./rolatech-angular-platform-application-detail-Bzgydts3.mjs').then((m) => m.ApplicationDetail),
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
path: ':appId/edit',
|
|
16
|
-
loadComponent: () => import('./rolatech-angular-platform-application-create-
|
|
16
|
+
loadComponent: () => import('./rolatech-angular-platform-application-create-CwJeutMN.mjs').then((m) => m.ApplicationCreate),
|
|
17
17
|
},
|
|
18
18
|
{
|
|
19
19
|
path: ':appId/organizations',
|
|
20
|
-
loadComponent: () => import('./rolatech-angular-platform-application-organization-index-
|
|
20
|
+
loadComponent: () => import('./rolatech-angular-platform-application-organization-index-CX4KNdF7.mjs').then((m) => m.ApplicationOrganizationIndex),
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
path: ':appId/members',
|
|
24
|
+
loadComponent: () => import('./rolatech-angular-platform-application-member-index-D7po13YP.mjs').then((m) => m.ApplicationMemberIndex),
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
path: ':appId/members/:memberId',
|
|
28
|
+
loadComponent: () => import('./rolatech-angular-platform-application-member-detail-D3ESzMBX.mjs').then((m) => m.ApplicationMemberDetail),
|
|
21
29
|
},
|
|
22
30
|
{
|
|
23
31
|
path: ':appId/settings',
|
|
24
|
-
loadComponent: () => import('./rolatech-angular-platform-application-
|
|
32
|
+
loadComponent: () => import('./rolatech-angular-platform-application-create-CwJeutMN.mjs').then((m) => m.ApplicationCreate),
|
|
25
33
|
},
|
|
26
34
|
{
|
|
27
35
|
path: ':appId/roles',
|
|
28
|
-
loadComponent: () => import('./rolatech-angular-platform-application-role-index-
|
|
36
|
+
loadComponent: () => import('./rolatech-angular-platform-application-role-index-BymGtx1Z.mjs').then((m) => m.ApplicationRoleIndex),
|
|
29
37
|
},
|
|
30
38
|
{
|
|
31
39
|
path: ':appId/roles/:id/permissions',
|
|
32
40
|
data: { scope: 'application' },
|
|
33
|
-
loadComponent: () => import('./rolatech-angular-platform-role-permission-page-
|
|
41
|
+
loadComponent: () => import('./rolatech-angular-platform-role-permission-page-CgRpVi8e.mjs').then((m) => m.RolePermissionPage),
|
|
34
42
|
},
|
|
35
43
|
];
|
|
36
44
|
|
|
37
45
|
export { APPLICATION_ROUTES };
|
|
38
|
-
//# sourceMappingURL=rolatech-angular-platform-application-routes-
|
|
46
|
+
//# sourceMappingURL=rolatech-angular-platform-application-routes-kbstcOg1.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rolatech-angular-platform-application-routes-kbstcOg1.mjs","sources":["../../../../packages/angular-platform/src/lib/pages/application/application-routes.ts"],"sourcesContent":["import { Routes } from '@angular/router';\n\nexport const APPLICATION_ROUTES: Routes = [\n {\n path: '',\n loadComponent: () => import('./application-index/application-index').then((m) => m.ApplicationIndex),\n },\n {\n path: 'new',\n loadComponent: () => import('./application-create/application-create').then((m) => m.ApplicationCreate),\n },\n {\n path: ':appId',\n loadComponent: () => import('./application-detail/application-detail').then((m) => m.ApplicationDetail),\n },\n {\n path: ':appId/edit',\n loadComponent: () => import('./application-create/application-create').then((m) => m.ApplicationCreate),\n },\n {\n path: ':appId/organizations',\n loadComponent: () =>\n import('./application-organization-index/application-organization-index').then((m) => m.ApplicationOrganizationIndex),\n },\n {\n path: ':appId/members',\n loadComponent: () => import('./application-member-index/application-member-index').then((m) => m.ApplicationMemberIndex),\n },\n {\n path: ':appId/members/:memberId',\n loadComponent: () => import('./application-member-detail/application-member-detail').then((m) => m.ApplicationMemberDetail),\n },\n\n {\n path: ':appId/settings',\n loadComponent: () => import('./application-create/application-create').then((m) => m.ApplicationCreate),\n },\n {\n path: ':appId/roles',\n loadComponent: () => import('./application-role-index/application-role-index').then((m) => m.ApplicationRoleIndex),\n },\n {\n path: ':appId/roles/:id/permissions',\n data: { scope: 'application' },\n loadComponent: () => import('../role/role-permission-page/role-permission-page').then((m) => m.RolePermissionPage),\n },\n];\n"],"names":[],"mappings":"AAEO,MAAM,kBAAkB,GAAW;AACxC,IAAA;AACE,QAAA,IAAI,EAAE,EAAE;AACR,QAAA,aAAa,EAAE,MAAM,OAAO,4DAAuC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,gBAAgB,CAAC;AACrG,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,KAAK;AACX,QAAA,aAAa,EAAE,MAAM,OAAO,6DAAyC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,iBAAiB,CAAC;AACxG,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,QAAQ;AACd,QAAA,aAAa,EAAE,MAAM,OAAO,6DAAyC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,iBAAiB,CAAC;AACxG,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,aAAa;AACnB,QAAA,aAAa,EAAE,MAAM,OAAO,6DAAyC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,iBAAiB,CAAC;AACxG,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,sBAAsB;AAC5B,QAAA,aAAa,EAAE,MACb,OAAO,yEAAiE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,4BAA4B,CAAC;AACxH,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,gBAAgB;AACtB,QAAA,aAAa,EAAE,MAAM,OAAO,mEAAqD,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,sBAAsB,CAAC;AACzH,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,0BAA0B;AAChC,QAAA,aAAa,EAAE,MAAM,OAAO,oEAAuD,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,uBAAuB,CAAC;AAC5H,KAAA;AAED,IAAA;AACE,QAAA,IAAI,EAAE,iBAAiB;AACvB,QAAA,aAAa,EAAE,MAAM,OAAO,6DAAyC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,iBAAiB,CAAC;AACxG,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,cAAc;AACpB,QAAA,aAAa,EAAE,MAAM,OAAO,iEAAiD,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,oBAAoB,CAAC;AACnH,KAAA;AACD,IAAA;AACE,QAAA,IAAI,EAAE,8BAA8B;AACpC,QAAA,IAAI,EAAE,EAAE,KAAK,EAAE,aAAa,EAAE;AAC9B,QAAA,aAAa,EAAE,MAAM,OAAO,+DAAmD,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,kBAAkB,CAAC;AACnH,KAAA;;;;;"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, input, signal, computed, effect, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { RouterLink, RouterLinkActive } from '@angular/router';
|
|
4
|
+
import { firstValueFrom } from 'rxjs';
|
|
5
|
+
import { ApplicationService } from '@rolatech/angular-services';
|
|
6
|
+
import { PlatformPageHeader, PlatformStatCard, PlatformStatusBadge, PlatformTabs } from './rolatech-angular-platform.mjs';
|
|
7
|
+
|
|
8
|
+
class ApplicationWorkspaceShell {
|
|
9
|
+
applicationService = inject(ApplicationService);
|
|
10
|
+
appId = input.required(...(ngDevMode ? [{ debugName: "appId" }] : []));
|
|
11
|
+
activeTab = input.required(...(ngDevMode ? [{ debugName: "activeTab" }] : []));
|
|
12
|
+
sectionTitle = input('', ...(ngDevMode ? [{ debugName: "sectionTitle" }] : []));
|
|
13
|
+
sectionDescription = input('', ...(ngDevMode ? [{ debugName: "sectionDescription" }] : []));
|
|
14
|
+
showEditButton = input(false, ...(ngDevMode ? [{ debugName: "showEditButton" }] : []));
|
|
15
|
+
loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
16
|
+
item = signal(null, ...(ngDevMode ? [{ debugName: "item" }] : []));
|
|
17
|
+
error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
|
|
18
|
+
overviewLink = computed(() => ['/platform/applications', this.appId()], ...(ngDevMode ? [{ debugName: "overviewLink" }] : []));
|
|
19
|
+
organizationsLink = computed(() => ['/platform/applications', this.appId(), 'organizations'], ...(ngDevMode ? [{ debugName: "organizationsLink" }] : []));
|
|
20
|
+
membersLink = computed(() => ['/platform/applications', this.appId(), 'members'], ...(ngDevMode ? [{ debugName: "membersLink" }] : []));
|
|
21
|
+
rolesLink = computed(() => ['/platform/applications', this.appId(), 'roles'], ...(ngDevMode ? [{ debugName: "rolesLink" }] : []));
|
|
22
|
+
settingsLink = computed(() => ['/platform/applications', this.appId(), 'settings'], ...(ngDevMode ? [{ debugName: "settingsLink" }] : []));
|
|
23
|
+
editLink = computed(() => ['/platform/applications', this.appId(), 'edit'], ...(ngDevMode ? [{ debugName: "editLink" }] : []));
|
|
24
|
+
breadcrumbLabel = computed(() => {
|
|
25
|
+
switch (this.activeTab()) {
|
|
26
|
+
case 'organizations':
|
|
27
|
+
return 'Organizations';
|
|
28
|
+
case 'members':
|
|
29
|
+
return 'Members';
|
|
30
|
+
case 'roles':
|
|
31
|
+
return 'Roles';
|
|
32
|
+
case 'settings':
|
|
33
|
+
return 'Settings';
|
|
34
|
+
default:
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
}, ...(ngDevMode ? [{ debugName: "breadcrumbLabel" }] : []));
|
|
38
|
+
constructor() {
|
|
39
|
+
effect(() => {
|
|
40
|
+
const appId = this.appId();
|
|
41
|
+
if (!appId) {
|
|
42
|
+
this.item.set(null);
|
|
43
|
+
this.error.set('Application context is missing.');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
void this.load(appId);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async load(appId) {
|
|
50
|
+
this.loading.set(true);
|
|
51
|
+
this.error.set(null);
|
|
52
|
+
try {
|
|
53
|
+
this.item.set(await firstValueFrom(this.applicationService.findApplicationById(appId)));
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
console.error(error);
|
|
57
|
+
this.item.set(null);
|
|
58
|
+
this.error.set('Unable to load the application workspace.');
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
this.loading.set(false);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationWorkspaceShell, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
65
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: ApplicationWorkspaceShell, isStandalone: true, selector: "rolatech-application-workspace-shell", inputs: { appId: { classPropertyName: "appId", publicName: "appId", isSignal: true, isRequired: true, transformFunction: null }, activeTab: { classPropertyName: "activeTab", publicName: "activeTab", isSignal: true, isRequired: true, transformFunction: null }, sectionTitle: { classPropertyName: "sectionTitle", publicName: "sectionTitle", isSignal: true, isRequired: false, transformFunction: null }, sectionDescription: { classPropertyName: "sectionDescription", publicName: "sectionDescription", isSignal: true, isRequired: false, transformFunction: null }, showEditButton: { classPropertyName: "showEditButton", publicName: "showEditButton", isSignal: true, isRequired: false, transformFunction: null } }, 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 (loading()) {\n <section class=\"rounded-[28px] border border-(--rt-border-color) bg-card p-10 text-center text-muted-foreground shadow-sm\">\n Loading application workspace...\n </section>\n } @else if (item(); as item) {\n <section class=\"overflow-hidden rounded-[28px] border border-(--rt-border-color) bg-card shadow-sm\">\n <div class=\"p-6\">\n <rolatech-platform-page-header>\n <div header-left class=\"space-y-3\">\n <div class=\"flex flex-wrap items-center gap-2 text-sm text-muted-foreground\">\n <a [routerLink]=\"['/platform/applications']\" class=\"hover:underline cursor-pointer\">Applications</a>\n <span>/</span>\n <a [routerLink]=\"overviewLink()\" class=\"hover:underline cursor-pointer\">{{ item.name }}</a>\n @if (breadcrumbLabel()) {\n <span>/</span>\n <span>{{ breadcrumbLabel() }}</span>\n }\n </div>\n\n <div>\n <h1 class=\"text-2xl font-semibold tracking-tight\">{{ item.name }}</h1>\n <div class=\"mt-1 text-sm text-muted-foreground\">{{ item.code }}</div>\n </div>\n\n @if (item.description) {\n <p class=\"max-w-3xl text-sm text-muted-foreground\">{{ item.description }}</p>\n }\n\n <div class=\"flex flex-wrap gap-2\">\n <rolatech-platform-status-badge [status]=\"item.status\" />\n @if (item.type) {\n <span class=\"inline-flex rounded-full border border-(--rt-border-color) px-2 py-1 text-xs\">{{ item.type }}</span>\n }\n </div>\n </div>\n\n <div header-actions>\n <ng-content select=\"[workspace-actions]\"></ng-content>\n\n @if (showEditButton()) {\n <a\n [routerLink]=\"editLink()\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-4 py-2 text-sm font-medium cursor-pointer\"\n >\n Edit Application\n </a>\n }\n </div>\n </rolatech-platform-page-header>\n\n <div class=\"mt-6 grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <rolatech-platform-stat-card>\n <div stat-label>Organizations</div>\n <div stat-value>{{ item.organizationCount }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Roles</div>\n <div stat-value>{{ item.roleCount }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Members</div>\n <div stat-value>{{ item.memberCount }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Updated</div>\n <div stat-value class=\"text-sm\">{{ item.updatedAt || '-' }}</div>\n </rolatech-platform-stat-card>\n </div>\n </div>\n\n <rolatech-platform-tabs>\n <a\n [routerLink]=\"overviewLink()\"\n routerLinkActive=\"rt-application-workspace-tab--active\"\n [routerLinkActiveOptions]=\"{ exact: true }\"\n class=\"rt-application-workspace-tab\"\n >\n Overview\n </a>\n\n <a [routerLink]=\"organizationsLink()\" routerLinkActive=\"rt-application-workspace-tab--active\" class=\"rt-application-workspace-tab\">\n Organizations\n </a>\n\n <a [routerLink]=\"membersLink()\" routerLinkActive=\"rt-application-workspace-tab--active\" class=\"rt-application-workspace-tab\">\n Members\n </a>\n\n <a [routerLink]=\"rolesLink()\" routerLinkActive=\"rt-application-workspace-tab--active\" class=\"rt-application-workspace-tab\">\n Roles\n </a>\n\n <a\n [routerLink]=\"settingsLink()\"\n routerLinkActive=\"rt-application-workspace-tab--active\"\n [routerLinkActiveOptions]=\"{ exact: true }\"\n class=\"rt-application-workspace-tab\"\n >\n Settings\n </a>\n </rolatech-platform-tabs>\n </section>\n\n @if (sectionTitle() || sectionDescription()) {\n <section class=\"space-y-1\">\n @if (sectionTitle()) {\n <h2 class=\"text-xl font-semibold tracking-tight\">{{ sectionTitle() }}</h2>\n }\n @if (sectionDescription()) {\n <p class=\"text-sm text-muted-foreground\">{{ sectionDescription() }}</p>\n }\n </section>\n }\n\n <ng-content></ng-content>\n } @else {\n <section class=\"rounded-[28px] border border-(--rt-border-color) bg-card p-10 text-center text-muted-foreground shadow-sm\">\n {{ error() || 'Application not found.' }}\n </section>\n }\n</section>\n", styles: [":host{display:block}.rt-application-workspace-tab{display:inline-flex;align-items:center;justify-content:center;min-height:2.75rem;padding:.625rem 1rem;border-radius:.9rem;border:1px solid transparent;color:var(--rt-text-secondary);font-size:.925rem;font-weight:600;text-decoration:none;transition:background-color .12s ease,border-color .12s ease,color .12s ease}.rt-application-workspace-tab:hover{background-color:var(--rt-raised-background);color:var(--rt-text-primary)}.rt-application-workspace-tab--active{border-color:var(--rt-text-primary);background-color:var(--rt-text-primary);color:var(--rt-base-background)}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: PlatformPageHeader, selector: "rolatech-platform-page-header" }, { kind: "component", type: PlatformStatCard, selector: "rolatech-platform-stat-card" }, { kind: "component", type: PlatformStatusBadge, selector: "rolatech-platform-status-badge", inputs: ["status"] }, { kind: "component", type: PlatformTabs, selector: "rolatech-platform-tabs" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
66
|
+
}
|
|
67
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: ApplicationWorkspaceShell, decorators: [{
|
|
68
|
+
type: Component,
|
|
69
|
+
args: [{ selector: 'rolatech-application-workspace-shell', standalone: true, imports: [RouterLink, RouterLinkActive, PlatformPageHeader, PlatformStatCard, PlatformStatusBadge, PlatformTabs], changeDetection: ChangeDetectionStrategy.OnPush, template: "<section class=\"rt-platform-theme flex flex-col gap-6 bg-(--rt-base-background) p-6 text-(--rt-text-primary)\">\n @if (loading()) {\n <section class=\"rounded-[28px] border border-(--rt-border-color) bg-card p-10 text-center text-muted-foreground shadow-sm\">\n Loading application workspace...\n </section>\n } @else if (item(); as item) {\n <section class=\"overflow-hidden rounded-[28px] border border-(--rt-border-color) bg-card shadow-sm\">\n <div class=\"p-6\">\n <rolatech-platform-page-header>\n <div header-left class=\"space-y-3\">\n <div class=\"flex flex-wrap items-center gap-2 text-sm text-muted-foreground\">\n <a [routerLink]=\"['/platform/applications']\" class=\"hover:underline cursor-pointer\">Applications</a>\n <span>/</span>\n <a [routerLink]=\"overviewLink()\" class=\"hover:underline cursor-pointer\">{{ item.name }}</a>\n @if (breadcrumbLabel()) {\n <span>/</span>\n <span>{{ breadcrumbLabel() }}</span>\n }\n </div>\n\n <div>\n <h1 class=\"text-2xl font-semibold tracking-tight\">{{ item.name }}</h1>\n <div class=\"mt-1 text-sm text-muted-foreground\">{{ item.code }}</div>\n </div>\n\n @if (item.description) {\n <p class=\"max-w-3xl text-sm text-muted-foreground\">{{ item.description }}</p>\n }\n\n <div class=\"flex flex-wrap gap-2\">\n <rolatech-platform-status-badge [status]=\"item.status\" />\n @if (item.type) {\n <span class=\"inline-flex rounded-full border border-(--rt-border-color) px-2 py-1 text-xs\">{{ item.type }}</span>\n }\n </div>\n </div>\n\n <div header-actions>\n <ng-content select=\"[workspace-actions]\"></ng-content>\n\n @if (showEditButton()) {\n <a\n [routerLink]=\"editLink()\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-4 py-2 text-sm font-medium cursor-pointer\"\n >\n Edit Application\n </a>\n }\n </div>\n </rolatech-platform-page-header>\n\n <div class=\"mt-6 grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <rolatech-platform-stat-card>\n <div stat-label>Organizations</div>\n <div stat-value>{{ item.organizationCount }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Roles</div>\n <div stat-value>{{ item.roleCount }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Members</div>\n <div stat-value>{{ item.memberCount }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Updated</div>\n <div stat-value class=\"text-sm\">{{ item.updatedAt || '-' }}</div>\n </rolatech-platform-stat-card>\n </div>\n </div>\n\n <rolatech-platform-tabs>\n <a\n [routerLink]=\"overviewLink()\"\n routerLinkActive=\"rt-application-workspace-tab--active\"\n [routerLinkActiveOptions]=\"{ exact: true }\"\n class=\"rt-application-workspace-tab\"\n >\n Overview\n </a>\n\n <a [routerLink]=\"organizationsLink()\" routerLinkActive=\"rt-application-workspace-tab--active\" class=\"rt-application-workspace-tab\">\n Organizations\n </a>\n\n <a [routerLink]=\"membersLink()\" routerLinkActive=\"rt-application-workspace-tab--active\" class=\"rt-application-workspace-tab\">\n Members\n </a>\n\n <a [routerLink]=\"rolesLink()\" routerLinkActive=\"rt-application-workspace-tab--active\" class=\"rt-application-workspace-tab\">\n Roles\n </a>\n\n <a\n [routerLink]=\"settingsLink()\"\n routerLinkActive=\"rt-application-workspace-tab--active\"\n [routerLinkActiveOptions]=\"{ exact: true }\"\n class=\"rt-application-workspace-tab\"\n >\n Settings\n </a>\n </rolatech-platform-tabs>\n </section>\n\n @if (sectionTitle() || sectionDescription()) {\n <section class=\"space-y-1\">\n @if (sectionTitle()) {\n <h2 class=\"text-xl font-semibold tracking-tight\">{{ sectionTitle() }}</h2>\n }\n @if (sectionDescription()) {\n <p class=\"text-sm text-muted-foreground\">{{ sectionDescription() }}</p>\n }\n </section>\n }\n\n <ng-content></ng-content>\n } @else {\n <section class=\"rounded-[28px] border border-(--rt-border-color) bg-card p-10 text-center text-muted-foreground shadow-sm\">\n {{ error() || 'Application not found.' }}\n </section>\n }\n</section>\n", styles: [":host{display:block}.rt-application-workspace-tab{display:inline-flex;align-items:center;justify-content:center;min-height:2.75rem;padding:.625rem 1rem;border-radius:.9rem;border:1px solid transparent;color:var(--rt-text-secondary);font-size:.925rem;font-weight:600;text-decoration:none;transition:background-color .12s ease,border-color .12s ease,color .12s ease}.rt-application-workspace-tab:hover{background-color:var(--rt-raised-background);color:var(--rt-text-primary)}.rt-application-workspace-tab--active{border-color:var(--rt-text-primary);background-color:var(--rt-text-primary);color:var(--rt-base-background)}\n"] }]
|
|
70
|
+
}], ctorParameters: () => [], propDecorators: { appId: [{ type: i0.Input, args: [{ isSignal: true, alias: "appId", required: true }] }], activeTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeTab", required: true }] }], sectionTitle: [{ type: i0.Input, args: [{ isSignal: true, alias: "sectionTitle", required: false }] }], sectionDescription: [{ type: i0.Input, args: [{ isSignal: true, alias: "sectionDescription", required: false }] }], showEditButton: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEditButton", required: false }] }] } });
|
|
71
|
+
|
|
72
|
+
export { ApplicationWorkspaceShell as A };
|
|
73
|
+
//# sourceMappingURL=rolatech-angular-platform-application-workspace-shell-MPkdKJ2X.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rolatech-angular-platform-application-workspace-shell-MPkdKJ2X.mjs","sources":["../../../../packages/angular-platform/src/lib/pages/application/application-workspace-shell/application-workspace-shell.ts","../../../../packages/angular-platform/src/lib/pages/application/application-workspace-shell/application-workspace-shell.html"],"sourcesContent":["import { ChangeDetectionStrategy, Component, computed, effect, inject, input, signal } from '@angular/core';\nimport { RouterLink, RouterLinkActive } from '@angular/router';\nimport { firstValueFrom } from 'rxjs';\nimport { ApplicationService } from '@rolatech/angular-services';\nimport { ApplicationDetailModel } from '../../../model/application.models';\nimport { PlatformPageHeader, PlatformStatCard, PlatformStatusBadge, PlatformTabs } from '../../../shared';\n\ntype ApplicationWorkspaceTab = 'overview' | 'organizations' | 'members' | 'roles' | 'settings';\n\n@Component({\n selector: 'rolatech-application-workspace-shell',\n standalone: true,\n imports: [RouterLink, RouterLinkActive, PlatformPageHeader, PlatformStatCard, PlatformStatusBadge, PlatformTabs],\n templateUrl: './application-workspace-shell.html',\n styleUrl: './application-workspace-shell.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ApplicationWorkspaceShell {\n private readonly applicationService = inject(ApplicationService);\n\n readonly appId = input.required<string>();\n readonly activeTab = input.required<ApplicationWorkspaceTab>();\n readonly sectionTitle = input<string>('');\n readonly sectionDescription = input<string>('');\n readonly showEditButton = input(false);\n\n readonly loading = signal(false);\n readonly item = signal<ApplicationDetailModel | null>(null);\n readonly error = signal<string | null>(null);\n\n readonly overviewLink = computed(() => ['/platform/applications', this.appId()]);\n readonly organizationsLink = computed(() => ['/platform/applications', this.appId(), 'organizations']);\n readonly membersLink = computed(() => ['/platform/applications', this.appId(), 'members']);\n readonly rolesLink = computed(() => ['/platform/applications', this.appId(), 'roles']);\n readonly settingsLink = computed(() => ['/platform/applications', this.appId(), 'settings']);\n readonly editLink = computed(() => ['/platform/applications', this.appId(), 'edit']);\n readonly breadcrumbLabel = computed(() => {\n switch (this.activeTab()) {\n case 'organizations':\n return 'Organizations';\n case 'members':\n return 'Members';\n case 'roles':\n return 'Roles';\n case 'settings':\n return 'Settings';\n default:\n return null;\n }\n });\n\n constructor() {\n effect(() => {\n const appId = this.appId();\n if (!appId) {\n this.item.set(null);\n this.error.set('Application context is missing.');\n return;\n }\n\n void this.load(appId);\n });\n }\n\n private async load(appId: string): Promise<void> {\n this.loading.set(true);\n this.error.set(null);\n\n try {\n this.item.set(await firstValueFrom(this.applicationService.findApplicationById(appId)));\n } catch (error) {\n console.error(error);\n this.item.set(null);\n this.error.set('Unable to load the application workspace.');\n } finally {\n this.loading.set(false);\n }\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 (loading()) {\n <section class=\"rounded-[28px] border border-(--rt-border-color) bg-card p-10 text-center text-muted-foreground shadow-sm\">\n Loading application workspace...\n </section>\n } @else if (item(); as item) {\n <section class=\"overflow-hidden rounded-[28px] border border-(--rt-border-color) bg-card shadow-sm\">\n <div class=\"p-6\">\n <rolatech-platform-page-header>\n <div header-left class=\"space-y-3\">\n <div class=\"flex flex-wrap items-center gap-2 text-sm text-muted-foreground\">\n <a [routerLink]=\"['/platform/applications']\" class=\"hover:underline cursor-pointer\">Applications</a>\n <span>/</span>\n <a [routerLink]=\"overviewLink()\" class=\"hover:underline cursor-pointer\">{{ item.name }}</a>\n @if (breadcrumbLabel()) {\n <span>/</span>\n <span>{{ breadcrumbLabel() }}</span>\n }\n </div>\n\n <div>\n <h1 class=\"text-2xl font-semibold tracking-tight\">{{ item.name }}</h1>\n <div class=\"mt-1 text-sm text-muted-foreground\">{{ item.code }}</div>\n </div>\n\n @if (item.description) {\n <p class=\"max-w-3xl text-sm text-muted-foreground\">{{ item.description }}</p>\n }\n\n <div class=\"flex flex-wrap gap-2\">\n <rolatech-platform-status-badge [status]=\"item.status\" />\n @if (item.type) {\n <span class=\"inline-flex rounded-full border border-(--rt-border-color) px-2 py-1 text-xs\">{{ item.type }}</span>\n }\n </div>\n </div>\n\n <div header-actions>\n <ng-content select=\"[workspace-actions]\"></ng-content>\n\n @if (showEditButton()) {\n <a\n [routerLink]=\"editLink()\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-4 py-2 text-sm font-medium cursor-pointer\"\n >\n Edit Application\n </a>\n }\n </div>\n </rolatech-platform-page-header>\n\n <div class=\"mt-6 grid gap-4 md:grid-cols-2 xl:grid-cols-4\">\n <rolatech-platform-stat-card>\n <div stat-label>Organizations</div>\n <div stat-value>{{ item.organizationCount }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Roles</div>\n <div stat-value>{{ item.roleCount }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Members</div>\n <div stat-value>{{ item.memberCount }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Updated</div>\n <div stat-value class=\"text-sm\">{{ item.updatedAt || '-' }}</div>\n </rolatech-platform-stat-card>\n </div>\n </div>\n\n <rolatech-platform-tabs>\n <a\n [routerLink]=\"overviewLink()\"\n routerLinkActive=\"rt-application-workspace-tab--active\"\n [routerLinkActiveOptions]=\"{ exact: true }\"\n class=\"rt-application-workspace-tab\"\n >\n Overview\n </a>\n\n <a [routerLink]=\"organizationsLink()\" routerLinkActive=\"rt-application-workspace-tab--active\" class=\"rt-application-workspace-tab\">\n Organizations\n </a>\n\n <a [routerLink]=\"membersLink()\" routerLinkActive=\"rt-application-workspace-tab--active\" class=\"rt-application-workspace-tab\">\n Members\n </a>\n\n <a [routerLink]=\"rolesLink()\" routerLinkActive=\"rt-application-workspace-tab--active\" class=\"rt-application-workspace-tab\">\n Roles\n </a>\n\n <a\n [routerLink]=\"settingsLink()\"\n routerLinkActive=\"rt-application-workspace-tab--active\"\n [routerLinkActiveOptions]=\"{ exact: true }\"\n class=\"rt-application-workspace-tab\"\n >\n Settings\n </a>\n </rolatech-platform-tabs>\n </section>\n\n @if (sectionTitle() || sectionDescription()) {\n <section class=\"space-y-1\">\n @if (sectionTitle()) {\n <h2 class=\"text-xl font-semibold tracking-tight\">{{ sectionTitle() }}</h2>\n }\n @if (sectionDescription()) {\n <p class=\"text-sm text-muted-foreground\">{{ sectionDescription() }}</p>\n }\n </section>\n }\n\n <ng-content></ng-content>\n } @else {\n <section class=\"rounded-[28px] border border-(--rt-border-color) bg-card p-10 text-center text-muted-foreground shadow-sm\">\n {{ error() || 'Application not found.' }}\n </section>\n }\n</section>\n"],"names":[],"mappings":"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"}
|