ng-tablekit 1.0.0
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/LICENSE +21 -0
- package/PUBLISHING.md +46 -0
- package/README.md +102 -0
- package/bin/tablekit.mjs +436 -0
- package/package.json +81 -0
- package/src/app/core/config/table.config.ts +18 -0
- package/src/app/core/data/record.data.ts +26 -0
- package/src/app/core/models/table.models.ts +61 -0
- package/src/app/core/utils/table.utils.ts +49 -0
- package/src/app/templates/master-page/master-map-drawer.component.css +118 -0
- package/src/app/templates/master-page/master-map-drawer.component.html +49 -0
- package/src/app/templates/master-page/master-map-drawer.component.ts +94 -0
- package/src/app/templates/master-page/master-page.component.css +311 -0
- package/src/app/templates/master-page/master-page.component.html +131 -0
- package/src/app/templates/master-page/master-page.component.ts +290 -0
- package/src/app/templates/master-page/master-record-drawer.component.css +3 -0
- package/src/app/templates/master-page/master-record-drawer.component.html +52 -0
- package/src/app/templates/master-page/master-record-drawer.component.ts +74 -0
- package/src/app/templates/report-page/report-page.component.css +274 -0
- package/src/app/templates/report-page/report-page.component.html +75 -0
- package/src/app/templates/report-page/report-page.component.ts +174 -0
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { TableAction, TableColumn, TableRecord } from '../models/table.models';
|
|
2
|
+
|
|
3
|
+
export const STANDARD_COLUMNS: TableColumn<TableRecord>[] = [
|
|
4
|
+
{ key: 'name', title: 'Name', type: 'text', sortable: true, width: '220px', align: 'left' },
|
|
5
|
+
{ key: 'code', title: 'Code', type: 'text', sortable: true, width: '130px', align: 'center' },
|
|
6
|
+
{ key: 'category', title: 'Category', type: 'text', sortable: true, filterable: true, width: '150px', align: 'left' },
|
|
7
|
+
// { key: 'amount', title: 'Amount', type: 'currency', sortable: true, width: '120px', align: 'right' },
|
|
8
|
+
{ key: 'createdDate', title: 'Created Date', type: 'date', sortable: true, width: '150px', align: 'center' },
|
|
9
|
+
{ key: 'status', title: 'Status', type: 'status', filterable: true, align: 'center', width: '120px' }
|
|
10
|
+
];
|
|
11
|
+
|
|
12
|
+
export const PAGE_SIZE_OPTIONS = [10, 20, 30, 40, 50];
|
|
13
|
+
|
|
14
|
+
export const STANDARD_ACTIONS: TableAction[] = [
|
|
15
|
+
{ key: 'view', label: 'View', icon: 'eye' },
|
|
16
|
+
{ key: 'edit', label: 'Edit', icon: 'edit' },
|
|
17
|
+
{ key: 'delete', label: 'Delete', icon: 'delete', danger: true }
|
|
18
|
+
];
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { TableRecord } from '../models/table.models';
|
|
2
|
+
|
|
3
|
+
const categories = ['Category A', 'Category B', 'Category C', 'Category D'];
|
|
4
|
+
const types = ['Standard', 'Priority', 'Internal', 'External'];
|
|
5
|
+
const people = ['Alex Morgan', 'Jordan Lee', 'Taylor Smith', 'Casey Brown', 'Morgan Davis'];
|
|
6
|
+
const statuses: TableRecord['status'][] = ['Active', 'Inactive', 'Pending', 'Approved', 'Rejected'];
|
|
7
|
+
|
|
8
|
+
export const TABLE_RECORDS: TableRecord[] = Array.from({ length: 125 }, (_, index) => {
|
|
9
|
+
const number = index + 1;
|
|
10
|
+
const created = new Date(2026, index % 8, (index % 26) + 1);
|
|
11
|
+
return {
|
|
12
|
+
id: number,
|
|
13
|
+
name: `${['Alpha','Beta','Gamma','Delta','Omega'][index % 5]} Record ${String(number).padStart(3, '0')}`,
|
|
14
|
+
code: `REC-${String(number).padStart(3, '0')}`,
|
|
15
|
+
category: categories[index % categories.length],
|
|
16
|
+
type: types[index % types.length],
|
|
17
|
+
referenceNumber: `REF-${2026000 + number}`,
|
|
18
|
+
sequence: number,
|
|
19
|
+
createdDate: created.toISOString(),
|
|
20
|
+
assignedTo: people[index % people.length],
|
|
21
|
+
amount: 1250 + number * 87.5,
|
|
22
|
+
status: statuses[index % statuses.length],
|
|
23
|
+
active: index % 3 !== 0,
|
|
24
|
+
description: `Generic record ${number} used to demonstrate reusable Angular table behavior.`
|
|
25
|
+
};
|
|
26
|
+
});
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export type RecordStatus = 'Active' | 'Inactive' | 'Pending' | 'Approved' | 'Rejected';
|
|
2
|
+
export type TableColumnType = 'text' | 'number' | 'date' | 'currency' | 'status' | 'boolean' | 'action';
|
|
3
|
+
export type TableAlign = 'left' | 'center' | 'right';
|
|
4
|
+
export type TableSortOrder = 'ascend' | 'descend' | null;
|
|
5
|
+
|
|
6
|
+
export interface TableRecord {
|
|
7
|
+
id: number;
|
|
8
|
+
name: string;
|
|
9
|
+
code: string;
|
|
10
|
+
category: string;
|
|
11
|
+
type: string;
|
|
12
|
+
referenceNumber: string;
|
|
13
|
+
sequence: number;
|
|
14
|
+
createdDate: string;
|
|
15
|
+
assignedTo: string;
|
|
16
|
+
amount: number;
|
|
17
|
+
status: RecordStatus;
|
|
18
|
+
active: boolean;
|
|
19
|
+
description: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface TableFilterOption {
|
|
23
|
+
text: string;
|
|
24
|
+
value: string | number | boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface TableColumn<T extends object = TableRecord> {
|
|
28
|
+
key: keyof T & string;
|
|
29
|
+
title: string;
|
|
30
|
+
type?: TableColumnType;
|
|
31
|
+
sortable?: boolean;
|
|
32
|
+
filterable?: boolean;
|
|
33
|
+
filters?: TableFilterOption[];
|
|
34
|
+
width?: string;
|
|
35
|
+
align?: TableAlign;
|
|
36
|
+
dateFormat?: string;
|
|
37
|
+
currencyCode?: string;
|
|
38
|
+
visible?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface TableAction {
|
|
42
|
+
key: 'view' | 'edit' | 'delete' | string;
|
|
43
|
+
label: string;
|
|
44
|
+
icon?: string;
|
|
45
|
+
danger?: boolean;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface TableQuery {
|
|
49
|
+
pageIndex: number;
|
|
50
|
+
pageSize: number;
|
|
51
|
+
searchText: string;
|
|
52
|
+
sortField: string | null;
|
|
53
|
+
sortOrder: TableSortOrder;
|
|
54
|
+
filters: Record<string, Array<string | number | boolean>>;
|
|
55
|
+
createdDateRange?: [Date, Date] | null;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface TableResponse<T> {
|
|
59
|
+
data: T[];
|
|
60
|
+
total: number;
|
|
61
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { TableRecord, TableSortOrder } from '../models/table.models';
|
|
2
|
+
|
|
3
|
+
export function getStatusColor(status: TableRecord['status']): string {
|
|
4
|
+
const colors: Record<TableRecord['status'], string> = {
|
|
5
|
+
Active: 'green',
|
|
6
|
+
Inactive: 'default',
|
|
7
|
+
Pending: 'orange',
|
|
8
|
+
Approved: 'blue',
|
|
9
|
+
Rejected: 'red'
|
|
10
|
+
};
|
|
11
|
+
return colors[status];
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function sortRecords<T extends Record<string, unknown>>(records: T[], field: string | null, order: TableSortOrder): T[] {
|
|
15
|
+
if (!field || !order) return [...records];
|
|
16
|
+
return [...records].sort((left, right) => {
|
|
17
|
+
const a = left[field];
|
|
18
|
+
const b = right[field];
|
|
19
|
+
const result = String(a ?? '').localeCompare(String(b ?? ''), undefined, { numeric: true, sensitivity: 'base' });
|
|
20
|
+
return order === 'ascend' ? result : -result;
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const sortFnCache = new Map<string, any>();
|
|
25
|
+
|
|
26
|
+
export function createColumnSortFn<T extends object>(key: keyof T): (left: T, right: T) => number {
|
|
27
|
+
const cacheKey = String(key);
|
|
28
|
+
if (!sortFnCache.has(cacheKey)) {
|
|
29
|
+
sortFnCache.set(cacheKey, (left: T, right: T) => String(left[key] ?? '').localeCompare(String(right[key] ?? ''), undefined, {
|
|
30
|
+
numeric: true,
|
|
31
|
+
sensitivity: 'base'
|
|
32
|
+
}));
|
|
33
|
+
}
|
|
34
|
+
return sortFnCache.get(cacheKey);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function globalRecordSearch(record: TableRecord, searchText: string): boolean {
|
|
38
|
+
if (!searchText) return true;
|
|
39
|
+
const haystack = [record.name, record.code, record.category, record.type, record.referenceNumber, record.assignedTo, record.status]
|
|
40
|
+
.join(' ')
|
|
41
|
+
.toLowerCase();
|
|
42
|
+
return haystack.includes(searchText.trim().toLowerCase());
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function formatDateValue(value: unknown): string {
|
|
46
|
+
const date = new Date(String(value ?? ''));
|
|
47
|
+
if (Number.isNaN(date.getTime())) return '';
|
|
48
|
+
return new Intl.DateTimeFormat('en-GB', { day: '2-digit', month: 'short', year: 'numeric' }).format(date);
|
|
49
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
:host {
|
|
2
|
+
display: block;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
/* Toolbar */
|
|
6
|
+
.table-toolbar {
|
|
7
|
+
display: flex;
|
|
8
|
+
align-items: center;
|
|
9
|
+
justify-content: space-between;
|
|
10
|
+
gap: 8px;
|
|
11
|
+
flex-wrap: wrap;
|
|
12
|
+
background: transparent;
|
|
13
|
+
padding: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
.table-toolbar__right {
|
|
17
|
+
display: flex;
|
|
18
|
+
align-items: center;
|
|
19
|
+
justify-content: flex-end;
|
|
20
|
+
gap: 8px;
|
|
21
|
+
flex-wrap: wrap;
|
|
22
|
+
margin-left: auto;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Compact Buttons (Filter, Excel, Actions) */
|
|
26
|
+
.compact-btn {
|
|
27
|
+
height: 32px !important;
|
|
28
|
+
min-width: 32px !important;
|
|
29
|
+
border-radius: 6px !important;
|
|
30
|
+
display: inline-flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
gap: 6px;
|
|
34
|
+
padding: 0 12px !important;
|
|
35
|
+
font-size: 12px !important;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.compact-btn.icon-only {
|
|
39
|
+
padding: 0 !important;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/* Search Field */
|
|
43
|
+
.search-field {
|
|
44
|
+
width: 260px;
|
|
45
|
+
margin-bottom: 0;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.new-role-field {
|
|
49
|
+
width: 190px;
|
|
50
|
+
height: 32px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.text-danger {
|
|
54
|
+
padding: 0;
|
|
55
|
+
border: 0;
|
|
56
|
+
background: transparent;
|
|
57
|
+
color: #cf1322;
|
|
58
|
+
cursor: pointer;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.drawer-wrapper ::ng-deep .search-field .ant-input {
|
|
62
|
+
height: 32px !important;
|
|
63
|
+
border-radius: 8px 0 0 8px !important;
|
|
64
|
+
font-size: 12px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.drawer-wrapper ::ng-deep .search-field .ant-input-group-addon .ant-btn {
|
|
68
|
+
height: 32px !important;
|
|
69
|
+
width: 40px !important;
|
|
70
|
+
border-radius: 0 8px 8px 0 !important;
|
|
71
|
+
display: flex;
|
|
72
|
+
align-items: center;
|
|
73
|
+
justify-content: center;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/* Table Overrides */
|
|
77
|
+
.drawer-wrapper ::ng-deep .ant-table {
|
|
78
|
+
background: #ffffff !important;
|
|
79
|
+
font-family: Poppins, Arial, sans-serif;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.drawer-wrapper ::ng-deep .ant-table-bordered .ant-table-container {
|
|
83
|
+
border: 0 !important;
|
|
84
|
+
border-left: 1px solid #e5e7eb !important;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.drawer-wrapper ::ng-deep .ant-table-thead>tr>th {
|
|
88
|
+
background: #fafafa !important;
|
|
89
|
+
color: #262626 !important;
|
|
90
|
+
font-family: Poppins, Arial, sans-serif;
|
|
91
|
+
font-size: 14px !important;
|
|
92
|
+
font-weight: 600 !important;
|
|
93
|
+
white-space: nowrap;
|
|
94
|
+
padding: 8px 12px !important;
|
|
95
|
+
border-bottom: 1px solid #e5e7eb !important;
|
|
96
|
+
vertical-align: middle !important;
|
|
97
|
+
text-align: center !important;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.drawer-wrapper ::ng-deep .ant-table-tbody>tr>td {
|
|
101
|
+
color: #333 !important;
|
|
102
|
+
font-size: 12px !important;
|
|
103
|
+
font-weight: 400 !important;
|
|
104
|
+
padding: 6px 12px !important;
|
|
105
|
+
vertical-align: middle !important;
|
|
106
|
+
border-bottom: 1px solid #e5e7eb !important;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.drawer-wrapper ::ng-deep .ant-pagination {
|
|
110
|
+
margin-top: 12px !important;
|
|
111
|
+
display: flex;
|
|
112
|
+
justify-content: flex-end;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Form Overrides */
|
|
116
|
+
.status-switch {
|
|
117
|
+
min-width: 70px;
|
|
118
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
<nz-drawer
|
|
2
|
+
class="drawer-wrapper"
|
|
3
|
+
[nzVisible]="visible"
|
|
4
|
+
[nzTitle]="title"
|
|
5
|
+
[nzWidth]="800"
|
|
6
|
+
(nzOnClose)="onClose()"
|
|
7
|
+
>
|
|
8
|
+
<ng-container *nzDrawerContent>
|
|
9
|
+
<div class="table-toolbar" style="margin-bottom: 16px; padding: 0;">
|
|
10
|
+
<div class="table-toolbar__right" style="width: 100%; margin: 0;">
|
|
11
|
+
<div class="search-field">
|
|
12
|
+
<nz-input-group nzSearch [nzAddOnAfter]="mapSearchBtn">
|
|
13
|
+
<input type="text" nz-input placeholder="Search roles" [(ngModel)]="searchText" (keydown.enter)="applySearch()" />
|
|
14
|
+
</nz-input-group>
|
|
15
|
+
<ng-template #mapSearchBtn>
|
|
16
|
+
<button nz-button class="compact-btn icon-only" nzType="primary" type="button" (click)="applySearch()" aria-label="Search roles"><span nz-icon nzType="search"></span></button>
|
|
17
|
+
</ng-template>
|
|
18
|
+
</div>
|
|
19
|
+
<input class="new-role-field" type="text" nz-input placeholder="New role name" [(ngModel)]="newRoleName" (keydown.enter)="addRole()" />
|
|
20
|
+
<button nz-button nzType="primary" class="compact-btn" type="button" [disabled]="!newRoleName.trim()" (click)="addRole()">
|
|
21
|
+
<span nz-icon nzType="plus"></span> Add New Role
|
|
22
|
+
</button>
|
|
23
|
+
</div>
|
|
24
|
+
</div>
|
|
25
|
+
|
|
26
|
+
<nz-table #mapTable nzBordered nzSize="small" [nzData]="filteredRoles" [nzShowPagination]="true" [nzPageSize]="10">
|
|
27
|
+
<thead>
|
|
28
|
+
<tr>
|
|
29
|
+
<th nzWidth="100px" nzAlign="center">Action</th>
|
|
30
|
+
<th nzAlign="center">Role Name</th>
|
|
31
|
+
<th nzWidth="120px" nzAlign="center">Is Active</th>
|
|
32
|
+
</tr>
|
|
33
|
+
</thead>
|
|
34
|
+
<tbody>
|
|
35
|
+
@for(role of mapTable.data; track role.id) {
|
|
36
|
+
<tr>
|
|
37
|
+
<td nzAlign="center">
|
|
38
|
+
<button class="text-danger" type="button" nz-popconfirm nzPopconfirmTitle="Delete this role?" (nzOnConfirm)="deleteRole(role.id)">Delete</button>
|
|
39
|
+
</td>
|
|
40
|
+
<td nzAlign="center">{{ role.name }}</td>
|
|
41
|
+
<td nzAlign="center">
|
|
42
|
+
<nz-switch [(ngModel)]="role.active" (ngModelChange)="persistRoles()" nzCheckedChildren="Active" nzUnCheckedChildren="Inactive" class="status-switch"></nz-switch>
|
|
43
|
+
</td>
|
|
44
|
+
</tr>
|
|
45
|
+
}
|
|
46
|
+
</tbody>
|
|
47
|
+
</nz-table>
|
|
48
|
+
</ng-container>
|
|
49
|
+
</nz-drawer>
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
|
2
|
+
import { FormsModule } from '@angular/forms';
|
|
3
|
+
import { PlusOutline, SearchOutline } from '@ant-design/icons-angular/icons';
|
|
4
|
+
import { NzButtonModule } from 'ng-zorro-antd/button';
|
|
5
|
+
import { NzDrawerModule } from 'ng-zorro-antd/drawer';
|
|
6
|
+
import { NzIconModule, provideNzIconsPatch } from 'ng-zorro-antd/icon';
|
|
7
|
+
import { NzInputModule } from 'ng-zorro-antd/input';
|
|
8
|
+
import { NzPopconfirmModule } from 'ng-zorro-antd/popconfirm';
|
|
9
|
+
import { NzSwitchModule } from 'ng-zorro-antd/switch';
|
|
10
|
+
import { NzTableModule } from 'ng-zorro-antd/table';
|
|
11
|
+
import { TableRecord } from '@core/models/table.models';
|
|
12
|
+
|
|
13
|
+
interface MappedRole {
|
|
14
|
+
id: number;
|
|
15
|
+
name: string;
|
|
16
|
+
active: boolean;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@Component({
|
|
20
|
+
selector: 'app-master-map-drawer',
|
|
21
|
+
standalone: true,
|
|
22
|
+
imports: [
|
|
23
|
+
FormsModule, NzButtonModule, NzDrawerModule, NzIconModule,
|
|
24
|
+
NzInputModule, NzPopconfirmModule, NzSwitchModule, NzTableModule
|
|
25
|
+
],
|
|
26
|
+
providers: [...provideNzIconsPatch([PlusOutline, SearchOutline])],
|
|
27
|
+
templateUrl: './master-map-drawer.component.html',
|
|
28
|
+
styleUrl: './master-map-drawer.component.css'
|
|
29
|
+
})
|
|
30
|
+
export class MasterMapDrawerComponent {
|
|
31
|
+
@Input() visible = false;
|
|
32
|
+
|
|
33
|
+
@Input()
|
|
34
|
+
set record(value: TableRecord | null) {
|
|
35
|
+
if (value) {
|
|
36
|
+
this.title = `${value.name} Role Map`;
|
|
37
|
+
this.selectedRecordId = value.id;
|
|
38
|
+
const savedRoles = this.roleMappings.get(value.id) ?? this.createDefaultRoles();
|
|
39
|
+
this.mapRoles = savedRoles.map(role => ({ ...role }));
|
|
40
|
+
this.searchText = '';
|
|
41
|
+
this.appliedSearchText = '';
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
@Output() close = new EventEmitter<void>();
|
|
46
|
+
|
|
47
|
+
protected title = '';
|
|
48
|
+
protected searchText = '';
|
|
49
|
+
protected newRoleName = '';
|
|
50
|
+
protected mapRoles: MappedRole[] = [];
|
|
51
|
+
private appliedSearchText = '';
|
|
52
|
+
private selectedRecordId: number | null = null;
|
|
53
|
+
private readonly roleMappings = new Map<number, MappedRole[]>();
|
|
54
|
+
|
|
55
|
+
protected get filteredRoles(): MappedRole[] {
|
|
56
|
+
const search = this.appliedSearchText.toLowerCase();
|
|
57
|
+
return search ? this.mapRoles.filter(role => role.name.toLowerCase().includes(search)) : this.mapRoles;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
protected applySearch(): void {
|
|
61
|
+
this.appliedSearchText = this.searchText.trim();
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
protected addRole(): void {
|
|
65
|
+
const name = this.newRoleName.trim();
|
|
66
|
+
if (!name) return;
|
|
67
|
+
const nextId = Math.max(0, ...this.mapRoles.map(role => role.id)) + 1;
|
|
68
|
+
this.mapRoles = [...this.mapRoles, { id: nextId, name, active: true }];
|
|
69
|
+
this.newRoleName = '';
|
|
70
|
+
this.persistRoles();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
protected deleteRole(roleId: number): void {
|
|
74
|
+
this.mapRoles = this.mapRoles.filter(role => role.id !== roleId);
|
|
75
|
+
this.persistRoles();
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
protected persistRoles(): void {
|
|
79
|
+
if (this.selectedRecordId !== null) {
|
|
80
|
+
this.roleMappings.set(this.selectedRecordId, this.mapRoles.map(role => ({ ...role })));
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
protected onClose(): void {
|
|
85
|
+
this.close.emit();
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
private createDefaultRoles(): MappedRole[] {
|
|
89
|
+
return [
|
|
90
|
+
{ id: 1, name: 'Asset Manager', active: true },
|
|
91
|
+
{ id: 2, name: 'Employee', active: false }
|
|
92
|
+
];
|
|
93
|
+
}
|
|
94
|
+
}
|