@genesislcap/blank-app-seed 5.7.0-prerelease.2 → 5.7.0-prerelease.20

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.
Files changed (77) hide show
  1. package/.genx/configure.js +114 -0
  2. package/.genx/package.json +5 -2
  3. package/.genx/prompts/api.js +25 -0
  4. package/.genx/prompts/ui.js +12 -0
  5. package/.genx/prompts.js +8 -2
  6. package/.genx/static.js +1 -0
  7. package/.genx/templates/angular/component/component.hbs +31 -3
  8. package/.genx/templates/angular/entityManager.hbs +17 -6
  9. package/.genx/templates/angular/grid.hbs +5 -2
  10. package/.genx/templates/angular/slices/eventing.slice.hbs +41 -0
  11. package/.genx/templates/angular/store.hbs +16 -0
  12. package/.genx/templates/react/component/component.hbs +84 -15
  13. package/.genx/templates/react/entityManager.hbs +11 -17
  14. package/.genx/templates/react/grid.hbs +5 -9
  15. package/.genx/templates/react/gridLayout.hbs +4 -4
  16. package/.genx/templates/react/horizontalLayout.hbs +1 -1
  17. package/.genx/templates/react/route.hbs +12 -1
  18. package/.genx/templates/react/slices/eventing.slice.hbs +39 -0
  19. package/.genx/templates/react/store.hbs +24 -0
  20. package/.genx/templates/react/tabsLayout.hbs +1 -1
  21. package/.genx/templates/web-components/component/component.hbs +26 -0
  22. package/.genx/templates/web-components/entityManager.hbs +17 -9
  23. package/.genx/templates/web-components/grid.hbs +13 -5
  24. package/.genx/templates/web-components/slices/eventing.slice.hbs +44 -0
  25. package/.genx/templates/web-components/store.hbs +18 -0
  26. package/.genx/utils/fontUtils.js +75 -0
  27. package/.genx/utils/formatRouteData.js +5 -0
  28. package/.genx/utils/generateRoute.js +1 -1
  29. package/.genx/utils/generateStore.js +98 -0
  30. package/.genx/utils/index.js +4 -0
  31. package/.genx/versions.json +3 -3
  32. package/.github/CODEOWNERS +1 -1
  33. package/.github/pull_request_template.md +6 -0
  34. package/.github/workflows/upgrade.yml +0 -1
  35. package/CHANGELOG.md +160 -0
  36. package/client-tmp/angular/package.json +5 -0
  37. package/client-tmp/angular/src/app/app.component.ts +2 -31
  38. package/client-tmp/angular/src/app/app.module.ts +3 -0
  39. package/client-tmp/angular/src/app/layouts/default/default.layout.css +8 -0
  40. package/client-tmp/angular/src/app/layouts/default/default.layout.html +3 -0
  41. package/client-tmp/angular/src/styles/design-tokens.json +1 -1
  42. package/client-tmp/angular/src/styles/styles.css +15 -1
  43. package/client-tmp/react/index.html +0 -1
  44. package/client-tmp/react/package.json +16 -28
  45. package/client-tmp/react/public/index.html +3 -1
  46. package/client-tmp/react/src/App.tsx +12 -29
  47. package/client-tmp/react/src/components/routes/AppRoutes.tsx +4 -4
  48. package/client-tmp/react/src/config.ts +1 -1
  49. package/client-tmp/react/src/layouts/blank/BlankLayout.tsx +1 -1
  50. package/client-tmp/react/src/layouts/default/DefaultLayout.module.css +8 -0
  51. package/client-tmp/react/src/layouts/default/DefaultLayout.tsx +7 -4
  52. package/client-tmp/react/src/main.tsx +1 -1
  53. package/client-tmp/react/src/pages/AuthPage/AuthPage.tsx +1 -1
  54. package/client-tmp/react/src/pages/NotFoundPage/NotFoundPage.tsx +1 -1
  55. package/client-tmp/react/src/pages/NotPermittedPage/NotPermittedPage.test.tsx +1 -1
  56. package/client-tmp/react/src/pages/NotPermittedPage/NotPermittedPage.tsx +1 -1
  57. package/client-tmp/react/src/pbc/container.tsx +1 -1
  58. package/client-tmp/react/src/share/foundation-login.ts +2 -2
  59. package/client-tmp/react/src/store/RoutesContext.tsx +6 -6
  60. package/client-tmp/react/src/styles/design-tokens.json +1 -1
  61. package/client-tmp/react/src/styles/styles.css +15 -1
  62. package/client-tmp/react/src/utils/getLayoutNameByRoute.ts +1 -1
  63. package/client-tmp/react/src/utils/goldenLayout.helper.ts +59 -0
  64. package/client-tmp/react/test/e2e/fixture.ts +1 -1
  65. package/client-tmp/web-components/package.json +4 -0
  66. package/client-tmp/web-components/src/layouts/default.ts +12 -2
  67. package/client-tmp/web-components/src/main/main.css +12 -0
  68. package/client-tmp/web-components/src/main/main.template.ts +0 -1
  69. package/client-tmp/web-components/src/main/main.ts +1 -34
  70. package/client-tmp/web-components/src/styles/design-tokens.json +1 -1
  71. package/client-tmp/web-components/src/styles/typography.ts +6 -4
  72. package/package.json +1 -1
  73. package/client-tmp/angular/src/app/store/store.ts +0 -34
  74. package/client-tmp/react/lint-css.ts +0 -19
  75. package/client-tmp/react/src/services/store.service.ts +0 -48
  76. package/client-tmp/react/vite.config.ts +0 -70
  77. package/client-tmp/web-components/src/store/store.ts +0 -29
