@genesislcap/blank-app-seed 3.21.0 → 3.22.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/.genx/package.json +1 -1
- package/.genx/templates/angular/chart.hbs +21 -9
- package/.genx/templates/angular/entityManager.hbs +57 -45
- package/.genx/templates/angular/form.hbs +21 -8
- package/.genx/templates/angular/grid.hbs +30 -18
- package/.genx/templates/angular/route.hbs +8 -5
- package/.genx/templates/web-components/entityManager.hbs +1 -1
- package/CHANGELOG.md +7 -0
- package/client-tmp/angular/angular.json +21 -12
- package/client-tmp/angular/package.json +45 -20
- package/client-tmp/angular/src/app/app-routing.module.ts +10 -3
- package/client-tmp/angular/src/app/app.component.spec.ts +2 -8
- package/client-tmp/angular/src/app/app.component.ts +0 -1
- package/client-tmp/angular/src/app/app.config.ts +1 -0
- package/client-tmp/angular/src/app/components/error-message/error-message.component.html +15 -0
- package/client-tmp/angular/src/app/components/error-message/error-message.component.spec.ts +74 -0
- package/client-tmp/angular/src/app/components/error-message/error-message.component.ts +15 -0
- package/client-tmp/angular/src/app/guards/auth.guard.ts +3 -3
- package/client-tmp/angular/src/app/guards/permissions.guard.ts +24 -0
- package/client-tmp/angular/src/app/layouts/blank/blank.layout.html +0 -1
- package/client-tmp/angular/src/app/layouts/blank/blank.layout.spec.ts +1 -1
- package/client-tmp/angular/src/app/layouts/default/default.layout.html +0 -1
- package/client-tmp/angular/src/app/layouts/default/default.layout.spec.ts +30 -15
- package/client-tmp/angular/src/app/pages/auth-login/auth-login.component.spec.ts +6 -6
- package/client-tmp/angular/src/app/pages/not-permitted/not-permitted.component.html +4 -0
- package/client-tmp/angular/src/app/pages/not-permitted/not-permitted.component.scss +12 -0
- package/client-tmp/angular/src/app/pages/not-permitted/not-permitted.component.spec.ts +32 -0
- package/client-tmp/angular/src/app/pages/not-permitted/not-permitted.component.ts +13 -0
- package/client-tmp/angular/src/app/services/auth.service.ts +12 -4
- package/client-tmp/angular/src/app/share/foundation-login.ts +3 -0
- package/client-tmp/angular/src/app/utils/index.ts +1 -0
- package/client-tmp/angular/src/app/utils/permissions.ts +7 -0
- package/client-tmp/angular/src/styles/_mixins.scss +8 -0
- package/package.json +1 -1
package/.genx/package.json
CHANGED
|
@@ -1,9 +1,21 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
<section style="height: 100%; width: 100%;">
|
|
2
|
+
<ng-container *ngIf="hasUserPermission('{{config.permissions.viewRight}}'); else notPermitted{{ config.index }}">
|
|
3
|
+
<rapid-g2plot-chart
|
|
4
|
+
type="{{ config.type }}"
|
|
5
|
+
[config]="tile{{ config.index }}.chartConfig"
|
|
6
|
+
>
|
|
7
|
+
<chart-datasource
|
|
8
|
+
resourceName="{{ config.resourceName }}"
|
|
9
|
+
server-fields="{{ config.xField }} {{ config.yField }}"
|
|
10
|
+
></chart-datasource>
|
|
11
|
+
</rapid-g2plot-chart>
|
|
12
|
+
</ng-container>
|
|
13
|
+
|
|
14
|
+
<ng-template #notPermitted{{ config.index }}>
|
|
15
|
+
<app-error-message
|
|
16
|
+
style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;"
|
|
17
|
+
elementType="h3"
|
|
18
|
+
message="You do not have access to view this component.">
|
|
19
|
+
</app-error-message>
|
|
20
|
+
</ng-template>
|
|
21
|
+
</section>
|
|
@@ -1,45 +1,57 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
1
|
+
<section style="height: 100%; width: 100%;">
|
|
2
|
+
<ng-container *ngIf="hasUserPermission('{{config.permissions.viewRight}}'); else notPermitted{{ config.index }}">
|
|
3
|
+
<entity-management
|
|
4
|
+
design-system-prefix="rapid"
|
|
5
|
+
enable-row-flashing
|
|
6
|
+
enable-cell-flashing
|
|
7
|
+
{{#if config.title}}
|
|
8
|
+
title="{{ config.title }}"
|
|
9
|
+
{{/if}}
|
|
10
|
+
resourceName="{{ config.resourceName }}"
|
|
11
|
+
{{#if config.createEvent}}
|
|
12
|
+
[createEvent]="hasUserPermission('{{config.permissions.updateRight}}') ? '{{ config.createEvent }}' : undefined"
|
|
13
|
+
{{#if config.createFormUiSchema}}
|
|
14
|
+
[createFormUiSchema]="tile{{ config.index }}.createFormUiSchema"
|
|
15
|
+
{{/if}}
|
|
16
|
+
{{/if}}
|
|
17
|
+
{{#if config.updateEvent}}
|
|
18
|
+
[updateEvent]="hasUserPermission('{{config.permissions.updateRight}}') ? '{{ config.updateEvent }}' : undefined"
|
|
19
|
+
{{#if config.updateFormUiSchema}}
|
|
20
|
+
[updateFormUiSchema]="tile{{ config.index }}.updateFormUiSchema"
|
|
21
|
+
{{/if}}
|
|
22
|
+
{{/if}}
|
|
23
|
+
{{#if config.deleteEvent}}
|
|
24
|
+
[deleteEvent]="hasUserPermission('{{config.permissions.updateRight}}') ? '{{ config.deleteEvent }}' : undefined"
|
|
25
|
+
{{/if}}
|
|
26
|
+
{{#if config.gridOptions}}
|
|
27
|
+
[gridOptions]="{{ config.gridOptions }}"
|
|
28
|
+
{{/if}}
|
|
29
|
+
{{#if config.snapshot}}
|
|
30
|
+
[datasourceConfig]="{ isSnapshot: {{ config.snapshot }} }"
|
|
31
|
+
{{/if}}
|
|
32
|
+
{{#if config.reqrep}}
|
|
33
|
+
[datasourceConfig]="tile{{ config.index }}.reqrep"
|
|
34
|
+
{{/if}}
|
|
35
|
+
{{#if config.columns}}
|
|
36
|
+
[columns]="tile{{ config.index }}.columns"
|
|
37
|
+
{{/if}}
|
|
38
|
+
{{#if config.modalPosition}}
|
|
39
|
+
modal-position="{{ config.modalPosition }}"
|
|
40
|
+
{{/if}}
|
|
41
|
+
{{#if config.sizeColumnsToFit}}
|
|
42
|
+
size-columns-to-fit
|
|
43
|
+
{{/if}}
|
|
44
|
+
{{#if config.enableSearchBar}}
|
|
45
|
+
enable-search-bar
|
|
46
|
+
{{/if}}
|
|
47
|
+
></entity-management>
|
|
48
|
+
</ng-container>
|
|
49
|
+
|
|
50
|
+
<ng-template #notPermitted{{ config.index }}>
|
|
51
|
+
<app-error-message
|
|
52
|
+
style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;"
|
|
53
|
+
elementType="h3"
|
|
54
|
+
message="You do not have access to view this component.">
|
|
55
|
+
</app-error-message>
|
|
56
|
+
</ng-template>
|
|
57
|
+
</section>
|
|
@@ -1,8 +1,21 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
<section style="height: 100%; width: 100%;">
|
|
2
|
+
<ng-container *ngIf="hasUserPermission('{{config.permissions.updateRight}}'); else notPermitted{{ config.index }}">
|
|
3
|
+
<foundation-form
|
|
4
|
+
design-system-prefix="rapid"
|
|
5
|
+
resourceName="{{config.resourceName}}"
|
|
6
|
+
{{#if config.uischema}}
|
|
7
|
+
[uischema]="tile{{ config.index }}.uischema"
|
|
8
|
+
{{/if}}
|
|
9
|
+
>
|
|
10
|
+
</foundation-form>
|
|
11
|
+
</ng-container>
|
|
12
|
+
|
|
13
|
+
<ng-template #notPermitted{{ config.index }}>
|
|
14
|
+
<app-error-message
|
|
15
|
+
style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;"
|
|
16
|
+
elementType="h3"
|
|
17
|
+
message="You do not have access to view this component.">
|
|
18
|
+
</app-error-message>
|
|
19
|
+
</ng-template>
|
|
20
|
+
</section>
|
|
21
|
+
|
|
@@ -1,18 +1,30 @@
|
|
|
1
|
-
<
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
<section style="height: 100%; width: 100%;">
|
|
2
|
+
<ng-container *ngIf="hasUserPermission('{{config.permissions.viewRight}}'); else notPermitted{{ config.index }}">
|
|
3
|
+
<rapid-grid-pro
|
|
4
|
+
enable-row-flashing
|
|
5
|
+
enable-cell-flashing
|
|
6
|
+
>
|
|
7
|
+
<grid-pro-genesis-datasource
|
|
8
|
+
resource-name="{{config.resourceName}}"
|
|
9
|
+
{{#if config.snapshot}}
|
|
10
|
+
isSnapshot="{{config.snapshot}}"
|
|
11
|
+
{{/if}}
|
|
12
|
+
{{#if config.reqrep}}
|
|
13
|
+
[datasourceConfig]="tile{{ config.index }}.reqrep"
|
|
14
|
+
{{/if}}
|
|
15
|
+
{{#if config.gridOptions}}
|
|
16
|
+
[deferredGridOptions]="tile{{ config.index }}.gridOptions"
|
|
17
|
+
{{/if}}
|
|
18
|
+
>
|
|
19
|
+
</grid-pro-genesis-datasource>
|
|
20
|
+
</rapid-grid-pro>
|
|
21
|
+
</ng-container>
|
|
22
|
+
|
|
23
|
+
<ng-template #notPermitted{{ config.index }}>
|
|
24
|
+
<app-error-message
|
|
25
|
+
style="width: 100%; height: 100%; display: flex; justify-content: center; align-items: center;"
|
|
26
|
+
elementType="h3"
|
|
27
|
+
message="You do not have access to view this component.">
|
|
28
|
+
</app-error-message>
|
|
29
|
+
</ng-template>
|
|
30
|
+
</section>
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import {Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';
|
|
2
|
-
import {CommonModule} from '@angular/common';
|
|
3
|
-
{
|
|
4
|
-
import { getDateFormatter, getNumberFormatter } from '../../utils';
|
|
5
|
-
{
|
|
1
|
+
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
import { User, getUser } from '@genesislcap/foundation-user';
|
|
4
|
+
import { getDateFormatter, getNumberFormatter, getViewUpdateRightComponent } from '../../utils';
|
|
5
|
+
import { ErrorMessageComponent } from '../../components/error-message/error-message.component';
|
|
6
6
|
|
|
7
7
|
@Component({
|
|
8
8
|
selector: 'app-{{pascalCase route.name}}',
|
|
9
9
|
standalone: true,
|
|
10
10
|
imports: [
|
|
11
|
+
ErrorMessageComponent,
|
|
11
12
|
CommonModule,
|
|
12
13
|
],
|
|
13
14
|
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
@@ -15,6 +16,8 @@ import { getDateFormatter, getNumberFormatter } from '../../utils';
|
|
|
15
16
|
styleUrls: ['./{{kebabCase route.name}}.component.css'],
|
|
16
17
|
})
|
|
17
18
|
export class {{pascalCase route.name}}Component {
|
|
19
|
+
hasUserPermission = (permissionCode: string) => getViewUpdateRightComponent(getUser(), permissionCode);
|
|
20
|
+
|
|
18
21
|
{{#each route.tiles}}
|
|
19
22
|
tile{{this.config.index}} = { {{#if this.config.createFormUiSchema}}
|
|
20
23
|
"createFormUiSchema": {{{ this.config.createFormUiSchema }}},{{/if}}{{#if this.config.updateFormUiSchema}}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [3.22.0](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v3.21.0...v3.22.0) (2024-07-15)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* angular handle route, component view/update permissions - [FUI-2066](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/2066) (#273) 8c73b16
|
|
9
|
+
|
|
3
10
|
## [3.21.0](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v3.20.5...v3.21.0) (2024-07-09)
|
|
4
11
|
|
|
5
12
|
|
|
@@ -13,12 +13,6 @@
|
|
|
13
13
|
"build": {
|
|
14
14
|
"builder": "@angular-builders/custom-webpack:browser",
|
|
15
15
|
"options": {
|
|
16
|
-
"customWebpackConfig": {
|
|
17
|
-
"path": "./custom-webpack.config.js",
|
|
18
|
-
"mergeStrategies": {
|
|
19
|
-
"externals": "replace"
|
|
20
|
-
}
|
|
21
|
-
},
|
|
22
16
|
"outputPath": "dist/{{pkgName}}",
|
|
23
17
|
"index": "src/index.html",
|
|
24
18
|
"main": "src/main.ts",
|
|
@@ -39,7 +33,9 @@
|
|
|
39
33
|
"size-sensor",
|
|
40
34
|
"pdfast",
|
|
41
35
|
"fmin",
|
|
42
|
-
"@json-schema-tools/dereferencer"
|
|
36
|
+
"@json-schema-tools/dereferencer",
|
|
37
|
+
"numeral",
|
|
38
|
+
"numeral/locales"
|
|
43
39
|
]
|
|
44
40
|
},
|
|
45
41
|
"configurations": {
|
|
@@ -107,13 +103,26 @@
|
|
|
107
103
|
},
|
|
108
104
|
"test": {
|
|
109
105
|
"builder": "@angular-builders/custom-webpack:karma",
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"
|
|
113
|
-
|
|
114
|
-
"
|
|
106
|
+
"configurations": {
|
|
107
|
+
"production": {
|
|
108
|
+
"customWebpackConfig": {
|
|
109
|
+
"path": "./webpack.prod.config.js",
|
|
110
|
+
"mergeStrategies": {
|
|
111
|
+
"externals": "replace"
|
|
112
|
+
}
|
|
115
113
|
}
|
|
116
114
|
},
|
|
115
|
+
"development": {
|
|
116
|
+
"customWebpackConfig": {
|
|
117
|
+
"path": "./webpack.dev.config.js",
|
|
118
|
+
"mergeStrategies": {
|
|
119
|
+
"externals": "replace"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
"defaultConfiguration": "development",
|
|
125
|
+
"options": {
|
|
117
126
|
"polyfills": ["zone.js", "zone.js/testing"],
|
|
118
127
|
"tsConfig": "tsconfig.spec.json",
|
|
119
128
|
"assets": ["src/favicon.ico", "src/assets"],
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "{{pkgName}}",
|
|
3
|
+
"description": "",
|
|
3
4
|
"version": "{{applicationVersionWeb}}",
|
|
5
|
+
"private": true,
|
|
6
|
+
"license": "UNLICENSED",
|
|
4
7
|
"scripts": {
|
|
5
8
|
"ng": "ng",
|
|
6
9
|
"bootstrap": "npm install --no-fund --no-audit",
|
|
@@ -9,7 +12,25 @@
|
|
|
9
12
|
"watch": "ng build --watch --configuration development",
|
|
10
13
|
"test": "ng test"
|
|
11
14
|
},
|
|
12
|
-
"
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"@angular-builders/custom-webpack": "^18.0.0",
|
|
17
|
+
"@angular-devkit/build-angular": "^18.0.4",
|
|
18
|
+
"@angular/cli": "^18.0.4",
|
|
19
|
+
"@angular/compiler-cli": "^18.0.4",
|
|
20
|
+
"@genesislcap/build-kit": "{{versions.UI}}",
|
|
21
|
+
"@types/jasmine": "~5.1.0",
|
|
22
|
+
"@types/numeral": "^2.0.5",
|
|
23
|
+
"file-loader": "^6.2.0",
|
|
24
|
+
"jasmine-core": "~5.1.0",
|
|
25
|
+
"karma": "~6.4.0",
|
|
26
|
+
"karma-chrome-launcher": "~3.2.0",
|
|
27
|
+
"karma-coverage": "~2.2.0",
|
|
28
|
+
"karma-jasmine": "~5.1.0",
|
|
29
|
+
"karma-jasmine-html-reporter": "~2.1.0",
|
|
30
|
+
"svg-url-loader": "^8.0.0",
|
|
31
|
+
"typescript": "~5.4.5",
|
|
32
|
+
"ts-node": "10.9.2"
|
|
33
|
+
},
|
|
13
34
|
"dependencies": {
|
|
14
35
|
"@angular/animations": "^18.0.4",
|
|
15
36
|
"@angular/common": "^18.0.4",
|
|
@@ -24,32 +45,36 @@
|
|
|
24
45
|
"@genesislcap/foundation-entity-management": "{{versions.UI}}",
|
|
25
46
|
"@genesislcap/foundation-header": "{{versions.UI}}",
|
|
26
47
|
"@genesislcap/foundation-ui": "{{versions.UI}}",
|
|
48
|
+
"@genesislcap/foundation-user": "{{versions.UI}}",
|
|
27
49
|
"@genesislcap/rapid-design-system": "{{versions.UI}}",
|
|
28
50
|
"@genesislcap/rapid-grid-pro": "{{versions.UI}}",
|
|
29
51
|
"@genesislcap/foundation-layout": "{{versions.UI}}",
|
|
30
52
|
"@genesislcap/g2plot-chart": "{{versions.UI}}",
|
|
31
53
|
"numeral": "2.0.6",
|
|
32
|
-
"rxjs": "~7.8.0",
|
|
33
54
|
"tslib": "^2.3.0",
|
|
34
55
|
"zone.js": "~0.14.3"
|
|
35
56
|
},
|
|
36
|
-
"
|
|
37
|
-
"@angular
|
|
38
|
-
"@angular
|
|
39
|
-
"@angular/
|
|
40
|
-
"@angular/
|
|
41
|
-
"@
|
|
42
|
-
"@
|
|
43
|
-
"@
|
|
44
|
-
"
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"
|
|
49
|
-
"
|
|
50
|
-
"
|
|
51
|
-
"
|
|
52
|
-
"
|
|
53
|
-
"
|
|
57
|
+
"overrides": {
|
|
58
|
+
"@angular/animations": "^18.0.4",
|
|
59
|
+
"@angular/common": "^18.0.4",
|
|
60
|
+
"@angular/compiler": "^18.0.4",
|
|
61
|
+
"@angular/core": "^18.0.4",
|
|
62
|
+
"@angular/forms": "^18.0.4",
|
|
63
|
+
"@angular/platform-browser": "^18.0.4",
|
|
64
|
+
"@angular/platform-browser-dynamic": "^18.0.4",
|
|
65
|
+
"@angular/router": "^18.0.4",
|
|
66
|
+
"@genesislcap/foundation-comms": "{{versions.UI}}",
|
|
67
|
+
"@genesislcap/foundation-login": "{{versions.UI}}",
|
|
68
|
+
"@genesislcap/foundation-entity-management": "{{versions.UI}}",
|
|
69
|
+
"@genesislcap/foundation-header": "{{versions.UI}}",
|
|
70
|
+
"@genesislcap/foundation-ui": "{{versions.UI}}",
|
|
71
|
+
"@genesislcap/foundation-user": "{{versions.UI}}",
|
|
72
|
+
"@genesislcap/rapid-design-system": "{{versions.UI}}",
|
|
73
|
+
"@genesislcap/rapid-grid-pro": "{{versions.UI}}",
|
|
74
|
+
"@genesislcap/foundation-layout": "{{versions.UI}}",
|
|
75
|
+
"@genesislcap/g2plot-chart": "{{versions.UI}}",
|
|
76
|
+
"numeral": "2.0.6",
|
|
77
|
+
"tslib": "^2.3.0",
|
|
78
|
+
"zone.js": "~0.14.3"
|
|
54
79
|
}
|
|
55
80
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { NgModule } from '@angular/core';
|
|
2
2
|
import { RouterModule, Routes } from '@angular/router';
|
|
3
3
|
import { AuthGuard } from './guards/auth.guard';
|
|
4
|
+
import { PermissionsGuard } from './guards/permissions.guard';
|
|
4
5
|
import { AuthLoginComponent } from './pages/auth-login/auth-login.component';
|
|
6
|
+
import { NotPermittedComponent } from './pages/not-permitted/not-permitted.component';
|
|
5
7
|
{{#each routes}}
|
|
6
8
|
import { {{pascalCase this.name}}Component } from './pages/{{kebabCase this.name}}/{{kebabCase this.name}}.component';
|
|
7
9
|
{{/each}}
|
|
8
|
-
import { AUTH_PATH } from './app.config';
|
|
10
|
+
import { AUTH_PATH, NOT_PERMITTED_PATH } from './app.config';
|
|
9
11
|
|
|
10
12
|
export const routes: Routes = [
|
|
11
13
|
{
|
|
@@ -17,11 +19,16 @@ export const routes: Routes = [
|
|
|
17
19
|
path: `${AUTH_PATH}`,
|
|
18
20
|
component: AuthLoginComponent,
|
|
19
21
|
},
|
|
22
|
+
{
|
|
23
|
+
path: `${NOT_PERMITTED_PATH}`,
|
|
24
|
+
component: NotPermittedComponent,
|
|
25
|
+
},
|
|
20
26
|
{{#each routes}}
|
|
21
27
|
{
|
|
22
28
|
path: '{{kebabCase this.name}}',
|
|
23
|
-
canActivate: [AuthGuard],
|
|
24
|
-
component: {{pascalCase this.name}}Component
|
|
29
|
+
canActivate: [AuthGuard{{#if this.permissions.viewRight}}, PermissionsGuard{{/if}}],
|
|
30
|
+
component: {{pascalCase this.name}}Component,
|
|
31
|
+
data: { permissionCode: '{{this.permissions.viewRight}}' },
|
|
25
32
|
},
|
|
26
33
|
{{/each}}
|
|
27
34
|
];
|
|
@@ -4,7 +4,7 @@ import { AppComponent } from './app.component';
|
|
|
4
4
|
describe('AppComponent', () => {
|
|
5
5
|
beforeEach(async () => {
|
|
6
6
|
await TestBed.configureTestingModule({
|
|
7
|
-
|
|
7
|
+
declarations: [AppComponent],
|
|
8
8
|
}).compileComponents();
|
|
9
9
|
});
|
|
10
10
|
|
|
@@ -19,11 +19,5 @@ describe('AppComponent', () => {
|
|
|
19
19
|
const app = fixture.componentInstance;
|
|
20
20
|
expect(app.title).toEqual('{{capitalCase appName}}');
|
|
21
21
|
});
|
|
22
|
-
|
|
23
|
-
it('should render title', () => {
|
|
24
|
-
const fixture = TestBed.createComponent(AppComponent);
|
|
25
|
-
fixture.detectChanges();
|
|
26
|
-
const compiled = fixture.nativeElement as HTMLElement;
|
|
27
|
-
expect(compiled.querySelector('h1')?.textContent).toContain('Hello, {{capitalCase appName}}');
|
|
28
|
-
});
|
|
29
22
|
});
|
|
23
|
+
|
|
@@ -2,6 +2,7 @@ import type { MainMenu } from './types/menu'
|
|
|
2
2
|
import type { LayoutComponentName } from './types/layout';
|
|
3
3
|
|
|
4
4
|
export const AUTH_PATH = 'login'
|
|
5
|
+
export const NOT_PERMITTED_PATH = 'not-permitted'
|
|
5
6
|
|
|
6
7
|
export const layoutComponentName = {
|
|
7
8
|
default: 'DefaultLayoutComponent',
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<section class="error-message-wrapper">
|
|
2
|
+
<div class="error-message" style="color: var(--neutral-foreground-rest); background-color: var(--neutral-layer-4); border-color: var(--error-color); border-radius: 7px; border-style: solid; border-width: 4px; padding: 5px; margin: 15px; text-align: center; width: fit-content;">
|
|
3
|
+
<ng-container [ngSwitch]="elementType">
|
|
4
|
+
<h1 *ngSwitchCase="'h1'">\{{ message }}</h1>
|
|
5
|
+
<h2 *ngSwitchCase="'h2'">\{{ message }}</h2>
|
|
6
|
+
<h3 *ngSwitchCase="'h3'">\{{ message }}</h3>
|
|
7
|
+
<h4 *ngSwitchCase="'h4'">\{{ message }}</h4>
|
|
8
|
+
<h5 *ngSwitchCase="'h5'">\{{ message }}</h5>
|
|
9
|
+
<h6 *ngSwitchCase="'h6'">\{{ message }}</h6>
|
|
10
|
+
<p *ngSwitchCase="'p'">\{{ message }}</p>
|
|
11
|
+
<span *ngSwitchCase="'span'">\{{ message }}</span>
|
|
12
|
+
<div *ngSwitchDefault>\{{ message }}</div>
|
|
13
|
+
</ng-container>
|
|
14
|
+
</div>
|
|
15
|
+
</section>
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
import { ErrorMessageComponent } from './error-message.component';
|
|
3
|
+
|
|
4
|
+
describe('ErrorMessageComponent', () => {
|
|
5
|
+
let component: ErrorMessageComponent;
|
|
6
|
+
let fixture: ComponentFixture<ErrorMessageComponent>;
|
|
7
|
+
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
await TestBed.configureTestingModule({
|
|
10
|
+
imports: [ErrorMessageComponent],
|
|
11
|
+
}).compileComponents();
|
|
12
|
+
|
|
13
|
+
fixture = TestBed.createComponent(ErrorMessageComponent);
|
|
14
|
+
component = fixture.componentInstance;
|
|
15
|
+
fixture.detectChanges();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('should create', () => {
|
|
19
|
+
expect(component).toBeTruthy();
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('should render a message inside an h1 element', () => {
|
|
23
|
+
component.elementType = 'h1';
|
|
24
|
+
component.message = 'Error: Something went wrong!';
|
|
25
|
+
fixture.detectChanges();
|
|
26
|
+
|
|
27
|
+
const compiled = fixture.nativeElement;
|
|
28
|
+
const element = compiled.querySelector('h1');
|
|
29
|
+
expect(element).toBeTruthy();
|
|
30
|
+
expect(element.textContent).toContain('Error: Something went wrong!');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should render a message inside an h3 element', () => {
|
|
34
|
+
component.elementType = 'h3';
|
|
35
|
+
component.message = 'Warning: Check your inputs.';
|
|
36
|
+
fixture.detectChanges();
|
|
37
|
+
|
|
38
|
+
const compiled = fixture.nativeElement;
|
|
39
|
+
const element = compiled.querySelector('h3');
|
|
40
|
+
expect(element).toBeTruthy();
|
|
41
|
+
expect(element.textContent).toContain('Warning: Check your inputs.');
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
it('should render a message inside a p element', () => {
|
|
45
|
+
component.elementType = 'p';
|
|
46
|
+
component.message = 'Info: Your operation was successful.';
|
|
47
|
+
fixture.detectChanges();
|
|
48
|
+
|
|
49
|
+
const compiled = fixture.nativeElement;
|
|
50
|
+
const element = compiled.querySelector('p');
|
|
51
|
+
expect(element).toBeTruthy();
|
|
52
|
+
expect(element.textContent).toContain('Info: Your operation was successful.');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should default to div element if no elementType is provided', () => {
|
|
56
|
+
component.elementType = '';
|
|
57
|
+
component.message = 'Default to div element.';
|
|
58
|
+
fixture.detectChanges();
|
|
59
|
+
|
|
60
|
+
const compiled = fixture.nativeElement;
|
|
61
|
+
const element = compiled.querySelector('div');
|
|
62
|
+
expect(element.textContent).toContain('Default to div element.');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('should apply error-message class to the rendered element', () => {
|
|
66
|
+
component.elementType = 'h2';
|
|
67
|
+
component.message = 'Testing class application.';
|
|
68
|
+
fixture.detectChanges();
|
|
69
|
+
|
|
70
|
+
const compiled = fixture.nativeElement;
|
|
71
|
+
const element = compiled.querySelector('.error-message');
|
|
72
|
+
expect(element).toBeTruthy();
|
|
73
|
+
});
|
|
74
|
+
});
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Component, Input } from '@angular/core';
|
|
2
|
+
import { CommonModule } from '@angular/common';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'app-error-message',
|
|
6
|
+
templateUrl: './error-message.component.html',
|
|
7
|
+
standalone: true,
|
|
8
|
+
imports: [
|
|
9
|
+
CommonModule,
|
|
10
|
+
],
|
|
11
|
+
})
|
|
12
|
+
export class ErrorMessageComponent {
|
|
13
|
+
@Input() elementType: string = 'div';
|
|
14
|
+
@Input() message: string = '';
|
|
15
|
+
}
|
|
@@ -12,11 +12,11 @@ export class AuthGuard implements CanActivate {
|
|
|
12
12
|
private router: Router,
|
|
13
13
|
) {}
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
const isUserAuthenticated =
|
|
15
|
+
canActivate(): boolean {
|
|
16
|
+
const isUserAuthenticated = this.authService.isUserAuthenticated();
|
|
17
17
|
|
|
18
18
|
if (!isUserAuthenticated) {
|
|
19
|
-
|
|
19
|
+
this.router.navigate([`/${AUTH_PATH}`]);
|
|
20
20
|
return false;
|
|
21
21
|
}
|
|
22
22
|
return true;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Injectable } from '@angular/core';
|
|
2
|
+
import { CanActivate, Router, ActivatedRouteSnapshot } from '@angular/router';
|
|
3
|
+
import { AuthService } from '../services/auth.service';
|
|
4
|
+
import { NOT_PERMITTED_PATH } from '../app.config';
|
|
5
|
+
|
|
6
|
+
@Injectable({
|
|
7
|
+
providedIn: 'root',
|
|
8
|
+
})
|
|
9
|
+
export class PermissionsGuard implements CanActivate {
|
|
10
|
+
constructor(
|
|
11
|
+
private authService: AuthService,
|
|
12
|
+
private router: Router,
|
|
13
|
+
) {}
|
|
14
|
+
|
|
15
|
+
async canActivate(route: ActivatedRouteSnapshot): Promise<boolean> {
|
|
16
|
+
const isPermitted = await this.authService.hasUserPermission(route.data['permissionCode']);
|
|
17
|
+
|
|
18
|
+
if (!isPermitted) {
|
|
19
|
+
await this.router.navigate([`/${NOT_PERMITTED_PATH}`]);
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -10,7 +10,7 @@ describe('BlankLayoutComponent', () => {
|
|
|
10
10
|
beforeEach(() => {
|
|
11
11
|
TestBed.configureTestingModule({
|
|
12
12
|
declarations: [BlankLayoutComponent],
|
|
13
|
-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
13
|
+
schemas: [ CUSTOM_ELEMENTS_SCHEMA ],
|
|
14
14
|
});
|
|
15
15
|
fixture = TestBed.createComponent(BlankLayoutComponent);
|
|
16
16
|
component = fixture.componentInstance;
|
|
@@ -1,34 +1,49 @@
|
|
|
1
|
-
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
2
1
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
3
|
-
import {
|
|
4
|
-
import * as StateChangerSelector from '../../store/state-changer/state-changer.selectors';
|
|
5
|
-
|
|
2
|
+
import { Router } from '@angular/router';
|
|
6
3
|
import { DefaultLayoutComponent } from './default.layout';
|
|
4
|
+
import { ElementRef, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
5
|
+
|
|
6
|
+
class MockRouter {
|
|
7
|
+
navigate = jasmine.createSpy('navigate');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
class MockElementRef implements ElementRef {
|
|
11
|
+
nativeElement = {};
|
|
12
|
+
}
|
|
7
13
|
|
|
8
14
|
describe('DefaultLayoutComponent', () => {
|
|
9
15
|
let component: DefaultLayoutComponent;
|
|
10
16
|
let fixture: ComponentFixture<DefaultLayoutComponent>;
|
|
17
|
+
let router: MockRouter;
|
|
18
|
+
let elementRef: MockElementRef;
|
|
11
19
|
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
TestBed.configureTestingModule({
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
await TestBed.configureTestingModule({
|
|
14
22
|
declarations: [DefaultLayoutComponent],
|
|
15
23
|
providers: [
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
selectors: [
|
|
19
|
-
{ selector: StateChangerSelector.getCriteria, value: 'initial-criteria' },
|
|
20
|
-
{ selector: StateChangerSelector.getResourceName, value: 'initial-resource-name' },
|
|
21
|
-
],
|
|
22
|
-
}),
|
|
24
|
+
{ provide: Router, useClass: MockRouter },
|
|
25
|
+
{ provide: ElementRef, useClass: MockElementRef }
|
|
23
26
|
],
|
|
24
|
-
schemas: [CUSTOM_ELEMENTS_SCHEMA],
|
|
25
|
-
});
|
|
27
|
+
schemas: [ CUSTOM_ELEMENTS_SCHEMA ],
|
|
28
|
+
}).compileComponents();
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
beforeEach(() => {
|
|
26
32
|
fixture = TestBed.createComponent(DefaultLayoutComponent);
|
|
27
33
|
component = fixture.componentInstance;
|
|
34
|
+
router = TestBed.inject(Router) as unknown as MockRouter;
|
|
35
|
+
elementRef = TestBed.inject(ElementRef) as unknown as MockElementRef;
|
|
36
|
+
component.designSystemProviderElement = elementRef;
|
|
28
37
|
fixture.detectChanges();
|
|
29
38
|
});
|
|
30
39
|
|
|
31
40
|
it('should create', () => {
|
|
32
41
|
expect(component).toBeTruthy();
|
|
33
42
|
});
|
|
43
|
+
|
|
44
|
+
it('should navigate to a path', () => {
|
|
45
|
+
const path = 'some/path';
|
|
46
|
+
component.navigateAngular(path);
|
|
47
|
+
expect(router.navigate).toHaveBeenCalledWith([path]);
|
|
48
|
+
});
|
|
34
49
|
});
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { AuthLoginComponent } from './auth-login.component';
|
|
4
4
|
|
|
5
|
-
describe('
|
|
6
|
-
let component:
|
|
7
|
-
let fixture: ComponentFixture<
|
|
5
|
+
describe('AuthLoginComponent', () => {
|
|
6
|
+
let component: AuthLoginComponent;
|
|
7
|
+
let fixture: ComponentFixture<AuthLoginComponent>;
|
|
8
8
|
|
|
9
9
|
beforeEach(async () => {
|
|
10
10
|
await TestBed.configureTestingModule({
|
|
11
|
-
imports: [
|
|
11
|
+
imports: [AuthLoginComponent],
|
|
12
12
|
}).compileComponents();
|
|
13
13
|
|
|
14
|
-
fixture = TestBed.createComponent(
|
|
14
|
+
fixture = TestBed.createComponent(AuthLoginComponent);
|
|
15
15
|
component = fixture.componentInstance;
|
|
16
16
|
fixture.detectChanges();
|
|
17
17
|
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
|
2
|
+
import { NotPermittedComponent } from './not-permitted.component';
|
|
3
|
+
|
|
4
|
+
const MESSAGE_NOT_PERMITTED = 'You do not have permission to access this part of the application, please contact your administrator.';
|
|
5
|
+
|
|
6
|
+
describe('NotPermittedComponent', () => {
|
|
7
|
+
let component: NotPermittedComponent;
|
|
8
|
+
let fixture: ComponentFixture<NotPermittedComponent>;
|
|
9
|
+
|
|
10
|
+
beforeEach(async () => {
|
|
11
|
+
await TestBed.configureTestingModule({
|
|
12
|
+
imports: [ NotPermittedComponent ]
|
|
13
|
+
})
|
|
14
|
+
.compileComponents();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
fixture = TestBed.createComponent(NotPermittedComponent);
|
|
19
|
+
component = fixture.componentInstance;
|
|
20
|
+
fixture.detectChanges();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should create', () => {
|
|
24
|
+
expect(component).toBeTruthy();
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('should display the correct error message', () => {
|
|
28
|
+
const compiled = fixture.nativeElement;
|
|
29
|
+
const errorMessageElement = compiled.querySelector('app-error-message h1');
|
|
30
|
+
expect(errorMessageElement.textContent).toBe(MESSAGE_NOT_PERMITTED);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
2
|
+
import { ErrorMessageComponent } from '../../components/error-message/error-message.component';
|
|
3
|
+
|
|
4
|
+
@Component({
|
|
5
|
+
selector: 'app-not-permitted',
|
|
6
|
+
standalone: true,
|
|
7
|
+
imports: [ ErrorMessageComponent ],
|
|
8
|
+
templateUrl: './not-permitted.component.html',
|
|
9
|
+
styleUrls: ['./not-permitted.component.scss'],
|
|
10
|
+
schemas: [ CUSTOM_ELEMENTS_SCHEMA ],
|
|
11
|
+
})
|
|
12
|
+
export class NotPermittedComponent {
|
|
13
|
+
}
|
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { Injectable } from '@angular/core';
|
|
2
2
|
import { Auth } from '@genesislcap/foundation-comms';
|
|
3
|
-
import {DI} from "@microsoft/fast-foundation";
|
|
3
|
+
import { DI } from "@microsoft/fast-foundation";
|
|
4
4
|
|
|
5
5
|
@Injectable({
|
|
6
6
|
providedIn: 'root',
|
|
7
7
|
})
|
|
8
8
|
export class AuthService {
|
|
9
|
+
auth: Auth;
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
constructor() {
|
|
12
|
+
this.auth = DI.getOrCreateDOMContainer().get(Auth);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
isUserAuthenticated(): boolean {
|
|
16
|
+
return this.auth.isLoggedIn;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
hasUserPermission(permissionCode: string): boolean {
|
|
20
|
+
return this.auth.currentUser.hasPermission(permissionCode);
|
|
13
21
|
}
|
|
14
22
|
}
|
|
@@ -3,6 +3,9 @@ import type { Router } from '@angular/router';
|
|
|
3
3
|
import { AUTH_PATH } from '../app.config';
|
|
4
4
|
import { DI } from '@microsoft/fast-foundation';
|
|
5
5
|
|
|
6
|
+
// eslint-disable-next-line
|
|
7
|
+
declare var GENX_ENABLE_SSO: boolean;
|
|
8
|
+
|
|
6
9
|
const ssoSettings =
|
|
7
10
|
typeof GENX_ENABLE_SSO !== 'undefined' && GENX_ENABLE_SSO === true
|
|
8
11
|
? {
|