@genesislcap/blank-app-seed 5.11.0 → 5.12.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.
@@ -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.11.0",
4
+ "version": "5.12.0-prerelease.2",
5
5
  "license": "Apache-2.0",
6
6
  "scripts": {
7
7
  "lint": "eslint .",
@@ -1,7 +1,12 @@
1
1
  {{#if tile.config.columns~}}
2
2
  import { ColDef } from '@ag-grid-community/core';
3
3
  {{/if}}
4
- import { getNumberFormatter, getDateFormatter } from '@genesislcap/foundation-utils';
4
+ {{#if tile.config.hasNumberFormatter~}}
5
+ import { getNumberFormatter } from '@genesislcap/foundation-utils';
6
+ {{/if}}
7
+ {{#if tile.config.hasDateFormatter~}}
8
+ import { getDateFormatter } from '@genesislcap/foundation-utils';
9
+ {{/if}}
5
10
  {{#if route.FDC3EventHandlersEnabled~}}
6
11
  import { sendEventOnChannel } from '../../../utils';
7
12
  {{/if}}
@@ -1,7 +1,12 @@
1
1
  {{#if tile.config.gridOptions~}}
2
2
  import { GridOptionsConfig } from '@genesislcap/rapid-grid-pro';
3
3
  {{/if}}
4
- import { getNumberFormatter, getDateFormatter } from '@genesislcap/foundation-utils';
4
+ {{#if tile.config.hasNumberFormatter~}}
5
+ import { getNumberFormatter } from '@genesislcap/foundation-utils';
6
+ {{/if}}
7
+ {{#if tile.config.hasDateFormatter~}}
8
+ import { getDateFormatter } from '@genesislcap/foundation-utils';
9
+ {{/if}}
5
10
  {{#if route.FDC3EventHandlersEnabled~}}
6
11
  import { sendEventOnChannel } from '../../../utils';
7
12
  {{/if}}
@@ -1,6 +1,7 @@
1
1
  import React, { useRef } from 'react';
2
2
  import { Layout, Model, TabNode } from 'flexlayout-react';
3
3
  import { getFlexLayoutStorageKey } from '../../utils/layout';
4
+ import { TileErrorBoundary } from '../../components/error-boundary/ErrorBoundary';
4
5
  {{#each route.tiles}}
5
6
  import { {{pascalCase this.componentName}} } from './{{pascalCase this.title}}{{pascalCase this.componentType}}';
6
7
  {{/each}}
@@ -31,7 +32,14 @@ const {{pascalCase route.name}} = () => {
31
32
 
32
33
  const factory = (node: TabNode) => {
33
34
  const Component = componentMap[node.getComponent() ?? ''];
34
- return Component ? <Component /> : null;
35
+ return Component ? (
36
+ <TileErrorBoundary
37
+ title={node.getName() ?? node.getComponent() ?? ''}
38
+ tileRegistration={node.getComponent() ?? ''}
39
+ >
40
+ <Component />
41
+ </TileErrorBoundary>
42
+ ) : null;
35
43
  };
36
44
 
37
45
  const onModelChange = (model: Model) => {
@@ -1,4 +1,6 @@
1
+ {{#if listeners.length}}
1
2
  import { CriteriaBuilder, ExpressionBuilder, Serialisers } from '@genesislcap/foundation-criteria';
3
+ {{/if}}
2
4
  import { createSlice } from '@genesislcap/foundation-redux';
3
5
 
4
6
  export const eventingSlice = createSlice({
@@ -47,6 +47,11 @@ const formatRouteData = (framework, route) => {
47
47
  eventing,
48
48
  } = config;
49
49
 
50
+ const hasFormatter = (name, colsOrOpts) => {
51
+ const cols = Array.isArray(colsOrOpts) ? colsOrOpts : colsOrOpts?.columns;
52
+ return cols?.some((col) => col.valueFormatter?.name === name);
53
+ };
54
+
50
55
  return {
51
56
  ...tile,
52
57
  componentName,
@@ -61,6 +66,12 @@ const formatRouteData = (framework, route) => {
61
66
  filterFormUiSchema: formatJSONValue(filterFormUiSchema),
62
67
  uischema: formatJSONValue(uischema),
63
68
  columns: gridColumnsSerializer(columns),
69
+ hasNumberFormatter:
70
+ hasFormatter('getNumberFormatter', columns) ||
71
+ hasFormatter('getNumberFormatter', gridOptions),
72
+ hasDateFormatter:
73
+ hasFormatter('getDateFormatter', columns) ||
74
+ hasFormatter('getDateFormatter', gridOptions),
64
75
  customEvents: formatCustomEvents(customEvents),
65
76
  eventing: {
66
77
  publishEventName: eventing?.publishEventName || null,
@@ -1,5 +1,5 @@
1
1
  {
2
- "UI": "14.426.0",
3
- "GSF": "8.15.12",
4
- "Auth": "8.15.2"
2
+ "UI": "14.430.1",
3
+ "GSF": "8.15.14",
4
+ "Auth": "8.15.3"
5
5
  }
package/CHANGELOG.md CHANGED
@@ -1,28 +1,33 @@
1
1
  # Changelog
2
2
 
3
- ## [5.11.0](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v5.10.3...v5.11.0) (2026-04-29)
3
+ ## [5.12.0-prerelease.2](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v5.12.0-prerelease.1...v5.12.0-prerelease.2) (2026-05-08)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **react:** resolve TypeScript errors in generated React app templates [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) ab0903c
9
+ * resolve TypeScript errors in generated React app templates [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) (#570) 5e3a583
10
+
11
+ ## [5.12.0-prerelease.1](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v5.11.0...v5.12.0-prerelease.1) (2026-05-05)
4
12
 
5
13
 
6
14
  ### Features
7
15
 
8
- * flexlayout + react wrappers + GSF/FUI update [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) (#566) ed36d1f
9
- * replace foundation-layout with flex-layout in React [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) (#561) 13a521f
10
- * replace foundation-layout with flex-layout in React templates [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) 9c13246
11
- * update FUI version [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) 13373e5
12
- * update FUI version [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) 11096f0
13
- * update FUI version [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) (#562) 9aa31ba
16
+ * add default error boundary for components [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) 0353f8d
17
+ * add default error boundary for React generated apps (#567) fd39752
14
18
 
15
19
 
16
20
  ### Bug Fixes
17
21
 
18
- * backport main [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) (#560) f956a18
19
- * FUI update [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) 8a984be
20
- * GSF update [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) 4ffdbe6
21
- * hide close button in layout items [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) 58dd5ec
22
- * update GSF versions [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) c771f3f
23
- * update GSF versions [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) (#564) def3ad3
24
- * update slack notifications [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) 19dd19a
25
- * update slack notifications [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) (#563) 8f51a0b
22
+ * backport main [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) (#568) 2ef601d
23
+
24
+ ## [5.11.0-prerelease.4](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v5.11.0-prerelease.3...v5.11.0-prerelease.4) (2026-05-04)
25
+
26
+
27
+ ### Features
28
+
29
+ * add default error boundary for components [FUI-0](https://github.com/genesiscommunitysuccess/blank-app-seed/issues/0) 0353f8d
30
+ * add default error boundary for React generated apps (#567) fd39752
26
31
 
27
32
  ## [5.11.0-prerelease.3](https://github.com/genesiscommunitysuccess/blank-app-seed/compare/v5.11.0-prerelease.2...v5.11.0-prerelease.3) (2026-04-29)
28
33
 
@@ -1,12 +1,11 @@
1
1
  import { useCallback, useEffect, useState } from 'react';
2
2
  import { BrowserRouter as Router } from 'react-router-dom';
3
+ {{#if FDC3.channels.length~}}
3
4
  import {
4
- setApiHost,
5
- {{#if FDC3.channels.length~}}
6
5
  listenToChannel,
7
6
  onFDC3Ready,
8
- {{/if}}
9
7
  } from './utils';
8
+ {{/if}}
10
9
  import { customEventFactory, registerStylesTarget } from './pbc/utils';
11
10
  import { RoutesProvider } from './store/RoutesContext';
12
11
  import { registerComponents as genesisRegisterComponents } from './share/genesis-components';
@@ -41,7 +40,6 @@ const App: React.FC<AppProps> = ({ rootElement }) => {
41
40
  }, []);
42
41
  useEffect(() => {
43
42
  let mounted = true;
44
- setApiHost();
45
43
  (async () => {
46
44
  await genesisRegisterComponents();
47
45
  if (mounted) {
@@ -0,0 +1,250 @@
1
+ import React, { useState } from 'react';
2
+ import { errorBoundaryStyles } from './ErrorBoundaryStyles';
3
+
4
+ type ErrorBoundaryScope = 'application' | 'tile';
5
+
6
+ type ErrorBoundaryFallbackProps = {
7
+ scope: ErrorBoundaryScope;
8
+ referenceId: string;
9
+ title: string;
10
+ subtitle: string;
11
+ details: string;
12
+ onRetry: () => void;
13
+ };
14
+
15
+ type BaseErrorBoundaryProps = {
16
+ scope: ErrorBoundaryScope;
17
+ title: string;
18
+ tileRegistration?: string;
19
+ children: React.ReactNode;
20
+ };
21
+
22
+ type BaseErrorBoundaryState = {
23
+ hasError: boolean;
24
+ error: Error | null;
25
+ componentStack: string;
26
+ capturedAt: string;
27
+ referenceId: string;
28
+ };
29
+
30
+ const initialBoundaryState: BaseErrorBoundaryState = {
31
+ hasError: false,
32
+ error: null,
33
+ componentStack: '',
34
+ capturedAt: '',
35
+ referenceId: '',
36
+ };
37
+
38
+ const toError = (value: unknown): Error => {
39
+ if (value instanceof Error) {
40
+ return value;
41
+ }
42
+
43
+ if (typeof value === 'string') {
44
+ return new Error(value);
45
+ }
46
+
47
+ try {
48
+ return new Error(JSON.stringify(value));
49
+ } catch {
50
+ return new Error('Unknown non-serializable error');
51
+ }
52
+ };
53
+
54
+ const createReferenceId = (): string => {
55
+ const timestamp = new Date().toISOString().split(':').join('-');
56
+ const random = Math.random().toString(36).slice(2, 8).toUpperCase();
57
+ return `APP-${timestamp}-${random}`;
58
+ };
59
+
60
+ const ErrorBoundaryFallback: React.FC<ErrorBoundaryFallbackProps> = ({
61
+ scope,
62
+ referenceId,
63
+ title,
64
+ subtitle,
65
+ details,
66
+ onRetry,
67
+ }) => {
68
+ const [copied, setCopied] = useState(false);
69
+ const [copyHelpVisible, setCopyHelpVisible] = useState(false);
70
+
71
+ const handleCopy = async () => {
72
+ try {
73
+ await navigator.clipboard.writeText(details);
74
+ setCopied(true);
75
+ setCopyHelpVisible(false);
76
+ window.setTimeout(() => {
77
+ setCopied(false);
78
+ }, 2_000);
79
+ } catch {
80
+ setCopyHelpVisible(true);
81
+ }
82
+ };
83
+
84
+ return (
85
+ <section className="error-boundary" role="alert">
86
+ <style>{errorBoundaryStyles}</style>
87
+ <div className="error-boundary__top">
88
+ <span className="error-boundary__status">
89
+ {scope === 'application' ? 'Application incident' : 'Tile incident'}
90
+ </span>
91
+ <span className="error-boundary__reference">Ref: {referenceId}</span>
92
+ </div>
93
+ <h2 className="error-boundary__title">{title}</h2>
94
+ <p className="error-boundary__subtitle">{subtitle}</p>
95
+ <p className="error-boundary__hint">
96
+ Tip: copy diagnostics and paste directly into Cursor to speed up debugging.
97
+ </p>
98
+ <textarea
99
+ className="error-boundary__details"
100
+ readOnly
101
+ value={details}
102
+ aria-label="Error diagnostics details"
103
+ />
104
+ <div className="error-boundary__actions">
105
+ <button type="button" className="error-boundary__button" onClick={onRetry}>
106
+ Retry
107
+ </button>
108
+ <button
109
+ type="button"
110
+ className="error-boundary__button error-boundary__button--secondary"
111
+ onClick={handleCopy}
112
+ >
113
+ {copied ? 'Copied' : 'Copy diagnostics'}
114
+ </button>
115
+ </div>
116
+ {copyHelpVisible ? (
117
+ <p className="error-boundary__manual-copy-help">
118
+ Clipboard access is blocked in this browser context. Please select the diagnostics text
119
+ and copy it manually.
120
+ </p>
121
+ ) : null}
122
+ </section>
123
+ );
124
+ };
125
+
126
+ class BaseErrorBoundary extends React.Component<BaseErrorBoundaryProps, BaseErrorBoundaryState> {
127
+ public constructor(props: BaseErrorBoundaryProps) {
128
+ super(props);
129
+ this.state = initialBoundaryState;
130
+ }
131
+
132
+ public static getDerivedStateFromError(error: unknown): Partial<BaseErrorBoundaryState> {
133
+ const normalized = toError(error);
134
+ return {
135
+ hasError: true,
136
+ error: normalized,
137
+ capturedAt: new Date().toISOString(),
138
+ referenceId: createReferenceId(),
139
+ };
140
+ }
141
+
142
+ public componentDidCatch(error: unknown, errorInfo: React.ErrorInfo): void {
143
+ const normalized = toError(error);
144
+ this.setState({
145
+ componentStack: errorInfo.componentStack ?? '',
146
+ });
147
+
148
+ console.error(`[${this.props.scope}] error boundary captured an error`, {
149
+ referenceId: this.state.referenceId,
150
+ title: this.props.title,
151
+ tileRegistration: this.props.tileRegistration,
152
+ error: normalized,
153
+ componentStack: errorInfo.componentStack,
154
+ });
155
+ }
156
+
157
+ private readonly handleRetry = (): void => {
158
+ this.setState(initialBoundaryState);
159
+ };
160
+
161
+ public render(): React.ReactNode {
162
+ if (!this.state.hasError || !this.state.error) {
163
+ return this.props.children;
164
+ }
165
+
166
+ const { scope, title, tileRegistration } = this.props;
167
+ const diagnostics = [
168
+ `Reference: ${this.state.referenceId}`,
169
+ `Scope: ${scope}`,
170
+ `Title: ${title}`,
171
+ `Tile registration: ${tileRegistration ?? 'N/A'}`,
172
+ `Captured at: ${this.state.capturedAt}`,
173
+ `URL: ${window.location.href}`,
174
+ `User agent: ${window.navigator.userAgent}`,
175
+ `Error name: ${this.state.error.name}`,
176
+ `Error message: ${this.state.error.message}`,
177
+ 'Error stack:',
178
+ this.state.error.stack ?? 'No stack available',
179
+ 'Component stack:',
180
+ this.state.componentStack || 'No component stack available',
181
+ ].join('\n');
182
+
183
+ const fallbackTitle =
184
+ scope === 'application'
185
+ ? 'Something went wrong'
186
+ : `Something went wrong in "${title}"`;
187
+ const fallbackSubtitle =
188
+ scope === 'application'
189
+ ? 'The app hit an unexpected error. You can retry or copy diagnostics for a fast fix.'
190
+ : 'This tile crashed, but the rest of the application keeps running. Retry or copy diagnostics.';
191
+
192
+ return (
193
+ <ErrorBoundaryFallback
194
+ scope={scope}
195
+ referenceId={this.state.referenceId}
196
+ title={fallbackTitle}
197
+ subtitle={fallbackSubtitle}
198
+ details={diagnostics}
199
+ onRetry={this.handleRetry}
200
+ />
201
+ );
202
+ }
203
+ }
204
+
205
+ type AppErrorBoundaryProps = {
206
+ children: React.ReactNode;
207
+ };
208
+
209
+ export const AppErrorBoundary: React.FC<AppErrorBoundaryProps> = ({ children }) => {
210
+ return (
211
+ <BaseErrorBoundary scope="application" title="Application">
212
+ {children}
213
+ </BaseErrorBoundary>
214
+ );
215
+ };
216
+
217
+ type TileErrorBoundaryProps = {
218
+ title: string;
219
+ tileRegistration: string;
220
+ children: React.ReactNode;
221
+ };
222
+
223
+ export const TileErrorBoundary: React.FC<TileErrorBoundaryProps> = ({
224
+ title,
225
+ tileRegistration,
226
+ children,
227
+ }) => {
228
+ return (
229
+ <BaseErrorBoundary scope="tile" title={title} tileRegistration={tileRegistration}>
230
+ {children}
231
+ </BaseErrorBoundary>
232
+ );
233
+ };
234
+
235
+ export const withTileErrorBoundary = (
236
+ Component: React.ComponentType,
237
+ title: string,
238
+ tileRegistration: string,
239
+ ): React.FC => {
240
+ const WrappedWithErrorBoundary: React.FC = () => {
241
+ return (
242
+ <TileErrorBoundary title={title} tileRegistration={tileRegistration}>
243
+ <Component />
244
+ </TileErrorBoundary>
245
+ );
246
+ };
247
+
248
+ WrappedWithErrorBoundary.displayName = `WithTileErrorBoundary(${title}:${tileRegistration}:${Component.displayName || Component.name || 'TileComponent'})`;
249
+ return WrappedWithErrorBoundary;
250
+ };
@@ -0,0 +1,161 @@
1
+ export const errorBoundaryStyles = `
2
+ .error-boundary,
3
+ .error-boundary__tile-wrap {
4
+ width: 100%;
5
+ height: 100%;
6
+ }
7
+
8
+ .error-boundary {
9
+ --eb-bg: #f6f8fb;
10
+ --eb-surface: #ffffff;
11
+ --eb-text: #18212f;
12
+ --eb-text-muted: #5f6f84;
13
+ --eb-border: #d3dae6;
14
+ --eb-accent: #2f6fed;
15
+ --eb-accent-hover: #255dcc;
16
+ --eb-accent-foreground: #ffffff;
17
+ --eb-error: #c53d3d;
18
+ --eb-focus: #2f6fed;
19
+ --eb-font: 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
20
+
21
+ box-sizing: border-box;
22
+ display: flex;
23
+ flex-direction: column;
24
+ gap: 12px;
25
+ align-items: flex-start;
26
+ padding: 16px;
27
+ background: var(--eb-bg);
28
+ color: var(--eb-text);
29
+ }
30
+
31
+ .error-boundary__top,
32
+ .error-boundary__title,
33
+ .error-boundary__subtitle,
34
+ .error-boundary__hint,
35
+ .error-boundary__details,
36
+ .error-boundary__actions,
37
+ .error-boundary__manual-copy-help {
38
+ width: 100%;
39
+ }
40
+
41
+ .error-boundary__top {
42
+ display: flex;
43
+ width: 100%;
44
+ align-items: center;
45
+ justify-content: space-between;
46
+ gap: 10px;
47
+ flex-wrap: wrap;
48
+ }
49
+
50
+ .error-boundary__status {
51
+ display: inline-flex;
52
+ align-items: center;
53
+ border: 1px solid var(--eb-error);
54
+ border-radius: 999px;
55
+ padding: 5px 10px;
56
+ font-family: var(--eb-font);
57
+ text-transform: uppercase;
58
+ letter-spacing: 0.13em;
59
+ font-size: 11px;
60
+ font-weight: 700;
61
+ color: var(--eb-error);
62
+ background: #fff4f4;
63
+ }
64
+
65
+ .error-boundary__reference {
66
+ font-family: 'Menlo', 'Consolas', 'Liberation Mono', monospace;
67
+ font-size: 11px;
68
+ letter-spacing: 0.08em;
69
+ color: var(--eb-text-muted);
70
+ text-transform: uppercase;
71
+ }
72
+
73
+ .error-boundary__title {
74
+ margin: 0;
75
+ font-family: var(--eb-font);
76
+ font-size: clamp(22px, 3vw, 30px);
77
+ line-height: 1.15;
78
+ font-weight: 700;
79
+ color: var(--eb-text);
80
+ text-wrap: balance;
81
+ }
82
+
83
+ .error-boundary__subtitle {
84
+ margin: 0;
85
+ max-width: 80ch;
86
+ font-family: var(--eb-font);
87
+ color: var(--eb-text);
88
+ line-height: 1.45;
89
+ }
90
+
91
+ .error-boundary__hint {
92
+ margin: -2px 0 2px;
93
+ font-family: var(--eb-font);
94
+ color: var(--eb-text-muted);
95
+ font-size: 13px;
96
+ }
97
+
98
+ .error-boundary__details {
99
+ box-sizing: border-box;
100
+ width: 100%;
101
+ min-height: 190px;
102
+ max-height: 360px;
103
+ padding: 12px;
104
+ border: 1px solid var(--eb-border);
105
+ border-radius: 10px;
106
+ background: var(--eb-surface);
107
+ color: var(--eb-text);
108
+ font-family: 'Menlo', 'Consolas', 'Liberation Mono', 'Courier New', monospace;
109
+ font-size: 12px;
110
+ line-height: 1.5;
111
+ resize: vertical;
112
+ }
113
+
114
+ .error-boundary__actions {
115
+ display: flex;
116
+ gap: 10px;
117
+ flex-wrap: wrap;
118
+ }
119
+
120
+ .error-boundary__button {
121
+ border: 1px solid var(--eb-accent);
122
+ border-radius: 999px;
123
+ background: var(--eb-accent);
124
+ color: var(--eb-accent-foreground);
125
+ cursor: pointer;
126
+ padding: 9px 16px;
127
+ font-family: var(--eb-font);
128
+ font-size: 12px;
129
+ font-weight: 700;
130
+ letter-spacing: 0.04em;
131
+ text-transform: uppercase;
132
+ transition: transform 180ms ease, background-color 180ms ease;
133
+ }
134
+
135
+ .error-boundary__button--secondary {
136
+ border-color: var(--eb-border);
137
+ background: var(--eb-surface);
138
+ color: var(--eb-text);
139
+ }
140
+
141
+ .error-boundary__button:hover {
142
+ background: var(--eb-accent-hover);
143
+ transform: translateY(-1px);
144
+ }
145
+
146
+ .error-boundary__button--secondary:hover {
147
+ background: #eef2f8;
148
+ }
149
+
150
+ .error-boundary__button:focus-visible {
151
+ outline: 2px solid var(--eb-focus);
152
+ outline-offset: 2px;
153
+ }
154
+
155
+ .error-boundary__manual-copy-help {
156
+ margin: 2px 0 0;
157
+ font-size: 13px;
158
+ color: var(--eb-text-muted);
159
+ line-height: 1.4;
160
+ }
161
+ `;
@@ -1,6 +1,8 @@
1
1
  import { Routes, Route, Navigate } from 'react-router-dom';
2
2
  import AuthPage from '../../pages/AuthPage/AuthPage';
3
+ {{#if routes.[0]}}
3
4
  import {{pascalCase routes.[0].name}} from '../../pages/{{pascalCase routes.[0].name}}/{{pascalCase routes.[0].name}}';
5
+ {{/if}}
4
6
  import DefaultLayout from '../../layouts/default/DefaultLayout';
5
7
  import ProtectedRoute from './ProtectedRoute';
6
8
  import { useRoutesContext } from '../../store/RoutesContext';
@@ -1,6 +1,7 @@
1
1
  import React from 'react'
2
2
  import ReactDOM from 'react-dom/client'
3
3
  import App from './App.tsx'
4
+ import { AppErrorBoundary } from './components/error-boundary/ErrorBoundary'
4
5
 
5
6
  import { registerPBCs } from './pbc/utils';
6
7
  import { createLogger } from '@genesislcap/foundation-logger';
@@ -16,7 +17,9 @@ function bootstrapApp() {
16
17
  if (rootEelement) {
17
18
  ReactDOM.createRoot(rootEelement!).render(
18
19
  <React.StrictMode>
19
- <App rootElement={rootEelement} />
20
+ <AppErrorBoundary>
21
+ <App rootElement={rootEelement} />
22
+ </AppErrorBoundary>
20
23
  </React.StrictMode>,
21
24
  )
22
25
  }
@@ -1,5 +1,6 @@
1
1
  import React, { createContext, useContext, ReactNode } from 'react';
2
- import { RouteObject, Navigate } from 'react-router-dom';
2
+ import { Navigate } from 'react-router-dom';
3
+ import type { AppRoute } from '../types/AppRoute';
3
4
  import { getApp } from '@genesislcap/foundation-shell/app';
4
5
  import AuthPage from '../pages/AuthPage/AuthPage';
5
6
  import NotFoundPage from '../pages/NotFoundPage/NotFoundPage';
@@ -49,7 +50,7 @@ const routes = [
49
50
  {{/each}}
50
51
  ];
51
52
 
52
- const RoutesContext = createContext<RouteObject[]>([]);
53
+ const RoutesContext = createContext<AppRoute[]>([]);
53
54
 
54
55
  export const RoutesProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
55
56
  const pbcRoutes = getApp().routes.map((route) => ({
@@ -0,0 +1,15 @@
1
+ import type { AppRoute as FoundationAppRoute } from '@genesislcap/foundation-shell/app';
2
+ import type { ReactNode } from 'react';
3
+
4
+ export interface AppRoute {
5
+ path?: string;
6
+ element?: ReactNode;
7
+ children?: AppRoute[];
8
+ data?: {
9
+ permissionCode?: string;
10
+ navItems?: unknown[];
11
+ pbcElement?: FoundationAppRoute['element'];
12
+ pbcElementTag?: unknown;
13
+ [key: string]: unknown;
14
+ };
15
+ }
@@ -2,4 +2,3 @@ export * from './fdc3';
2
2
  export * from './getLayoutNameByRoute';
3
3
  export * from './layout';
4
4
  export * from './permissions';
5
- export * from './setApiHost';
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": "5.11.0",
4
+ "version": "5.12.0-prerelease.2",
5
5
  "license": "Apache-2.0",
6
6
  "scripts": {
7
7
  "release": "semantic-release"
@@ -1,26 +0,0 @@
1
- import { DI } from '@microsoft/fast-foundation';
2
- import { Connect } from '@genesislcap/foundation-comms';
3
- import { API_DATA } from '../config';
4
-
5
- class ConnectService {
6
- private container = DI.getOrCreateDOMContainer();
7
- private connect: Connect = this.container.get(Connect);
8
-
9
- getContainer() {
10
- return this.container;
11
- }
12
-
13
- getConnect() {
14
- return this.connect;
15
- }
16
-
17
- isConnected() {
18
- return this.connect.isConnected;
19
- }
20
-
21
- init() {
22
- return this.connect.connect(API_DATA.URL);
23
- }
24
- }
25
-
26
- export const connectService = new ConnectService();
@@ -1,9 +0,0 @@
1
- import { API_DATA } from '../config';
2
-
3
- export const setApiHost = () => {
4
- const { URL: apiHost } = API_DATA;
5
-
6
- if (apiHost) {
7
- sessionStorage.setItem('hostUrl', apiHost);
8
- }
9
- };