@genesislcap/blank-app-seed 5.10.4-prerelease.1 → 5.11.0-prerelease.2
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/react/component/component.hbs +16 -39
- package/.genx/templates/react/entityManager.hbs +11 -5
- package/.genx/templates/react/grid.hbs +7 -0
- package/.genx/templates/react/gridLayout.hbs +36 -30
- package/.genx/templates/react/horizontalLayout.hbs +11 -7
- package/.genx/templates/react/route.hbs +35 -13
- package/.genx/templates/react/route.styles.hbs +3 -2
- package/.genx/templates/react/store.hbs +0 -8
- package/.genx/templates/react/tabsLayout.hbs +17 -7
- package/.genx/utils/generateStore.js +3 -9
- package/.genx/versions.json +1 -1
- package/.github/workflows/slack.yml +1 -1
- package/CHANGELOG.md +28 -0
- package/client-tmp/react/package.json +2 -0
- package/client-tmp/react/src/components/routes/ProtectedRoute.tsx +4 -2
- package/client-tmp/react/src/config.ts +0 -2
- package/client-tmp/react/src/custom-elements.d.ts +0 -3
- package/client-tmp/react/src/layouts/default/DefaultLayout.tsx +44 -32
- package/client-tmp/react/src/main.tsx +2 -0
- package/client-tmp/react/src/share/foundation-login.ts +9 -5
- package/client-tmp/react/src/share/genesis-components.ts +0 -2
- package/client-tmp/react/src/styles/flexlayout-theme.css +102 -0
- package/client-tmp/react/src/utils/layout.ts +3 -4
- package/package.json +1 -1
- package/.genx/.prettierrc +0 -5
- package/client-tmp/react/src/environments/environment.prod.ts +0 -8
- package/client-tmp/react/src/environments/environment.ts +0 -9
- package/client-tmp/react/src/utils/goldenLayout.helper.ts +0 -59
package/.genx/package.json
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { useEffect } from 'react';
|
|
2
1
|
{{#ifEquals tile.type 'entity-manager'}}
|
|
3
2
|
import { EntityManagement } from '@genesislcap/foundation-entity-management/react';
|
|
4
3
|
{{/ifEquals}}
|
|
@@ -55,8 +54,9 @@ import { actions } from '../../../store/store';
|
|
|
55
54
|
import { useSelector } from 'react-redux';
|
|
56
55
|
import { selectors } from '../../../store/store';
|
|
57
56
|
{{/if}}
|
|
58
|
-
|
|
59
|
-
import {
|
|
57
|
+
{{#ifAny tile.config.snapshot tile.config.reqrep tile.config.eventing.listener}}
|
|
58
|
+
import { DatasourceConfiguration } from '@genesislcap/foundation-entity-management';
|
|
59
|
+
{{/ifAny}}
|
|
60
60
|
import './{{pascalCase tile.title}}Component.css';
|
|
61
61
|
|
|
62
62
|
{{#ifAny tile.metadata.comment tile.metadata.todo}}
|
|
@@ -76,7 +76,11 @@ export const {{pascalCase tile.componentName}}: React.FC = () => {
|
|
|
76
76
|
{{/if}}
|
|
77
77
|
{{#if tile.config.eventing.publishEventName}}
|
|
78
78
|
const handleRowSelection = (e: any) => {
|
|
79
|
+
{{#ifEquals tile.type 'entity-manager'}}
|
|
80
|
+
const selectedRows = e.detail.api.getSelectedRows();
|
|
81
|
+
{{else}}
|
|
79
82
|
const selectedRows = e.api.getSelectedRows();
|
|
83
|
+
{{/ifEquals}}
|
|
80
84
|
if (!selectedRows || !selectedRows.length) {
|
|
81
85
|
actions.eventing.publish{{pascalCase tile.config.eventing.publishEventName}}(null);
|
|
82
86
|
return;
|
|
@@ -100,8 +104,9 @@ export const {{pascalCase tile.componentName}}: React.FC = () => {
|
|
|
100
104
|
{{#if tile.config.columns}}
|
|
101
105
|
const columnDefs: typeof columnDefsTile = [...columnDefsTile];
|
|
102
106
|
{{/if}}
|
|
107
|
+
{{#ifEquals tile.type 'grid-pro'}}
|
|
103
108
|
{{#ifAny tile.config.gridOptions tile.config.eventing.publishEventName}}
|
|
104
|
-
const gridOptions:
|
|
109
|
+
const gridOptions: GridOptionsConfig = {
|
|
105
110
|
{{#if tile.config.gridOptions}}
|
|
106
111
|
onRowClicked: gridOptionsTile?.onRowClicked,
|
|
107
112
|
{{/if}}
|
|
@@ -111,56 +116,28 @@ export const {{pascalCase tile.componentName}}: React.FC = () => {
|
|
|
111
116
|
{{/if}}
|
|
112
117
|
}
|
|
113
118
|
{{/ifAny}}
|
|
114
|
-
|
|
119
|
+
{{/ifEquals}}
|
|
120
|
+
{{#ifAny tile.config.snapshot tile.config.reqrep tile.config.eventing.listener}}
|
|
121
|
+
const datasourceConfig: DatasourceConfiguration = {
|
|
115
122
|
{{#if tile.config.snapshot}}
|
|
116
123
|
isSnapshot: {{ tile.config.snapshot }},
|
|
117
124
|
{{/if}}
|
|
118
125
|
{{#if tile.config.reqrep}}
|
|
119
|
-
pollingInterval:
|
|
120
|
-
requestAutoSetup:
|
|
126
|
+
pollingInterval: 5000,
|
|
127
|
+
requestAutoSetup: false,
|
|
121
128
|
{{/if}}
|
|
122
129
|
{{#if tile.config.eventing.listener}}
|
|
123
130
|
criteria: useSelector(selectors.eventing.getCriteriaFor{{pascalCase tile.title}}),
|
|
124
131
|
{{/if}}
|
|
125
132
|
}
|
|
126
|
-
{{
|
|
127
|
-
{{#ifEquals tile.componentType 'grid'}}
|
|
128
|
-
useEffect(() => {
|
|
129
|
-
const componentElement = layoutComponentsMap.get(LayoutComponentNames.{{constantCase tile.componentName}});
|
|
130
|
-
const componentDatasource = componentElement ? getElementByTagFromComponent(componentElement, 'grid-pro-genesis-datasource') : undefined;
|
|
131
|
-
|
|
132
|
-
if (componentDatasource) {
|
|
133
|
-
{{#if tile.config.eventing.listener}}
|
|
134
|
-
componentDatasource.criteria = datasourceConfig.criteria;
|
|
135
|
-
{{/if}}
|
|
136
|
-
{{#if tile.config.reqrep}}
|
|
137
|
-
componentDatasource.requestAutoSetup = datasourceConfig.requestAutoSetup;
|
|
138
|
-
componentDatasource.pollingInterval = datasourceConfig.pollingInterval;
|
|
139
|
-
{{/if}}
|
|
140
|
-
}
|
|
141
|
-
}, [datasourceConfig]);
|
|
142
|
-
{{/ifEquals}}
|
|
143
|
-
{{/if}}
|
|
144
|
-
{{#if tile.componentType}}
|
|
145
|
-
{{#ifEquals tile.componentType 'manager'}}
|
|
146
|
-
useEffect(() => {
|
|
147
|
-
const componentElement = layoutComponentsMap.get(LayoutComponentNames.{{constantCase tile.componentName}});
|
|
148
|
-
const componentDatasource = componentElement ? getElementByTagFromComponent(componentElement, 'entity-management') : undefined;
|
|
149
|
-
|
|
150
|
-
if (componentDatasource) {
|
|
151
|
-
componentDatasource.datasourceConfig = datasourceConfig;
|
|
152
|
-
}
|
|
153
|
-
}, [datasourceConfig]);
|
|
154
|
-
{{/ifEquals}}
|
|
155
|
-
{{/if}}
|
|
156
|
-
|
|
133
|
+
{{/ifAny}}
|
|
157
134
|
{{#if tile.config.type}}
|
|
158
135
|
const chartConfig: ChartConfig = {
|
|
159
136
|
{{#ifEquals tile.config.type 'pie'}}
|
|
160
137
|
radius: 0.75,
|
|
161
138
|
angleField: 'value',
|
|
162
139
|
colorField: 'groupBy',
|
|
163
|
-
{{else
|
|
140
|
+
{{else}}
|
|
164
141
|
xField: 'groupBy',
|
|
165
142
|
yField: 'value',
|
|
166
143
|
{{/ifEquals}}
|
|
@@ -6,6 +6,9 @@ hasUserPermission('{{config.permissions.viewRight}}') ? (
|
|
|
6
6
|
prefix="rapid"
|
|
7
7
|
enableRowFlashing
|
|
8
8
|
enableCellFlashing
|
|
9
|
+
{{#ifAny config.snapshot config.reqrep config.eventing.listener}}
|
|
10
|
+
datasourceConfig={datasourceConfig}
|
|
11
|
+
{{/ifAny}}
|
|
9
12
|
{{#if config.title~}}
|
|
10
13
|
title="{{ config.title }}"
|
|
11
14
|
{{/if}}
|
|
@@ -13,7 +16,7 @@ hasUserPermission('{{config.permissions.viewRight}}') ? (
|
|
|
13
16
|
{{#if config.createEvent~}}
|
|
14
17
|
{{#if config.permissions.updateRight}}
|
|
15
18
|
createEvent={hasUserPermission('{{config.permissions.updateRight}}') ? '{{ config.createEvent }}' : undefined}
|
|
16
|
-
{{else
|
|
19
|
+
{{else}}
|
|
17
20
|
createEvent="{{ config.createEvent }}"
|
|
18
21
|
{{/if}}
|
|
19
22
|
{{#if config.createFormUiSchema}}
|
|
@@ -23,7 +26,7 @@ hasUserPermission('{{config.permissions.viewRight}}') ? (
|
|
|
23
26
|
{{#if config.updateEvent~}}
|
|
24
27
|
{{#if config.permissions.updateRight}}
|
|
25
28
|
updateEvent={hasUserPermission('{{config.permissions.updateRight}}') ? '{{ config.updateEvent }}' : undefined}
|
|
26
|
-
{{else
|
|
29
|
+
{{else}}
|
|
27
30
|
updateEvent="{{ config.updateEvent }}"
|
|
28
31
|
{{/if}}
|
|
29
32
|
{{#if config.updateFormUiSchema}}
|
|
@@ -33,13 +36,16 @@ hasUserPermission('{{config.permissions.viewRight}}') ? (
|
|
|
33
36
|
{{#if config.deleteEvent~}}
|
|
34
37
|
{{#if config.permissions.updateRight}}
|
|
35
38
|
deleteEvent={hasUserPermission('{{config.permissions.updateRight}}') ? '{{ config.deleteEvent }}' : undefined}
|
|
36
|
-
{{else
|
|
39
|
+
{{else}}
|
|
37
40
|
deleteEvent="{{ config.deleteEvent }}"
|
|
38
41
|
{{/if}}
|
|
39
42
|
{{/if}}
|
|
40
|
-
{{#
|
|
43
|
+
{{#if config.gridOptions}}
|
|
41
44
|
gridOptions={gridOptions}
|
|
42
|
-
{{/
|
|
45
|
+
{{/if}}
|
|
46
|
+
{{#if config.eventing.publishEventName}}
|
|
47
|
+
onSelectionChanged={handleRowSelection}
|
|
48
|
+
{{/if}}
|
|
43
49
|
{{#if config.columns}}
|
|
44
50
|
columns={columnDefs}
|
|
45
51
|
{{/if}}
|
|
@@ -17,6 +17,13 @@ hasUserPermission('{{config.permissions.viewRight}}') ? (
|
|
|
17
17
|
{{#ifAny config.gridOptions config.eventing.publishEventName}}
|
|
18
18
|
deferredGridOptions={gridOptions}
|
|
19
19
|
{{/ifAny}}
|
|
20
|
+
{{#if config.eventing.listener}}
|
|
21
|
+
criteria={datasourceConfig.criteria}
|
|
22
|
+
{{/if}}
|
|
23
|
+
{{#if config.reqrep}}
|
|
24
|
+
requestAutoSetup={datasourceConfig.requestAutoSetup}
|
|
25
|
+
pollingInterval={datasourceConfig.pollingInterval}
|
|
26
|
+
{{/if}}
|
|
20
27
|
/>
|
|
21
28
|
{{#if config.gridOptions}}
|
|
22
29
|
{gridOptionsTile?.columnDefs?.map((columnDef, index) => (
|
|
@@ -1,30 +1,36 @@
|
|
|
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
|
-
|
|
1
|
+
const defaultLayout = {
|
|
2
|
+
global: { tabEnableClose: false },
|
|
3
|
+
layout: {
|
|
4
|
+
type: 'row',
|
|
5
|
+
children: [
|
|
6
|
+
{
|
|
7
|
+
type: 'row',
|
|
8
|
+
weight: 50,
|
|
9
|
+
children: [
|
|
10
|
+
{{#each route.tiles}}
|
|
11
|
+
{{#ifEquals @index 0}}
|
|
12
|
+
{ type: 'tabset', weight: 50, children: [{ type: 'tab', name: '{{this.title}}', component: '{{camelCase this.componentName}}' }] },
|
|
13
|
+
{{/ifEquals}}
|
|
14
|
+
{{#ifEquals @index 2}}
|
|
15
|
+
{ type: 'tabset', weight: 50, children: [{ type: 'tab', name: '{{this.title}}', component: '{{camelCase this.componentName}}' }] },
|
|
16
|
+
{{/ifEquals}}
|
|
17
|
+
{{/each}}
|
|
18
|
+
],
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
type: 'row',
|
|
22
|
+
weight: 50,
|
|
23
|
+
children: [
|
|
24
|
+
{{#each route.tiles}}
|
|
25
|
+
{{#ifEquals @index 1}}
|
|
26
|
+
{ type: 'tabset', weight: 50, children: [{ type: 'tab', name: '{{this.title}}', component: '{{camelCase this.componentName}}' }] },
|
|
27
|
+
{{/ifEquals}}
|
|
28
|
+
{{#ifEquals @index 3}}
|
|
29
|
+
{ type: 'tabset', weight: 50, children: [{ type: 'tab', name: '{{this.title}}', component: '{{camelCase this.componentName}}' }] },
|
|
30
|
+
{{/ifEquals}}
|
|
31
|
+
{{/each}}
|
|
32
|
+
],
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
},
|
|
36
|
+
};
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
{
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
const defaultLayout = {
|
|
2
|
+
global: { tabEnableClose: false },
|
|
3
|
+
layout: {
|
|
4
|
+
type: 'row',
|
|
5
|
+
children: [
|
|
6
|
+
{{#each route.tiles}}
|
|
7
|
+
{ type: 'tabset', children: [{ type: 'tab', name: '{{this.title}}', component: '{{camelCase this.componentName}}' }] },
|
|
8
|
+
{{/each}}
|
|
9
|
+
],
|
|
10
|
+
},
|
|
11
|
+
};
|
|
@@ -1,27 +1,49 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { LayoutComponentNames, layoutComponentsMap } from '../../store/store';
|
|
5
|
-
import { useRef, useEffect } from 'react';
|
|
1
|
+
import React, { useRef } from 'react';
|
|
2
|
+
import { Layout, Model, TabNode } from 'flexlayout-react';
|
|
3
|
+
import { getFlexLayoutStorageKey } from '../../utils/layout';
|
|
6
4
|
{{#each route.tiles}}
|
|
7
5
|
import { {{pascalCase this.componentName}} } from './{{pascalCase this.title}}{{pascalCase this.componentType}}';
|
|
8
6
|
{{/each}}
|
|
7
|
+
import './{{pascalCase route.name}}.css';
|
|
8
|
+
|
|
9
|
+
const STORAGE_KEY = getFlexLayoutStorageKey('{{route.layoutKey}}');
|
|
10
|
+
|
|
11
|
+
{{> (lookup ./route 'layoutType') }}
|
|
12
|
+
|
|
13
|
+
const componentMap: Record<string, React.FC> = {
|
|
14
|
+
{{#each route.tiles}}
|
|
15
|
+
'{{camelCase this.componentName}}': {{pascalCase this.componentName}},
|
|
16
|
+
{{/each}}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
function loadModel(): Model {
|
|
20
|
+
if (STORAGE_KEY) {
|
|
21
|
+
const saved = localStorage.getItem(STORAGE_KEY);
|
|
22
|
+
if (saved) {
|
|
23
|
+
try { return Model.fromJson(JSON.parse(saved)); } catch {}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return Model.fromJson(defaultLayout);
|
|
27
|
+
}
|
|
9
28
|
|
|
10
29
|
const {{pascalCase route.name}} = () => {
|
|
11
|
-
const
|
|
30
|
+
const modelRef = useRef<Model>(loadModel());
|
|
31
|
+
|
|
32
|
+
const factory = (node: TabNode) => {
|
|
33
|
+
const Component = componentMap[node.getComponent() ?? ''];
|
|
34
|
+
return Component ? <Component /> : null;
|
|
35
|
+
};
|
|
12
36
|
|
|
13
|
-
|
|
14
|
-
if (
|
|
15
|
-
|
|
37
|
+
const onModelChange = (model: Model) => {
|
|
38
|
+
if (STORAGE_KEY) {
|
|
39
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(model.toJson()));
|
|
16
40
|
}
|
|
17
|
-
}
|
|
41
|
+
};
|
|
18
42
|
|
|
19
43
|
return (
|
|
20
44
|
<section className="{{kebabCase route.name}}-page">
|
|
21
45
|
{{#if route.tiles}}
|
|
22
|
-
<
|
|
23
|
-
{{> (lookup ./route 'layoutType') }}
|
|
24
|
-
</rapid-layout>
|
|
46
|
+
<Layout model={modelRef.current} factory={factory} onModelChange={onModelChange} />
|
|
25
47
|
{{else}}
|
|
26
48
|
Welcome to {{sentenceCase route.name}}
|
|
27
49
|
{{/if}}
|
|
@@ -1,14 +1,6 @@
|
|
|
1
1
|
import { createStore } from '@genesislcap/foundation-redux';
|
|
2
2
|
import { eventingSlice } from './slices/eventing.slice';
|
|
3
3
|
|
|
4
|
-
export const layoutComponentsMap: Map<string, any> = new Map();
|
|
5
|
-
|
|
6
|
-
export const LayoutComponentNames = {
|
|
7
|
-
{{#each layoutComponents}}
|
|
8
|
-
{{constantCase componentName}}: '{{componentName}}',
|
|
9
|
-
{{/each}}
|
|
10
|
-
} as const;
|
|
11
|
-
|
|
12
4
|
export const { reduxStore, store, actions, selectors } = createStore([eventingSlice], {
|
|
13
5
|
eventing: {
|
|
14
6
|
{{#each events}}
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
{
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
1
|
+
const defaultLayout = {
|
|
2
|
+
global: { tabEnableClose: false },
|
|
3
|
+
layout: {
|
|
4
|
+
type: 'row',
|
|
5
|
+
children: [
|
|
6
|
+
{
|
|
7
|
+
type: 'tabset',
|
|
8
|
+
weight: 100,
|
|
9
|
+
children: [
|
|
10
|
+
{{#each route.tiles}}
|
|
11
|
+
{ type: 'tab', name: '{{this.title}}', component: '{{camelCase this.componentName}}' },
|
|
12
|
+
{{/each}}
|
|
13
|
+
],
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
};
|
|
@@ -44,24 +44,18 @@ const aggregateFromRoutes = (routes = []) => {
|
|
|
44
44
|
mappings: t.config.eventing.listener.mappings || [],
|
|
45
45
|
}));
|
|
46
46
|
|
|
47
|
-
const routeLayoutComponents = (route.tiles || [])
|
|
48
|
-
.map((t) => ({
|
|
49
|
-
componentName: `${route.name}-${t.title.replace(/[^0-9a-z]/gi, '')}-${t.componentType}`,
|
|
50
|
-
}));
|
|
51
|
-
|
|
52
47
|
acc.events = Array.from(new Set(acc.events.concat(routeEvents)));
|
|
53
48
|
acc.listeners = acc.listeners.concat(routeListeners);
|
|
54
|
-
acc.layoutComponents = acc.layoutComponents.concat(routeLayoutComponents);
|
|
55
49
|
return acc;
|
|
56
50
|
},
|
|
57
|
-
{ events: [], listeners: []
|
|
51
|
+
{ events: [], listeners: [] },
|
|
58
52
|
);
|
|
59
53
|
|
|
60
54
|
return aggregation;
|
|
61
55
|
};
|
|
62
56
|
|
|
63
57
|
const generateStore = (routesOrAggregation, { writeFileWithData }, framework) => {
|
|
64
|
-
const { events = [], listeners = []
|
|
58
|
+
const { events = [], listeners = [] } = Array.isArray(routesOrAggregation)
|
|
65
59
|
? aggregateFromRoutes(routesOrAggregation)
|
|
66
60
|
: (routesOrAggregation || {});
|
|
67
61
|
const sourceTemplateDir = `../${DIR_TEMPLATE_BY_FRAMEWORK[framework]}`;
|
|
@@ -79,7 +73,7 @@ const generateStore = (routesOrAggregation, { writeFileWithData }, framework) =>
|
|
|
79
73
|
// Write store.ts
|
|
80
74
|
writeFileWithData(
|
|
81
75
|
storeTarget,
|
|
82
|
-
{ events, listeners
|
|
76
|
+
{ events, listeners },
|
|
83
77
|
resolve(__dirname, storeTemplate),
|
|
84
78
|
);
|
|
85
79
|
|
package/.genx/versions.json
CHANGED
|
@@ -10,7 +10,7 @@ jobs:
|
|
|
10
10
|
runs-on: ubuntu-latest
|
|
11
11
|
steps:
|
|
12
12
|
- name: Slack Notification
|
|
13
|
-
uses:
|
|
13
|
+
uses: youscan/gitactions-slack-notification@3.0.0
|
|
14
14
|
env:
|
|
15
15
|
SLACK_CHANNEL: 'platform-seeds'
|
|
16
16
|
SLACK_INCOMING_WEBHOOK: ${{secrets.SLACK_WEBHOOK}}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,33 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [5.11.0-prerelease.2](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v5.11.0-prerelease.1...v5.11.0-prerelease.2) (2026-04-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* update FUI version [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) 13373e5
|
|
9
|
+
* update FUI version [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) (#562) 9aa31ba
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* update slack notifications [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) 19dd19a
|
|
15
|
+
* update slack notifications [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) (#563) 8f51a0b
|
|
16
|
+
|
|
17
|
+
## [5.11.0-prerelease.1](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v5.10.4-prerelease.1...v5.11.0-prerelease.1) (2026-04-27)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* replace foundation-layout with flex-layout in React [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) (#561) 13a521f
|
|
23
|
+
* replace foundation-layout with flex-layout in React templates [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) 9c13246
|
|
24
|
+
* update FUI version [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) 11096f0
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Bug Fixes
|
|
28
|
+
|
|
29
|
+
* hide close button in layout items [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) 58dd5ec
|
|
30
|
+
|
|
3
31
|
## [5.10.4-prerelease.1](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v5.10.3...v5.10.4-prerelease.1) (2026-04-22)
|
|
4
32
|
|
|
5
33
|
|
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
"test:e2e:debug": "genx test --e2e --debug",
|
|
34
34
|
"test:e2e:ui": "genx test --e2e --interactive"
|
|
35
35
|
},
|
|
36
|
+
"prettier": "@genesislcap/prettier-config",
|
|
36
37
|
"dependencies": {
|
|
37
38
|
"@microsoft/fast-react-wrapper": ">=0.3.25",
|
|
38
39
|
"@ag-grid-community/client-side-row-model": "29.2.0",
|
|
@@ -67,6 +68,7 @@
|
|
|
67
68
|
"@genesislcap/grid-tabulator": "{{versions.UI}}",
|
|
68
69
|
"@genesislcap/web-core": "{{versions.UI}}",
|
|
69
70
|
"@genesislcap/g2plot-chart": "{{versions.UI}}",
|
|
71
|
+
"flexlayout-react": "^0.8.19",
|
|
70
72
|
"change-case": "^4.1.2",
|
|
71
73
|
"tabulator-tables": "6.3.1",
|
|
72
74
|
"history": "^5.3.0",
|
|
@@ -6,9 +6,11 @@ interface ProtectedRouteProps {
|
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
function ProtectedRoute({ children }: ProtectedRouteProps) {
|
|
9
|
+
const location = useLocation();
|
|
10
|
+
|
|
9
11
|
if (!getUser().isAuthenticated) {
|
|
10
|
-
const
|
|
11
|
-
return <Navigate to="/login" state={
|
|
12
|
+
const loginState = { from: location };
|
|
13
|
+
return <Navigate to="/login" state={loginState} replace />;
|
|
12
14
|
}
|
|
13
15
|
|
|
14
16
|
return <>{children}</>;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { RouteLayouts } from './types/RouteLayouts';
|
|
2
|
-
import { environment } from './environments/environment';
|
|
3
2
|
|
|
4
3
|
export const routeLayouts: RouteLayouts = {
|
|
5
4
|
'/login': 'blank',
|
|
@@ -10,7 +9,6 @@ export const AUTH_PATH = 'login';
|
|
|
10
9
|
export const NOT_PERMITTED_PATH = 'not-permitted';
|
|
11
10
|
|
|
12
11
|
export const API_DATA = {
|
|
13
|
-
URL: environment.API_HOST,
|
|
14
12
|
AUTH: {
|
|
15
13
|
username: '', // provide login to a user in given environment
|
|
16
14
|
password: '', // provide password to a user in given environment
|
|
@@ -8,9 +8,6 @@ declare module "react/jsx-runtime" {
|
|
|
8
8
|
'rapid-design-system-provider': CustomElement;
|
|
9
9
|
'client-app-login': CustomElement;
|
|
10
10
|
'rapid-modal': CustomElement;
|
|
11
|
-
'rapid-layout': CustomElement;
|
|
12
|
-
'rapid-layout-region': CustomElement;
|
|
13
|
-
'rapid-layout-item': CustomElement;
|
|
14
11
|
'foundation-header': CustomElement;
|
|
15
12
|
}
|
|
16
13
|
}
|
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import React, { useEffect, useRef } from 'react';
|
|
1
|
+
import React, { useEffect, useRef, useSyncExternalStore } from 'react';
|
|
2
2
|
import { RouteObject, useNavigate, Outlet } from 'react-router-dom';
|
|
3
3
|
import { configureDesignSystem, getNavItems } from '@genesislcap/foundation-ui';
|
|
4
|
-
import {
|
|
5
|
-
baseLayerLuminance,
|
|
6
|
-
StandardLuminance,
|
|
7
|
-
} from '@microsoft/fast-components';
|
|
4
|
+
import { baseLayerLuminance, StandardLuminance } from '@microsoft/fast-components';
|
|
8
5
|
import styles from './DefaultLayout.module.css';
|
|
9
6
|
import PBCElementsRenderer from '../../pbc/elementsRenderer';
|
|
10
7
|
import { registerStylesTarget } from '../../pbc/utils';
|
|
11
8
|
import * as designTokens from '../../styles/design-tokens.json';
|
|
12
9
|
import { useRoutesContext } from '../../store/RoutesContext';
|
|
13
10
|
import { useDocumentTitle } from '../../utils/useDocumentTitle';
|
|
14
|
-
import { AUTH_PATH } from '../../config';
|
|
15
11
|
import { LOGOUT_URL } from '@genesislcap/foundation-utils';
|
|
12
|
+
import { DI } from '@genesislcap/web-core';
|
|
13
|
+
import { Connect } from '@genesislcap/foundation-comms';
|
|
16
14
|
import type { AppTargetId } from '@genesislcap/foundation-shell/app';
|
|
17
15
|
|
|
18
16
|
// Stable target arrays so PBCElementsRenderer effect doesn't re-run on every parent re-render
|
|
@@ -29,16 +27,27 @@ type ExtendedRouteObject = RouteObject & {
|
|
|
29
27
|
navItems?: any;
|
|
30
28
|
};
|
|
31
29
|
path: string;
|
|
32
|
-
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const connect = DI.getOrCreateDOMContainer().get(Connect);
|
|
33
|
+
|
|
34
|
+
const subscribe = (onChange: () => void) => {
|
|
35
|
+
const sub = connect.isConnected$?.subscribe(() => onChange());
|
|
36
|
+
return () => sub?.unsubscribe();
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const getSnapshot = () => connect.isConnected;
|
|
33
40
|
|
|
34
41
|
const DefaultLayout: React.FC<DefaultLayoutProps> = () => {
|
|
35
42
|
const navigate = useNavigate();
|
|
36
43
|
const designSystemProviderRef = useRef<HTMLElement>(null);
|
|
37
44
|
const routes = useRoutesContext() as ExtendedRouteObject[];
|
|
38
|
-
const navItems = getNavItems(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
45
|
+
const navItems = getNavItems(
|
|
46
|
+
routes.flatMap((route) => ({
|
|
47
|
+
path: route.path || '',
|
|
48
|
+
navItems: route.data?.navItems,
|
|
49
|
+
})),
|
|
50
|
+
);
|
|
42
51
|
|
|
43
52
|
useDocumentTitle();
|
|
44
53
|
|
|
@@ -54,6 +63,8 @@ const DefaultLayout: React.FC<DefaultLayoutProps> = () => {
|
|
|
54
63
|
}
|
|
55
64
|
};
|
|
56
65
|
|
|
66
|
+
const connected = useSyncExternalStore(subscribe, getSnapshot);
|
|
67
|
+
|
|
57
68
|
useEffect(() => {
|
|
58
69
|
if (designSystemProviderRef.current) {
|
|
59
70
|
configureDesignSystem(designSystemProviderRef.current, designTokens);
|
|
@@ -61,38 +72,39 @@ const DefaultLayout: React.FC<DefaultLayoutProps> = () => {
|
|
|
61
72
|
registerStylesTarget(document.body, 'header');
|
|
62
73
|
registerStylesTarget(document.body, 'content');
|
|
63
74
|
}
|
|
64
|
-
|
|
65
|
-
return () => {
|
|
66
|
-
};
|
|
67
75
|
}, []);
|
|
68
76
|
|
|
69
77
|
const className = `${styles['default-layout']}`;
|
|
70
78
|
|
|
71
79
|
return (
|
|
72
80
|
<rapid-design-system-provider ref={designSystemProviderRef} class={className}>
|
|
73
|
-
|
|
74
|
-
|
|
81
|
+
{connected && (
|
|
82
|
+
<>
|
|
83
|
+
<PBCElementsRenderer target={TARGET_LAYOUT_START} />
|
|
84
|
+
<foundation-header
|
|
75
85
|
{{#if headerLogoSrc}}
|
|
76
|
-
|
|
86
|
+
logo-src="{{headerLogoSrc}}"
|
|
77
87
|
{{/if}}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
onluminance-icon-clicked={onLuminanceToggle}
|
|
89
|
+
logout={async () => {
|
|
90
|
+
await fetch(LOGOUT_URL);
|
|
91
|
+
window.location.reload();
|
|
92
|
+
}}
|
|
93
|
+
show-luminance-toggle-button
|
|
94
|
+
show-misc-toggle-button
|
|
95
|
+
routeNavItems={navItems}
|
|
96
|
+
navigateTo={(path: string) => navigate(path)}
|
|
97
|
+
>
|
|
98
|
+
<PBCElementsRenderer target={TARGET_HEADER_NAV} />
|
|
99
|
+
</foundation-header>
|
|
100
|
+
</>
|
|
101
|
+
)}
|
|
90
102
|
<section className={styles['content']}>
|
|
91
|
-
<PBCElementsRenderer target={TARGET_CONTENT_START} />
|
|
103
|
+
{connected && <PBCElementsRenderer target={TARGET_CONTENT_START} />}
|
|
92
104
|
<Outlet />
|
|
93
|
-
<PBCElementsRenderer target={TARGET_CONTENT} />
|
|
105
|
+
{connected && <PBCElementsRenderer target={TARGET_CONTENT} />}
|
|
94
106
|
</section>
|
|
95
|
-
<PBCElementsRenderer target={TARGET_LAYOUT_END} />
|
|
107
|
+
{connected && <PBCElementsRenderer target={TARGET_LAYOUT_END} />}
|
|
96
108
|
</rapid-design-system-provider>
|
|
97
109
|
);
|
|
98
110
|
};
|
|
@@ -6,6 +6,8 @@ import { registerPBCs } from './pbc/utils';
|
|
|
6
6
|
import { createLogger } from '@genesislcap/foundation-logger';
|
|
7
7
|
|
|
8
8
|
import './styles/styles.css'
|
|
9
|
+
import 'flexlayout-react/style/dark.css'
|
|
10
|
+
import './styles/flexlayout-theme.css'
|
|
9
11
|
|
|
10
12
|
const logger = createLogger('main');
|
|
11
13
|
|
|
@@ -13,12 +13,17 @@ interface LocationState {
|
|
|
13
13
|
/**
|
|
14
14
|
* Configure the micro frontend
|
|
15
15
|
*/
|
|
16
|
-
export const configureFoundationLogin = ({
|
|
16
|
+
export const configureFoundationLogin = ({
|
|
17
|
+
navigate,
|
|
18
|
+
location,
|
|
19
|
+
}: {
|
|
20
|
+
navigate: NavigateFunction;
|
|
21
|
+
location: RouterLocation<LocationState>;
|
|
22
|
+
}) => {
|
|
17
23
|
const baseElement = document.querySelector('base');
|
|
18
24
|
const basePath = baseElement?.getAttribute('href') || '';
|
|
19
25
|
const connect = DI.getOrCreateDOMContainer().get(Connect);
|
|
20
26
|
|
|
21
|
-
|
|
22
27
|
configure({
|
|
23
28
|
name: 'client-app-login',
|
|
24
29
|
omitRoutes: ['request-account', 'forgot-password'],
|
|
@@ -34,6 +39,5 @@ export const configureFoundationLogin = ({navigate, location}: { navigate: Navig
|
|
|
34
39
|
const from = location.state?.from?.pathname || '/';
|
|
35
40
|
navigate(from, { replace: true });
|
|
36
41
|
},
|
|
37
|
-
})
|
|
38
|
-
}
|
|
39
|
-
|
|
42
|
+
});
|
|
43
|
+
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { foundationLayoutComponents } from '@genesislcap/foundation-layout';
|
|
2
1
|
import { getApp } from '@genesislcap/foundation-shell/app';
|
|
3
2
|
import { g2plotChartsComponents } from '@genesislcap/g2plot-chart';
|
|
4
3
|
import * as rapidDesignSystem from '@genesislcap/rapid-design-system';
|
|
@@ -41,7 +40,6 @@ export async function registerComponents() {
|
|
|
41
40
|
}),
|
|
42
41
|
rapidGridComponents,
|
|
43
42
|
g2plotChartsComponents,
|
|
44
|
-
foundationLayoutComponents,
|
|
45
43
|
);
|
|
46
44
|
|
|
47
45
|
configureHeader({
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/* Genesis design token overrides for flexlayout dark theme */
|
|
2
|
+
.flexlayout__layout {
|
|
3
|
+
--color-text: var(--neutral-foreground-rest, #eeeeee);
|
|
4
|
+
--color-background: var(--neutral-layer-1, #141414);
|
|
5
|
+
|
|
6
|
+
/* Layered grays mapped to Genesis neutral layers */
|
|
7
|
+
--color-1: var(--neutral-layer-4, #1e1e1e);
|
|
8
|
+
--color-2: #252525;
|
|
9
|
+
--color-3: #2d2d2d;
|
|
10
|
+
--color-4: var(--neutral-stroke-rest, #3a3a3a);
|
|
11
|
+
--color-5: #484848;
|
|
12
|
+
--color-6: #555555;
|
|
13
|
+
|
|
14
|
+
/* Drag indicators use accent colour */
|
|
15
|
+
--color-drag1: var(--accent-fill-rest, #00bcd4);
|
|
16
|
+
--color-drag2: var(--accent-fill-rest, #00bcd4);
|
|
17
|
+
--color-drag1-background: rgba(0, 188, 212, 0.12);
|
|
18
|
+
--color-drag2-background: rgba(0, 188, 212, 0.08);
|
|
19
|
+
|
|
20
|
+
--font-size: 13px;
|
|
21
|
+
|
|
22
|
+
/* Tab bar / tabset */
|
|
23
|
+
--color-tabset-background: var(--neutral-layer-1, #141414);
|
|
24
|
+
--color-tabset-background-selected: var(--neutral-layer-1, #141414);
|
|
25
|
+
--color-tabset-background-maximized: var(--neutral-layer-4, #1e1e1e);
|
|
26
|
+
--color-tabset-divider-line: var(--neutral-stroke-rest, #3a3a3a);
|
|
27
|
+
--color-tabset-header-background: var(--neutral-layer-4, #1e1e1e);
|
|
28
|
+
--color-tabset-header: var(--neutral-foreground-rest, #eeeeee);
|
|
29
|
+
|
|
30
|
+
/* Active / inactive tabs */
|
|
31
|
+
--color-tab-content: var(--neutral-layer-1, #141414);
|
|
32
|
+
--color-tab-selected: var(--neutral-foreground-rest, #ffffff);
|
|
33
|
+
--color-tab-selected-background: var(--neutral-layer-1, #141414);
|
|
34
|
+
--color-tab-unselected: var(--neutral-foreground-rest, #a0a0a0);
|
|
35
|
+
--color-tab-unselected-background: transparent;
|
|
36
|
+
|
|
37
|
+
/* Splitters */
|
|
38
|
+
--color-splitter: var(--neutral-stroke-rest, #3a3a3a);
|
|
39
|
+
--color-splitter-hover: var(--accent-fill-rest, #00bcd4);
|
|
40
|
+
--color-splitter-drag: var(--accent-fill-rest, #00bcd4);
|
|
41
|
+
|
|
42
|
+
/* Drag-drop rectangle */
|
|
43
|
+
--color-drag-rect-border: var(--accent-fill-rest, rgba(0, 188, 212, 0.6));
|
|
44
|
+
--color-drag-rect-background: rgba(0, 0, 0, 0.45);
|
|
45
|
+
--color-drag-rect: var(--neutral-foreground-rest, #eeeeee);
|
|
46
|
+
|
|
47
|
+
/* Overflow / icon */
|
|
48
|
+
--color-overflow: var(--neutral-foreground-rest, #a0a0a0);
|
|
49
|
+
--color-icon: var(--neutral-foreground-rest, #a0a0a0);
|
|
50
|
+
|
|
51
|
+
/* Popup menu */
|
|
52
|
+
--color-popup-border: var(--neutral-stroke-rest, #3a3a3a);
|
|
53
|
+
--color-popup-unselected: var(--neutral-foreground-rest, #eeeeee);
|
|
54
|
+
--color-popup-unselected-background: var(--neutral-layer-4, #1e1e1e);
|
|
55
|
+
--color-popup-selected: var(--neutral-foreground-rest, #ffffff);
|
|
56
|
+
--color-popup-selected-background: var(--neutral-stroke-rest, #3a3a3a);
|
|
57
|
+
|
|
58
|
+
--color-toolbar-button-hover: var(--neutral-fill-stealth-active, rgba(255, 255, 255, 0.08));
|
|
59
|
+
|
|
60
|
+
--color-edge-marker: var(--accent-fill-rest, #00bcd4);
|
|
61
|
+
--color-edge-icon: var(--neutral-foreground-rest, #eeeeee);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/* Remove dark theme gradients — use flat Genesis layer colours */
|
|
65
|
+
.flexlayout__tabset-selected {
|
|
66
|
+
background-image: none !important;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.flexlayout__tabset-maximized {
|
|
70
|
+
background-image: none !important;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/* Active tab: accent underline matching Genesis style */
|
|
74
|
+
.flexlayout__tab_button--selected {
|
|
75
|
+
position: relative;
|
|
76
|
+
color: var(--neutral-foreground-rest, #ffffff) !important;
|
|
77
|
+
background-color: var(--neutral-layer-1, #141414) !important;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.flexlayout__tab_button--selected::after {
|
|
81
|
+
content: "";
|
|
82
|
+
position: absolute;
|
|
83
|
+
bottom: 0;
|
|
84
|
+
left: 0;
|
|
85
|
+
width: 100%;
|
|
86
|
+
height: 2px;
|
|
87
|
+
background-color: var(--accent-fill-rest, #00bcd4);
|
|
88
|
+
z-index: 10;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/* Inactive tab hover */
|
|
92
|
+
.flexlayout__tab_button--unselected:hover {
|
|
93
|
+
color: var(--neutral-foreground-rest, #e0e0e0) !important;
|
|
94
|
+
background-color: var(--neutral-fill-stealth-active, rgba(255, 255, 255, 0.06)) !important;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/* Remove border-radius from dark theme tab overrides */
|
|
98
|
+
.flexlayout__tab_top,
|
|
99
|
+
.flexlayout__tab_bottom {
|
|
100
|
+
border-radius: 0 !important;
|
|
101
|
+
box-shadow: none !important;
|
|
102
|
+
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
import { isDev } from '@genesislcap/foundation-utils';
|
|
2
2
|
import pkg from '../../package.json';
|
|
3
3
|
|
|
4
|
-
//
|
|
5
|
-
|
|
6
|
-
export const persistLayout = (id: string) => {
|
|
4
|
+
// Returns null to disable persistence in dev unless PERSIST_LAYOUT_IN_DEV=true
|
|
5
|
+
export const getFlexLayoutStorageKey = (id: string): string | null => {
|
|
7
6
|
if (isDev() && (pkg as any)?.config.PERSIST_LAYOUT_IN_DEV !== true) {
|
|
8
7
|
return null;
|
|
9
8
|
}
|
|
10
|
-
return id
|
|
9
|
+
return `flexlayout_${id}`;
|
|
11
10
|
};
|
package/package.json
CHANGED
package/.genx/.prettierrc
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
const ERROR_PREFIX = 'Golden layout helper - ';
|
|
2
|
-
|
|
3
|
-
export const setComponentItemsMap = (
|
|
4
|
-
layoutNativeElement: any,
|
|
5
|
-
componentMapInstance: Map<string, any>,
|
|
6
|
-
): (() => void) => {
|
|
7
|
-
if (!layoutNativeElement || !layoutNativeElement.layout) {
|
|
8
|
-
throw new Error(`${ERROR_PREFIX} - layout is not defined`);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
const componentSetter = ({ _target: componentItem }: any) => {
|
|
12
|
-
componentMapInstance.set(componentItem.componentName, componentItem);
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
layoutNativeElement.layout.on('componentCreated', componentSetter);
|
|
16
|
-
|
|
17
|
-
return () => layoutNativeElement.layout.off('componentCreated', componentSetter);
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
const getElementRoot = (componentInstance: any): any => {
|
|
21
|
-
if (componentInstance) {
|
|
22
|
-
const { _element } = componentInstance;
|
|
23
|
-
return _element;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
throw new Error(`${ERROR_PREFIX} - component instance is not defined`);
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
export const getElementsBySelectorFromComponent = (
|
|
30
|
-
componentInstance: any,
|
|
31
|
-
selectorValue: string,
|
|
32
|
-
): any => {
|
|
33
|
-
const element = getElementRoot(componentInstance);
|
|
34
|
-
return element.querySelectorAll(`[data-selector=${selectorValue}]`);
|
|
35
|
-
};
|
|
36
|
-
|
|
37
|
-
export const getElementBySelectorFromComponent = (
|
|
38
|
-
componentInstance: any,
|
|
39
|
-
selector: string,
|
|
40
|
-
): any => {
|
|
41
|
-
return getElementsBySelectorFromComponent(componentInstance, selector)[0];
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export const getElementsByTagFromComponent = (
|
|
45
|
-
componentInstance: any,
|
|
46
|
-
tag: string,
|
|
47
|
-
): any => {
|
|
48
|
-
const element = getElementRoot(componentInstance);
|
|
49
|
-
return element.getElementsByTagName(tag);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
export const getElementByTagFromComponent = (
|
|
53
|
-
componentInstance: any,
|
|
54
|
-
tag: string,
|
|
55
|
-
): any => {
|
|
56
|
-
return getElementsByTagFromComponent(componentInstance, tag)[0];
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
|