@rolatech/angular-platform 20.3.0-beta.3 → 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-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.mjs +1 -1
- package/package.json +1 -1
- package/fesm2022/rolatech-angular-platform-role-permission-index-CkFgu7BW.mjs +0 -139
- package/fesm2022/rolatech-angular-platform-role-permission-index-CkFgu7BW.mjs.map +0 -1
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { inject, signal, computed, Injectable, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { take, finalize } from 'rxjs';
|
|
4
|
+
import { PermissionService } from '@rolatech/angular-services';
|
|
5
|
+
import { Router } from '@angular/router';
|
|
6
|
+
import { TabsComponent, TabComponent } from '@rolatech/angular-components';
|
|
7
|
+
import { PlatformPageHeader, PlatformStatCard, PlatformFilterPanel, PlatformDataTable, PlatformScopeBadge } from './rolatech-angular-platform.mjs';
|
|
8
|
+
|
|
9
|
+
class RolePermissionIndexFacade {
|
|
10
|
+
permissionService = inject(PermissionService);
|
|
11
|
+
loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
12
|
+
items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
13
|
+
options = signal({
|
|
14
|
+
mode: 'PLATFORM',
|
|
15
|
+
}, ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
16
|
+
tabs = [
|
|
17
|
+
{ label: 'Platform', scope: 'PLATFORM' },
|
|
18
|
+
{ label: 'Application', scope: 'APP' },
|
|
19
|
+
{ label: 'Organization', scope: 'ORG' },
|
|
20
|
+
];
|
|
21
|
+
keyword = signal('', ...(ngDevMode ? [{ debugName: "keyword" }] : []));
|
|
22
|
+
scope = signal('PLATFORM', ...(ngDevMode ? [{ debugName: "scope" }] : []));
|
|
23
|
+
application = signal('', ...(ngDevMode ? [{ debugName: "application" }] : []));
|
|
24
|
+
organization = signal('', ...(ngDevMode ? [{ debugName: "organization" }] : []));
|
|
25
|
+
filteredItems = computed(() => {
|
|
26
|
+
const keyword = this.keyword().trim().toLowerCase();
|
|
27
|
+
const application = this.application().trim().toLowerCase();
|
|
28
|
+
const organization = this.organization().trim().toLowerCase();
|
|
29
|
+
return this.items().filter((item) => {
|
|
30
|
+
const matchesKeyword = !keyword || item.name.toLowerCase().includes(keyword) || item.code.toLowerCase().includes(keyword);
|
|
31
|
+
const matchesApplication = !application || (item.applicationName ?? '').toLowerCase().includes(application);
|
|
32
|
+
const matchesOrganization = !organization || (item.organizationName ?? '').toLowerCase().includes(organization);
|
|
33
|
+
return matchesKeyword && matchesApplication && matchesOrganization;
|
|
34
|
+
});
|
|
35
|
+
}, ...(ngDevMode ? [{ debugName: "filteredItems" }] : []));
|
|
36
|
+
totalRoles = computed(() => this.items().length, ...(ngDevMode ? [{ debugName: "totalRoles" }] : []));
|
|
37
|
+
totalPermissions = computed(() => this.items().reduce((sum, item) => sum + item.permissionCount, 0), ...(ngDevMode ? [{ debugName: "totalPermissions" }] : []));
|
|
38
|
+
emptyRoles = computed(() => this.items().filter((item) => item.permissionCount === 0).length, ...(ngDevMode ? [{ debugName: "emptyRoles" }] : []));
|
|
39
|
+
activeRoles = computed(() => this.items().filter((item) => item.active).length, ...(ngDevMode ? [{ debugName: "activeRoles" }] : []));
|
|
40
|
+
setOptions(options) {
|
|
41
|
+
this.options.set(options);
|
|
42
|
+
this.scope.set(this.scopeForMode(options.mode));
|
|
43
|
+
}
|
|
44
|
+
load() {
|
|
45
|
+
const options = this.options();
|
|
46
|
+
this.loading.set(true);
|
|
47
|
+
this.permissionService
|
|
48
|
+
.findRoles({
|
|
49
|
+
scope: this.scope(),
|
|
50
|
+
applicationId: options.applicationId ?? null,
|
|
51
|
+
organizationId: options.organizationId ?? null,
|
|
52
|
+
active: null,
|
|
53
|
+
manageScope: options.mode === 'PLATFORM' ? 'PLATFORM' : options.mode === 'APPLICATION' ? 'APP' : 'ORG',
|
|
54
|
+
})
|
|
55
|
+
.pipe(take(1), finalize(() => this.loading.set(false)))
|
|
56
|
+
.subscribe({
|
|
57
|
+
next: (response) => {
|
|
58
|
+
this.items.set(response.data ?? []);
|
|
59
|
+
},
|
|
60
|
+
error: () => {
|
|
61
|
+
this.items.set([]);
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
reload() {
|
|
66
|
+
this.load();
|
|
67
|
+
}
|
|
68
|
+
setKeyword(value) {
|
|
69
|
+
this.keyword.set(value);
|
|
70
|
+
}
|
|
71
|
+
setScope(value) {
|
|
72
|
+
if (this.scope() === value) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
this.scope.set(value);
|
|
76
|
+
this.load();
|
|
77
|
+
}
|
|
78
|
+
setApplication(value) {
|
|
79
|
+
this.application.set(value);
|
|
80
|
+
}
|
|
81
|
+
setOrganization(value) {
|
|
82
|
+
this.organization.set(value);
|
|
83
|
+
}
|
|
84
|
+
scopeForMode(mode) {
|
|
85
|
+
if (mode === 'APPLICATION') {
|
|
86
|
+
return 'APP';
|
|
87
|
+
}
|
|
88
|
+
if (mode === 'ORGANIZATION') {
|
|
89
|
+
return 'ORG';
|
|
90
|
+
}
|
|
91
|
+
return 'PLATFORM';
|
|
92
|
+
}
|
|
93
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: RolePermissionIndexFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
94
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: RolePermissionIndexFacade });
|
|
95
|
+
}
|
|
96
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: RolePermissionIndexFacade, decorators: [{
|
|
97
|
+
type: Injectable
|
|
98
|
+
}] });
|
|
99
|
+
|
|
100
|
+
class RolePermissionIndex {
|
|
101
|
+
facade = inject(RolePermissionIndexFacade);
|
|
102
|
+
router = inject(Router);
|
|
103
|
+
scopeTabIndex = signal(0, ...(ngDevMode ? [{ debugName: "scopeTabIndex" }] : []));
|
|
104
|
+
ngOnInit() {
|
|
105
|
+
void this.facade.load();
|
|
106
|
+
}
|
|
107
|
+
onKeywordInput(event) {
|
|
108
|
+
const value = event.target.value;
|
|
109
|
+
this.facade.setKeyword(value);
|
|
110
|
+
}
|
|
111
|
+
onScopeTabChange(index) {
|
|
112
|
+
const tab = this.facade.tabs[index];
|
|
113
|
+
if (!tab) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
this.scopeTabIndex.set(index);
|
|
117
|
+
this.facade.setScope(tab.scope);
|
|
118
|
+
}
|
|
119
|
+
onApplicationInput(event) {
|
|
120
|
+
const value = event.target.value;
|
|
121
|
+
this.facade.setApplication(value);
|
|
122
|
+
}
|
|
123
|
+
onOrganizationInput(event) {
|
|
124
|
+
const value = event.target.value;
|
|
125
|
+
this.facade.setOrganization(value);
|
|
126
|
+
}
|
|
127
|
+
reload() {
|
|
128
|
+
this.facade.reload();
|
|
129
|
+
}
|
|
130
|
+
clearFilters() {
|
|
131
|
+
this.facade.setKeyword('');
|
|
132
|
+
this.facade.setApplication('');
|
|
133
|
+
this.facade.setOrganization('');
|
|
134
|
+
}
|
|
135
|
+
openRolePermissions(item) {
|
|
136
|
+
const baseCommands = item.scope === 'APP'
|
|
137
|
+
? ['/platform/roles/application', item.id]
|
|
138
|
+
: item.scope === 'ORG'
|
|
139
|
+
? ['/platform/roles/organization', item.id]
|
|
140
|
+
: ['/platform/roles/platform', item.id];
|
|
141
|
+
void this.router.navigate(baseCommands, {
|
|
142
|
+
queryParams: {
|
|
143
|
+
appId: item.applicationId ?? undefined,
|
|
144
|
+
orgId: item.organizationId ?? undefined,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: RolePermissionIndex, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
149
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: RolePermissionIndex, isStandalone: true, selector: "rolatech-role-permission-index", providers: [RolePermissionIndexFacade], 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\">Roles</h1>\n <p class=\"text-sm text-muted-foreground\">View platform, application, and organization roles from one index.</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 Roles</div>\n <div stat-value>{{ facade.totalRoles() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Total Assigned Permissions</div>\n <div stat-value>{{ facade.totalPermissions() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Roles With No Permissions</div>\n <div stat-value>{{ facade.emptyRoles() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Active Roles</div>\n <div stat-value>{{ facade.activeRoles() }}</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 roles by keyword and owner.</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 role name or code\"\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\">Application</span>\n <input\n type=\"text\"\n [value]=\"facade.application()\"\n (input)=\"onApplicationInput($event)\"\n placeholder=\"Filter by application name\"\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\">Organization</span>\n <input\n type=\"text\"\n [value]=\"facade.organization()\"\n (input)=\"onOrganizationInput($event)\"\n placeholder=\"Filter by organization name\"\n class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\"\n />\n </label>\n\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-4 py-2 text-sm font-medium\"\n (click)=\"clearFilters()\"\n >\n Clear\n </button>\n\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-4 py-2 text-sm font-medium\"\n [disabled]=\"facade.loading()\"\n (click)=\"reload()\"\n >\n Refresh\n </button>\n </div>\n </rolatech-platform-filter-panel>\n\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex flex-col gap-4\">\n <rolatech-tabs [select]=\"scopeTabIndex()\" (selectChange)=\"onScopeTabChange($event)\" [loading]=\"facade.loading()\">\n @for (tab of facade.tabs; track tab.scope) {\n <rolatech-tab [label]=\"tab.label\"></rolatech-tab>\n }\n </rolatech-tabs>\n\n <div class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Role List</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.filteredItems().length }} items</div>\n </div>\n </div>\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">Role</th>\n <th class=\"px-4 py-3 font-medium\">Scope</th>\n <th class=\"px-4 py-3 font-medium\">Application</th>\n <th class=\"px-4 py-3 font-medium\">Organization</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.loading()) {\n <tr>\n <td colspan=\"8\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading roles...</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 roles 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 }}</div>\n </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 text-muted-foreground\">{{ item.applicationName || '\u2014' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.organizationName || '\u2014' }}</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 <span class=\"inline-flex rounded-full border border-(--rt-border-color) px-2.5 py-1 text-xs\">\n {{ item.active ? 'Enabled' : 'Disabled' }}\n </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)=\"openRolePermissions(item)\"\n >\n Manage Permissions\n </button>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n </section>\n</section>\n", styles: [""], 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" }, { kind: "component", type: PlatformScopeBadge, selector: "rolatech-platform-scope-badge", inputs: ["scope"] }, { kind: "component", type: TabsComponent, selector: "rolatech-tabs", inputs: ["select", "loading", "block", "mode"], outputs: ["selectChange"] }, { kind: "component", type: TabComponent, selector: "rolatech-tab", inputs: ["label"], outputs: ["selectRequested"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
150
|
+
}
|
|
151
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: RolePermissionIndex, decorators: [{
|
|
152
|
+
type: Component,
|
|
153
|
+
args: [{ selector: 'rolatech-role-permission-index', imports: [PlatformPageHeader, PlatformStatCard, PlatformFilterPanel, PlatformDataTable, PlatformScopeBadge, TabsComponent, TabComponent], changeDetection: ChangeDetectionStrategy.OnPush, providers: [RolePermissionIndexFacade], 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\">Roles</h1>\n <p class=\"text-sm text-muted-foreground\">View platform, application, and organization roles from one index.</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 Roles</div>\n <div stat-value>{{ facade.totalRoles() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Total Assigned Permissions</div>\n <div stat-value>{{ facade.totalPermissions() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Roles With No Permissions</div>\n <div stat-value>{{ facade.emptyRoles() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Active Roles</div>\n <div stat-value>{{ facade.activeRoles() }}</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 roles by keyword and owner.</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 role name or code\"\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\">Application</span>\n <input\n type=\"text\"\n [value]=\"facade.application()\"\n (input)=\"onApplicationInput($event)\"\n placeholder=\"Filter by application name\"\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\">Organization</span>\n <input\n type=\"text\"\n [value]=\"facade.organization()\"\n (input)=\"onOrganizationInput($event)\"\n placeholder=\"Filter by organization name\"\n class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\"\n />\n </label>\n\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-4 py-2 text-sm font-medium\"\n (click)=\"clearFilters()\"\n >\n Clear\n </button>\n\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-4 py-2 text-sm font-medium\"\n [disabled]=\"facade.loading()\"\n (click)=\"reload()\"\n >\n Refresh\n </button>\n </div>\n </rolatech-platform-filter-panel>\n\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex flex-col gap-4\">\n <rolatech-tabs [select]=\"scopeTabIndex()\" (selectChange)=\"onScopeTabChange($event)\" [loading]=\"facade.loading()\">\n @for (tab of facade.tabs; track tab.scope) {\n <rolatech-tab [label]=\"tab.label\"></rolatech-tab>\n }\n </rolatech-tabs>\n\n <div class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Role List</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.filteredItems().length }} items</div>\n </div>\n </div>\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">Role</th>\n <th class=\"px-4 py-3 font-medium\">Scope</th>\n <th class=\"px-4 py-3 font-medium\">Application</th>\n <th class=\"px-4 py-3 font-medium\">Organization</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.loading()) {\n <tr>\n <td colspan=\"8\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading roles...</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 roles 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 }}</div>\n </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 text-muted-foreground\">{{ item.applicationName || '\u2014' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.organizationName || '\u2014' }}</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 <span class=\"inline-flex rounded-full border border-(--rt-border-color) px-2.5 py-1 text-xs\">\n {{ item.active ? 'Enabled' : 'Disabled' }}\n </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)=\"openRolePermissions(item)\"\n >\n Manage Permissions\n </button>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n </section>\n</section>\n" }]
|
|
154
|
+
}] });
|
|
155
|
+
|
|
156
|
+
export { RolePermissionIndex };
|
|
157
|
+
//# sourceMappingURL=rolatech-angular-platform-role-permission-index-B4-9h-mZ.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rolatech-angular-platform-role-permission-index-B4-9h-mZ.mjs","sources":["../../../../packages/angular-platform/src/lib/store/role-permission-index.facade.ts","../../../../packages/angular-platform/src/lib/pages/role/role-permission-index/role-permission-index.ts","../../../../packages/angular-platform/src/lib/pages/role/role-permission-index/role-permission-index.html"],"sourcesContent":["import { Injectable, computed, inject, signal } from '@angular/core';\nimport { finalize, take } from 'rxjs';\nimport { PermissionService, RolePermissionIndexItem } from '@rolatech/angular-services';\nimport { RoleScope } from '../model/role.models';\nimport { RolePermissionPageOptions } from '../intefaces/role-permission-page-options';\n\n@Injectable()\nexport class RolePermissionIndexFacade {\n private readonly permissionService = inject(PermissionService);\n\n readonly loading = signal(false);\n readonly items = signal<RolePermissionIndexItem[]>([]);\n\n readonly options = signal<RolePermissionPageOptions>({\n mode: 'PLATFORM',\n });\n\n readonly tabs = [\n { label: 'Platform', scope: 'PLATFORM' as const },\n { label: 'Application', scope: 'APP' as const },\n { label: 'Organization', scope: 'ORG' as const },\n ];\n\n readonly keyword = signal('');\n readonly scope = signal<RoleScope>('PLATFORM');\n readonly application = signal('');\n readonly organization = signal('');\n\n readonly filteredItems = computed(() => {\n const keyword = this.keyword().trim().toLowerCase();\n const application = this.application().trim().toLowerCase();\n const organization = this.organization().trim().toLowerCase();\n\n return this.items().filter((item) => {\n const matchesKeyword = !keyword || item.name.toLowerCase().includes(keyword) || item.code.toLowerCase().includes(keyword);\n const matchesApplication = !application || (item.applicationName ?? '').toLowerCase().includes(application);\n const matchesOrganization = !organization || (item.organizationName ?? '').toLowerCase().includes(organization);\n\n return matchesKeyword && matchesApplication && matchesOrganization;\n });\n });\n\n readonly totalRoles = computed(() => this.items().length);\n\n readonly totalPermissions = computed(() => this.items().reduce((sum, item) => sum + item.permissionCount, 0));\n\n readonly emptyRoles = computed(() => this.items().filter((item) => item.permissionCount === 0).length);\n\n readonly activeRoles = computed(() => this.items().filter((item) => item.active).length);\n\n setOptions(options: RolePermissionPageOptions): void {\n this.options.set(options);\n this.scope.set(this.scopeForMode(options.mode));\n }\n\n load(): void {\n const options = this.options();\n\n this.loading.set(true);\n\n this.permissionService\n .findRoles({\n scope: this.scope(),\n applicationId: options.applicationId ?? null,\n organizationId: options.organizationId ?? null,\n active: null,\n manageScope: options.mode === 'PLATFORM' ? 'PLATFORM' : options.mode === 'APPLICATION' ? 'APP' : 'ORG',\n })\n .pipe(\n take(1),\n finalize(() => this.loading.set(false)),\n )\n .subscribe({\n next: (response) => {\n this.items.set(response.data ?? []);\n },\n error: () => {\n this.items.set([]);\n },\n });\n }\n\n reload(): void {\n this.load();\n }\n\n setKeyword(value: string): void {\n this.keyword.set(value);\n }\n\n setScope(value: RoleScope): void {\n if (this.scope() === value) {\n return;\n }\n\n this.scope.set(value);\n this.load();\n }\n\n setApplication(value: string): void {\n this.application.set(value);\n }\n\n setOrganization(value: string): void {\n this.organization.set(value);\n }\n\n private scopeForMode(mode: RolePermissionPageOptions['mode']): RoleScope {\n if (mode === 'APPLICATION') {\n return 'APP';\n }\n\n if (mode === 'ORGANIZATION') {\n return 'ORG';\n }\n\n return 'PLATFORM';\n }\n}\n","import { ChangeDetectionStrategy, Component, inject, OnInit, signal } from '@angular/core';\nimport { RolePermissionIndexFacade } from '../../../store/role-permission-index.facade';\nimport { Router } from '@angular/router';\nimport { TabComponent, TabsComponent } from '@rolatech/angular-components';\nimport {\n PlatformDataTable,\n PlatformFilterPanel,\n PlatformPageHeader,\n PlatformScopeBadge,\n PlatformStatCard,\n} from '../../../shared';\nimport { RolePermissionIndexItem } from '@rolatech/angular-services';\n\n@Component({\n selector: 'rolatech-role-permission-index',\n imports: [PlatformPageHeader, PlatformStatCard, PlatformFilterPanel, PlatformDataTable, PlatformScopeBadge, TabsComponent, TabComponent],\n templateUrl: './role-permission-index.html',\n styleUrl: './role-permission-index.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [RolePermissionIndexFacade],\n})\nexport class RolePermissionIndex implements OnInit {\n readonly facade = inject(RolePermissionIndexFacade);\n private readonly router = inject(Router);\n readonly scopeTabIndex = signal(0);\n\n ngOnInit(): void {\n void this.facade.load();\n }\n\n onKeywordInput(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n this.facade.setKeyword(value);\n }\n\n onScopeTabChange(index: number): void {\n const tab = this.facade.tabs[index];\n if (!tab) {\n return;\n }\n\n this.scopeTabIndex.set(index);\n this.facade.setScope(tab.scope);\n }\n\n onApplicationInput(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n this.facade.setApplication(value);\n }\n\n onOrganizationInput(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n this.facade.setOrganization(value);\n }\n\n reload(): void {\n this.facade.reload();\n }\n\n clearFilters(): void {\n this.facade.setKeyword('');\n this.facade.setApplication('');\n this.facade.setOrganization('');\n }\n\n openRolePermissions(item: RolePermissionIndexItem): void {\n const baseCommands =\n item.scope === 'APP'\n ? ['/platform/roles/application', item.id]\n : item.scope === 'ORG'\n ? ['/platform/roles/organization', item.id]\n : ['/platform/roles/platform', item.id];\n\n void this.router.navigate(baseCommands, {\n queryParams: {\n appId: item.applicationId ?? undefined,\n orgId: item.organizationId ?? undefined,\n },\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 <rolatech-platform-page-header>\n <div header-left class=\"space-y-1\">\n <h1 class=\"text-2xl font-semibold tracking-tight\">Roles</h1>\n <p class=\"text-sm text-muted-foreground\">View platform, application, and organization roles from one index.</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 Roles</div>\n <div stat-value>{{ facade.totalRoles() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Total Assigned Permissions</div>\n <div stat-value>{{ facade.totalPermissions() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Roles With No Permissions</div>\n <div stat-value>{{ facade.emptyRoles() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Active Roles</div>\n <div stat-value>{{ facade.activeRoles() }}</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 roles by keyword and owner.</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 role name or code\"\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\">Application</span>\n <input\n type=\"text\"\n [value]=\"facade.application()\"\n (input)=\"onApplicationInput($event)\"\n placeholder=\"Filter by application name\"\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\">Organization</span>\n <input\n type=\"text\"\n [value]=\"facade.organization()\"\n (input)=\"onOrganizationInput($event)\"\n placeholder=\"Filter by organization name\"\n class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\"\n />\n </label>\n\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-4 py-2 text-sm font-medium\"\n (click)=\"clearFilters()\"\n >\n Clear\n </button>\n\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-4 py-2 text-sm font-medium\"\n [disabled]=\"facade.loading()\"\n (click)=\"reload()\"\n >\n Refresh\n </button>\n </div>\n </rolatech-platform-filter-panel>\n\n <rolatech-platform-data-table>\n <div table-toolbar class=\"flex flex-col gap-4\">\n <rolatech-tabs [select]=\"scopeTabIndex()\" (selectChange)=\"onScopeTabChange($event)\" [loading]=\"facade.loading()\">\n @for (tab of facade.tabs; track tab.scope) {\n <rolatech-tab [label]=\"tab.label\"></rolatech-tab>\n }\n </rolatech-tabs>\n\n <div class=\"flex items-center justify-between gap-3\">\n <h2 class=\"text-base font-semibold\">Role List</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.filteredItems().length }} items</div>\n </div>\n </div>\n\n <thead class=\"bg-muted/40\">\n <tr class=\"text-left\">\n <th class=\"px-4 py-3 font-medium\">Role</th>\n <th class=\"px-4 py-3 font-medium\">Scope</th>\n <th class=\"px-4 py-3 font-medium\">Application</th>\n <th class=\"px-4 py-3 font-medium\">Organization</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.loading()) {\n <tr>\n <td colspan=\"8\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading roles...</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 roles 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 }}</div>\n </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 text-muted-foreground\">{{ item.applicationName || '—' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.organizationName || '—' }}</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 <span class=\"inline-flex rounded-full border border-(--rt-border-color) px-2.5 py-1 text-xs\">\n {{ item.active ? 'Enabled' : 'Disabled' }}\n </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)=\"openRolePermissions(item)\"\n >\n Manage Permissions\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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"}
|
|
@@ -31,7 +31,7 @@ const PLATFORM_ADMIN_ROUTES = [
|
|
|
31
31
|
{
|
|
32
32
|
path: 'roles',
|
|
33
33
|
pathMatch: 'full',
|
|
34
|
-
loadComponent: () => import('./rolatech-angular-platform-role-permission-index-
|
|
34
|
+
loadComponent: () => import('./rolatech-angular-platform-role-permission-index-B4-9h-mZ.mjs').then((m) => m.RolePermissionIndex),
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
path: 'roles/platform/:id',
|
package/package.json
CHANGED
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, signal, computed, Injectable, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
-
import { take, finalize } from 'rxjs';
|
|
4
|
-
import { PermissionService } from '@rolatech/angular-services';
|
|
5
|
-
import { Router } from '@angular/router';
|
|
6
|
-
import { PlatformPageHeader, PlatformStatCard, PlatformFilterPanel, PlatformDataTable, PlatformScopeBadge } from './rolatech-angular-platform.mjs';
|
|
7
|
-
|
|
8
|
-
class RolePermissionIndexFacade {
|
|
9
|
-
permissionService = inject(PermissionService);
|
|
10
|
-
loading = signal(false, ...(ngDevMode ? [{ debugName: "loading" }] : []));
|
|
11
|
-
items = signal([], ...(ngDevMode ? [{ debugName: "items" }] : []));
|
|
12
|
-
options = signal({
|
|
13
|
-
mode: 'PLATFORM',
|
|
14
|
-
}, ...(ngDevMode ? [{ debugName: "options" }] : []));
|
|
15
|
-
keyword = signal('', ...(ngDevMode ? [{ debugName: "keyword" }] : []));
|
|
16
|
-
scope = signal('ALL', ...(ngDevMode ? [{ debugName: "scope" }] : []));
|
|
17
|
-
application = signal('', ...(ngDevMode ? [{ debugName: "application" }] : []));
|
|
18
|
-
organization = signal('', ...(ngDevMode ? [{ debugName: "organization" }] : []));
|
|
19
|
-
filteredItems = computed(() => {
|
|
20
|
-
const keyword = this.keyword().trim().toLowerCase();
|
|
21
|
-
const scope = this.scope();
|
|
22
|
-
const application = this.application().trim().toLowerCase();
|
|
23
|
-
const organization = this.organization().trim().toLowerCase();
|
|
24
|
-
return this.items().filter((item) => {
|
|
25
|
-
const matchesKeyword = !keyword || item.name.toLowerCase().includes(keyword) || item.code.toLowerCase().includes(keyword);
|
|
26
|
-
const matchesScope = scope === 'ALL' || item.scope === scope;
|
|
27
|
-
const matchesApplication = !application || (item.applicationName ?? '').toLowerCase().includes(application);
|
|
28
|
-
const matchesOrganization = !organization || (item.organizationName ?? '').toLowerCase().includes(organization);
|
|
29
|
-
return matchesKeyword && matchesScope && matchesApplication && matchesOrganization;
|
|
30
|
-
});
|
|
31
|
-
}, ...(ngDevMode ? [{ debugName: "filteredItems" }] : []));
|
|
32
|
-
totalRoles = computed(() => this.items().length, ...(ngDevMode ? [{ debugName: "totalRoles" }] : []));
|
|
33
|
-
totalPermissions = computed(() => this.items().reduce((sum, item) => sum + item.permissionCount, 0), ...(ngDevMode ? [{ debugName: "totalPermissions" }] : []));
|
|
34
|
-
emptyRoles = computed(() => this.items().filter((item) => item.permissionCount === 0).length, ...(ngDevMode ? [{ debugName: "emptyRoles" }] : []));
|
|
35
|
-
activeRoles = computed(() => this.items().filter((item) => item.active).length, ...(ngDevMode ? [{ debugName: "activeRoles" }] : []));
|
|
36
|
-
setOptions(options) {
|
|
37
|
-
this.options.set(options);
|
|
38
|
-
if (options.mode !== 'PLATFORM') {
|
|
39
|
-
this.scope.set('ALL');
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
load() {
|
|
43
|
-
const options = this.options();
|
|
44
|
-
this.loading.set(true);
|
|
45
|
-
this.permissionService
|
|
46
|
-
.findRoles({
|
|
47
|
-
keyword: this.keyword() || null,
|
|
48
|
-
scope: this.scope(),
|
|
49
|
-
applicationId: options.applicationId ?? null,
|
|
50
|
-
organizationId: options.organizationId ?? null,
|
|
51
|
-
active: null,
|
|
52
|
-
manageScope: options.mode === 'PLATFORM' ? 'PLATFORM' : options.mode === 'APPLICATION' ? 'APP' : 'ORG',
|
|
53
|
-
})
|
|
54
|
-
.pipe(take(1), finalize(() => this.loading.set(false)))
|
|
55
|
-
.subscribe({
|
|
56
|
-
next: (response) => {
|
|
57
|
-
this.items.set(response.data ?? []);
|
|
58
|
-
},
|
|
59
|
-
error: () => {
|
|
60
|
-
this.items.set([]);
|
|
61
|
-
},
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
reload() {
|
|
65
|
-
this.load();
|
|
66
|
-
}
|
|
67
|
-
setKeyword(value) {
|
|
68
|
-
this.keyword.set(value);
|
|
69
|
-
}
|
|
70
|
-
setScope(value) {
|
|
71
|
-
this.scope.set(value);
|
|
72
|
-
}
|
|
73
|
-
setApplication(value) {
|
|
74
|
-
this.application.set(value);
|
|
75
|
-
}
|
|
76
|
-
setOrganization(value) {
|
|
77
|
-
this.organization.set(value);
|
|
78
|
-
}
|
|
79
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: RolePermissionIndexFacade, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
80
|
-
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: RolePermissionIndexFacade });
|
|
81
|
-
}
|
|
82
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: RolePermissionIndexFacade, decorators: [{
|
|
83
|
-
type: Injectable
|
|
84
|
-
}] });
|
|
85
|
-
|
|
86
|
-
class RolePermissionIndex {
|
|
87
|
-
facade = inject(RolePermissionIndexFacade);
|
|
88
|
-
router = inject(Router);
|
|
89
|
-
ngOnInit() {
|
|
90
|
-
void this.facade.load();
|
|
91
|
-
}
|
|
92
|
-
onKeywordInput(event) {
|
|
93
|
-
const value = event.target.value;
|
|
94
|
-
this.facade.setKeyword(value);
|
|
95
|
-
}
|
|
96
|
-
onScopeChange(event) {
|
|
97
|
-
const value = event.target.value;
|
|
98
|
-
this.facade.setScope(value);
|
|
99
|
-
}
|
|
100
|
-
onApplicationInput(event) {
|
|
101
|
-
const value = event.target.value;
|
|
102
|
-
this.facade.setApplication(value);
|
|
103
|
-
}
|
|
104
|
-
onOrganizationInput(event) {
|
|
105
|
-
const value = event.target.value;
|
|
106
|
-
this.facade.setOrganization(value);
|
|
107
|
-
}
|
|
108
|
-
reload() {
|
|
109
|
-
this.facade.reload();
|
|
110
|
-
}
|
|
111
|
-
clearFilters() {
|
|
112
|
-
this.facade.setKeyword('');
|
|
113
|
-
this.facade.setScope('ALL');
|
|
114
|
-
this.facade.setApplication('');
|
|
115
|
-
this.facade.setOrganization('');
|
|
116
|
-
}
|
|
117
|
-
openRolePermissions(item) {
|
|
118
|
-
const baseCommands = item.scope === 'APP'
|
|
119
|
-
? ['/platform/roles/application', item.id]
|
|
120
|
-
: item.scope === 'ORG'
|
|
121
|
-
? ['/platform/roles/organization', item.id]
|
|
122
|
-
: ['/platform/roles/platform', item.id];
|
|
123
|
-
void this.router.navigate(baseCommands, {
|
|
124
|
-
queryParams: {
|
|
125
|
-
appId: item.applicationId ?? undefined,
|
|
126
|
-
orgId: item.organizationId ?? undefined,
|
|
127
|
-
},
|
|
128
|
-
});
|
|
129
|
-
}
|
|
130
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: RolePermissionIndex, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
131
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.1", type: RolePermissionIndex, isStandalone: true, selector: "rolatech-role-permission-index", providers: [RolePermissionIndexFacade], 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\">Roles</h1>\n <p class=\"text-sm text-muted-foreground\">View platform, application, and organization roles from one index.</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 Roles</div>\n <div stat-value>{{ facade.totalRoles() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Total Assigned Permissions</div>\n <div stat-value>{{ facade.totalPermissions() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Roles With No Permissions</div>\n <div stat-value>{{ facade.emptyRoles() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Active Roles</div>\n <div stat-value>{{ facade.activeRoles() }}</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 roles by scope and owner.</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 role name or code\"\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\">Scope</span>\n <select class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\" [value]=\"facade.scope()\" (change)=\"onScopeChange($event)\">\n <option value=\"ALL\">All</option>\n <option value=\"PLATFORM\">Platform</option>\n <option value=\"APP\">Application</option>\n <option value=\"ORG\">Organization</option>\n </select>\n </label>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Application</span>\n <input\n type=\"text\"\n [value]=\"facade.application()\"\n (input)=\"onApplicationInput($event)\"\n placeholder=\"Filter by application name\"\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\">Organization</span>\n <input\n type=\"text\"\n [value]=\"facade.organization()\"\n (input)=\"onOrganizationInput($event)\"\n placeholder=\"Filter by organization name\"\n class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\"\n />\n </label>\n\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-4 py-2 text-sm font-medium\"\n (click)=\"clearFilters()\"\n >\n Clear\n </button>\n\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-4 py-2 text-sm font-medium\"\n [disabled]=\"facade.loading()\"\n (click)=\"reload()\"\n >\n Refresh\n </button>\n </div>\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\">Role List</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.filteredItems().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\">Role</th>\n <th class=\"px-4 py-3 font-medium\">Scope</th>\n <th class=\"px-4 py-3 font-medium\">Application</th>\n <th class=\"px-4 py-3 font-medium\">Organization</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.loading()) {\n <tr>\n <td colspan=\"8\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading roles...</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 roles 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 }}</div>\n </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 text-muted-foreground\">{{ item.applicationName || '\u2014' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.organizationName || '\u2014' }}</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 <span class=\"inline-flex rounded-full border border-(--rt-border-color) px-2.5 py-1 text-xs\">\n {{ item.active ? 'Enabled' : 'Disabled' }}\n </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)=\"openRolePermissions(item)\"\n >\n Manage Permissions\n </button>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n </section>\n</section>\n", styles: [""], 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" }, { kind: "component", type: PlatformScopeBadge, selector: "rolatech-platform-scope-badge", inputs: ["scope"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
132
|
-
}
|
|
133
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.1", ngImport: i0, type: RolePermissionIndex, decorators: [{
|
|
134
|
-
type: Component,
|
|
135
|
-
args: [{ selector: 'rolatech-role-permission-index', imports: [PlatformPageHeader, PlatformStatCard, PlatformFilterPanel, PlatformDataTable, PlatformScopeBadge], changeDetection: ChangeDetectionStrategy.OnPush, providers: [RolePermissionIndexFacade], 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\">Roles</h1>\n <p class=\"text-sm text-muted-foreground\">View platform, application, and organization roles from one index.</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 Roles</div>\n <div stat-value>{{ facade.totalRoles() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Total Assigned Permissions</div>\n <div stat-value>{{ facade.totalPermissions() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Roles With No Permissions</div>\n <div stat-value>{{ facade.emptyRoles() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Active Roles</div>\n <div stat-value>{{ facade.activeRoles() }}</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 roles by scope and owner.</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 role name or code\"\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\">Scope</span>\n <select class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\" [value]=\"facade.scope()\" (change)=\"onScopeChange($event)\">\n <option value=\"ALL\">All</option>\n <option value=\"PLATFORM\">Platform</option>\n <option value=\"APP\">Application</option>\n <option value=\"ORG\">Organization</option>\n </select>\n </label>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Application</span>\n <input\n type=\"text\"\n [value]=\"facade.application()\"\n (input)=\"onApplicationInput($event)\"\n placeholder=\"Filter by application name\"\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\">Organization</span>\n <input\n type=\"text\"\n [value]=\"facade.organization()\"\n (input)=\"onOrganizationInput($event)\"\n placeholder=\"Filter by organization name\"\n class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\"\n />\n </label>\n\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-4 py-2 text-sm font-medium\"\n (click)=\"clearFilters()\"\n >\n Clear\n </button>\n\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-4 py-2 text-sm font-medium\"\n [disabled]=\"facade.loading()\"\n (click)=\"reload()\"\n >\n Refresh\n </button>\n </div>\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\">Role List</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.filteredItems().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\">Role</th>\n <th class=\"px-4 py-3 font-medium\">Scope</th>\n <th class=\"px-4 py-3 font-medium\">Application</th>\n <th class=\"px-4 py-3 font-medium\">Organization</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.loading()) {\n <tr>\n <td colspan=\"8\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading roles...</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 roles 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 }}</div>\n </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 text-muted-foreground\">{{ item.applicationName || '\u2014' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.organizationName || '\u2014' }}</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 <span class=\"inline-flex rounded-full border border-(--rt-border-color) px-2.5 py-1 text-xs\">\n {{ item.active ? 'Enabled' : 'Disabled' }}\n </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)=\"openRolePermissions(item)\"\n >\n Manage Permissions\n </button>\n </td>\n </tr>\n } }\n </tbody>\n </rolatech-platform-data-table>\n </section>\n</section>\n" }]
|
|
136
|
-
}] });
|
|
137
|
-
|
|
138
|
-
export { RolePermissionIndex };
|
|
139
|
-
//# sourceMappingURL=rolatech-angular-platform-role-permission-index-CkFgu7BW.mjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"rolatech-angular-platform-role-permission-index-CkFgu7BW.mjs","sources":["../../../../packages/angular-platform/src/lib/store/role-permission-index.facade.ts","../../../../packages/angular-platform/src/lib/pages/role/role-permission-index/role-permission-index.ts","../../../../packages/angular-platform/src/lib/pages/role/role-permission-index/role-permission-index.html"],"sourcesContent":["import { Injectable, computed, inject, signal } from '@angular/core';\nimport { finalize, take } from 'rxjs';\nimport { PermissionService, RolePermissionIndexItem } from '@rolatech/angular-services';\nimport { RoleScope } from '../model/role.models';\nimport { RolePermissionPageOptions } from '../intefaces/role-permission-page-options';\n\n@Injectable()\nexport class RolePermissionIndexFacade {\n private readonly permissionService = inject(PermissionService);\n\n readonly loading = signal(false);\n readonly items = signal<RolePermissionIndexItem[]>([]);\n\n readonly options = signal<RolePermissionPageOptions>({\n mode: 'PLATFORM',\n });\n\n readonly keyword = signal('');\n readonly scope = signal<RoleScope | 'ALL'>('ALL');\n readonly application = signal('');\n readonly organization = signal('');\n\n readonly filteredItems = computed(() => {\n const keyword = this.keyword().trim().toLowerCase();\n const scope = this.scope();\n const application = this.application().trim().toLowerCase();\n const organization = this.organization().trim().toLowerCase();\n\n return this.items().filter((item) => {\n const matchesKeyword = !keyword || item.name.toLowerCase().includes(keyword) || item.code.toLowerCase().includes(keyword);\n\n const matchesScope = scope === 'ALL' || item.scope === scope;\n\n const matchesApplication = !application || (item.applicationName ?? '').toLowerCase().includes(application);\n\n const matchesOrganization = !organization || (item.organizationName ?? '').toLowerCase().includes(organization);\n\n return matchesKeyword && matchesScope && matchesApplication && matchesOrganization;\n });\n });\n\n readonly totalRoles = computed(() => this.items().length);\n\n readonly totalPermissions = computed(() => this.items().reduce((sum, item) => sum + item.permissionCount, 0));\n\n readonly emptyRoles = computed(() => this.items().filter((item) => item.permissionCount === 0).length);\n\n readonly activeRoles = computed(() => this.items().filter((item) => item.active).length);\n\n setOptions(options: RolePermissionPageOptions): void {\n this.options.set(options);\n\n if (options.mode !== 'PLATFORM') {\n this.scope.set('ALL');\n }\n }\n\n load(): void {\n const options = this.options();\n\n this.loading.set(true);\n\n this.permissionService\n .findRoles({\n keyword: this.keyword() || null,\n scope: this.scope(),\n applicationId: options.applicationId ?? null,\n organizationId: options.organizationId ?? null,\n active: null,\n manageScope: options.mode === 'PLATFORM' ? 'PLATFORM' : options.mode === 'APPLICATION' ? 'APP' : 'ORG',\n })\n .pipe(\n take(1),\n finalize(() => this.loading.set(false)),\n )\n .subscribe({\n next: (response) => {\n this.items.set(response.data ?? []);\n },\n error: () => {\n this.items.set([]);\n },\n });\n }\n\n reload(): void {\n this.load();\n }\n\n setKeyword(value: string): void {\n this.keyword.set(value);\n }\n\n setScope(value: RoleScope | 'ALL'): void {\n this.scope.set(value);\n }\n\n setApplication(value: string): void {\n this.application.set(value);\n }\n\n setOrganization(value: string): void {\n this.organization.set(value);\n }\n}\n","import { ChangeDetectionStrategy, Component, inject, OnInit } from '@angular/core';\nimport { RolePermissionIndexFacade } from '../../../store/role-permission-index.facade';\nimport { Router } from '@angular/router';\nimport {\n PlatformDataTable,\n PlatformFilterPanel,\n PlatformPageHeader,\n PlatformScopeBadge,\n PlatformStatCard,\n} from '../../../shared';\nimport { RolePermissionIndexItem } from '@rolatech/angular-services';\n\n@Component({\n selector: 'rolatech-role-permission-index',\n imports: [PlatformPageHeader, PlatformStatCard, PlatformFilterPanel, PlatformDataTable, PlatformScopeBadge],\n templateUrl: './role-permission-index.html',\n styleUrl: './role-permission-index.scss',\n changeDetection: ChangeDetectionStrategy.OnPush,\n providers: [RolePermissionIndexFacade],\n})\nexport class RolePermissionIndex implements OnInit {\n readonly facade = inject(RolePermissionIndexFacade);\n private readonly router = inject(Router);\n\n ngOnInit(): void {\n void this.facade.load();\n }\n\n onKeywordInput(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n this.facade.setKeyword(value);\n }\n\n onScopeChange(event: Event): void {\n const value = (event.target as HTMLSelectElement).value as 'ALL' | 'PLATFORM' | 'APP' | 'ORG';\n this.facade.setScope(value);\n }\n\n onApplicationInput(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n this.facade.setApplication(value);\n }\n\n onOrganizationInput(event: Event): void {\n const value = (event.target as HTMLInputElement).value;\n this.facade.setOrganization(value);\n }\n\n reload(): void {\n this.facade.reload();\n }\n\n clearFilters(): void {\n this.facade.setKeyword('');\n this.facade.setScope('ALL');\n this.facade.setApplication('');\n this.facade.setOrganization('');\n }\n\n openRolePermissions(item: RolePermissionIndexItem): void {\n const baseCommands =\n item.scope === 'APP'\n ? ['/platform/roles/application', item.id]\n : item.scope === 'ORG'\n ? ['/platform/roles/organization', item.id]\n : ['/platform/roles/platform', item.id];\n\n void this.router.navigate(baseCommands, {\n queryParams: {\n appId: item.applicationId ?? undefined,\n orgId: item.organizationId ?? undefined,\n },\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 <rolatech-platform-page-header>\n <div header-left class=\"space-y-1\">\n <h1 class=\"text-2xl font-semibold tracking-tight\">Roles</h1>\n <p class=\"text-sm text-muted-foreground\">View platform, application, and organization roles from one index.</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 Roles</div>\n <div stat-value>{{ facade.totalRoles() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Total Assigned Permissions</div>\n <div stat-value>{{ facade.totalPermissions() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Roles With No Permissions</div>\n <div stat-value>{{ facade.emptyRoles() }}</div>\n </rolatech-platform-stat-card>\n\n <rolatech-platform-stat-card>\n <div stat-label>Active Roles</div>\n <div stat-value>{{ facade.activeRoles() }}</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 roles by scope and owner.</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 role name or code\"\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\">Scope</span>\n <select class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\" [value]=\"facade.scope()\" (change)=\"onScopeChange($event)\">\n <option value=\"ALL\">All</option>\n <option value=\"PLATFORM\">Platform</option>\n <option value=\"APP\">Application</option>\n <option value=\"ORG\">Organization</option>\n </select>\n </label>\n\n <label class=\"flex flex-col gap-2\">\n <span class=\"text-sm font-medium\">Application</span>\n <input\n type=\"text\"\n [value]=\"facade.application()\"\n (input)=\"onApplicationInput($event)\"\n placeholder=\"Filter by application name\"\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\">Organization</span>\n <input\n type=\"text\"\n [value]=\"facade.organization()\"\n (input)=\"onOrganizationInput($event)\"\n placeholder=\"Filter by organization name\"\n class=\"h-10 rounded-xl border border-(--rt-border-color) px-3 text-sm outline-none\"\n />\n </label>\n\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-4 py-2 text-sm font-medium\"\n (click)=\"clearFilters()\"\n >\n Clear\n </button>\n\n <button\n type=\"button\"\n class=\"inline-flex items-center rounded-xl border border-(--rt-border-color) px-4 py-2 text-sm font-medium\"\n [disabled]=\"facade.loading()\"\n (click)=\"reload()\"\n >\n Refresh\n </button>\n </div>\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\">Role List</h2>\n <div class=\"text-sm text-muted-foreground\">{{ facade.filteredItems().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\">Role</th>\n <th class=\"px-4 py-3 font-medium\">Scope</th>\n <th class=\"px-4 py-3 font-medium\">Application</th>\n <th class=\"px-4 py-3 font-medium\">Organization</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.loading()) {\n <tr>\n <td colspan=\"8\" class=\"px-4 py-10 text-center text-muted-foreground\">Loading roles...</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 roles 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 }}</div>\n </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 text-muted-foreground\">{{ item.applicationName || '—' }}</td>\n <td class=\"px-4 py-3 text-muted-foreground\">{{ item.organizationName || '—' }}</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 <span class=\"inline-flex rounded-full border border-(--rt-border-color) px-2.5 py-1 text-xs\">\n {{ item.active ? 'Enabled' : 'Disabled' }}\n </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)=\"openRolePermissions(item)\"\n >\n Manage Permissions\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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"}
|