@carbonorm/carbonreact 3.6.2 → 4.0.1
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 +1 -1
- package/dist/CarbonReact.d.ts +17 -8
- package/dist/components/Alert/Alert.d.ts +5 -1
- package/dist/components/Errors/BackendThrowable.d.ts +4 -1
- package/dist/components/WebSocket/CarbonWebSocket.d.ts +3 -1
- package/dist/hoc/KeysMatching.d.ts +1 -1
- package/dist/hoc/SubsetMatching.d.ts +4 -0
- package/dist/hoc/deleteRestfulObjectArrays.d.ts +17 -3
- package/dist/hoc/updateRestfulObjectArrays.d.ts +25 -11
- package/dist/index.cjs.js +156 -169
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.esm.js +157 -170
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/CarbonReact.tsx +36 -21
- package/src/components/Alert/Alert.tsx +32 -29
- package/src/components/Errors/BackendThrowable.tsx +11 -8
- package/src/components/WebSocket/CarbonWebSocket.tsx +21 -15
- package/src/hoc/KeysMatching.ts +4 -2
- package/src/hoc/SubsetMatching.ts +6 -0
- package/src/hoc/deleteRestfulObjectArrays.tsx +51 -52
- package/src/hoc/updateRestfulObjectArrays.tsx +97 -97
- package/src/index.ts +1 -0
- package/src/variables/C6.tsx +1 -1
- package/dist/variables/C6.d.ts +0 -842
package/package.json
CHANGED
package/src/CarbonReact.tsx
CHANGED
|
@@ -2,15 +2,21 @@ import {clearCache} from "@carbonorm/carbonnode";
|
|
|
2
2
|
import changed from "hoc/changed";
|
|
3
3
|
import {GlobalHistory} from "hoc/GlobalHistory";
|
|
4
4
|
import hexToRgb from "hoc/hexToRgb";
|
|
5
|
-
import {Component, Context, createContext,
|
|
5
|
+
import {Component, Context, createContext, ReactElement, ReactNode} from 'react';
|
|
6
6
|
import {ToastContainer} from 'react-toastify';
|
|
7
7
|
import 'react-toastify/dist/ReactToastify.min.css';
|
|
8
8
|
import BackendThrowable from 'components/Errors/BackendThrowable';
|
|
9
9
|
import Nest from 'components/Nest/Nest';
|
|
10
10
|
import {initialRestfulObjectsState, iRestfulObjectArrayTypes} from "variables/C6";
|
|
11
11
|
import CarbonWebSocket, {iCarbonWebSocketProps} from "./components/WebSocket/CarbonWebSocket";
|
|
12
|
+
import updateRestfulObjectArrays, {iUpdateRestfulObjectArrays} from "./hoc/updateRestfulObjectArrays";
|
|
13
|
+
import deleteRestfulObjectArrays, {iDeleteRestfulObjectArrays} from "./hoc/deleteRestfulObjectArrays";
|
|
12
14
|
|
|
13
15
|
|
|
16
|
+
export type tStatefulApiData<T extends {
|
|
17
|
+
[key: string]: any
|
|
18
|
+
} = {}> = T[] | undefined | null;
|
|
19
|
+
|
|
14
20
|
// our central container, single page application
|
|
15
21
|
export interface iCarbonReactState {
|
|
16
22
|
alertsWaiting: any[],
|
|
@@ -42,33 +48,33 @@ export function isJsonString(str: string) {
|
|
|
42
48
|
return true;
|
|
43
49
|
}
|
|
44
50
|
|
|
45
|
-
|
|
46
|
-
// Create a context
|
|
47
|
-
|
|
48
51
|
const persistentStateMap = new Map<string, iCarbonReactState>();
|
|
49
52
|
|
|
50
|
-
abstract class CarbonReact<P = {}, S = {}> extends Component<{
|
|
53
|
+
abstract class CarbonReact<P = {}, S extends { [key: string]: any; } = {}> extends Component<{
|
|
51
54
|
children?: ReactNode | ReactNode[],
|
|
52
55
|
instanceId?: string,
|
|
53
|
-
websocket?: iCarbonWebSocketProps | boolean
|
|
56
|
+
websocket?: Omit<iCarbonWebSocketProps, "instance"> | boolean
|
|
54
57
|
} & P, S & iCarbonReactState> {
|
|
55
58
|
|
|
56
59
|
context: Context<S & iCarbonReactState> = createContext(this.state);
|
|
57
60
|
|
|
58
61
|
// Private static member
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
} & any, any & iCarbonReactState>;
|
|
62
|
+
// we actually implement this in the constructor todo - test this
|
|
63
|
+
protected static instance: CarbonReact;
|
|
62
64
|
|
|
63
|
-
protected
|
|
64
|
-
return CarbonReact.instance.state;
|
|
65
|
-
}
|
|
65
|
+
protected target: typeof CarbonReact;
|
|
66
66
|
|
|
67
|
-
protected
|
|
68
|
-
|
|
69
|
-
|
|
67
|
+
protected updateRestfulObjectArrays = <ObjectType extends { [key: string]: any; } = {}>
|
|
68
|
+
(rest: Omit<iUpdateRestfulObjectArrays<ObjectType, S, P>, "instance">) => updateRestfulObjectArrays<ObjectType, S, P>({
|
|
69
|
+
instance: this,
|
|
70
|
+
...rest
|
|
71
|
+
});
|
|
70
72
|
|
|
71
|
-
protected
|
|
73
|
+
protected deleteRestfulObjectArrays = <ObjectType extends { [key: string]: any } = {}>
|
|
74
|
+
(rest: Omit<iDeleteRestfulObjectArrays<ObjectType, S, P>, "instance">) => deleteRestfulObjectArrays<ObjectType, S, P>({
|
|
75
|
+
instance: this,
|
|
76
|
+
...rest
|
|
77
|
+
});
|
|
72
78
|
|
|
73
79
|
static lastLocation = window.location.pathname;
|
|
74
80
|
|
|
@@ -76,13 +82,22 @@ abstract class CarbonReact<P = {}, S = {}> extends Component<{
|
|
|
76
82
|
// noinspection JSUnusedGlobalSymbols
|
|
77
83
|
static whyDidYouRender = true;
|
|
78
84
|
|
|
79
|
-
|
|
85
|
+
|
|
86
|
+
protected constructor(props: {
|
|
87
|
+
children?: ReactNode | ReactNode[];
|
|
88
|
+
shouldStatePersist?: boolean | undefined;
|
|
89
|
+
websocket?: boolean | iCarbonWebSocketProps | undefined;
|
|
90
|
+
} & P) {
|
|
80
91
|
|
|
81
92
|
super(props);
|
|
82
93
|
|
|
94
|
+
this.target = new.target;
|
|
95
|
+
|
|
83
96
|
console.log('CarbonORM TSX CONSTRUCTOR');
|
|
84
97
|
|
|
85
|
-
|
|
98
|
+
// this is the magic that allows each class that's extends this to have a static instance - a singleton pattern
|
|
99
|
+
// new.target is a meta-property introduced in ES6 that references the constructor that was directly invoked with the new keyword.
|
|
100
|
+
Object.assign(new.target, {
|
|
86
101
|
instance: this
|
|
87
102
|
})
|
|
88
103
|
|
|
@@ -112,7 +127,6 @@ abstract class CarbonReact<P = {}, S = {}> extends Component<{
|
|
|
112
127
|
}
|
|
113
128
|
|
|
114
129
|
|
|
115
|
-
|
|
116
130
|
shouldComponentUpdate(
|
|
117
131
|
nextProps: Readonly<any>,
|
|
118
132
|
nextState: Readonly<iCarbonReactState>,
|
|
@@ -155,7 +169,7 @@ abstract class CarbonReact<P = {}, S = {}> extends Component<{
|
|
|
155
169
|
|
|
156
170
|
return <>
|
|
157
171
|
{nest}
|
|
158
|
-
<BackendThrowable/>
|
|
172
|
+
<BackendThrowable instance={CarbonReact.instance}/>
|
|
159
173
|
</>;
|
|
160
174
|
|
|
161
175
|
}
|
|
@@ -165,7 +179,8 @@ abstract class CarbonReact<P = {}, S = {}> extends Component<{
|
|
|
165
179
|
return <>
|
|
166
180
|
<GlobalHistory/>
|
|
167
181
|
{this.props.websocket &&
|
|
168
|
-
<CarbonWebSocket {...(true === this.props.websocket ? {} : this.props.websocket)}
|
|
182
|
+
<CarbonWebSocket {...(true === this.props.websocket ? {} : this.props.websocket)}
|
|
183
|
+
instance={CarbonReact.instance}/>}
|
|
169
184
|
<Context value={this.state}>
|
|
170
185
|
{this.props.children}
|
|
171
186
|
</Context>
|
|
@@ -2,7 +2,7 @@ import classNames from "classnames";
|
|
|
2
2
|
import CarbonReact from "CarbonReact";
|
|
3
3
|
import {ReactNode} from "react";
|
|
4
4
|
import Popup from "components/Popup/Popup";
|
|
5
|
-
import
|
|
5
|
+
import getStyles from "hoc/getStyles";
|
|
6
6
|
import {faClose} from "@fortawesome/free-solid-svg-icons";
|
|
7
7
|
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
|
8
8
|
import isProduction from "variables/isProduction";
|
|
@@ -21,6 +21,7 @@ export interface iAlertButtonOptions {
|
|
|
21
21
|
export interface iAlert {
|
|
22
22
|
title: string,
|
|
23
23
|
text: string,
|
|
24
|
+
instance: CarbonReact,
|
|
24
25
|
component?: ReactNode,
|
|
25
26
|
icon?: "warning" | "error" | "success" | "info" | "question" | null,
|
|
26
27
|
buttons?: (iAlertButtonOptions)[] | undefined, //['No thanks!', 'Yes, Delete it'],
|
|
@@ -34,7 +35,7 @@ export interface iAlert {
|
|
|
34
35
|
|
|
35
36
|
export function addAlert(props: iAlert) {
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
props.instance.setState(previousState => ({
|
|
38
39
|
alertsWaiting: previousState.alertsWaiting.length === 0
|
|
39
40
|
? [props]
|
|
40
41
|
: [...previousState.alertsWaiting, props]
|
|
@@ -42,9 +43,11 @@ export function addAlert(props: iAlert) {
|
|
|
42
43
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
|
-
export default function Alert(
|
|
46
|
+
export default function Alert({
|
|
47
|
+
instance
|
|
48
|
+
}: { instance: CarbonReact }) {
|
|
46
49
|
|
|
47
|
-
const {alertsWaiting, backendThrowable} =
|
|
50
|
+
const {alertsWaiting, backendThrowable} = instance.state
|
|
48
51
|
|
|
49
52
|
let alert: iAlert | undefined = undefined;
|
|
50
53
|
|
|
@@ -66,9 +69,10 @@ export default function Alert() {
|
|
|
66
69
|
})
|
|
67
70
|
}
|
|
68
71
|
|
|
69
|
-
const backendThrowable =
|
|
72
|
+
const backendThrowable = instance.state.backendThrowable[0]
|
|
70
73
|
|
|
71
74
|
alert = {
|
|
75
|
+
instance: instance,
|
|
72
76
|
title: "Oh no! An issue occurred!",
|
|
73
77
|
text: backendThrowable?.['DropInGaming\\PHP\\Errors\\DropException'] ?? 'An unknown issue occurred. Please try again.',
|
|
74
78
|
timeout: 0,
|
|
@@ -81,7 +85,7 @@ export default function Alert() {
|
|
|
81
85
|
|
|
82
86
|
if (value === 'Expand') {
|
|
83
87
|
|
|
84
|
-
|
|
88
|
+
instance.setState(previousState => {
|
|
85
89
|
|
|
86
90
|
let backendThrowable = previousState.backendThrowable.pop()
|
|
87
91
|
|
|
@@ -99,7 +103,7 @@ export default function Alert() {
|
|
|
99
103
|
})
|
|
100
104
|
|
|
101
105
|
} else {
|
|
102
|
-
|
|
106
|
+
instance.setState(previousState => ({
|
|
103
107
|
backendThrowable: previousState.backendThrowable.slice(1)
|
|
104
108
|
}))
|
|
105
109
|
}
|
|
@@ -120,9 +124,7 @@ export default function Alert() {
|
|
|
120
124
|
|
|
121
125
|
const timeout = alert?.timeout || 15000
|
|
122
126
|
|
|
123
|
-
const
|
|
124
|
-
|
|
125
|
-
const dig = getStyles()
|
|
127
|
+
const styles = getStyles()
|
|
126
128
|
|
|
127
129
|
let cancelTimeout: any = null
|
|
128
130
|
|
|
@@ -132,7 +134,7 @@ export default function Alert() {
|
|
|
132
134
|
}
|
|
133
135
|
|
|
134
136
|
if (alert?.backendThrowable === undefined) {
|
|
135
|
-
|
|
137
|
+
instance.setState(previousState => ({
|
|
136
138
|
alertsWaiting: previousState.alertsWaiting.slice(1)
|
|
137
139
|
}))
|
|
138
140
|
}
|
|
@@ -153,19 +155,19 @@ export default function Alert() {
|
|
|
153
155
|
}
|
|
154
156
|
|
|
155
157
|
return <Popup handleClose={handleClose}>
|
|
156
|
-
<div className={classNames("model-content",
|
|
158
|
+
<div className={classNames("model-content", styles.rounded0, styles.border0)} style={{
|
|
157
159
|
maxWidth: '75vw',
|
|
158
160
|
maxHeight: '75vh',
|
|
159
161
|
}}>
|
|
160
|
-
<div className={classNames(
|
|
162
|
+
<div className={classNames(styles.modalHeader, styles.rounded0, styles.border0, {
|
|
161
163
|
// icon?: "warning" | "error" | "success" | "info" | "question"
|
|
162
|
-
[
|
|
163
|
-
[
|
|
164
|
-
[
|
|
165
|
-
[
|
|
166
|
-
[
|
|
164
|
+
[styles.bg_primary]: "info" === alert.icon || alert.icon === undefined || alert.icon === null,
|
|
165
|
+
[styles.bg_success]: "success" === alert.icon,
|
|
166
|
+
[styles.bg_warning]: "warning" === alert.icon,
|
|
167
|
+
[styles.bg_danger]: "error" === alert.icon, // TODO - change to red
|
|
168
|
+
[styles.bgPrimary]: "question" === alert.icon,
|
|
167
169
|
})}>
|
|
168
|
-
<h3 className={classNames(
|
|
170
|
+
<h3 className={classNames(styles.modalTitle, styles.textDark)} id="staticBackdropLabel">
|
|
169
171
|
#{alertWaiting} {alert.title}
|
|
170
172
|
</h3>
|
|
171
173
|
<div onClick={handleClose}>
|
|
@@ -174,26 +176,27 @@ export default function Alert() {
|
|
|
174
176
|
size={'xl'}/>
|
|
175
177
|
</div>
|
|
176
178
|
</div>
|
|
177
|
-
<div className={classNames(
|
|
178
|
-
<div className={
|
|
179
|
+
<div className={classNames(styles.modalBody, styles.border0, styles.textWhite)}>
|
|
180
|
+
<div className={styles.textCenter}>
|
|
179
181
|
{alert.text}
|
|
180
182
|
{alert.component}
|
|
181
183
|
</div>
|
|
182
184
|
</div>
|
|
183
185
|
{undefined !== alert.buttons &&
|
|
184
|
-
<div className={classNames(
|
|
185
|
-
{alert.footerText &&
|
|
186
|
+
<div className={classNames(styles.modalFooter, styles.border0, styles.rounded0)}>
|
|
187
|
+
{alert.footerText &&
|
|
188
|
+
<div className={classNames(styles.textCenter, styles.textWhite)}>{alert.footerText}</div>}
|
|
186
189
|
|
|
187
190
|
{alert.buttons?.map((button: iAlertButtonOptions, index: number) => {
|
|
188
191
|
|
|
189
192
|
return <button key={index}
|
|
190
|
-
className={classNames(
|
|
193
|
+
className={classNames(styles.btn, styles.btnLg, {
|
|
191
194
|
// todo - color: "default" | "primary" | "secondary" | "inherit" | "danger" | "info" | "success" | "warning" | undefined,
|
|
192
|
-
[
|
|
193
|
-
[
|
|
194
|
-
[
|
|
195
|
-
[
|
|
196
|
-
}, "btn-Yes",
|
|
195
|
+
[styles.bg_success]: "success" === button.color,
|
|
196
|
+
[styles.bg_danger]: "danger" === button.color,
|
|
197
|
+
[styles.bg_primary]: "primary" === button.color,
|
|
198
|
+
[styles.bg_warning]: "warning" === button.color,
|
|
199
|
+
}, "btn-Yes", styles.rounded0)}
|
|
197
200
|
onClick={() => {
|
|
198
201
|
handleClose()
|
|
199
202
|
alert?.then?.(button.value ?? button.text)
|
|
@@ -3,18 +3,20 @@ import OutsideClickHandler from 'react-outside-click-handler';
|
|
|
3
3
|
import CarbonReact from "../../CarbonReact";
|
|
4
4
|
import {ReactElement} from "react";
|
|
5
5
|
|
|
6
|
-
export default (
|
|
6
|
+
export default (props: {
|
|
7
|
+
instance: CarbonReact,
|
|
8
|
+
}): ReactElement => {
|
|
7
9
|
|
|
8
|
-
const
|
|
10
|
+
const {instance} = props;
|
|
9
11
|
|
|
10
|
-
const currentThrowable =
|
|
12
|
+
const currentThrowable = instance.state.backendThrowable[0];
|
|
11
13
|
|
|
12
|
-
console.log([
|
|
14
|
+
console.log([instance.state.backendThrowable, currentThrowable]);
|
|
13
15
|
|
|
14
16
|
return <div className={styles.maintenanceHero}>
|
|
15
17
|
<h1 className={styles.httpStatusCode}>{currentThrowable?.status || 500}</h1>
|
|
16
18
|
<OutsideClickHandler
|
|
17
|
-
onOutsideClick={() =>
|
|
19
|
+
onOutsideClick={() => instance.setState(currentState => ({backendThrowable: currentState.backendThrowable.slice(1)}))}>
|
|
18
20
|
<div className={styles.centeredContainer}>
|
|
19
21
|
{Object.keys(currentThrowable).map((key, index) => {
|
|
20
22
|
|
|
@@ -26,14 +28,15 @@ export default () : ReactElement => {
|
|
|
26
28
|
<div className={styles.errorTextGeneral}> > <span className={styles.errorKeys}>{key}</span>:
|
|
27
29
|
{valueIsString
|
|
28
30
|
? (valueIsCode ? <div
|
|
29
|
-
style={{
|
|
30
|
-
dangerouslySetInnerHTML={{
|
|
31
|
+
style={{backgroundColor: 'black', fontSize: 'xx-small'}}
|
|
32
|
+
dangerouslySetInnerHTML={{__html: currentThrowable[key]}}/> :
|
|
31
33
|
<i className={styles.errorValues}>"{currentThrowable[key]}"</i>)
|
|
32
34
|
: ''}
|
|
33
35
|
</div>
|
|
34
36
|
{valueIsString
|
|
35
37
|
? ''
|
|
36
|
-
: <pre
|
|
38
|
+
: <pre
|
|
39
|
+
className={styles.errorPre}>{JSON.stringify(currentThrowable[key], undefined, 4)}</pre>}
|
|
37
40
|
</div>;
|
|
38
41
|
})}
|
|
39
42
|
</div>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import CarbonReact, {isJsonString} from "CarbonReact";
|
|
2
2
|
import {addAlert} from "../Alert/Alert";
|
|
3
3
|
import {useEffectOnce} from "../../api/hoc/useEffectOnce";
|
|
4
4
|
import {tC6Tables, tC6RestApi} from "@carbonorm/carbonnode";
|
|
@@ -8,6 +8,7 @@ export interface iCarbonWebSocketProps {
|
|
|
8
8
|
url?: string,
|
|
9
9
|
timeoutSeconds?: number,
|
|
10
10
|
heartbeatSeconds?: number,
|
|
11
|
+
instance: CarbonReact,
|
|
11
12
|
TABLES?: tC6Tables,
|
|
12
13
|
WsLiveUpdates?: tC6RestApi,
|
|
13
14
|
}
|
|
@@ -16,15 +17,19 @@ export interface iCarbonWebSocketProps {
|
|
|
16
17
|
* @function connect
|
|
17
18
|
* This function establishes a connection with the websocket and also ensures constant reconnection if connection closes
|
|
18
19
|
**/
|
|
19
|
-
export function initiateWebsocket({
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
export function initiateWebsocket(props: iCarbonWebSocketProps) {
|
|
21
|
+
|
|
22
|
+
let {
|
|
23
|
+
instance,
|
|
24
|
+
TABLES = undefined,
|
|
25
|
+
WsLiveUpdates = undefined,
|
|
26
|
+
url = 'ws' + (window.location.protocol === 'https:' ? 's' : '') + '://' + window.location.host + '/carbonorm/websocket',
|
|
27
|
+
timeoutSeconds = 250,
|
|
28
|
+
heartbeatSeconds = 60
|
|
29
|
+
} = props;
|
|
30
|
+
|
|
31
|
+
const {websocket} = instance.state;
|
|
26
32
|
|
|
27
|
-
const {websocket} = CarbonReact.instance.state;
|
|
28
33
|
|
|
29
34
|
if (!("WebSocket" in window)) {
|
|
30
35
|
|
|
@@ -33,6 +38,7 @@ export function initiateWebsocket({
|
|
|
33
38
|
title: 'Browser does not support websockets, live updates will fail. You may need to refresh the page to see the newest content.',
|
|
34
39
|
text: 'Please use a modern browser.',
|
|
35
40
|
icon: 'warning',
|
|
41
|
+
instance
|
|
36
42
|
})
|
|
37
43
|
|
|
38
44
|
}
|
|
@@ -50,7 +56,7 @@ export function initiateWebsocket({
|
|
|
50
56
|
|
|
51
57
|
console.log("Connecting websocket url", url);
|
|
52
58
|
|
|
53
|
-
|
|
59
|
+
instance.setState({
|
|
54
60
|
websocket: connection
|
|
55
61
|
}, () => {
|
|
56
62
|
|
|
@@ -62,7 +68,7 @@ export function initiateWebsocket({
|
|
|
62
68
|
|
|
63
69
|
function heartbeat() {
|
|
64
70
|
|
|
65
|
-
const {websocket} =
|
|
71
|
+
const {websocket} = instance.state;
|
|
66
72
|
|
|
67
73
|
if (!websocket) return;
|
|
68
74
|
|
|
@@ -86,7 +92,7 @@ export function initiateWebsocket({
|
|
|
86
92
|
return;
|
|
87
93
|
}
|
|
88
94
|
|
|
89
|
-
|
|
95
|
+
instance.setState((prevState: Readonly<any>) => ({
|
|
90
96
|
websocketEvents: prevState.websocketEvents.concat(message),
|
|
91
97
|
websocketData: prevState.websocketData.concat(parsedData), // JSON.parse no good - base64?
|
|
92
98
|
}), () => {
|
|
@@ -133,7 +139,7 @@ export function initiateWebsocket({
|
|
|
133
139
|
|
|
134
140
|
const TABLE_NAME_SHORT = TABLE_NAME.substring(TABLE_PREFIX.length);
|
|
135
141
|
|
|
136
|
-
const currentCache: [] =
|
|
142
|
+
const currentCache: [] = instance.state[TABLE_NAME_SHORT]
|
|
137
143
|
|
|
138
144
|
// just because we have a websocket update, doesn't mean we need the update
|
|
139
145
|
// check to see if the primary key is in the current cache
|
|
@@ -196,7 +202,7 @@ export function initiateWebsocket({
|
|
|
196
202
|
|
|
197
203
|
};
|
|
198
204
|
|
|
199
|
-
window.addEventListener("focus", () => initiateWebsocket());
|
|
205
|
+
window.addEventListener("focus", () => initiateWebsocket(props));
|
|
200
206
|
|
|
201
207
|
// websocket onclose event listener
|
|
202
208
|
connection.addEventListener('close', event => {
|
|
@@ -215,7 +221,7 @@ export function initiateWebsocket({
|
|
|
215
221
|
|
|
216
222
|
console.log(`WebSocket reconnect will be attempted in ${retrySeconds} second(s).`)
|
|
217
223
|
|
|
218
|
-
connectInterval = setTimeout(() => initiateWebsocket(), retrySeconds);
|
|
224
|
+
connectInterval = setTimeout(() => initiateWebsocket(props), retrySeconds);
|
|
219
225
|
|
|
220
226
|
}
|
|
221
227
|
|
package/src/hoc/KeysMatching.ts
CHANGED
|
@@ -1,36 +1,54 @@
|
|
|
1
|
-
import CarbonReact from "CarbonReact";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
import CarbonReact, { iCarbonReactState, tStatefulApiData } from "CarbonReact";
|
|
2
|
+
import { KeysMatching } from "./KeysMatching";
|
|
3
|
+
|
|
4
|
+
export interface iDeleteRestfulObjectArrays<
|
|
5
|
+
ObjectType extends {
|
|
6
|
+
[key: string]: any
|
|
7
|
+
} = {},
|
|
8
|
+
S extends { [key: string]: any; } = CarbonReact['state'],
|
|
9
|
+
P = CarbonReact['props']
|
|
10
|
+
> {
|
|
11
|
+
instance: CarbonReact<P, S>,
|
|
12
|
+
dataOrCallback: ObjectType[] | ((state: Readonly<S>, props: Readonly<P>) => ObjectType[] | null),
|
|
13
|
+
stateKey: KeysMatching<S, tStatefulApiData<ObjectType>>,
|
|
14
|
+
uniqueObjectId: keyof ObjectType | (keyof ObjectType)[],
|
|
15
|
+
callback?: () => void
|
|
16
|
+
}
|
|
5
17
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
18
|
+
export default function deleteRestfulObjectArrays<
|
|
19
|
+
ObjectType extends {
|
|
20
|
+
[key: string]: any
|
|
21
|
+
} = {},
|
|
22
|
+
S extends { [key: string]: any; } = CarbonReact['state'],
|
|
23
|
+
P = CarbonReact['props']
|
|
24
|
+
>({
|
|
25
|
+
instance,
|
|
26
|
+
dataOrCallback,
|
|
27
|
+
stateKey,
|
|
28
|
+
uniqueObjectId,
|
|
29
|
+
callback
|
|
30
|
+
}: iDeleteRestfulObjectArrays<ObjectType, S, P>): void {
|
|
16
31
|
|
|
17
|
-
const uniqueObjectIds = uniqueObjectId
|
|
32
|
+
const uniqueObjectIds = Array.isArray(uniqueObjectId) ? uniqueObjectId : [uniqueObjectId];
|
|
18
33
|
|
|
19
|
-
|
|
34
|
+
instance.setState((
|
|
35
|
+
previousBootstrapState: Readonly<S & iCarbonReactState>,
|
|
36
|
+
props: Readonly<P>
|
|
37
|
+
): Pick<S & iCarbonReactState, keyof S> | null => {
|
|
20
38
|
|
|
21
|
-
let newOrReplacementData: ObjectType[]
|
|
39
|
+
let newOrReplacementData: ObjectType[] = [];
|
|
22
40
|
|
|
23
|
-
if (dataOrCallback
|
|
41
|
+
if (Array.isArray(dataOrCallback)) {
|
|
24
42
|
|
|
25
|
-
newOrReplacementData = dataOrCallback
|
|
43
|
+
newOrReplacementData = dataOrCallback;
|
|
26
44
|
|
|
27
|
-
} else if (dataOrCallback
|
|
45
|
+
} else if (typeof dataOrCallback === 'function') {
|
|
28
46
|
|
|
29
|
-
|
|
47
|
+
const callbackReturn = dataOrCallback(previousBootstrapState, props);
|
|
30
48
|
|
|
31
|
-
if (
|
|
49
|
+
if (callbackReturn === null) {
|
|
32
50
|
|
|
33
|
-
return ;
|
|
51
|
+
return null; // No updates needed (noop)
|
|
34
52
|
|
|
35
53
|
}
|
|
36
54
|
|
|
@@ -38,40 +56,21 @@ export default function deleteRestfulObjectArrays<ObjectType = tRestfulObjectArr
|
|
|
38
56
|
|
|
39
57
|
} else {
|
|
40
58
|
|
|
41
|
-
throw Error('The dataOrCallback parameter was not an array or function')
|
|
59
|
+
throw new Error('The dataOrCallback parameter was not an array or function');
|
|
42
60
|
|
|
43
61
|
}
|
|
44
62
|
|
|
45
|
-
const previousStateProperty
|
|
46
|
-
|
|
47
|
-
return {
|
|
48
|
-
[stateKey]: [
|
|
49
|
-
|
|
50
|
-
...previousStateProperty?.filter(item => false === (newOrReplacementData?.find(value => {
|
|
51
|
-
|
|
52
|
-
let isMatch = true;
|
|
53
|
-
|
|
54
|
-
uniqueObjectIds.find(uniqueObjectId => {
|
|
55
|
-
|
|
56
|
-
if (value[uniqueObjectId] !== item[uniqueObjectId]) {
|
|
57
|
-
|
|
58
|
-
isMatch = false;
|
|
63
|
+
const previousStateProperty: tStatefulApiData<ObjectType> = previousBootstrapState[stateKey] as tStatefulApiData<ObjectType>;
|
|
59
64
|
|
|
60
|
-
|
|
65
|
+
const updatedStateProperty = previousStateProperty?.filter(item =>
|
|
66
|
+
!newOrReplacementData.some(value =>
|
|
67
|
+
uniqueObjectIds.every(uniqueId => value[uniqueId] === item[uniqueId])
|
|
68
|
+
)
|
|
69
|
+
) ?? [];
|
|
61
70
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
return isMatch;
|
|
69
|
-
|
|
70
|
-
}) || false)) || []
|
|
71
|
+
return {
|
|
72
|
+
[stateKey]: updatedStateProperty
|
|
73
|
+
} as Pick<S & iCarbonReactState, keyof S>;
|
|
71
74
|
|
|
72
|
-
]
|
|
73
|
-
}
|
|
74
75
|
}, callback);
|
|
75
|
-
|
|
76
76
|
}
|
|
77
|
-
|