@genesislcap/blank-app-seed 3.20.5 → 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/static.js +8 -0
- 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/component/component.column.defs.hbs +6 -0
- package/.genx/templates/web-components/component/component.create.form.hbs +8 -0
- package/.genx/templates/web-components/component/component.gridOptions.hbs +6 -0
- package/.genx/templates/web-components/component/component.hbs +13 -0
- package/.genx/templates/web-components/component/component.index.hbs +1 -0
- package/.genx/templates/web-components/component/component.styles.hbs +7 -0
- package/.genx/templates/web-components/component/component.template.hbs +23 -0
- package/.genx/templates/web-components/component/component.update.form.hbs +5 -0
- package/.genx/templates/web-components/entityManager.hbs +5 -11
- package/.genx/templates/web-components/form.hbs +1 -3
- package/.genx/templates/web-components/grid.hbs +1 -3
- package/.genx/templates/web-components/gridLayout.hbs +30 -0
- package/.genx/templates/web-components/horizontalLayout.hbs +7 -0
- package/.genx/templates/web-components/route.template.hbs +8 -2
- package/.genx/templates/web-components/tabsLayout.hbs +7 -0
- package/.genx/utils/formatRouteData.js +5 -0
- package/.genx/utils/generateRoute.js +8 -0
- package/.genx/utils/generateTile.js +137 -0
- package/.genx/utils/gridSerializers.js +10 -10
- package/.genx/utils/registerPartials.js +4 -3
- package/CHANGELOG.md +14 -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/templates/{gridLayout.hbs → angular/gridLayout.hbs} +0 -0
- /package/.genx/templates/{horizontalLayout.hbs → angular/horizontalLayout.hbs} +0 -0
- /package/.genx/templates/{tabsLayout.hbs → angular/tabsLayout.hbs} +0 -0
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
const { resolve } = require('node:path');
|
|
2
|
+
const makeDirectory = require('./makeDirectory');
|
|
3
|
+
const {
|
|
4
|
+
COMPONENT_TYPE,
|
|
5
|
+
FRAMEWORK_WEB_COMPONENTS_ALIAS,
|
|
6
|
+
FRAMEWORK_ANGULAR_ALIAS,
|
|
7
|
+
DIR_TEMPLATE_BY_FRAMEWORK,
|
|
8
|
+
} = require('../static');
|
|
9
|
+
|
|
10
|
+
const getPathByFramework = {
|
|
11
|
+
[FRAMEWORK_WEB_COMPONENTS_ALIAS]: {
|
|
12
|
+
clientSrcPath: `../../client/src/routes`,
|
|
13
|
+
route: (clientSrcPath, tileName, tileType, routeName) => `${clientSrcPath}/${routeName}/${tileName}-${tileType}`,
|
|
14
|
+
index: (componentPath) => `${componentPath}/index.ts`,
|
|
15
|
+
component: (componentPath, tileName) => `${componentPath}/${tileName}.ts`,
|
|
16
|
+
template: (componentPath, tileName) => `${componentPath}/${tileName}.template.ts`,
|
|
17
|
+
style: (componentPath, tileName) => `${componentPath}/${tileName}.styles.ts`,
|
|
18
|
+
addForm: (componentPath, tileName) => `${componentPath}/${tileName}.create.form.schema.ts`,
|
|
19
|
+
updateForm: (componentPath, tileName) => `${componentPath}/${tileName}.update.form.schema.ts`,
|
|
20
|
+
columnDefs: (componentPath, tileName) => `${componentPath}/${tileName}.column.defs.ts`,
|
|
21
|
+
gridOptions: (componentPath, tileName) => `${componentPath}/${tileName}.gridOptions.ts`,
|
|
22
|
+
},
|
|
23
|
+
// Placeholder for angular part
|
|
24
|
+
[FRAMEWORK_ANGULAR_ALIAS]: {},
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const getFilesToWrite = (tile, tileName, routeName, path, sourceTemplateDir) => {
|
|
28
|
+
const {
|
|
29
|
+
clientSrcPath,
|
|
30
|
+
route: getRouteDir,
|
|
31
|
+
index: getComponentIndexTarget,
|
|
32
|
+
component: getComponentTarget,
|
|
33
|
+
template: getTemplateTarget,
|
|
34
|
+
style: getStyleTarget,
|
|
35
|
+
addForm: getAddFormTarget,
|
|
36
|
+
updateForm: getUpdateFormTarget,
|
|
37
|
+
columnDefs: getColumnDefsTarget,
|
|
38
|
+
gridOptions: getGridOptionsTarget,
|
|
39
|
+
} = path;
|
|
40
|
+
|
|
41
|
+
const routeDir = getRouteDir(clientSrcPath, tileName, tile.componentType, routeName);
|
|
42
|
+
|
|
43
|
+
const componentIndexFile = {
|
|
44
|
+
source: `${sourceTemplateDir}/component/component.index.hbs`,
|
|
45
|
+
target: getComponentIndexTarget(routeDir, tileName),
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const componentFile = {
|
|
49
|
+
source: `${sourceTemplateDir}/component/component.hbs`,
|
|
50
|
+
target: getComponentTarget(routeDir, tileName),
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
const componentTemplateFile = {
|
|
54
|
+
source: `${sourceTemplateDir}/component/component.template.hbs`,
|
|
55
|
+
target: getTemplateTarget(routeDir, tileName),
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const componentStylesFile = {
|
|
59
|
+
source: `${sourceTemplateDir}/component/component.styles.hbs`,
|
|
60
|
+
target: getStyleTarget(routeDir, tileName),
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const componentAddFormFile = {
|
|
64
|
+
source: `${sourceTemplateDir}/component/component.create.form.hbs`,
|
|
65
|
+
target: getAddFormTarget(routeDir, tileName),
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const componentUpdateFormFile = {
|
|
69
|
+
source: `${sourceTemplateDir}/component/component.update.form.hbs`,
|
|
70
|
+
target: getUpdateFormTarget(routeDir, tileName),
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const componentColumnsFile = {
|
|
74
|
+
source: `${sourceTemplateDir}/component/component.column.defs.hbs`,
|
|
75
|
+
target: getColumnDefsTarget(routeDir, tileName),
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
const componentGridOptionsFile = {
|
|
79
|
+
source: `${sourceTemplateDir}/component/component.gridOptions.hbs`,
|
|
80
|
+
target: getGridOptionsTarget(routeDir, tileName),
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
const filesToWrite = [componentIndexFile, componentFile, componentTemplateFile, componentStylesFile];
|
|
84
|
+
|
|
85
|
+
switch (tile.type) {
|
|
86
|
+
case 'entity-manager':
|
|
87
|
+
if (tile.config?.columns) {
|
|
88
|
+
filesToWrite.push(componentColumnsFile);
|
|
89
|
+
}
|
|
90
|
+
if (tile.config?.gridOptions) {
|
|
91
|
+
filesToWrite.push(componentGridOptionsFile);
|
|
92
|
+
}
|
|
93
|
+
if (tile.config?.createFormUiSchema) {
|
|
94
|
+
filesToWrite.push(componentAddFormFile);
|
|
95
|
+
}
|
|
96
|
+
if (tile.config?.updateFormUiSchema) {
|
|
97
|
+
filesToWrite.push(componentUpdateFormFile);
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
case 'grid-pro':
|
|
101
|
+
if (tile.config?.gridOptions) {
|
|
102
|
+
filesToWrite.push(componentGridOptionsFile);
|
|
103
|
+
}
|
|
104
|
+
break;
|
|
105
|
+
case 'smart-form':
|
|
106
|
+
filesToWrite.push(componentAddFormFile);
|
|
107
|
+
break
|
|
108
|
+
default:
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return filesToWrite
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const generateTile = (tile, route, { changeCase, writeFileWithData }, framework) => {
|
|
116
|
+
const tileName = changeCase.paramCase(tile.title);
|
|
117
|
+
const routeName = changeCase.paramCase(route.name);
|
|
118
|
+
const sourceTemplateDir = `../${DIR_TEMPLATE_BY_FRAMEWORK[framework]}`;
|
|
119
|
+
const {
|
|
120
|
+
clientSrcPath,
|
|
121
|
+
route: getRouteDir,
|
|
122
|
+
} = getPathByFramework[framework];
|
|
123
|
+
const routeDir = getRouteDir(clientSrcPath, tileName, tile.componentType, routeName);
|
|
124
|
+
|
|
125
|
+
const filesToWrite = getFilesToWrite(tile, tileName, routeName, getPathByFramework[framework], sourceTemplateDir)
|
|
126
|
+
|
|
127
|
+
makeDirectory(resolve(__dirname, routeDir));
|
|
128
|
+
filesToWrite.forEach(({ source, target }) => {
|
|
129
|
+
writeFileWithData(
|
|
130
|
+
resolve(__dirname, target),
|
|
131
|
+
{ tile, route },
|
|
132
|
+
resolve(__dirname, source),
|
|
133
|
+
);
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
module.exports = generateTile;
|
|
@@ -1,45 +1,45 @@
|
|
|
1
1
|
const formatJSONValue = require('./formatJSONValue');
|
|
2
2
|
|
|
3
|
-
function gridColumnsSerializer(columns, pad
|
|
3
|
+
function gridColumnsSerializer(columns, pad) {
|
|
4
4
|
if (!columns) {
|
|
5
5
|
return undefined;
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
try {
|
|
9
9
|
const columnsSerialized = columns.map((column) => {
|
|
10
|
-
return gridOptionsSerializer(column);
|
|
10
|
+
return gridOptionsSerializer(column, pad);
|
|
11
11
|
});
|
|
12
|
-
return `[
|
|
12
|
+
return `[${columnsSerialized}\n]`;
|
|
13
13
|
} catch (e) {
|
|
14
14
|
console.error('Error serializing grid columns:', e.message);
|
|
15
15
|
throw e;
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
function gridOptionsSerializer(options, pad = '
|
|
19
|
+
function gridOptionsSerializer(options, pad = ' ') {
|
|
20
20
|
if (!options) {
|
|
21
21
|
return undefined;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
try {
|
|
25
|
-
let output =
|
|
25
|
+
let output = `\n${pad}{\n`;
|
|
26
26
|
Object.keys(options).forEach((key) => {
|
|
27
27
|
const value = options[key];
|
|
28
28
|
if (key === 'columns') {
|
|
29
|
-
output += `${pad}${'columnDefs'}: ${gridColumnsSerializer(value)},\n`;
|
|
29
|
+
output += `${pad}${pad}${'columnDefs'}: ${gridColumnsSerializer(value, ' ')},\n`;
|
|
30
30
|
} else if (
|
|
31
31
|
value?.type === 'function' ||
|
|
32
32
|
value?.type === 'valueFormatter'
|
|
33
33
|
) {
|
|
34
34
|
const args = value.arguments?.map(JSON.stringify).join(', ');
|
|
35
|
-
output += `${pad}${key}: ${value.name}(${args}),\n`;
|
|
35
|
+
output += `${pad}${pad}${key}: ${value.name}(${args}),\n`;
|
|
36
36
|
} else if (key === 'hide') {
|
|
37
|
-
output += `${pad}${key}: ${value},\n`;
|
|
37
|
+
output += `${pad}${pad}${key}: ${value},\n`;
|
|
38
38
|
} else {
|
|
39
|
-
output += `${pad}${key}: ${formatJSONValue(value)},\n`;
|
|
39
|
+
output += `${pad}${pad}${key}: ${formatJSONValue(value)},\n`;
|
|
40
40
|
}
|
|
41
41
|
});
|
|
42
|
-
output += `${pad}}
|
|
42
|
+
output += `${pad}}`;
|
|
43
43
|
return output;
|
|
44
44
|
} catch (e) {
|
|
45
45
|
console.error('Error serializing grid options:', e.message);
|
|
@@ -6,20 +6,21 @@ const {
|
|
|
6
6
|
} = require('../static');
|
|
7
7
|
|
|
8
8
|
const registerPartials = ({ registerPartial }, framework) => {
|
|
9
|
+
// It can be reverted after adding changes for angular
|
|
9
10
|
const rootTemplateDir = `../${DIRS_MAP.get(DIR_TEMPLATE_ROOT_ALIAS)}`;
|
|
10
11
|
const sourceTemplateDir = `../${DIR_TEMPLATE_BY_FRAMEWORK[framework]}`;
|
|
11
12
|
|
|
12
13
|
registerPartial(
|
|
13
14
|
'grid-layout',
|
|
14
|
-
resolve(__dirname, `${
|
|
15
|
+
resolve(__dirname, `${sourceTemplateDir}/gridLayout.hbs`),
|
|
15
16
|
);
|
|
16
17
|
registerPartial(
|
|
17
18
|
'tabs-layout',
|
|
18
|
-
resolve(__dirname, `${
|
|
19
|
+
resolve(__dirname, `${sourceTemplateDir}/tabsLayout.hbs`),
|
|
19
20
|
);
|
|
20
21
|
registerPartial(
|
|
21
22
|
'horizontal-layout',
|
|
22
|
-
resolve(__dirname, `${
|
|
23
|
+
resolve(__dirname, `${sourceTemplateDir}/horizontalLayout.hbs`),
|
|
23
24
|
);
|
|
24
25
|
registerPartial(
|
|
25
26
|
'smart-form',
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
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
|
+
|
|
10
|
+
## [3.21.0](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v3.20.5...v3.21.0) (2024-07-09)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Features
|
|
14
|
+
|
|
15
|
+
* implement the generated UI code structure proposal GENC-533 (#275) 9bc3847
|
|
16
|
+
|
|
3
17
|
## [3.20.5](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v3.20.4...v3.20.5) (2024-07-09)
|
|
4
18
|
|
|
5
19
|
|
|
@@ -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;
|