@@ -1,4 +1,12 @@
1
1
  const versions = require('./versions.json');
2
+ const fs = require('fs');
3
+ const path = require('path');
4
+ const {
5
+ DIRS_MAP,
6
+ DIR_CLIENT_MAIN_ALIAS,
7
+ DIR_CLIENT_TEMP_ALIAS,
8
+ FRAMEWORKS_DIR_MAP,
9
+ } = require('./static');
2
10
  const {
3
11
  excludeFrameworks,
4
12
  formatRouteData,
@@ -8,6 +16,8 @@ const {
8
16
  registerPartials,
9
17
  validateRoute,
10
18
  deleteGradleWrappers,
19
+ generateStore,
20
+ fontUtils,
11
21
  } = require('./utils');
12
22
 
13
23
  /**
@@ -38,8 +48,111 @@ module.exports = async (data, utils) => {
38
48
  includeDependencies: !!(FDC3ListenersEnabled || FDC3EventHandlersEnabled),
39
49
  channels: data.ui?.fdc3?.channels || [],
40
50
  };
51
+
52
+ if (data.designTokens && Object.keys(data.designTokens).length > 0) {
53
+ try {
54
+ const frameworkDir = FRAMEWORKS_DIR_MAP.get(data.framework);
55
+ const templateFile = path.join(__dirname, '..', DIR_CLIENT_TEMP_ALIAS, frameworkDir, 'src/styles/design-tokens.json');
56
+ const jsonContent = JSON.stringify(data.designTokens, null, 2);
57
+ const templateDir = path.dirname(templateFile);
58
+ if (!fs.existsSync(templateDir)) {
59
+ fs.mkdirSync(templateDir, { recursive: true });
60
+ }
61
+ fs.writeFileSync(templateFile, jsonContent);
62
+ } catch (err) {
63
+ console.warn('Failed to write designTokens to template:', err?.message || err);
64
+ }
65
+ }
66
+
67
+ // Handle header logo copy
68
+ if (data.headerLogo && data.headerLogo.trim() !== '') {
69
+ try {
70
+ const sourcePath = path.resolve(data.headerLogo);
71
+ if (!fs.existsSync(sourcePath)) {
72
+ console.warn(`Header logo file not found: ${sourcePath}`);
73
+ } else {
74
+ const ext = path.extname(sourcePath);
75
+ const frameworkDir = FRAMEWORKS_DIR_MAP.get(data.framework);
76
+ let targetDir;
77
+
78
+ // Angular uses src/assets, others use public
79
+ if (data.framework === 'angular') {
80
+ targetDir = path.join(__dirname, '..', DIR_CLIENT_TEMP_ALIAS, frameworkDir, 'src/assets');
81
+ } else {
82
+ targetDir = path.join(__dirname, '..', DIR_CLIENT_TEMP_ALIAS, frameworkDir, 'public');
83
+ }
84
+
85
+ // Ensure target directory exists
86
+ if (!fs.existsSync(targetDir)) {
87
+ fs.mkdirSync(targetDir, { recursive: true });
88
+ }
89
+
90
+ const targetPath = path.join(targetDir, `header-logo${ext}`);
91
+ fs.copyFileSync(sourcePath, targetPath);
92
+
93
+ // Store the logo source path for templates
94
+ data.headerLogoSrc = `/header-logo${ext}`;
95
+
96
+ console.log(`Header logo copied to: ${targetPath}`);
97
+ }
98
+ } catch (err) {
99
+ console.warn('Failed to copy header logo:', err?.message || err);
100
+ }
101
+ }
102
+
103
+ // Handle custom fonts
104
+ if (data.customFonts && data.customFonts.trim() !== '') {
105
+ try {
106
+ const customFontsObj = typeof data.customFonts === 'string'
107
+ ? JSON.parse(data.customFonts)
108
+ : data.customFonts;
109
+
110
+ const processedFonts = fontUtils.processFontFiles(customFontsObj);
111
+
112
+ if (processedFonts) {
113
+ const { fontFamily, fontData } = processedFonts;
114
+ const frameworkDir = FRAMEWORKS_DIR_MAP.get(data.framework);
115
+
116
+ // Set data immediately so templates can use it even if file copy fails
117
+ data.fontFamily = fontFamily;
118
+ data.fontData = fontData;
119
+
120
+ // Determine target directory
121
+ let targetDir;
122
+ if (data.framework === 'angular') {
123
+ targetDir = path.join(__dirname, '..', DIR_CLIENT_TEMP_ALIAS, frameworkDir, 'src/assets/fonts');
124
+ } else {
125
+ targetDir = path.join(__dirname, '..', DIR_CLIENT_TEMP_ALIAS, frameworkDir, 'public/fonts');
126
+ }
127
+
128
+ // Create directory
129
+ if (!fs.existsSync(targetDir)) {
130
+ fs.mkdirSync(targetDir, { recursive: true });
131
+ }
132
+
133
+ // Copy font files
134
+ customFontsObj.files.forEach((fontPath, index) => {
135
+ const sourcePath = path.resolve(fontPath.trim());
136
+
137
+ if (fs.existsSync(sourcePath)) {
138
+ const fileName = path.basename(sourcePath);
139
+ const targetPath = path.join(targetDir, fileName);
140
+ fs.copyFileSync(sourcePath, targetPath);
141
+ console.log(`Font copied: ${fileName}`);
142
+ } else {
143
+ console.warn(`Font file not found: ${sourcePath}`);
144
+ }
145
+ });
146
+ }
147
+ } catch (err) {
148
+ console.warn('Failed to process custom fonts:', err?.message || err);
149
+ }
150
+ }
151
+
41
152
  excludeFrameworks(data.framework);
42
153
 
154
+ generateStore(data.routes, utils, data.framework);
155
+
43
156
  data.routes.forEach((route) => {
44
157
  generateRoute(route, utils, data.framework);
45
158
  });
@@ -50,6 +163,7 @@ module.exports = async (data, utils) => {
50
163
  generateCsv(entity, utils);
51
164
  });
52
165
 
166
+
53
167
  if (data.excludeGradleWrapper) {
54
168
  deleteGradleWrappers();
55
169
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@genesislcap/blank-app-seed-config",
3
3
  "description": "Genesis Blank App Seed Configuration",
4
- "version": "5.7.0-prerelease.2",
4
+ "version": "5.7.0-prerelease.20",
5
5
  "license": "Apache-2.0",
6
6
  "scripts": {
7
7
  "lint": "eslint .",
@@ -38,17 +38,20 @@
38
38
  "product-info",
39
39
  ".yml",
40
40
  ".sh",
41
- ".json",
42
41
  ".js",
43
42
  ".kt",
44
43
  ".kts",
45
44
  ".ts",
45
+ ".css",
46
46
  ".md",
47
47
  ".properties",
48
48
  ".html",
49
49
  ".gitignore",
50
50
  ".xml",
51
51
  ".iml"
52
+ ],
53
+ "exclude": [
54
+ "design-tokens.json"
52
55
  ]
53
56
  }
54
57
  }
@@ -1,6 +1,8 @@
1
1
  const { websocketValidator } = require('./validators');
2
2
  const { TEXTS } = require('../static');
3
3
 
4
+ const defaultHeaderLogo = '';
5
+
4
6
  const apiHostIntro = () => console.log(TEXTS.INTRO_API_HOST);
5
7
  const ssoIntro = () => console.log(TEXTS.INTRO_API_SSO);
6
8
 
@@ -26,8 +28,31 @@ module.exports = async (inquirer, prevAns = {}) => {
26
28
  when: prevAns.enableSSO === undefined,
27
29
  },
28
30
  ]);
31
+
32
+ const { headerLogo = prevAns.headerLogo } = await inquirer.prompt([
33
+ {
34
+ name: 'headerLogo',
35
+ type: 'input',
36
+ message: 'Header logo file path (optional)',
37
+ default: defaultHeaderLogo,
38
+ when: prevAns.headerLogo === undefined,
39
+ },
40
+ ]);
41
+
42
+ const { customFonts = prevAns.customFonts } = await inquirer.prompt([
43
+ {
44
+ name: 'customFonts',
45
+ type: 'input',
46
+ message: 'Custom fonts JSON (optional, e.g. {"files":["./Font-Regular.ttf","./Font-Bold.ttf"]})',
47
+ default: prevAns.customFonts || '',
48
+ when: prevAns.customFonts === undefined,
49
+ },
50
+ ]);
51
+
29
52
  return {
30
53
  apiHost,
31
54
  enableSSO,
55
+ headerLogo,
56
+ customFonts,
32
57
  };
33
58
  };
@@ -13,6 +13,9 @@ const parseRoutes = parseJSONArgument('routes', defaultRoutes);
13
13
  const defaultUI = {};
14
14
  const parseUI = parseJSONArgument('ui', defaultUI);
15
15
 
16
+ const defaultDesignTokens = {};
17
+ const parseDesignTokens = parseJSONArgument('designTokens', defaultDesignTokens);
18
+
16
19
  const selectedFrameworkInfo = (framework) => {
17
20
  if (framework && frameworkValidator(framework) === true) {
18
21
  console.log(
@@ -28,6 +31,7 @@ module.exports = async (inquirer, prevAns = {}) => {
28
31
  framework = prevAns.framework,
29
32
  ui = prevAns.ui,
30
33
  routes = prevAns.routes,
34
+ designTokens = prevAns.designTokens,
31
35
  } = await inquirer.prompt([
32
36
  {
33
37
  name: 'framework',
@@ -55,11 +59,19 @@ module.exports = async (inquirer, prevAns = {}) => {
55
59
  when: !prevAns.routes,
56
60
  default: JSON.stringify(defaultRoutes),
57
61
  },
62
+ {
63
+ name: 'designTokens',
64
+ type: 'input',
65
+ message: TEXTS.MESSAGE_UI_DESIGN_TOKENS,
66
+ when: !prevAns.designTokens,
67
+ default: JSON.stringify(defaultDesignTokens),
68
+ },
58
69
  ]);
59
70
 
60
71
  return {
61
72
  routes: parseRoutes(routes),
62
73
  ui: parseUI(ui),
74
+ designTokens: parseDesignTokens(designTokens),
63
75
  framework: normalizeFrameworkAlias(framework),
64
76
  };
65
77
  };
package/.genx/prompts.js CHANGED
@@ -16,7 +16,7 @@ module.exports = async (inquirer, prevAns = {}) => {
16
16
  Version: ${version}
17
17
  License: ${license}`);
18
18
 
19
- const { apiHost, enableSSO } = await apiPrompts(inquirer, prevAns);
19
+ const { apiHost, enableSSO, headerLogo, customFonts } = await apiPrompts(inquirer, prevAns);
20
20
  const {
21
21
  description,
22
22
  groupId,
@@ -25,12 +25,17 @@ module.exports = async (inquirer, prevAns = {}) => {
25
25
  csv,
26
26
  excludeGradleWrapper,
27
27
  } = await genesisServerPrompts(inquirer, prevAns);
28
- const { routes, ui, framework } = await uiPrompts(inquirer, prevAns);
28
+ const { routes, ui, framework, designTokens } = await uiPrompts(
29
+ inquirer,
30
+ prevAns,
31
+ );
29
32
 
30
33
  return {
31
34
  apiHost,
32
35
  routes,
33
36
  enableSSO,
37
+ headerLogo,
38
+ customFonts,
34
39
  description,
35
40
  groupId,
36
41
  applicationVersion,
@@ -39,5 +44,6 @@ module.exports = async (inquirer, prevAns = {}) => {
39
44
  ui,
40
45
  framework,
41
46
  excludeGradleWrapper,
47
+ designTokens,
42
48
  };
43
49
  };
package/.genx/static.js CHANGED
@@ -78,6 +78,7 @@ const TEXTS = {
78
78
  'Generate empty CSV for entities? (config in JSON format)',
79
79
  MESSAGE_UI_ROTUES: 'Pages config in JSON format',
80
80
  MESSAGE_UI_CONFIG: 'UI configuration in JSON format',
81
+ MESSAGE_UI_DESIGN_TOKENS: 'Design tokens JSON (leave empty to use defaults)',
81
82
  MESSAGE_UI_FRAMEWORK: 'Framework',
82
83
  ERROR_VALIDATOR_FRAMEWORK: 'Selected framework is not supported',
83
84
  ERROR_VALIDATOR_WEBSOCKET: 'Not a valid websocket',
@@ -24,6 +24,10 @@ import { columnDefs } from './{{kebabCase tile.title}}.column.defs';
24
24
  {{#if tile.config.gridOptions}}
25
25
  import { gridOptions } from './{{kebabCase tile.title}}.gridOptions';
26
26
  {{/if}}
27
+ {{#ifAny tile.config.eventing.publishEventName tile.config.eventing.listener}}
28
+ import { actions, selectors } from '../../../store/store';
29
+ import { injectSelector } from '@reduxjs/angular-redux';
30
+ {{/ifAny}}
27
31
 
28
32
  {{#ifAny tile.metadata.comment tile.metadata.todo}}
29
33
  /**
@@ -50,8 +54,7 @@ export class {{pascalCase tile.componentName}} {
50
54
  createFormSchema = createFormSchema;{{/if}}{{#if tile.config.uischema}}
51
55
  uischema = createFormSchema;{{/if}}{{#if tile.config.updateFormUiSchema}}
52
56
  updateFormSchema = updateFormSchema;{{/if}}{{#if tile.config.gridOptions}}
53
- gridOptions = gridOptions as GridOptionsConfig;{{/if}}{{#if tile.config.reqrep}}
54
- reqrep = { pollingInterval: 5000, requestAutoSetup: false };{{/if}}{{#if tile.config.columns}}
57
+ gridOptions = gridOptions as GridOptionsConfig;{{/if}}{{#if tile.config.columns}}
55
58
  columnDefs = [
56
59
  ...columnDefs,
57
60
  ];{{/if}}{{#if tile.config.type}}
@@ -62,5 +65,30 @@ export class {{pascalCase tile.componentName}} {
62
65
  "xField": "groupBy",
63
66
  "yField": "value",{{/ifEquals}}
64
67
  };{{/if}}{{#if tile.config.customEvents}}
65
- customActions = emCustomActions;{{/if}}
68
+ customActions = emCustomActions;{{/if}}{{#ifAny tile.config.eventing.publishEventName tile.config.eventing.listener}}
69
+ {{#if tile.config.eventing.listener}}
70
+ criteria = injectSelector(selectors.eventing.getCriteriaFor{{pascalCase tile.title}});
71
+ {{/if}}
72
+ {{/ifAny}}{{#if tile.config.eventing.publishEventName}}
73
+ handleRowSelection = (e: any) => {
74
+ {{#ifEquals tile.componentType 'grid'}}
75
+ const selectedRows = e.api.getSelectedRows();
76
+ {{else}}
77
+ const selectedRows = e.detail.api.getSelectedRows();
78
+ {{/ifEquals}}
79
+ if (!selectedRows || !selectedRows.length) {
80
+ actions.eventing.publish{{pascalCase tile.config.eventing.publishEventName}}(null);
81
+ return;
82
+ };
83
+ const { TIMESTAMP, RECORD_ID, ROW_REF, ...data } = selectedRows[0];
84
+ actions.eventing.publish{{pascalCase tile.config.eventing.publishEventName}}(data);
85
+ };{{/if}}
86
+ {{#ifAny tile.config.gridOptions tile.config.eventing.publishEventName}}
87
+ gridOptionsModel = {
88
+ {{#if tile.config.gridOptions}}
89
+ onRowClicked: gridOptions?.onRowClicked,{{/if}}{{#if tile.config.eventing.publishEventName}}{{#ifEquals tile.componentType 'grid'}}
90
+ onSelectionChanged: this.handleRowSelection,
91
+ rowSelection: 'single'{{/ifEquals}}{{/if}}
92
+ };
93
+ {{/ifAny}}
66
94
  }
@@ -25,14 +25,25 @@
25
25
  [deleteEvent]="hasUserPermission('{{config.permissions.updateRight}}') ? '{{ config.deleteEvent }}' : undefined"
26
26
  {{/if}}
27
27
  {{#if config.gridOptions}}
28
- [gridOptions]="{{ config.gridOptions }}"
28
+ [gridOptions]="gridOptionsModel"
29
29
  {{/if}}
30
- {{#if config.snapshot}}
31
- [datasourceConfig]="{ isSnapshot: {{ config.snapshot }} }"
32
- {{/if}}
33
- {{#if config.reqrep}}
34
- [datasourceConfig]="reqrep"
30
+ {{#if config.eventing.publishEventName}}
31
+ (selectionChanged)="handleRowSelection($event)"
35
32
  {{/if}}
33
+ {{#ifAny config.snapshot config.reqrep config.eventing.listener}}
34
+ [datasourceConfig]="{
35
+ {{#if config.snapshot}}
36
+ isSnapshot: {{ config.snapshot }},
37
+ {{/if}}
38
+ {{#if config.reqrep}}
39
+ pollingInterval: 5000,
40
+ requestAutoSetup: false,
41
+ {{/if}}
42
+ {{#if config.eventing.listener}}
43
+ criteria: criteria()
44
+ {{/if}}
45
+ }"
46
+ {{/ifAny}}
36
47
  {{#if config.entityName}}
37
48
  entityLabel="{{ config.entityName }}"
38
49
  {{/if}}
@@ -14,9 +14,12 @@
14
14
  polling-interval="5000"
15
15
  request-auto-setup="false"
16
16
  {{/if}}
17
- {{#if config.gridOptions}}
18
- [deferredGridOptions]="{ onRowClicked: gridOptions.onRowClicked }"
17
+ {{#if config.eventing.listener}}
18
+ [criteria]="criteria()"
19
19
  {{/if}}
20
+ {{#ifAny config.gridOptions config.eventing.publishEventName}}
21
+ [deferredGridOptions]="gridOptionsModel"
22
+ {{/ifAny}}
20
23
  ></grid-pro-genesis-datasource>
21
24
  {{#if config.gridOptions}}
22
25
  <grid-pro-column *ngFor="let columnDef of gridOptions?.columnDefs" [definition]="columnDef"></grid-pro-column>
@@ -0,0 +1,41 @@
1
+ import { CriteriaBuilder, ExpressionBuilder, Serialisers } from '@genesislcap/foundation-criteria';
2
+ import { createSlice } from '@genesislcap/foundation-redux';
3
+
4
+ export const eventingSlice = createSlice({
5
+ name: 'eventing',
6
+ initialState: {
7
+ {{#each events}}
8
+ {{this}}: null{{#unless @last}},{{/unless}}
9
+ {{/each}}
10
+ },
11
+ reducers: {
12
+ {{#each events}}
13
+ publish{{pascalCase this}}: (state, action) => {
14
+ state.{{this}} = action.payload;
15
+ }{{#unless @last}},{{/unless}}
16
+ {{/each}}
17
+ },
18
+ selectors: {
19
+ {{#each listeners}}
20
+ getCriteriaFor{{pascalCase tileName}}: (state) => {
21
+ const criteriaBuilder = new CriteriaBuilder();
22
+ const data: any = state.{{eventName}};
23
+ if (!data) return '';
24
+
25
+ {{#each mappings}}
26
+ if (data.{{sourceField}}) {
27
+ criteriaBuilder.And(new ExpressionBuilder()
28
+ .withField('{{targetField}}')
29
+ .withValue(data.{{sourceField}})
30
+ .withSerialiser(Serialisers.EQ)
31
+ .build());
32
+ }
33
+ {{/each}}
34
+
35
+ return criteriaBuilder.build();
36
+ }{{#unless @last}},{{/unless}}
37
+ {{/each}}
38
+ },
39
+ });
40
+
41
+
@@ -0,0 +1,16 @@
1
+ import { createStore } from '@genesislcap/foundation-redux';
2
+ import { eventingSlice } from './slices/eventing.slice';
3
+
4
+ export const reduxStore = createStore([eventingSlice], {
5
+ eventing: {
6
+ {{#each events}}
7
+ {{this}}: null{{#unless @last}},{{/unless}}
8
+ {{/each}}
9
+ },
10
+ });
11
+
12
+ export const { store, actions, selectors } = reduxStore;
13
+
14
+ export type Store = typeof store;
15
+ export type Actions = typeof actions;
16
+ export type Selectors = typeof selectors;
@@ -1,3 +1,4 @@
1
+ import { useEffect } from 'react';
1
2
  {{#if tile.config.permissions.viewRight~}}
2
3
  import { getUser } from '@genesislcap/foundation-user';
3
4
  import { getViewUpdateRightComponent } from '../../../utils';
@@ -29,6 +30,15 @@ import { columnDefs as columnDefsTile } from './{{pascalCase tile.title}}ColumnD
29
30
  import { GridOptionsConfig } from '@genesislcap/rapid-grid-pro';
30
31
  import { gridOptions as gridOptionsTile } from './{{pascalCase tile.title}}GridOptions';
31
32
  {{/if}}
33
+ {{#if tile.config.eventing.publishEventName}}
34
+ import { actions } from '../../../store/store';
35
+ {{/if}}
36
+ {{#if tile.config.eventing.listener}}
37
+ import { useSelector } from 'react-redux';
38
+ import { selectors } from '../../../store/store';
39
+ {{/if}}
40
+ import { layoutComponentsMap, LayoutComponentNames } from '../../../store/store';
41
+ import { getElementByTagFromComponent } from '../../../utils/goldenLayout.helper';
32
42
  import './{{pascalCase tile.title}}Component.css';
33
43
 
34
44
  {{#ifAny tile.metadata.comment tile.metadata.todo}}
@@ -41,32 +51,91 @@ import './{{pascalCase tile.title}}Component.css';
41
51
  {{/ifAny}}
42
52
 
43
53
  export const {{pascalCase tile.componentName}}: React.FC = () => {
44
- {{#if tile.config.permissions.viewRight~}}
45
- const hasUserPermission = (permissionCode: string): boolean => getViewUpdateRightComponent(getUser(), permissionCode);
46
- {{else if tile.config.permissions.updateRight~}}
47
- const hasUserPermission = (permissionCode: string): boolean => getViewUpdateRightComponent(getUser(), permissionCode);
54
+ {{#if tile.config.permissions.viewRight}}
55
+ const hasUserPermission = (permissionCode: string): string | boolean => getViewUpdateRightComponent(getUser(), permissionCode);
56
+ {{else if tile.config.permissions.updateRight}}
57
+ const hasUserPermission = (permissionCode: string): string | boolean => getViewUpdateRightComponent(getUser(), permissionCode);
58
+ {{/if}}
59
+ {{#if tile.config.eventing.publishEventName}}
60
+ const handleRowSelection = (e: any) => {
61
+ const selectedRows = e.api.getSelectedRows();
62
+ if (!selectedRows || !selectedRows.length) {
63
+ actions.eventing.publish{{pascalCase tile.config.eventing.publishEventName}}(null);
64
+ return;
65
+ }
66
+ const { TIMESTAMP, RECORD_ID, ROW_REF, ...data } = selectedRows[0];
67
+ actions.eventing.publish{{pascalCase tile.config.eventing.publishEventName}}(data);
68
+ };
48
69
  {{/if}}
49
- {{#if tile.config.createFormUiSchema~}}
70
+ {{#if tile.config.createFormUiSchema}}
50
71
  const createFormSchema: typeof createFormSchemaTile = createFormSchemaTile;
51
72
  {{/if}}
52
- {{#if tile.config.uischema~}}
73
+ {{#if tile.config.uischema}}
53
74
  const uischema: typeof createFormSchemaTile = createFormSchemaTile;
54
75
  {{/if}}
55
- {{#if tile.config.updateFormUiSchema~}}
76
+ {{#if tile.config.updateFormUiSchema}}
56
77
  const updateFormSchema: typeof updateFormSchemaTile = updateFormSchemaTile;
57
78
  {{/if}}
58
- {{#if tile.config.columns~}}
79
+ {{#if tile.config.columns}}
59
80
  const columnDefs: typeof columnDefsTile = [...columnDefsTile];
60
81
  {{/if}}
61
- {{#if tile.config.gridOptions~}}
62
- const deferredGridOptions: { onRowClicked: GridOptionsConfig.onRowClicked } = { onRowClicked: gridOptionsTile?.onRowClicked }
82
+ {{#ifAny tile.config.gridOptions tile.config.eventing.publishEventName}}
83
+ const gridOptions: { {{#if tile.config.gridOptions}}onRowClicked: GridOptionsConfig.onRowClicked, {{/if}}{{#if tile.config.eventing.publishEventName}}onSelectionChanged: any, rowSelection: 'multiple' | 'single'{{/if}} } = {
84
+ {{#if tile.config.gridOptions}}
85
+ onRowClicked: gridOptionsTile?.onRowClicked,
86
+ {{/if}}
87
+ {{#if tile.config.eventing.publishEventName}}
88
+ onSelectionChanged: handleRowSelection,
89
+ rowSelection: 'single',
90
+ {{/if}}
91
+ }
92
+ {{/ifAny}}
93
+ const datasourceConfig: { isSnapshot?: boolean, pollingInterval?: string, requestAutoSetup?: string, criteria?: string } = {
94
+ {{#if tile.config.snapshot}}
95
+ isSnapshot: {{ tile.config.snapshot }},
96
+ {{/if}}
97
+ {{#if tile.config.reqrep}}
98
+ pollingInterval: '5000',
99
+ requestAutoSetup: 'false',
100
+ {{/if}}
101
+ {{#if tile.config.eventing.listener}}
102
+ criteria: useSelector(selectors.eventing.getCriteriaFor{{pascalCase tile.title}}),
103
+ {{/if}}
104
+ }
105
+ {{#if tile.componentType}}
106
+ {{#ifEquals tile.componentType 'grid'}}
107
+ useEffect(() => {
108
+ const componentElement = layoutComponentsMap.get(LayoutComponentNames.{{constantCase tile.componentName}});
109
+ const componentDatasource = componentElement ? getElementByTagFromComponent(componentElement, 'grid-pro-genesis-datasource') : undefined;
110
+
111
+ if (componentDatasource) {
112
+ {{#if tile.config.eventing.listener}}
113
+ componentDatasource.criteria = datasourceConfig.criteria;
114
+ {{/if}}
115
+ {{#if tile.config.reqrep}}
116
+ componentDatasource.requestAutoSetup = datasourceConfig.requestAutoSetup;
117
+ componentDatasource.pollingInterval = datasourceConfig.pollingInterval;
118
+ {{/if}}
119
+ }
120
+ }, [datasourceConfig]);
121
+ {{/ifEquals}}
63
122
  {{/if}}
64
- {{#if tile.config.reqrep~}}
65
- const reqrep: { pollingInterval: number } = { pollingInterval: 5000, requestAutoSetup: false };
123
+ {{#if tile.componentType}}
124
+ {{#ifEquals tile.componentType 'manager'}}
125
+ useEffect(() => {
126
+ const componentElement = layoutComponentsMap.get(LayoutComponentNames.{{constantCase tile.componentName}});
127
+ const componentDatasource = componentElement ? getElementByTagFromComponent(componentElement, 'entity-management') : undefined;
128
+
129
+ if (componentDatasource) {
130
+ componentDatasource.datasourceConfig = datasourceConfig;
131
+ }
132
+ }, [datasourceConfig]);
133
+ {{/ifEquals}}
66
134
  {{/if}}
67
- {{#if tile.config.type~}}
135
+
136
+ {{#if tile.config.type}}
68
137
  const chartConfig: {
69
- {{#ifEquals tile.config.type 'pie'~}}
138
+ {{#ifEquals tile.config.type 'pie'}}
70
139
  radius: number;
71
140
  angleField: string;
72
141
  colorField: string;
@@ -75,7 +144,7 @@ export const {{pascalCase tile.componentName}}: React.FC = () => {
75
144
  yField: string;
76
145
  {{/ifEquals}}
77
146
  } = {
78
- {{#ifEquals tile.config.type 'pie'~}}
147
+ {{#ifEquals tile.config.type 'pie'}}
79
148
  radius: 0.75,
80
149
  angleField: 'value',
81
150
  colorField: 'groupBy',
@@ -11,54 +11,48 @@ hasUserPermission('{{config.permissions.viewRight}}') ? (
11
11
  {{/if}}
12
12
  resourceName="{{ config.resourceName }}"
13
13
  {{#if config.createEvent~}}
14
- {{#if config.permissions.updateRight~}}
14
+ {{#if config.permissions.updateRight}}
15
15
  createEvent={hasUserPermission('{{config.permissions.updateRight}}') ? '{{ config.createEvent }}' : undefined}
16
16
  {{else~}}
17
17
  createEvent="{{ config.createEvent }}"
18
18
  {{/if}}
19
- {{#if config.createFormUiSchema~}}
19
+ {{#if config.createFormUiSchema}}
20
20
  createFormUiSchema={createFormSchema}
21
21
  {{/if}}
22
22
  {{/if}}
23
23
  {{#if config.updateEvent~}}
24
- {{#if config.permissions.updateRight~}}
24
+ {{#if config.permissions.updateRight}}
25
25
  updateEvent={hasUserPermission('{{config.permissions.updateRight}}') ? '{{ config.updateEvent }}' : undefined}
26
26
  {{else~}}
27
27
  updateEvent="{{ config.updateEvent }}"
28
28
  {{/if}}
29
- {{#if config.updateFormUiSchema~}}
29
+ {{#if config.updateFormUiSchema}}
30
30
  updateFormUiSchema={updateFormSchema}
31
31
  {{/if}}
32
32
  {{/if}}
33
33
  {{#if config.deleteEvent~}}
34
- {{#if config.permissions.updateRight~}}
34
+ {{#if config.permissions.updateRight}}
35
35
  deleteEvent={hasUserPermission('{{config.permissions.updateRight}}') ? '{{ config.deleteEvent }}' : undefined}
36
36
  {{else~}}
37
37
  deleteEvent="{{ config.deleteEvent }}"
38
38
  {{/if}}
39
39
  {{/if}}
40
- {{#if config.gridOptions~}}
40
+ {{#ifAny config.gridOptions config.eventing.publishEventName}}
41
41
  gridOptions={gridOptions}
42
- {{/if}}
43
- {{#if config.snapshot~}}
44
- datasourceConfig={ isSnapshot: {{ config.snapshot }} }
45
- {{/if}}
46
- {{#if config.reqrep~}}
47
- datasourceConfig={reqrep}
48
- {{/if}}
49
- {{#if config.columns~}}
42
+ {{/ifAny}}
43
+ {{#if config.columns}}
50
44
  columns={columnDefs}
51
45
  {{/if}}
52
46
  {{#if config.entityName}}
53
47
  entityLabel="{{ config.entityName }}"
54
48
  {{/if}}
55
- {{#if config.modalPosition~}}
49
+ {{#if config.modalPosition}}
56
50
  modal-position="{{ config.modalPosition }}"
57
51
  {{/if}}
58
- {{#if config.sizeColumnsToFit~}}
52
+ {{#if config.sizeColumnsToFit}}
59
53
  size-columns-to-fit
60
54
  {{/if}}
61
- {{#if config.enableSearchBar~}}
55
+ {{#if config.enableSearchBar}}
62
56
  enable-search-bar
63
57
  {{/if}}
64
58
  {{#if config.customEvents}}