@genesislcap/blank-app-seed 2.8.0 → 2.10.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.
@@ -1,5 +1,5 @@
1
1
  const versions = require('./versions.json');
2
- const { registerPartials, generateRoute, generateEmptyCsv, formatRouteData } = require('./utils');
2
+ const { registerPartials, generateRoute, generateEmptyCsv, formatRouteData, validateRoute } = require('./utils');
3
3
 
4
4
  /**
5
5
  * Signature is `async (data: inquirer.Answers, utils: SeedConfigurationUtils)`
@@ -14,15 +14,20 @@ module.exports = async (data, utils) => {
14
14
 
15
15
  registerPartials(utils);
16
16
 
17
- data.routes
18
- .forEach((route) => {
19
- if (!route.name) {
20
- console.warn('Invalid route - missing name', route);
21
- return;
22
- }
23
- const routeData = formatRouteData(route);
24
- generateRoute(routeData, utils);
25
- });
17
+ data.routes = data.routes
18
+ .filter(validateRoute)
19
+ .map(formatRouteData);
20
+
21
+ const FDC3EventHandlersEnabled = data.routes.find(route => route.FDC3EventHandlersEnabled);
22
+ const FDC3ListenersEnabled = data.ui?.fdc3?.channels?.length;
23
+ data.FDC3 = {
24
+ includeDependencies: !!(FDC3ListenersEnabled || FDC3EventHandlersEnabled),
25
+ channels: data.ui?.fdc3?.channels || []
26
+ };
27
+
28
+ data.routes.forEach(route => {
29
+ generateRoute(route, utils);
30
+ });
26
31
 
27
32
  data.csv
28
33
  .map(entity => ({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@genesislcap/blank-app-seed-config",
3
3
  "description": "Genesis Blank App Seed Configuration",
4
- "version": "2.8.0",
4
+ "version": "2.10.0",
5
5
  "license": "Apache-2.0",
6
6
  "genxSeedConfig": {
7
7
  "exclude": [
@@ -1,16 +1,7 @@
1
1
  const {mavenArtifactVersionRegex} = require('./validators');
2
+ const {parseJSONArgument} = require('../utils');
2
3
 
3
- const parsecsv = (inputEntities) => {
4
- if (!inputEntities){
5
- return [];
6
- }
7
- try {
8
- return JSON.parse(inputEntities);
9
- } catch (error) {
10
- console.error("Error parsing `csv` parameter as JSON:", error.message);
11
- return [];
12
- }
13
- }
4
+ const parsecsv = parseJSONArgument('csv', []);
14
5
 
15
6
  module.exports = async (inquirer, prevAns = {}) => {
16
7
  const {
@@ -44,7 +35,7 @@ module.exports = async (inquirer, prevAns = {}) => {
44
35
  {
45
36
  name: 'csv',
46
37
  type: 'input',
47
- message: 'Generate empty CSV for entities? (config in json format)',
38
+ message: 'Generate empty CSV for entities? (config in JSON format)',
48
39
  when: !prevAns.csv,
49
40
  default: '[]'
50
41
  },
@@ -1,37 +1,38 @@
1
- const routesInto = () => console.log(`
1
+ const {parseJSONArgument} = require('../utils');
2
+
3
+ const defaultRoutes = [{ name: 'home' }];
4
+ const parseRoutes = parseJSONArgument('routes', defaultRoutes);
5
+ const routesIntro = () => console.log(`
2
6
  Pages to be added to the navigation header
3
7
  `);
4
8
 
5
- const defaultRoutes = '[{"name":"home"}]';
9
+ const defaultUI = {};
10
+ const parseUI = parseJSONArgument('ui', defaultUI);
6
11
 
7
12
  module.exports = async (inquirer, prevAns = {}) => {
8
- routesInto();
13
+ routesIntro();
9
14
  const {
10
15
  routes = prevAns.routes,
16
+ ui = prevAns.ui,
11
17
  } = await inquirer.prompt([
12
18
  {
13
19
  name: 'routes',
14
20
  type: 'input',
15
- message: 'Pages config in json format',
21
+ message: 'Pages config in JSON format',
16
22
  when: !prevAns.routes,
17
- default: defaultRoutes,
23
+ default: JSON.stringify(defaultRoutes),
24
+ },
25
+ {
26
+ name: 'ui',
27
+ type: 'input',
28
+ message: 'UI configuration in JSON format',
29
+ when: !prevAns.ui,
30
+ default: JSON.stringify(defaultUI),
18
31
  },
19
32
  ])
20
33
 
21
- let routesParsed;
22
- if (routes) {
23
- try {
24
- routesParsed = JSON.parse(routes);
25
- } catch (error) {
26
- console.error("Error parsing `routes` parameter as JSON:", error.message);
27
- console.log("Falling back to the default routes value");
28
- routesParsed = JSON.parse(defaultRoutes);
29
- }
30
- } else {
31
- routesParsed = JSON.parse(defaultRoutes);
32
- }
33
-
34
34
  return {
35
- routes: routesParsed,
35
+ routes: parseRoutes(routes),
36
+ ui: parseUI(ui),
36
37
  };
37
38
  };
package/.genx/prompts.js CHANGED
@@ -13,7 +13,7 @@ module.exports = async (inquirer, prevAns = {}) => {
13
13
 
14
14
  const {apiHost, enableSSO} = await apiPrompts(inquirer, prevAns)
15
15
  const {groupId, applicationVersion, enableDeployPlugin, csv} = await genesisServerPrompts(inquirer, prevAns);
16
- const {routes} = await uiPrompts(inquirer, prevAns);
16
+ const {routes, ui} = await uiPrompts(inquirer, prevAns);
17
17
 
18
18
  return {
19
19
  apiHost,
@@ -23,5 +23,6 @@ module.exports = async (inquirer, prevAns = {}) => {
23
23
  applicationVersion,
24
24
  enableDeployPlugin,
25
25
  csv,
26
+ ui,
26
27
  };
27
28
  };
@@ -22,6 +22,11 @@
22
22
  {{#if config.deleteEvent}}
23
23
  deleteEvent="{{ config.deleteEvent }}"
24
24
  {{/if}}
25
+ {{#if config.gridOptions}}
26
+ :gridOptions=${() => (
27
+ {{{config.gridOptions}}}
28
+ )}
29
+ {{/if}}
25
30
  {{#if config.snapshot}}
26
31
  :datasourceConfig=${() => ({isSnapshot: {{ config.snapshot }} })}
27
32
  {{/if}}
@@ -4,9 +4,9 @@
4
4
  {{#if config.snapshot}}
5
5
  isSnapshot="{{config.snapshot}}"
6
6
  {{/if}}
7
- {{#if config.deferredGridOptions}}
7
+ {{#if config.gridOptions}}
8
8
  :deferredGridOptions=${() => (
9
- {{{config.deferredGridOptions}}}
9
+ {{{config.gridOptions}}}
10
10
  )}
11
11
  {{/if}}
12
12
  >
@@ -0,0 +1,30 @@
1
+ <zero-layout-region type="horizontal">
2
+ <zero-layout-region type="vertical">
3
+ {{#each route.tiles}}
4
+ {{#ifEquals @index 0}}
5
+ <zero-layout-item title="{{../title}}">
6
+ {{> (lookup ../this 'type') ../this}}
7
+ </zero-layout-item>
8
+ {{/ifEquals}}
9
+ {{#ifEquals @index 1}}
10
+ <zero-layout-item title="{{../title}}">
11
+ {{> (lookup ../this 'type') ../this}}
12
+ </zero-layout-item>
13
+ {{/ifEquals}}
14
+ {{/each}}
15
+ </zero-layout-region>
16
+ <zero-layout-region type="vertical">
17
+ {{#each route.tiles}}
18
+ {{#ifEquals @index 2}}
19
+ <zero-layout-item title="{{../title}}">
20
+ {{> (lookup ../this 'type') ../this}}
21
+ </zero-layout-item>
22
+ {{/ifEquals}}
23
+ {{#ifEquals @index 3}}
24
+ <zero-layout-item title="{{../title}}">
25
+ {{> (lookup ../this 'type') ../this}}
26
+ </zero-layout-item>
27
+ {{/ifEquals}}
28
+ {{/each}}
29
+ </zero-layout-region>
30
+ </zero-layout-region>
@@ -0,0 +1,7 @@
1
+ <zero-layout-region>
2
+ {{#each route.tiles}}
3
+ <zero-layout-item title="{{this.title}}">
4
+ {{> (lookup . 'type') }}
5
+ </zero-layout-item>
6
+ {{/each}}
7
+ </zero-layout-region>
@@ -1,16 +1,13 @@
1
1
  import { html } from '@microsoft/fast-element';
2
+ {{#if route.FDC3EventHandlersEnabled}}
3
+ import { sendEventOnChannel } from '../../utils';
4
+ {{/if}}
2
5
  import type { {{pascalCase route.name}} } from './{{kebabCase route.name}}';
3
6
 
4
7
  export const {{pascalCase route.name}}Template = html<{{pascalCase route.name}}>`
5
8
  {{#if route.tiles}}
6
9
  <zero-layout auto-save-key="{{route.layoutKey}}">
7
- <zero-layout-region>
8
- {{#each route.tiles}}
9
- <zero-layout-item title="{{this.title}}">
10
- {{> (lookup . 'type') }}
11
- </zero-layout-item>
12
- {{/each}}
13
- </zero-layout-region>
10
+ {{> (lookup ./route 'layoutType') }}
14
11
  </zero-layout>
15
12
  {{else}}
16
13
  <!-- insert template code here -->
@@ -0,0 +1,7 @@
1
+ <zero-layout-region type="tabs">
2
+ {{#each route.tiles}}
3
+ <zero-layout-item title="{{this.title}}">
4
+ {{> (lookup . 'type') }}
5
+ </zero-layout-item>
6
+ {{/each}}
7
+ </zero-layout-region>
package/.genx/utils.js CHANGED
@@ -8,6 +8,9 @@ const makeDirectory = (directory) => {
8
8
  };
9
9
 
10
10
  const registerPartials = ({ registerPartial }) => {
11
+ registerPartial('grid-layout', resolve(__dirname, 'templates/gridLayout.hbs'))
12
+ registerPartial('tabs-layout', resolve(__dirname, 'templates/tabsLayout.hbs'))
13
+ registerPartial('horizontal-layout', resolve(__dirname, 'templates/horizontalLayout.hbs'))
11
14
  registerPartial('smart-form', resolve(__dirname, 'templates/form.hbs'))
12
15
  registerPartial('chart', resolve(__dirname, 'templates/chart.hbs'))
13
16
  registerPartial('entity-manager', resolve(__dirname, 'templates/entityManager.hbs'))
@@ -34,15 +37,58 @@ const formatJSONValue = (value) => {
34
37
  }
35
38
  }
36
39
 
40
+ const gridOptionsSerializer = (options, pad = ' ') => {
41
+ if (!options) {
42
+ return undefined;
43
+ }
44
+ try {
45
+ let output = `{\n`;
46
+ Object.keys(options).forEach((key) => {
47
+ const value = options[key];
48
+ if (value?.type === 'function') {
49
+ const args = value.arguments?.map(JSON.stringify).join(', ');
50
+ output += `${pad}${key}: ${value.name}(${args}),\n`;
51
+ } else {
52
+ output += `${pad}${key}: ${formatJSONValue(value)},\n`;
53
+ }
54
+ });
55
+ output += `${pad}}\n`;
56
+ return output;
57
+ } catch (e) {
58
+ return undefined;
59
+ }
60
+ };
61
+
62
+ const validateRoute = (route) => {
63
+ if (!route.name) {
64
+ console.warn('Invalid route - missing name', route);
65
+ }
66
+ return !!route.name;
67
+ }
68
+
69
+ const getLayoutType = (route) => {
70
+ if (route?.tiles?.length < 4) {
71
+ return 'horizontal-layout'
72
+ } else if (route?.tiles?.length === 4) {
73
+ return 'grid-layout'
74
+ }
75
+ return 'tabs-layout'
76
+ }
77
+
37
78
  const formatRouteData = (route) => {
38
79
  const layoutKey = route?.layoutKey || `${route.name}_${Date.now()}`;
80
+ const layoutType = route?.layoutType || getLayoutType(route);
81
+
82
+ const FDC3ClickCategory = 'fdc3';
83
+ const FDC3EventHandlersEnabled = !!route.tiles?.find(t => t.config?.gridOptions?.onRowClicked?.category === FDC3ClickCategory);
84
+
39
85
  const tiles = route.tiles?.map(tile => ({
40
86
  ...tile,
41
87
  config: {
42
88
  ...(tile.config || {}),
89
+ gridOptions: gridOptionsSerializer(tile.config?.gridOptions),
43
90
  createFormUiSchema: formatJSONValue(tile.config?.createFormUiSchema),
44
91
  updateFormUiSchema: formatJSONValue(tile.config?.updateFormUiSchema),
45
- deferredGridOptions: formatJSONValue(tile.config?.deferredGridOptions),
46
92
  uischema: formatJSONValue(tile.config?.uischema),
47
93
  columns: formatJSONValue(tile.config?.columns)
48
94
  }
@@ -50,15 +96,32 @@ const formatRouteData = (route) => {
50
96
 
51
97
  return {
52
98
  ...route,
99
+ layoutType,
53
100
  layoutKey,
54
- tiles
101
+ tiles,
102
+ FDC3EventHandlersEnabled,
103
+ }
104
+ };
105
+
106
+ const parseJSONArgument = (name, defaultValue) =>
107
+ (value) => {
108
+ if (!value){
109
+ return defaultValue;
110
+ }
111
+ try {
112
+ return JSON.parse(value);
113
+ } catch (error) {
114
+ console.error(`Error parsing "${name}" parameter as JSON:`, error.message);
115
+ return defaultValue;
116
+ }
55
117
  }
56
- }
57
118
 
58
119
  module.exports = {
59
120
  makeDirectory,
60
121
  registerPartials,
61
122
  generateRoute,
123
+ validateRoute,
62
124
  generateEmptyCsv,
63
125
  formatRouteData,
126
+ parseJSONArgument,
64
127
  };
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.10.0](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v2.9.0...v2.10.0) (2024-04-12)
4
+
5
+
6
+ ### Features
7
+
8
+ * new layout types GENC-286 (#182) 06a6641
9
+
10
+ ## [2.9.0](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v2.8.0...v2.9.0) (2024-04-12)
11
+
12
+
13
+ ### Features
14
+
15
+ * FDC3 support GENC-224 (#180) ac35e42
16
+
3
17
  ## [2.8.0](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v2.7.0...v2.8.0) (2024-04-11)
4
18
 
5
19
 
@@ -87,6 +87,9 @@
87
87
  "lint-staged": "^12.4.1"
88
88
  },
89
89
  "dependencies": {
90
+ {{#if FDC3.includeDependencies}}
91
+ "@finos/fdc3": "^1.2.0",
92
+ {{/if}}
90
93
  "@genesislcap/foundation-comms": "{{versions.UI}}",
91
94
  "@genesislcap/foundation-entity-management": "{{versions.UI}}",
92
95
  "@genesislcap/foundation-events": "{{versions.UI}}",
@@ -11,6 +11,9 @@ import * as Components from '../components';
11
11
  import { MainRouterConfig } from '../routes';
12
12
  import { Store, StoreEventDetailMap } from '../store';
13
13
  import designTokens from '../styles/design-tokens.json';
14
+ {{#if FDC3.channels.length}}
15
+ import { listenToChannel, onFDC3Ready } from '../utils';
16
+ {{/if}}
14
17
  import { MainStyles as styles } from './main.styles';
15
18
  import { DynamicTemplate as template, LoadingTemplate, MainTemplate } from './main.template';
16
19
 
@@ -44,6 +47,9 @@ export class MainApplication extends EventEmitter<StoreEventDetailMap>(FASTEleme
44
47
  this.readyStore();
45
48
  await this.loadPBCs();
46
49
  await this.loadRemotes();
50
+ {{#if FDC3.channels.length}}
51
+ onFDC3Ready(this.FDC3ReadyHandler);
52
+ {{/if}}
47
53
  DOM.queueUpdate(() => {
48
54
  configureDesignSystem(this.provider, designTokens);
49
55
  });
@@ -89,6 +95,18 @@ export class MainApplication extends EventEmitter<StoreEventDetailMap>(FASTEleme
89
95
  return this.ready ? MainTemplate : LoadingTemplate;
90
96
  }
91
97
 
98
+ {{#if FDC3.channels.length}}
99
+ FDC3ReadyHandler = () => {
100
+ {{#each FDC3.channels}}
101
+ listenToChannel('{{this.name}}', '{{this.type}}', (result) => {
102
+ console.log('Received FDC3 channel message on: {{this.name}} channel, type: {{this.type}}', result);
103
+ // TODO: Add your listener logic here
104
+ // E.g. open a modal or route to specific page: Route.path.push(`[Route name]`);
105
+ });
106
+ {{/each}}
107
+ };
108
+
109
+ {{/if}}
92
110
  private registerDIDependencies() {
93
111
  this.container.register(
94
112
  Registration.transient(DefaultRouteRecognizer, DefaultRouteRecognizer),
@@ -0,0 +1,62 @@
1
+ {{#if FDC3.includeDependencies}}
2
+ import { getOrCreateChannel, raiseIntent, addIntentListener } from '@finos/fdc3';
3
+ {{/if}}
4
+ export const isFDC3 = (): boolean => !!(window as any).fdc3;
5
+ {{#if FDC3.includeDependencies}}
6
+
7
+ export const onFDC3Ready = async (FDC3ReadyCb: () => any): Promise<void> => {
8
+ isFDC3()
9
+ ? await FDC3ReadyCb()
10
+ : window.addEventListener('fdc3Ready', async () => {
11
+ await FDC3ReadyCb();
12
+ });
13
+ };
14
+
15
+ export const sendMessageOnChannel = async (
16
+ channelName: string,
17
+ type: string,
18
+ payload: any,
19
+ ): Promise<void> => {
20
+ const channel = await getOrCreateChannel(channelName);
21
+
22
+ const m: any = {
23
+ type,
24
+ id: payload,
25
+ };
26
+
27
+ await channel.broadcast(m);
28
+ };
29
+
30
+ export const listenToChannel = async (
31
+ channelName: string,
32
+ type: string,
33
+ callback: (result: any) => void,
34
+ ): Promise<void> => {
35
+ const channel = await getOrCreateChannel(channelName);
36
+ channel.addContextListener(type, (result) => callback(result));
37
+ };
38
+
39
+ export const doRaiseIntent = async (intent: string, type: string, context: any): Promise<void> => {
40
+ const message = {
41
+ type,
42
+ id: context,
43
+ };
44
+
45
+ const result = await raiseIntent(intent, message);
46
+ };
47
+
48
+ export const listenForIntent = async (
49
+ intent: string,
50
+ callback: (result: any) => void,
51
+ ): Promise<void> => {
52
+ addIntentListener(intent, (result) => callback(result));
53
+ };
54
+
55
+ export const sendEventOnChannel = (channelName: string, type: string) => {
56
+ return async (e: any) => {
57
+ // check for ag-grid-specific events, fall back to standard events
58
+ const payload = e.data?.payload || e.detail;
59
+ sendMessageOnChannel(channelName, type, payload);
60
+ };
61
+ };
62
+ {{/if}}
@@ -1 +1,2 @@
1
+ export * from './fdc3';
1
2
  export * from './logger';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@genesislcap/blank-app-seed",
3
3
  "description": "Genesis Blank App Seed",
4
- "version": "2.8.0",
4
+ "version": "2.10.0",
5
5
  "license": "Apache-2.0",
6
6
  "scripts": {
7
7
  "release": "semantic-release"