@carbonorm/carbonreact 4.0.13 → 4.0.15

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/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@carbonorm/carbonreact",
3
3
  "license": "MIT",
4
- "version": "4.0.13",
4
+ "version": "4.0.15",
5
5
  "browser": "dist/index.umd.js",
6
6
  "module": "dist/index.esm.js",
7
7
  "main": "dist/index.cjs.js",
8
8
  "types": "dist/index.d.ts",
9
9
  "type": "module",
10
10
  "dependencies": {
11
- "@carbonorm/carbonnode": "^2.0.0",
11
+ "@carbonorm/carbonnode": "^2.0.8",
12
12
  "@fortawesome/fontawesome-svg-core": "^6.4.0",
13
13
  "@fortawesome/free-solid-svg-icons": "^6.4.0",
14
14
  "@fortawesome/react-fontawesome": "^0.2.0",
@@ -1,4 +1,3 @@
1
- import { clearCache } from "@carbonorm/carbonnode";
2
1
  import changed from "hoc/changed";
3
2
  import { GlobalHistory } from "hoc/GlobalHistory";
4
3
  import hexToRgb from "hoc/hexToRgb";
@@ -12,10 +11,7 @@ import CarbonWebSocket, { iCarbonWebSocketProps } from "./components/WebSocket/C
12
11
  import updateRestfulObjectArrays, { iUpdateRestfulObjectArrays } from "./hoc/updateRestfulObjectArrays";
13
12
  import deleteRestfulObjectArrays, { iDeleteRestfulObjectArrays } from "./hoc/deleteRestfulObjectArrays";
14
13
 
15
-
16
- export type tStatefulApiData<T extends {
17
- [key: string]: any
18
- } = {}> = T[] | undefined | null;
14
+ export type tStatefulApiData<T extends { [key: string]: any } = {}> = T[] | undefined | null;
19
15
 
20
16
  // our central container, single page application
21
17
  export interface iCarbonReactState {
@@ -51,10 +47,11 @@ export function isJsonString(str: string) {
51
47
  abstract class CarbonReact<P = {}, S extends iCarbonReactState = iCarbonReactState> extends Component<{
52
48
  children?: ReactNode | ReactNode[],
53
49
  instanceId?: string,
50
+ persistentState?: boolean,
54
51
  websocket?: Omit<iCarbonWebSocketProps<P, S>, "instance"> | false
55
52
  } & P, S> {
56
53
 
57
- private static persistentStateMap = new Map<string, { [key: string]: any; }>();
54
+ private static allInstances = new Map<string, CarbonReact<any, any>>();
58
55
  private static activeInstances = new Map<string, CarbonReact<any, any>>();
59
56
 
60
57
  context: Context<S & iCarbonReactState> = createContext(this.state);
@@ -62,12 +59,28 @@ abstract class CarbonReact<P = {}, S extends iCarbonReactState = iCarbonReactSta
62
59
 
63
60
  protected static _instance: ThisType<CarbonReact<any, any>>;
64
61
 
65
- static getInstance<T extends CarbonReact<any, any>>(): T {
62
+ static getInstance<T extends CarbonReact<any, any>>(instanceId?: string): T {
63
+
64
+ const identifier = this.generateIdentifier(instanceId);
65
+
66
+ if (undefined !== instanceId) {
67
+ if (CarbonReact.activeInstances.has(identifier)) {
68
+ return CarbonReact.activeInstances.get(identifier) as T;
69
+ }
70
+ throw new Error(`No instance has been instantiated yet for class (${this.name}) with instanceId (${instanceId})`);
71
+ }
72
+
73
+ if (!this._instance) {
74
+ throw new Error(`No instance has been instantiated yet for class (${this.name})`);
75
+ }
76
+
66
77
  return this._instance as T;
67
78
  }
79
+
68
80
  static get instance() {
69
81
  return this.getInstance();
70
82
  }
83
+
71
84
  static set instance(instance: CarbonReact<any, any>) {
72
85
  this._instance = instance;
73
86
  }
@@ -90,39 +103,50 @@ abstract class CarbonReact<P = {}, S extends iCarbonReactState = iCarbonReactSta
90
103
 
91
104
  protected constructor(props: {
92
105
  children?: ReactNode | ReactNode[];
93
- shouldStatePersist?: boolean | undefined;
94
106
  websocket?: boolean | iCarbonWebSocketProps<P, S> | undefined;
95
107
  instanceId?: string; // Optional instanceId from props
108
+ persistentState?: boolean; // Optional persistentState from props
96
109
  } & P) {
97
110
  super(props);
98
111
 
99
- const target = new.target as typeof CarbonReact;
100
- const identifier = props.instanceId || target.name;
112
+ const identifier = this.generateIdentifier();
101
113
 
102
114
  if (CarbonReact.activeInstances.has(identifier)) {
103
- throw new Error(`Instance with ID ${identifier} already exists! CarbonReact extended classes can only be referenced once in DOM with the same identifier.`);
115
+ throw new Error(`${identifier} instance already exists in the DOM! Each instance should have a unique instanceId.`);
104
116
  }
105
117
 
118
+ // Register the new instance
106
119
  CarbonReact.activeInstances.set(identifier, this);
107
120
 
108
- this.target = target;
121
+ if (props.persistentState && CarbonReact.allInstances.has(identifier)) {
122
+ // Reuse the state from the existing instance
123
+ this.state = CarbonReact.allInstances.get(identifier)!.state as S & iCarbonReactState;
124
+ } else {
125
+ this.state = initialCarbonReactState as unknown as S & iCarbonReactState;
126
+ CarbonReact.allInstances.set(identifier, this);
127
+ }
128
+
129
+ this.target = new.target;
109
130
  console.log('CarbonORM TSX CONSTRUCTOR');
110
131
 
111
- Object.assign(target, {
132
+ Object.assign(this.target, {
112
133
  _instance: this
113
134
  });
135
+ }
114
136
 
115
- if (CarbonReact.persistentStateMap.has(identifier)) {
116
- this.state = CarbonReact.persistentStateMap.get(identifier) as S & iCarbonReactState;
117
- } else {
118
- clearCache({
119
- ignoreWarning: true
120
- });
121
- this.state = initialCarbonReactState as unknown as S & iCarbonReactState;
122
- }
137
+ private static generateIdentifier(instanceId?: string): string {
138
+ const className = this.name;
139
+ return instanceId ? `${className}-${instanceId}` : className;
140
+ }
141
+
142
+ private generateIdentifier(): string {
143
+ const className = (this.constructor as typeof CarbonReact).name;
144
+ return this.props.instanceId ? `${className}-${this.props.instanceId}` : className;
145
+ }
123
146
 
124
- // Save the initial state to the persistent state map with the identifier
125
- CarbonReact.persistentStateMap.set(identifier, this.state);
147
+ componentWillUnmount() {
148
+ const identifier = this.generateIdentifier();
149
+ CarbonReact.activeInstances.delete(identifier);
126
150
  }
127
151
 
128
152
  shouldComponentUpdate(
@@ -130,9 +154,6 @@ abstract class CarbonReact<P = {}, S extends iCarbonReactState = iCarbonReactSta
130
154
  nextState: Readonly<S>,
131
155
  _nextContext: any): boolean {
132
156
 
133
- const identifier = this.props.instanceId || (this.constructor as typeof CarbonReact).name;
134
- CarbonReact.persistentStateMap.set(identifier, nextState);
135
-
136
157
  changed(this.constructor.name + ' (C6Api)', 'props', this.props, nextProps);
137
158
  changed(this.constructor.name + ' (C6Api)', 'state', this.state, nextState);
138
159
 
@@ -179,11 +200,6 @@ abstract class CarbonReact<P = {}, S extends iCarbonReactState = iCarbonReactSta
179
200
  <ToastContainer />
180
201
  </>;
181
202
  }
182
-
183
- componentWillUnmount() {
184
- const identifier = this.props.instanceId || (this.constructor as typeof CarbonReact).name;
185
- CarbonReact.activeInstances.delete(identifier);
186
- }
187
203
  }
188
204
 
189
205
  export default CarbonReact;
@@ -1,40 +1,44 @@
1
- import CarbonReact, {iCarbonReactState, isJsonString} from "CarbonReact";
1
+ import CarbonReact, {iCarbonReactState, isJsonString, tStatefulApiData} from "CarbonReact";
2
2
  import {addAlert} from "../Alert/Alert";
3
3
  import {useEffectOnce} from "../../api/hoc/useEffectOnce";
4
- import {tC6Tables, tC6RestApi} from "@carbonorm/carbonnode";
4
+ import {iC6Object} from "@carbonorm/carbonnode";
5
5
 
6
6
 
7
- export interface iCarbonWebSocketProps<P,S extends iCarbonReactState> {
7
+ export interface iCarbonWebSocketProps<P, S extends iCarbonReactState> {
8
8
  url?: string,
9
9
  timeoutSeconds?: number,
10
10
  heartbeatSeconds?: number,
11
- instance: CarbonReact<P,S>,
12
- TABLES?: tC6Tables,
13
- WsLiveUpdates?: tC6RestApi,
11
+ instance: CarbonReact<P, S>,
12
+ C6?: iC6Object,
14
13
  }
15
14
 
16
15
  /**
17
16
  * @function connect
18
17
  * This function establishes a connection with the websocket and also ensures constant reconnection if connection closes
19
18
  **/
20
- export function initiateWebsocket<P,S extends iCarbonReactState>(props: iCarbonWebSocketProps<P,S>) {
19
+ export function initiateWebsocket<P, S extends iCarbonReactState>(props: iCarbonWebSocketProps<P, S>) {
21
20
 
22
21
  let {
23
22
  instance,
24
- TABLES = undefined,
25
- WsLiveUpdates = undefined,
26
23
  url = 'ws' + (window.location.protocol === 'https:' ? 's' : '') + '://' + window.location.host + '/carbonorm/websocket',
27
24
  timeoutSeconds = 250,
28
- heartbeatSeconds = 60
25
+ heartbeatSeconds = 60,
26
+ C6
29
27
  } = props;
30
28
 
29
+ const {
30
+ TABLES = undefined,
31
+ IMPORT = undefined,
32
+ } = C6 ?? {};
33
+
34
+
31
35
  const {websocket} = instance.state;
32
36
 
33
37
 
34
38
  if (!("WebSocket" in window)) {
35
39
 
36
40
  // todo - store that this has been shown in the state
37
- addAlert<P,S>({
41
+ addAlert<P, S>({
38
42
  title: 'Browser does not support websockets, live updates will fail. You may need to refresh the page to see the newest content.',
39
43
  text: 'Please use a modern browser.',
40
44
  icon: 'warning',
@@ -105,14 +109,6 @@ export function initiateWebsocket<P,S extends iCarbonReactState>(props: iCarbonW
105
109
 
106
110
  }
107
111
 
108
- if (undefined === WsLiveUpdates) {
109
-
110
- console.log('WebSocket updates without the WsLiveUpdates property passed will not automatically update the state.')
111
-
112
- return;
113
-
114
- }
115
-
116
112
  if (parsedData?.REST) {
117
113
 
118
114
  const TABLE_NAME: string = parsedData?.REST?.TABLE_NAME;
@@ -139,7 +135,7 @@ export function initiateWebsocket<P,S extends iCarbonReactState>(props: iCarbonW
139
135
 
140
136
  const TABLE_NAME_SHORT = TABLE_NAME.substring(TABLE_PREFIX.length);
141
137
 
142
- const currentCache: [] = instance.state[TABLE_NAME_SHORT]
138
+ const currentCache: tStatefulApiData<{ [key: string]: any }> = instance.state[TABLE_NAME_SHORT]
143
139
 
144
140
  // just because we have a websocket update, doesn't mean we need the update
145
141
  // check to see if the primary key is in the current cache
@@ -155,7 +151,8 @@ export function initiateWebsocket<P,S extends iCarbonReactState>(props: iCarbonW
155
151
 
156
152
  const primaryKeyKeys = Object.keys(REQUEST_PRIMARY_KEY)
157
153
 
158
- const elementsToUpdate = currentCache.filter((row: any) => {
154
+ // todo - which direction should we filter
155
+ const elementsToUpdate = currentCache?.filter((row: any) => {
159
156
 
160
157
  for (const element of primaryKeyKeys) {
161
158
 
@@ -174,7 +171,7 @@ export function initiateWebsocket<P,S extends iCarbonReactState>(props: iCarbonW
174
171
 
175
172
  return true
176
173
 
177
- })
174
+ }) ?? []
178
175
 
179
176
  console.log('elementsToUpdate', elementsToUpdate)
180
177
 
@@ -192,8 +189,30 @@ export function initiateWebsocket<P,S extends iCarbonReactState>(props: iCarbonW
192
189
 
193
190
  })
194
191
 
195
- updatedElements.forEach((row: any) => {
196
- WsLiveUpdates[TABLE_NAME_SHORT][METHOD]({}, row)
192
+ updatedElements.forEach(async (row: any) => {
193
+
194
+ const RestRequests = await IMPORT?.(TABLE_NAME_SHORT)
195
+
196
+ const {
197
+ postState,
198
+ deleteState,
199
+ putState,
200
+ } = RestRequests;
201
+
202
+ switch (METHOD) {
203
+ case 'POST':
204
+ postState({}, row)
205
+ break;
206
+ case 'DELETE':
207
+ deleteState({}, row)
208
+ break;
209
+ case 'PUT':
210
+ putState({}, row)
211
+ break;
212
+ default:
213
+ console.error('Method not supported', METHOD)
214
+ }
215
+
197
216
  })
198
217
 
199
218
  }
@@ -286,7 +305,7 @@ export function initiateWebsocket<P,S extends iCarbonReactState>(props: iCarbonW
286
305
 
287
306
  }
288
307
 
289
- export default function <P,S extends iCarbonReactState>(props: iCarbonWebSocketProps<P,S>) {
308
+ export default function <P, S extends iCarbonReactState>(props: iCarbonWebSocketProps<P, S>) {
290
309
 
291
310
  useEffectOnce(() => {
292
311