@carbonorm/carbonreact 3.4.7 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +225 -8
- package/dist/CarbonReact.d.ts +8 -3
- package/dist/components/WebSocket/CarbonWebSocket.d.ts +3 -2
- package/dist/index.cjs.js +66 -19
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +67 -20
- package/dist/index.esm.js.map +1 -1
- package/package.json +6 -5
- package/src/CarbonReact.tsx +27 -11
- package/src/components/Popup/Popup.tsx +1 -8
- package/src/components/WebSocket/CarbonWebSocket.tsx +88 -9
package/README.md
CHANGED
|
@@ -1,15 +1,232 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+

|
|
2
|
+

|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+

|
|
7
|
+

|
|
5
8
|
|
|
9
|
+
# CarbonReact
|
|
6
10
|
|
|
11
|
+
CarbonReact is a part of the CarbonORM series. It is a React MySQL ORM that is designed to generate all your boilerplate
|
|
12
|
+
code.
|
|
7
13
|
|
|
8
14
|
|
|
9
|
-
##
|
|
10
|
-
https://saturncloud.io/blog/whats-the-difference-between-dependencies-devdependencies-and-peerdependencies-in-npm-packagejson-file/
|
|
15
|
+
## Installation
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
CarbonReact is available on [NPM](https://www.npmjs.com/). You'll need to have [NodeJS](https://nodejs.org/en/) installed
|
|
18
|
+
which comes prepackaged with npm (node package manager).
|
|
14
19
|
|
|
20
|
+
```bash
|
|
21
|
+
npm install @carbonorm/carbonreact
|
|
22
|
+
```
|
|
15
23
|
|
|
24
|
+
## Generate Models
|
|
25
|
+
|
|
26
|
+
The command below will generate the models for the database. The models will be generated in the output directory. We do
|
|
27
|
+
recommend you keep this folder separate from other work. It is also best to track the output directory in your version
|
|
28
|
+
control system. All arguments are optional. If you do not provide them the defaults will be used. The example arguments
|
|
29
|
+
below are the defaults.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npx generateRestBindings --user root --pass password --host 127.0.0.1 --port 3306 --dbname carbonPHP --prefix carbon_ --output /src/api/rest
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
You can view the [code generated](https://github.com/CarbonORM/CarbonORM.dev/blob/www/src/api/rest/Users.tsx) by
|
|
36
|
+
[this command](https://github.com/CarbonORM/CarbonNode/blob/main/scripts/generateRestBindings.ts) in
|
|
37
|
+
[this repository](git@github.com:CarbonORM/CarbonNode.git). We use [Handlebars templates](https://mustache.github.io/)
|
|
38
|
+
to generate the code.
|
|
39
|
+
|
|
40
|
+
For more information on CarbonNode and the generations please see the [CarbonNode](https://github.com/CarbonORM/CarbonNode).
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
## QuickStart Implementation
|
|
44
|
+
|
|
45
|
+
CarbonReact is designed to be the Bootstrap of your application. It is in charge of managing the state of your application.
|
|
46
|
+
ideally once it has mounted it never gets unmounted. In application where this is not possible, you can provide the
|
|
47
|
+
`shouldStatePersist` property to the CarbonReact React Component. This will allow you to persist the state of your
|
|
48
|
+
application even if the component is unmounted. The behavior of accessing or updating state while the component is
|
|
49
|
+
unknown (undefined) and should be avoided. The example below shows a simple implementation of CarbonReact. Our user
|
|
50
|
+
defined component is in `CarbonORM` which is written to extend the `CarbonReact` class. Your implementation must also
|
|
51
|
+
extend `CarbonORM`.
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
[index.tsx](https://github.com/CarbonORM/CarbonORM.dev/blob/www/src/index.tsx)
|
|
55
|
+
|
|
56
|
+
```typescript jsx
|
|
57
|
+
|
|
58
|
+
import 'react-toastify/dist/ReactToastify.min.css'; // This is required for alerts to work and not break styling
|
|
59
|
+
|
|
60
|
+
const container = document.getElementById('root');
|
|
61
|
+
|
|
62
|
+
const root = createRoot(container!);
|
|
63
|
+
|
|
64
|
+
root.render(<React.StrictMode><CarbonORM /></React.StrictMode>);
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
CarbonReact should be loaded as soon as the page loads. There are plans to allow other alerting systems to be used, but
|
|
68
|
+
for now we use [React Toastify](https://www.npmjs.com/package/react-toastify). It must be required in one of your files
|
|
69
|
+
and typically can be done the root of your project.
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
[CarbonORM.tsx](https://github.com/CarbonORM/CarbonORM.dev/blob/www/src/CarbonORM.tsx)
|
|
73
|
+
|
|
74
|
+
```typescript jsx
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
export const initialCarbonORMState: typeof initialRestfulObjectsState
|
|
78
|
+
& typeof initialRequiredCarbonORMState
|
|
79
|
+
& iAuthenticate
|
|
80
|
+
& iVersions
|
|
81
|
+
& iUi
|
|
82
|
+
& {} = {
|
|
83
|
+
...initialVersionsState,
|
|
84
|
+
...initialRestfulObjectsState,
|
|
85
|
+
...initialRequiredCarbonORMState,
|
|
86
|
+
...initialAuthenticateState,
|
|
87
|
+
...initialUiState,
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export default class CarbonORM extends CarbonReact<{ browserRouter?: boolean }, typeof initialCarbonORMState> {
|
|
91
|
+
|
|
92
|
+
static instance: CarbonORM;
|
|
93
|
+
|
|
94
|
+
state = initialCarbonORMState;
|
|
95
|
+
|
|
96
|
+
constructor(props) {
|
|
97
|
+
super(props);
|
|
98
|
+
CarbonORM.instance = this;
|
|
99
|
+
CarbonReact.instance = this;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
componentDidMount() {
|
|
103
|
+
Carbons.Get()
|
|
104
|
+
authenticateUser()
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
render() {
|
|
108
|
+
console.log("CarbonORM TSX RENDER");
|
|
109
|
+
|
|
110
|
+
const {isLoaded, backendThrowable} = this.state;
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
if (backendThrowable.length > 0) {
|
|
114
|
+
|
|
115
|
+
return <BackendThrowable />
|
|
116
|
+
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const reactRouterContext = (children: any) => {
|
|
120
|
+
|
|
121
|
+
if (isTest) {
|
|
122
|
+
|
|
123
|
+
return <MemoryRouter initialEntries={['/']}>{children}</MemoryRouter>
|
|
124
|
+
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
return <HashRouter>{children}</HashRouter>
|
|
128
|
+
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return reactRouterContext(<>
|
|
132
|
+
<CarbonWebSocket url={'ws://localhost:8888/ws'}/>
|
|
133
|
+
<Routes>
|
|
134
|
+
<Route path={UI + "*"}>
|
|
135
|
+
<Route path={MATERIAL_DASHBOARD + "*"} element={ppr(Dashboard, {})}>
|
|
136
|
+
<Route path={DASHBOARD + '*'} element={ppr(DashboardPage, {})}/>
|
|
137
|
+
<Route path={USER_PROFILE + '*'} element={ppr(UserProfile, {})}/>
|
|
138
|
+
<Route path={TABLES + '*'} element={ppr(TableList, {})}/>
|
|
139
|
+
<Route path={TYPOGRAPHY + '*'} element={ppr(Typography, {})}/>
|
|
140
|
+
<Route path={ICONS + '*'} element={ppr(Icons, {})}/>
|
|
141
|
+
<Route path={MAPS + '*'} element={ppr(Maps, {})}/>
|
|
142
|
+
<Route path={NOTIFICATIONS + '*'} element={ppr(Notifications, {})}/>
|
|
143
|
+
<Route path={UPGRADE_TO_PRO + '*'} element={ppr(UpgradeToPro, {})}/>
|
|
144
|
+
<Route path={'*'} element={<Navigate to={'/' + UI + MATERIAL_DASHBOARD + DASHBOARD}/>}/>
|
|
145
|
+
</Route>
|
|
146
|
+
<Route path={MATERIAL_KIT + "*"} element={ppr(MaterialKit, {})}>
|
|
147
|
+
<Route path={SECTION_NAVBARS + '*'} element={ppr(SectionNavbars, {})}/>
|
|
148
|
+
<Route path={SECTION_BASICS + '*'} element={ppr(SectionBasics, {})}/>
|
|
149
|
+
<Route path={SECTION_TABS + '*'} element={ppr(SectionTabs, {})}/>
|
|
150
|
+
<Route path={SECTION_PILLS + '*'} element={ppr(SectionPills, {})}/>
|
|
151
|
+
<Route path={SECTION_NOTIFICATIONS + '*'} element={ppr(SectionNotifications, {})}/>
|
|
152
|
+
<Route path={SECTION_TYPOGRAPHY + '*'} element={ppr(SectionTypography, {})}/>
|
|
153
|
+
<Route path={SECTION_JAVASCRIPT + '*'} element={ppr(SectionJavascript, {})}/>
|
|
154
|
+
<Route path={SECTION_COMPLETED_EXAMPLES + '*'} element={ppr(SectionCompletedExamples, {})}/>
|
|
155
|
+
<Route path={SECTION_LOGIN + '*'} element={ppr(SectionLogin, {})}/>
|
|
156
|
+
<Route path={LANDING_PAGE + '*'} element={ppr(LandingPage, {})}/>
|
|
157
|
+
<Route path={SECTION_DOWNLOAD + '*'} element={ppr(SectionDownload, {})}/>
|
|
158
|
+
<Route path={'*'} element={<Navigate to={'/' + UI + MATERIAL_KIT + SECTION_NAVBARS}/>}/>
|
|
159
|
+
</Route>
|
|
160
|
+
<Route path={'*'} element={<Navigate to={'/' + UI + MATERIAL_DASHBOARD}/>}/>
|
|
161
|
+
</Route>
|
|
162
|
+
<Route path={DOCUMENTATION + '*'} element={ppr(Documentation, {})}>
|
|
163
|
+
<Route path={CARBON_ORM_INTRODUCTION + '*'} element={ppr(CarbonORMIntroduction, {})}/>
|
|
164
|
+
<Route path={SUPPORT + '*'} element={ppr(Support, {})}/>
|
|
165
|
+
<Route path={CARBONPHP + '*'} element={ppr(CarbonPHP, {})}/>
|
|
166
|
+
<Route path={DEPENDENCIES + '*'} element={ppr(Dependencies, {})}/>
|
|
167
|
+
<Route path={CHANGELOG + "*"} element={ppr(Changelog, {})}/>
|
|
168
|
+
<Route path={IMPLEMENTATIONS + "*"} element={ppr(Implementations, {})}/>
|
|
169
|
+
<Route path={LICENSE + "*"} element={ppr(License, {})}/>
|
|
170
|
+
<Route path={'*'} element={<Navigate to={'/' + DOCUMENTATION + CARBON_ORM_INTRODUCTION}/>}/>
|
|
171
|
+
</Route>
|
|
172
|
+
<Route path="/landing-page" element={ppr(LandingPage, {})}/>
|
|
173
|
+
<Route path={'*'} element={<Navigate to={'/documentation'}/>}/>
|
|
174
|
+
</Routes>
|
|
175
|
+
<ToastContainer
|
|
176
|
+
autoClose={3000}
|
|
177
|
+
draggable={false}
|
|
178
|
+
position="top-right"
|
|
179
|
+
hideProgressBar={false}
|
|
180
|
+
newestOnTop
|
|
181
|
+
closeOnClick
|
|
182
|
+
rtl={false}
|
|
183
|
+
pauseOnHover
|
|
184
|
+
/>
|
|
185
|
+
</>)
|
|
186
|
+
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
Our testing tool [Jest](https://www.npmjs.com/package/jest) requires [React Router Dom](https://www.npmjs.com/package/react-router-dom)
|
|
193
|
+
to be in `MemoryRouter` mode. This is because Jest does not have a DOM and therefore cannot render the `HashRouter` or
|
|
194
|
+
`BrowserRouter` component. CarbonReact does not require `React Router Dom` to be installed. You can use any router you
|
|
195
|
+
like. The example above uses `HashRouter` which is [necessary as this website](https://stackoverflow.com/questions/71984401/react-router-not-working-with-github-pages)
|
|
196
|
+
hosted for free using [GitHub Pages](https://pages.github.com/).
|
|
197
|
+
|
|
198
|
+
A folder named [state](https://github.com/CarbonORM/CarbonORM.dev/tree/www/src/state) in the root of your project
|
|
199
|
+
`src/state/` should contain all your state files. These files should be written with the intention of being imported
|
|
200
|
+
into your CarbonReact extended component. The example below shows a simple state file that is implemented above. Helper
|
|
201
|
+
functions are also included in the state files. These functions are designed to be used in your React Components. React
|
|
202
|
+
stateful operations must be wrapped in a function and thus must not be run during the initial page load.
|
|
203
|
+
|
|
204
|
+
Updating state is as simple as calling `CarbonORM.instance.setState({})`. The class name `CarbonORM` can be replaced with
|
|
205
|
+
any name of your liking. Typically, you will want to use the name of your project.
|
|
206
|
+
|
|
207
|
+
[ui.tsx](https://github.com/CarbonORM/CarbonORM.dev/blob/www/src/state/ui.tsx)
|
|
208
|
+
```typescript jsx
|
|
209
|
+
import CarbonORM from "CarbonORM";
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
export interface iUi {
|
|
213
|
+
pureWordpressPluginConfigured?: boolean,
|
|
214
|
+
documentationVersionURI: string,
|
|
215
|
+
isLoaded: boolean,
|
|
216
|
+
darkMode: boolean,
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export const initialUiState: iUi = {
|
|
220
|
+
pureWordpressPluginConfigured: false,
|
|
221
|
+
documentationVersionURI: '0.0.0',
|
|
222
|
+
isLoaded: false,
|
|
223
|
+
darkMode: true,
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
export const switchDarkAndLightTheme = () => {
|
|
228
|
+
CarbonORM.instance.setState({
|
|
229
|
+
darkMode: !CarbonORM.instance.state.darkMode
|
|
230
|
+
});
|
|
231
|
+
};
|
|
232
|
+
```
|
package/dist/CarbonReact.d.ts
CHANGED
|
@@ -19,10 +19,12 @@ declare const CarbonReact: {
|
|
|
19
19
|
context: unknown;
|
|
20
20
|
setState<K extends keyof iCarbonReactState | keyof S>(state: (S & iCarbonReactState) | ((prevState: Readonly<S & iCarbonReactState>, props: Readonly<{
|
|
21
21
|
children?: ReactNode | ReactNode[];
|
|
22
|
+
shouldStatePersist?: boolean | undefined;
|
|
22
23
|
} & P>) => (S & iCarbonReactState) | Pick<S & iCarbonReactState, K> | null) | Pick<S & iCarbonReactState, K> | null, callback?: (() => void) | undefined): void;
|
|
23
24
|
forceUpdate(callback?: (() => void) | undefined): void;
|
|
24
25
|
readonly props: Readonly<{
|
|
25
26
|
children?: ReactNode | ReactNode[];
|
|
27
|
+
shouldStatePersist?: boolean | undefined;
|
|
26
28
|
} & P>;
|
|
27
29
|
state: Readonly<S & iCarbonReactState>;
|
|
28
30
|
refs: {
|
|
@@ -33,29 +35,32 @@ declare const CarbonReact: {
|
|
|
33
35
|
componentDidCatch?(error: Error, errorInfo: import("react").ErrorInfo): void;
|
|
34
36
|
getSnapshotBeforeUpdate?(prevProps: Readonly<{
|
|
35
37
|
children?: ReactNode | ReactNode[];
|
|
38
|
+
shouldStatePersist?: boolean | undefined;
|
|
36
39
|
} & P>, prevState: Readonly<S & iCarbonReactState>): any;
|
|
37
40
|
componentWillMount?(): void;
|
|
38
41
|
UNSAFE_componentWillMount?(): void;
|
|
39
42
|
componentWillReceiveProps?(nextProps: Readonly<{
|
|
40
43
|
children?: ReactNode | ReactNode[];
|
|
44
|
+
shouldStatePersist?: boolean | undefined;
|
|
41
45
|
} & P>, nextContext: any): void;
|
|
42
46
|
UNSAFE_componentWillReceiveProps?(nextProps: Readonly<{
|
|
43
47
|
children?: ReactNode | ReactNode[];
|
|
48
|
+
shouldStatePersist?: boolean | undefined;
|
|
44
49
|
} & P>, nextContext: any): void;
|
|
45
50
|
componentWillUpdate?(nextProps: Readonly<{
|
|
46
51
|
children?: ReactNode | ReactNode[];
|
|
52
|
+
shouldStatePersist?: boolean | undefined;
|
|
47
53
|
} & P>, nextState: Readonly<S & iCarbonReactState>, nextContext: any): void;
|
|
48
54
|
UNSAFE_componentWillUpdate?(nextProps: Readonly<{
|
|
49
55
|
children?: ReactNode | ReactNode[];
|
|
56
|
+
shouldStatePersist?: boolean | undefined;
|
|
50
57
|
} & P>, nextState: Readonly<S & iCarbonReactState>, nextContext: any): void;
|
|
51
58
|
};
|
|
52
59
|
instance: Component<{
|
|
53
60
|
children?: ReactNode | ReactNode[];
|
|
54
61
|
} & any, any & iCarbonReactState>;
|
|
62
|
+
persistentState?: iCarbonReactState | undefined;
|
|
55
63
|
lastLocation: string;
|
|
56
|
-
websocketUrl: string;
|
|
57
|
-
websocketTimeoutSeconds: number;
|
|
58
|
-
websocketHeartbeatSeconds: number;
|
|
59
64
|
whyDidYouRender: boolean;
|
|
60
65
|
getState<S_1>(): S_1;
|
|
61
66
|
contextType?: import("react").Context<any> | undefined;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
import { tC6Tables } from "@carbonorm/carbonnode";
|
|
1
|
+
import { tC6Tables, tWsLiveUpdate } from "@carbonorm/carbonnode";
|
|
2
2
|
export interface iCarbonWebSocketProps {
|
|
3
3
|
url?: string;
|
|
4
4
|
timeoutSeconds?: number;
|
|
5
5
|
heartbeatSeconds?: number;
|
|
6
6
|
TABLES?: tC6Tables;
|
|
7
|
+
WsLiveUpdates?: tWsLiveUpdate;
|
|
7
8
|
}
|
|
8
9
|
/**
|
|
9
10
|
* @function connect
|
|
10
11
|
* This function establishes a connection with the websocket and also ensures constant reconnection if connection closes
|
|
11
12
|
**/
|
|
12
|
-
export declare function initiateWebsocket({ TABLES, url, timeoutSeconds, heartbeatSeconds }?: iCarbonWebSocketProps): void;
|
|
13
|
+
export declare function initiateWebsocket({ TABLES, WsLiveUpdates, url, timeoutSeconds, heartbeatSeconds }?: iCarbonWebSocketProps): void;
|
|
13
14
|
export default function (props: iCarbonWebSocketProps): null;
|
package/dist/index.cjs.js
CHANGED
|
@@ -3898,12 +3898,8 @@ function getStyles(overrides = {}) {
|
|
|
3898
3898
|
|
|
3899
3899
|
// @link https://stackoverflow.com/questions/58399637/include-modal-functionality-in-react-higher-order-component
|
|
3900
3900
|
function Popup({ open = true, handleClose, children, maxWidth, }) {
|
|
3901
|
-
if (false === open) {
|
|
3902
|
-
// @link https://legacy.reactjs.org/docs/conditional-rendering.html#preventing-component-from-rendering
|
|
3903
|
-
return jsxRuntime_1(jsxRuntime_3, {});
|
|
3904
|
-
}
|
|
3905
3901
|
const dig = getStyles();
|
|
3906
|
-
return jsxRuntime_1("div", { className: classNames(dig.modal, dig.fade, dig.show, dig.dBlock), style: { backgroundColor: "rgba(0,0,0,0.8)" }, id: "exampleModalCenter", tabIndex: -1, "aria-labelledby": "exampleModalCenterTitle", "aria-modal": "true", role: "dialog", children: jsxRuntime_1("div", { style: { maxWidth: maxWidth }, className: classNames(dig.modalDialog, dig.modalDialogCentered), children: jsxRuntime_1(OutsideClickHandler, { onOutsideClick: () => handleClose(), children: jsxRuntime_1("div", { className: classNames(dig.modalContent, dig.bgTransparent, dig.modalDialogScrollable), children: children }) }) }) });
|
|
3902
|
+
return jsxRuntime_1("div", { className: classNames(dig.modal, dig.fade, { [dig.show]: open }, dig.dBlock), style: { backgroundColor: "rgba(0,0,0,0.8)" }, id: "exampleModalCenter", tabIndex: -1, "aria-labelledby": "exampleModalCenterTitle", "aria-modal": "true", role: "dialog", children: jsxRuntime_1("div", { style: { maxWidth: maxWidth }, className: classNames(dig.modalDialog, dig.modalDialogCentered), children: jsxRuntime_1(OutsideClickHandler, { onOutsideClick: () => handleClose(), children: jsxRuntime_1("div", { className: classNames(dig.modalContent, dig.bgTransparent, dig.modalDialogScrollable), children: children }) }) }) });
|
|
3907
3903
|
}
|
|
3908
3904
|
|
|
3909
3905
|
const isProduction = window.location.host.split(".")[0] === "www";
|
|
@@ -4049,7 +4045,7 @@ const useEffectOnce = (effect) => {
|
|
|
4049
4045
|
* @function connect
|
|
4050
4046
|
* This function establishes a connection with the websocket and also ensures constant reconnection if connection closes
|
|
4051
4047
|
**/
|
|
4052
|
-
function initiateWebsocket({ TABLES = undefined, url = 'ws://localhost:8080/ws', timeoutSeconds = 250, heartbeatSeconds = 60 } = {}) {
|
|
4048
|
+
function initiateWebsocket({ TABLES = undefined, WsLiveUpdates = undefined, url = 'ws://localhost:8080/ws', timeoutSeconds = 250, heartbeatSeconds = 60 } = {}) {
|
|
4053
4049
|
const { websocket } = CarbonReact.instance.state;
|
|
4054
4050
|
if (!("WebSocket" in window)) {
|
|
4055
4051
|
// todo - store that this has been shown in the state
|
|
@@ -4084,17 +4080,59 @@ function initiateWebsocket({ TABLES = undefined, url = 'ws://localhost:8080/ws',
|
|
|
4084
4080
|
};
|
|
4085
4081
|
connection.onmessage = (message) => {
|
|
4086
4082
|
const parsedData = isJsonString(message?.data) ? JSON.parse(message?.data) : message?.data;
|
|
4083
|
+
if (message.data === 'pong') {
|
|
4084
|
+
return;
|
|
4085
|
+
}
|
|
4087
4086
|
CarbonReact.instance.setState((prevState) => ({
|
|
4088
4087
|
websocketEvents: prevState.websocketEvents.concat(message),
|
|
4089
4088
|
websocketData: prevState.websocketData.concat(parsedData), // JSON.parse no good - base64?
|
|
4090
|
-
}))
|
|
4091
|
-
|
|
4092
|
-
|
|
4093
|
-
|
|
4094
|
-
|
|
4095
|
-
|
|
4096
|
-
|
|
4097
|
-
|
|
4089
|
+
}), () => {
|
|
4090
|
+
if (undefined === TABLES) {
|
|
4091
|
+
console.log('WebSocket updates without the TABLES property passed will not automatically update the state.');
|
|
4092
|
+
return;
|
|
4093
|
+
}
|
|
4094
|
+
if (undefined === WsLiveUpdates) {
|
|
4095
|
+
console.log('WebSocket updates without the WsLiveUpdates property passed will not automatically update the state.');
|
|
4096
|
+
return;
|
|
4097
|
+
}
|
|
4098
|
+
if (parsedData?.REST) {
|
|
4099
|
+
const TABLE_NAME = parsedData?.REST?.TABLE_NAME;
|
|
4100
|
+
const TABLE_PREFIX = parsedData?.REST?.TABLE_PREFIX;
|
|
4101
|
+
const METHOD = parsedData?.REST?.METHOD;
|
|
4102
|
+
const REQUEST = parsedData?.REST?.REQUEST;
|
|
4103
|
+
const REQUEST_PRIMARY_KEY = parsedData?.REST?.REQUEST_PRIMARY_KEY ?? null;
|
|
4104
|
+
if (null === REQUEST_PRIMARY_KEY) {
|
|
4105
|
+
console.log('WebSocket updates without a primary key are not yet supported.');
|
|
4106
|
+
return;
|
|
4107
|
+
}
|
|
4108
|
+
console.log('todo - going to impl REST', TABLE_NAME, METHOD, REQUEST_PRIMARY_KEY, parsedData?.REST);
|
|
4109
|
+
const TABLE_NAME_SHORT = TABLE_NAME.substring(TABLE_PREFIX.length);
|
|
4110
|
+
const currentCache = CarbonReact.instance.state[TABLE_NAME_SHORT];
|
|
4111
|
+
// just because we have a websocket update, doesn't mean we need the update
|
|
4112
|
+
// check to see if the primary key is in the current cache
|
|
4113
|
+
const c6Table = TABLES[TABLE_NAME_SHORT] ?? null;
|
|
4114
|
+
if (null === c6Table) {
|
|
4115
|
+
console.error('WebSocket update could not find (' + TABLE_NAME_SHORT + ') in the TABLES property passed.', TABLES);
|
|
4116
|
+
return;
|
|
4117
|
+
}
|
|
4118
|
+
const primaryKeyKeys = Object.keys(REQUEST_PRIMARY_KEY);
|
|
4119
|
+
const elementsToUpdate = currentCache.filter((row) => {
|
|
4120
|
+
for (const element of primaryKeyKeys) {
|
|
4121
|
+
if (REQUEST_PRIMARY_KEY[element] !== row[element]) {
|
|
4122
|
+
return false;
|
|
4123
|
+
}
|
|
4124
|
+
}
|
|
4125
|
+
return true;
|
|
4126
|
+
});
|
|
4127
|
+
const updatedElements = elementsToUpdate.map((row) => {
|
|
4128
|
+
return {
|
|
4129
|
+
...row,
|
|
4130
|
+
...REQUEST
|
|
4131
|
+
};
|
|
4132
|
+
});
|
|
4133
|
+
WsLiveUpdates[TABLE_NAME_SHORT][METHOD]({}, updatedElements);
|
|
4134
|
+
}
|
|
4135
|
+
});
|
|
4098
4136
|
};
|
|
4099
4137
|
window.addEventListener("focus", () => initiateWebsocket());
|
|
4100
4138
|
// websocket onclose event listener
|
|
@@ -4191,16 +4229,19 @@ function isJsonString(str) {
|
|
|
4191
4229
|
}
|
|
4192
4230
|
const CarbonReact = class extends react.Component {
|
|
4193
4231
|
static instance;
|
|
4232
|
+
static persistentState = undefined;
|
|
4194
4233
|
static lastLocation = window.location.pathname;
|
|
4195
|
-
static websocketUrl = (window.location.protocol === 'https:' ? 'wss://' : 'ws://') + window.location.host + ':8888/ws';
|
|
4196
|
-
static websocketTimeoutSeconds = 250;
|
|
4197
|
-
static websocketHeartbeatSeconds = 250;
|
|
4198
4234
|
// @link https://github.com/welldone-software/why-did-you-render
|
|
4199
4235
|
// noinspection JSUnusedGlobalSymbols
|
|
4200
4236
|
static whyDidYouRender = true;
|
|
4201
4237
|
constructor(props) {
|
|
4202
4238
|
super(props);
|
|
4203
|
-
this.
|
|
4239
|
+
if (CarbonReact.persistentState !== undefined && this.props.shouldStatePersist !== false) {
|
|
4240
|
+
this.state = CarbonReact.persistentState;
|
|
4241
|
+
}
|
|
4242
|
+
else {
|
|
4243
|
+
this.state = initialCarbonReactState;
|
|
4244
|
+
}
|
|
4204
4245
|
// This should only ever be done here, when the full state is being trashed.
|
|
4205
4246
|
carbonnode.clearCache({
|
|
4206
4247
|
ignoreWarning: true
|
|
@@ -4216,6 +4257,12 @@ const CarbonReact = class extends react.Component {
|
|
|
4216
4257
|
return CarbonReact.instance.state;
|
|
4217
4258
|
}
|
|
4218
4259
|
shouldComponentUpdate(nextProps, nextState, _nextContext) {
|
|
4260
|
+
if (this.props.shouldStatePersist === false) {
|
|
4261
|
+
CarbonReact.persistentState = undefined;
|
|
4262
|
+
}
|
|
4263
|
+
else {
|
|
4264
|
+
CarbonReact.persistentState = nextState;
|
|
4265
|
+
}
|
|
4219
4266
|
changed(this.constructor.name + ' (DigApi)', 'props', this.props, nextProps);
|
|
4220
4267
|
changed(this.constructor.name + ' (DigApi)', 'state', this.state, nextState);
|
|
4221
4268
|
return true;
|
|
@@ -4238,7 +4285,7 @@ const CarbonReact = class extends react.Component {
|
|
|
4238
4285
|
if (this.state.backendThrowable.length > 0) {
|
|
4239
4286
|
return jsxRuntime_2(jsxRuntime_3, { children: [nest, jsxRuntime_1(BackendThrowable, {})] });
|
|
4240
4287
|
}
|
|
4241
|
-
return jsxRuntime_2(
|
|
4288
|
+
return jsxRuntime_2(jsxRuntime_3, { children: [jsxRuntime_1(GlobalHistory, {}), jsxRuntime_1(CarbonWebSocket, {}), this.props.children, jsxRuntime_1(reactToastify.ToastContainer, {})] });
|
|
4242
4289
|
}
|
|
4243
4290
|
};
|
|
4244
4291
|
|