@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/dist/index.cjs.js CHANGED
@@ -1411,11 +1411,11 @@ function hexToRgb (hex) {
1411
1411
 
1412
1412
  var styles = {"maintenance-hero":"C5KSPNF","maintenanceHero":"C5KSPNF","httpStatusCode":"NhyRQts","centeredContainer":"nA4Uno6","errorTextGeneral":"yJAgaUs","errorKeys":"SRIoY4m","error-values":"xQIsoNw","errorValues":"xQIsoNw","error-pre":"C6eWpJ3","errorPre":"C6eWpJ3","line-number":"NFRyo7M","lineNumber":"NFRyo7M","cl":"vR2jbfr","slide":"OO2C-Wp"};
1413
1413
 
1414
- var BackendThrowable = () => {
1415
- const bootstrap = CarbonReact.instance;
1416
- const currentThrowable = bootstrap.state.backendThrowable[0];
1417
- console.log([bootstrap.state.backendThrowable, currentThrowable]);
1418
- return jsxRuntime_2("div", { className: styles.maintenanceHero, children: [jsxRuntime_1("h1", { className: styles.httpStatusCode, children: currentThrowable?.status || 500 }), jsxRuntime_1(OutsideClickHandler, { onOutsideClick: () => bootstrap.setState(currentState => ({ backendThrowable: currentState.backendThrowable.slice(1) })), children: jsxRuntime_1("div", { className: styles.centeredContainer, children: Object.keys(currentThrowable).map((key, index) => {
1414
+ var BackendThrowable = (props) => {
1415
+ const { instance } = props;
1416
+ const currentThrowable = instance.state.backendThrowable[0];
1417
+ console.log([instance.state.backendThrowable, currentThrowable]);
1418
+ return jsxRuntime_2("div", { className: styles.maintenanceHero, children: [jsxRuntime_1("h1", { className: styles.httpStatusCode, children: currentThrowable?.status || 500 }), jsxRuntime_1(OutsideClickHandler, { onOutsideClick: () => instance.setState(currentState => ({ backendThrowable: currentState.backendThrowable.slice(1) })), children: jsxRuntime_1("div", { className: styles.centeredContainer, children: Object.keys(currentThrowable).map((key, index) => {
1419
1419
  const valueIsString = typeof currentThrowable[key] === 'string';
1420
1420
  const valueIsCode = 'THROWN NEAR' === key;
1421
1421
  return jsxRuntime_2("div", { children: [jsxRuntime_2("div", { className: styles.errorTextGeneral, children: [" > ", jsxRuntime_1("span", { className: styles.errorKeys, children: key }), ":", valueIsString
@@ -3924,14 +3924,14 @@ function Popup({ open = true, handleClose, children, maxWidth, }) {
3924
3924
  const isProduction = window.location.host.split(".")[0] === "www";
3925
3925
 
3926
3926
  function addAlert(props) {
3927
- CarbonReact.instance.setState(previousState => ({
3927
+ props.instance.setState(previousState => ({
3928
3928
  alertsWaiting: previousState.alertsWaiting.length === 0
3929
3929
  ? [props]
3930
3930
  : [...previousState.alertsWaiting, props]
3931
3931
  }));
3932
3932
  }
3933
- function Alert() {
3934
- const { alertsWaiting, backendThrowable } = CarbonReact.instance.state;
3933
+ function Alert({ instance }) {
3934
+ const { alertsWaiting, backendThrowable } = instance.state;
3935
3935
  let alert = undefined;
3936
3936
  const alertWaiting = alertsWaiting.length + backendThrowable.length;
3937
3937
  if (backendThrowable.length !== 0) {
@@ -3946,8 +3946,9 @@ function Alert() {
3946
3946
  color: 'primary',
3947
3947
  });
3948
3948
  }
3949
- const backendThrowable = CarbonReact.instance.state.backendThrowable[0];
3949
+ const backendThrowable = instance.state.backendThrowable[0];
3950
3950
  alert = {
3951
+ instance: instance,
3951
3952
  title: "Oh no! An issue occurred!",
3952
3953
  text: backendThrowable?.['DropInGaming\\PHP\\Errors\\DropException'] ?? 'An unknown issue occurred. Please try again.',
3953
3954
  timeout: 0,
@@ -3958,7 +3959,7 @@ function Alert() {
3958
3959
  backendThrowable: backendThrowable,
3959
3960
  then: (value) => {
3960
3961
  if (value === 'Expand') {
3961
- CarbonReact.instance.setState(previousState => {
3962
+ instance.setState(previousState => {
3962
3963
  let backendThrowable = previousState.backendThrowable.pop();
3963
3964
  if (backendThrowable === undefined) {
3964
3965
  return {
@@ -3972,7 +3973,7 @@ function Alert() {
3972
3973
  });
3973
3974
  }
3974
3975
  else {
3975
- CarbonReact.instance.setState(previousState => ({
3976
+ instance.setState(previousState => ({
3976
3977
  backendThrowable: previousState.backendThrowable.slice(1)
3977
3978
  }));
3978
3979
  }
@@ -3986,15 +3987,14 @@ function Alert() {
3986
3987
  return null;
3987
3988
  }
3988
3989
  const timeout = alert?.timeout || 15000;
3989
- const bootstrap = CarbonReact.instance;
3990
- const dig = getStyles();
3990
+ const styles = getStyles();
3991
3991
  let cancelTimeout = null;
3992
3992
  const handleClose = () => {
3993
3993
  if (null !== cancelTimeout) {
3994
3994
  clearTimeout(cancelTimeout);
3995
3995
  }
3996
3996
  if (alert?.backendThrowable === undefined) {
3997
- bootstrap.setState(previousState => ({
3997
+ instance.setState(previousState => ({
3998
3998
  alertsWaiting: previousState.alertsWaiting.slice(1)
3999
3999
  }));
4000
4000
  }
@@ -4008,25 +4008,26 @@ function Alert() {
4008
4008
  handleClose();
4009
4009
  }, timeout);
4010
4010
  }
4011
- return jsxRuntime_1(Popup, { handleClose: handleClose, children: jsxRuntime_2("div", { className: classNames("model-content", dig.rounded0, dig.border0), style: {
4011
+ return jsxRuntime_1(Popup, { handleClose: handleClose, children: jsxRuntime_2("div", { className: classNames("model-content", styles.rounded0, styles.border0), style: {
4012
4012
  maxWidth: '75vw',
4013
4013
  maxHeight: '75vh',
4014
- }, children: [jsxRuntime_2("div", { className: classNames(dig.modalHeader, dig.rounded0, dig.border0, {
4014
+ }, children: [jsxRuntime_2("div", { className: classNames(styles.modalHeader, styles.rounded0, styles.border0, {
4015
4015
  // icon?: "warning" | "error" | "success" | "info" | "question"
4016
- [dig.bg_primary]: "info" === alert.icon || alert.icon === undefined || alert.icon === null,
4017
- [dig.bg_success]: "success" === alert.icon,
4018
- [dig.bg_warning]: "warning" === alert.icon,
4019
- [dig.bg_danger]: "error" === alert.icon, // TODO - change to red
4020
- [dig.bgPrimary]: "question" === alert.icon,
4021
- }), children: [jsxRuntime_2("h3", { className: classNames(dig.modalTitle, dig.textDark), id: "staticBackdropLabel", children: ["#", alertWaiting, " ", alert.title] }), jsxRuntime_1("div", { onClick: handleClose, children: jsxRuntime_1(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faClose, size: 'xl' }) })] }), jsxRuntime_1("div", { className: classNames(dig.modalBody, dig.border0, dig.textWhite), children: jsxRuntime_2("div", { className: dig.textCenter, children: [alert.text, alert.component] }) }), undefined !== alert.buttons &&
4022
- jsxRuntime_2("div", { className: classNames(dig.modalFooter, dig.border0, dig.rounded0), children: [alert.footerText && jsxRuntime_1("div", { className: classNames(dig.textCenter, dig.textWhite), children: alert.footerText }), alert.buttons?.map((button, index) => {
4023
- return jsxRuntime_1("button", { className: classNames(dig.btn, dig.btnLg, {
4016
+ [styles.bg_primary]: "info" === alert.icon || alert.icon === undefined || alert.icon === null,
4017
+ [styles.bg_success]: "success" === alert.icon,
4018
+ [styles.bg_warning]: "warning" === alert.icon,
4019
+ [styles.bg_danger]: "error" === alert.icon, // TODO - change to red
4020
+ [styles.bgPrimary]: "question" === alert.icon,
4021
+ }), children: [jsxRuntime_2("h3", { className: classNames(styles.modalTitle, styles.textDark), id: "staticBackdropLabel", children: ["#", alertWaiting, " ", alert.title] }), jsxRuntime_1("div", { onClick: handleClose, children: jsxRuntime_1(reactFontawesome.FontAwesomeIcon, { icon: freeSolidSvgIcons.faClose, size: 'xl' }) })] }), jsxRuntime_1("div", { className: classNames(styles.modalBody, styles.border0, styles.textWhite), children: jsxRuntime_2("div", { className: styles.textCenter, children: [alert.text, alert.component] }) }), undefined !== alert.buttons &&
4022
+ jsxRuntime_2("div", { className: classNames(styles.modalFooter, styles.border0, styles.rounded0), children: [alert.footerText &&
4023
+ jsxRuntime_1("div", { className: classNames(styles.textCenter, styles.textWhite), children: alert.footerText }), alert.buttons?.map((button, index) => {
4024
+ return jsxRuntime_1("button", { className: classNames(styles.btn, styles.btnLg, {
4024
4025
  // todo - color: "default" | "primary" | "secondary" | "inherit" | "danger" | "info" | "success" | "warning" | undefined,
4025
- [dig.bg_success]: "success" === button.color,
4026
- [dig.bg_danger]: "danger" === button.color,
4027
- [dig.bg_primary]: "primary" === button.color,
4028
- [dig.bg_warning]: "warning" === button.color,
4029
- }, "btn-Yes", dig.rounded0), onClick: () => {
4026
+ [styles.bg_success]: "success" === button.color,
4027
+ [styles.bg_danger]: "danger" === button.color,
4028
+ [styles.bg_primary]: "primary" === button.color,
4029
+ [styles.bg_warning]: "warning" === button.color,
4030
+ }, "btn-Yes", styles.rounded0), onClick: () => {
4030
4031
  handleClose();
4031
4032
  alert?.then?.(button.value ?? button.text);
4032
4033
  }, children: button.text }, index);
@@ -4064,14 +4065,16 @@ const useEffectOnce = (effect) => {
4064
4065
  * @function connect
4065
4066
  * This function establishes a connection with the websocket and also ensures constant reconnection if connection closes
4066
4067
  **/
4067
- function initiateWebsocket({ TABLES = undefined, WsLiveUpdates = undefined, url = 'ws' + (window.location.protocol === 'https:' ? 's' : '') + '://' + window.location.host + '/carbonorm/websocket', timeoutSeconds = 250, heartbeatSeconds = 60 } = {}) {
4068
- const { websocket } = CarbonReact.instance.state;
4068
+ function initiateWebsocket(props) {
4069
+ let { instance, TABLES = undefined, WsLiveUpdates = undefined, url = 'ws' + (window.location.protocol === 'https:' ? 's' : '') + '://' + window.location.host + '/carbonorm/websocket', timeoutSeconds = 250, heartbeatSeconds = 60 } = props;
4070
+ const { websocket } = instance.state;
4069
4071
  if (!("WebSocket" in window)) {
4070
4072
  // todo - store that this has been shown in the state
4071
4073
  addAlert({
4072
4074
  title: 'Browser does not support websockets, live updates will fail. You may need to refresh the page to see the newest content.',
4073
4075
  text: 'Please use a modern browser.',
4074
4076
  icon: 'warning',
4077
+ instance
4075
4078
  });
4076
4079
  }
4077
4080
  if (false === (undefined === websocket || null === websocket)) {
@@ -4080,14 +4083,14 @@ function initiateWebsocket({ TABLES = undefined, WsLiveUpdates = undefined, url
4080
4083
  let connectInterval;
4081
4084
  const connection = new WebSocket(url);
4082
4085
  console.log("Connecting websocket url", url);
4083
- CarbonReact.instance.setState({
4086
+ instance.setState({
4084
4087
  websocket: connection
4085
4088
  }, () => {
4086
4089
  connection.onopen = () => {
4087
4090
  console.log('WebSocket Client Connected To :: ' + url);
4088
4091
  clearTimeout(connectInterval); // clear Interval on open of websocket connection
4089
4092
  function heartbeat() {
4090
- const { websocket } = CarbonReact.instance.state;
4093
+ const { websocket } = instance.state;
4091
4094
  if (!websocket)
4092
4095
  return;
4093
4096
  if (websocket.readyState !== 1)
@@ -4102,7 +4105,7 @@ function initiateWebsocket({ TABLES = undefined, WsLiveUpdates = undefined, url
4102
4105
  if (message.data === 'pong') {
4103
4106
  return;
4104
4107
  }
4105
- CarbonReact.instance.setState((prevState) => ({
4108
+ instance.setState((prevState) => ({
4106
4109
  websocketEvents: prevState.websocketEvents.concat(message),
4107
4110
  websocketData: prevState.websocketData.concat(parsedData), // JSON.parse no good - base64?
4108
4111
  }), () => {
@@ -4126,7 +4129,7 @@ function initiateWebsocket({ TABLES = undefined, WsLiveUpdates = undefined, url
4126
4129
  }
4127
4130
  console.log('todo - going to impl REST', TABLE_NAME, METHOD, REQUEST_PRIMARY_KEY, parsedData?.REST);
4128
4131
  const TABLE_NAME_SHORT = TABLE_NAME.substring(TABLE_PREFIX.length);
4129
- const currentCache = CarbonReact.instance.state[TABLE_NAME_SHORT];
4132
+ const currentCache = instance.state[TABLE_NAME_SHORT];
4130
4133
  // just because we have a websocket update, doesn't mean we need the update
4131
4134
  // check to see if the primary key is in the current cache
4132
4135
  const c6Table = TABLES[TABLE_NAME_SHORT] ?? null;
@@ -4163,7 +4166,7 @@ function initiateWebsocket({ TABLES = undefined, WsLiveUpdates = undefined, url
4163
4166
  }
4164
4167
  });
4165
4168
  };
4166
- window.addEventListener("focus", () => initiateWebsocket());
4169
+ window.addEventListener("focus", () => initiateWebsocket(props));
4167
4170
  // websocket onclose event listener
4168
4171
  connection.addEventListener('close', event => {
4169
4172
  let reason;
@@ -4172,7 +4175,7 @@ function initiateWebsocket({ TABLES = undefined, WsLiveUpdates = undefined, url
4172
4175
  const retrySeconds = Math.min(5000, (timeoutSeconds + timeoutSeconds) * 1000);
4173
4176
  timeoutSeconds = retrySeconds;
4174
4177
  console.log(`WebSocket reconnect will be attempted in ${retrySeconds} second(s).`);
4175
- connectInterval = setTimeout(() => initiateWebsocket(), retrySeconds);
4178
+ connectInterval = setTimeout(() => initiateWebsocket(props), retrySeconds);
4176
4179
  };
4177
4180
  // See https://www.rfc-editor.org/rfc/rfc6455#section-7.4.1
4178
4181
  switch (event.code) {
@@ -4236,6 +4239,106 @@ function CarbonWebSocket (props) {
4236
4239
  return null;
4237
4240
  }
4238
4241
 
4242
+ exports.eUpdateInsertMethod = void 0;
4243
+ (function (eUpdateInsertMethod) {
4244
+ eUpdateInsertMethod[eUpdateInsertMethod["REPLACE"] = 0] = "REPLACE";
4245
+ eUpdateInsertMethod[eUpdateInsertMethod["FIRST"] = 1] = "FIRST";
4246
+ eUpdateInsertMethod[eUpdateInsertMethod["LAST"] = 2] = "LAST";
4247
+ })(exports.eUpdateInsertMethod || (exports.eUpdateInsertMethod = {}));
4248
+ /**
4249
+ * Updates or inserts objects in a stateful array, merging new data with existing objects.
4250
+ * @param instance - The React component instance.
4251
+ * @param dataOrCallback - Array of objects or a callback function returning an array of objects.
4252
+ * @param stateKey - The key in the state where the data array is stored.
4253
+ * @param uniqueObjectId - The unique identifier(s) for objects, typically the primary key of the table.
4254
+ * @param insertUpdateOrder - The order in which new data should be inserted/updated.
4255
+ * @param callback - Optional callback function to run after state update.
4256
+ */
4257
+ function updateRestfulObjectArrays({ instance, dataOrCallback, stateKey, uniqueObjectId, insertUpdateOrder = exports.eUpdateInsertMethod.LAST, callback, }) {
4258
+ const uniqueObjectIds = Array.isArray(uniqueObjectId) ? uniqueObjectId : [uniqueObjectId];
4259
+ instance.setState((previousBootstrapState, props) => {
4260
+ let newOrReplacementData = [];
4261
+ if (Array.isArray(dataOrCallback)) {
4262
+ newOrReplacementData = dataOrCallback;
4263
+ }
4264
+ else if (typeof dataOrCallback === "function") {
4265
+ newOrReplacementData = dataOrCallback(previousBootstrapState, props);
4266
+ }
4267
+ else {
4268
+ throw new Error("The dataOrCallback parameter must be an array or function");
4269
+ }
4270
+ if (newOrReplacementData === null) {
4271
+ return null;
4272
+ }
4273
+ const findUniqueObjectIds = (item, value) => {
4274
+ return uniqueObjectIds.every((id) => item[id] === value[id]);
4275
+ };
4276
+ const previousStateProperty = previousBootstrapState[stateKey] ?? [];
4277
+ let updatedData = newOrReplacementData.map((value) => {
4278
+ const existingObject = previousStateProperty?.find((item) => findUniqueObjectIds(item, value)) || {};
4279
+ return { ...existingObject, ...value };
4280
+ });
4281
+ const filterOutUpdated = (array) => {
4282
+ return array?.filter((item) => !updatedData.some((value) => findUniqueObjectIds(item, value))) ?? [];
4283
+ };
4284
+ let newState = {};
4285
+ switch (insertUpdateOrder) {
4286
+ case exports.eUpdateInsertMethod.LAST:
4287
+ newState[stateKey] = [
4288
+ ...filterOutUpdated(previousStateProperty),
4289
+ ...updatedData,
4290
+ ];
4291
+ break;
4292
+ case exports.eUpdateInsertMethod.FIRST:
4293
+ newState[stateKey] = [
4294
+ ...updatedData,
4295
+ ...filterOutUpdated(previousStateProperty),
4296
+ ];
4297
+ break;
4298
+ case exports.eUpdateInsertMethod.REPLACE:
4299
+ newState[stateKey] = [
4300
+ ...(previousStateProperty?.map((oldObject) => {
4301
+ const index = updatedData.findIndex((item) => findUniqueObjectIds(item, oldObject));
4302
+ if (index !== -1) {
4303
+ return updatedData.splice(index, 1)[0];
4304
+ }
4305
+ return oldObject;
4306
+ }) ?? []),
4307
+ ...updatedData,
4308
+ ];
4309
+ break;
4310
+ default:
4311
+ throw new Error("The insertUpdateOrder (eUpdateInsertMethod) was not implemented");
4312
+ }
4313
+ return newState;
4314
+ }, callback);
4315
+ }
4316
+
4317
+ function deleteRestfulObjectArrays({ instance, dataOrCallback, stateKey, uniqueObjectId, callback }) {
4318
+ const uniqueObjectIds = Array.isArray(uniqueObjectId) ? uniqueObjectId : [uniqueObjectId];
4319
+ instance.setState((previousBootstrapState, props) => {
4320
+ let newOrReplacementData = [];
4321
+ if (Array.isArray(dataOrCallback)) {
4322
+ newOrReplacementData = dataOrCallback;
4323
+ }
4324
+ else if (typeof dataOrCallback === 'function') {
4325
+ const callbackReturn = dataOrCallback(previousBootstrapState, props);
4326
+ if (callbackReturn === null) {
4327
+ return null; // No updates needed (noop)
4328
+ }
4329
+ newOrReplacementData = callbackReturn;
4330
+ }
4331
+ else {
4332
+ throw new Error('The dataOrCallback parameter was not an array or function');
4333
+ }
4334
+ const previousStateProperty = previousBootstrapState[stateKey];
4335
+ const updatedStateProperty = previousStateProperty?.filter(item => !newOrReplacementData.some(value => uniqueObjectIds.every(uniqueId => value[uniqueId] === item[uniqueId]))) ?? [];
4336
+ return {
4337
+ [stateKey]: updatedStateProperty
4338
+ };
4339
+ }, callback);
4340
+ }
4341
+
4239
4342
  const initialRequiredCarbonORMState = {
4240
4343
  alertsWaiting: [],
4241
4344
  backendThrowable: [],
@@ -4256,27 +4359,32 @@ function isJsonString(str) {
4256
4359
  }
4257
4360
  return true;
4258
4361
  }
4259
- // Create a context
4260
4362
  const persistentStateMap = new Map();
4261
4363
  class CarbonReact extends react.Component {
4262
4364
  context = react.createContext(this.state);
4263
4365
  // Private static member
4366
+ // we actually implement this in the constructor todo - test this
4264
4367
  static instance;
4265
- static getState() {
4266
- return CarbonReact.instance.state;
4267
- }
4268
- static useContext() {
4269
- return () => react.useContext(CarbonReact.instance.context);
4270
- }
4271
- protected;
4368
+ target;
4369
+ updateRestfulObjectArrays = (rest) => updateRestfulObjectArrays({
4370
+ instance: this,
4371
+ ...rest
4372
+ });
4373
+ deleteRestfulObjectArrays = (rest) => deleteRestfulObjectArrays({
4374
+ instance: this,
4375
+ ...rest
4376
+ });
4272
4377
  static lastLocation = window.location.pathname;
4273
4378
  // @link https://github.com/welldone-software/why-did-you-render
4274
4379
  // noinspection JSUnusedGlobalSymbols
4275
4380
  static whyDidYouRender = true;
4276
4381
  constructor(props) {
4277
4382
  super(props);
4383
+ this.target = new.target;
4278
4384
  console.log('CarbonORM TSX CONSTRUCTOR');
4279
- Object.assign(this, {
4385
+ // this is the magic that allows each class that's extends this to have a static instance - a singleton pattern
4386
+ // new.target is a meta-property introduced in ES6 that references the constructor that was directly invoked with the new keyword.
4387
+ Object.assign(new.target, {
4280
4388
  instance: this
4281
4389
  });
4282
4390
  if (this.props.instanceId && persistentStateMap.has(this.props.instanceId)) {
@@ -4321,11 +4429,11 @@ class CarbonReact extends react.Component {
4321
4429
  console.log('%c color (' + colorHex + ')', 'color: ' + colorHex);
4322
4430
  const nest = jsxRuntime_1(Nest, { position: 'fixed', backgroundColor: '', color: hexToRgb(colorHex), count: 100 });
4323
4431
  if (this.state.backendThrowable.length > 0) {
4324
- return jsxRuntime_2(jsxRuntime_3, { children: [nest, jsxRuntime_1(BackendThrowable, {})] });
4432
+ return jsxRuntime_2(jsxRuntime_3, { children: [nest, jsxRuntime_1(BackendThrowable, { instance: CarbonReact.instance })] });
4325
4433
  }
4326
4434
  const Context = this.context.Provider;
4327
4435
  return jsxRuntime_2(jsxRuntime_3, { children: [jsxRuntime_1(GlobalHistory, {}), this.props.websocket &&
4328
- jsxRuntime_1(CarbonWebSocket, { ...(true === this.props.websocket ? {} : this.props.websocket) }), jsxRuntime_1(Context, { value: this.state, children: this.props.children }), jsxRuntime_1(reactToastify.ToastContainer, {})] });
4436
+ jsxRuntime_1(CarbonWebSocket, { ...(true === this.props.websocket ? {} : this.props.websocket), instance: CarbonReact.instance }), jsxRuntime_1(Context, { value: this.state, children: this.props.children }), jsxRuntime_1(reactToastify.ToastContainer, {})] });
4329
4437
  }
4330
4438
  }
4331
4439
 
@@ -4384,44 +4492,6 @@ function addValidSQL$1 (sql) {
4384
4492
  addValidSQL.push({ [expect.getState().currentTestName.replaceAll(" ", "_").toLowerCase()]: sql });
4385
4493
  }
4386
4494
 
4387
- //ObjectType, UniqueIdType extends keyof ObjectType
4388
- // @link https://www.typescriptlang.org/docs/handbook/2/mapped-types.html
4389
- function deleteRestfulObjectArrays(dataOrCallback, stateKey, uniqueObjectId, callback) {
4390
- const uniqueObjectIds = uniqueObjectId instanceof Array ? uniqueObjectId : [uniqueObjectId];
4391
- return CarbonReact.instance.setState((previousBootstrapState, props) => {
4392
- let newOrReplacementData = [];
4393
- if (dataOrCallback instanceof Array) {
4394
- newOrReplacementData = dataOrCallback;
4395
- }
4396
- else if (dataOrCallback instanceof Function) {
4397
- let callbackReturn = dataOrCallback(previousBootstrapState, props);
4398
- if (null === callbackReturn) {
4399
- return;
4400
- }
4401
- newOrReplacementData = callbackReturn;
4402
- }
4403
- else {
4404
- throw Error('The dataOrCallback parameter was not an array or function');
4405
- }
4406
- const previousStateProperty = previousBootstrapState[stateKey];
4407
- return {
4408
- [stateKey]: [
4409
- ...previousStateProperty?.filter(item => false === (newOrReplacementData?.find(value => {
4410
- let isMatch = true;
4411
- uniqueObjectIds.find(uniqueObjectId => {
4412
- if (value[uniqueObjectId] !== item[uniqueObjectId]) {
4413
- isMatch = false;
4414
- return true;
4415
- }
4416
- return false;
4417
- });
4418
- return isMatch;
4419
- }) || false)) || []
4420
- ]
4421
- };
4422
- }, callback);
4423
- }
4424
-
4425
4495
  // @link https://stackoverflow.com/questions/31721250/how-to-target-edge-browser-with-javascript
4426
4496
  // Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) \
4427
4497
  // Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.26
@@ -4561,89 +4631,6 @@ function setupTests ({ sqlDirectory = './logs/rest/', logsDirectory = './logs/te
4561
4631
  }, 65000);
4562
4632
  }
4563
4633
 
4564
- exports.eUpdateInsertMethod = void 0;
4565
- (function (eUpdateInsertMethod) {
4566
- eUpdateInsertMethod[eUpdateInsertMethod["REPLACE"] = 0] = "REPLACE";
4567
- eUpdateInsertMethod[eUpdateInsertMethod["FIRST"] = 1] = "FIRST";
4568
- eUpdateInsertMethod[eUpdateInsertMethod["LAST"] = 2] = "LAST";
4569
- })(exports.eUpdateInsertMethod || (exports.eUpdateInsertMethod = {}));
4570
- /**
4571
- *
4572
- * merged with existing objects.uniqueObjectId || {}.
4573
- * @param dataOrCallback
4574
- * @param uniqueObjectId - the uniqueObjectId of the object to update; typically the primary key of the table.
4575
- * @param stateKey -
4576
- * @param insertUpdateOrder
4577
- * @param callback - if you want to do something with the updated state, you can pass a callback here. Run as the second
4578
- * parameter of setState.
4579
- */
4580
- function updateRestfulObjectArrays(dataOrCallback, stateKey, uniqueObjectId, insertUpdateOrder = exports.eUpdateInsertMethod.LAST, callback) {
4581
- const uniqueObjectIds = uniqueObjectId instanceof Array ? uniqueObjectId : [uniqueObjectId];
4582
- const bootstrap = CarbonReact.instance;
4583
- return bootstrap.setState((previousBootstrapState, props) => {
4584
- let newOrReplacementData = [];
4585
- if (dataOrCallback instanceof Array) {
4586
- newOrReplacementData = dataOrCallback;
4587
- }
4588
- else if (dataOrCallback instanceof Function) {
4589
- newOrReplacementData = dataOrCallback(previousBootstrapState, props);
4590
- }
4591
- else {
4592
- throw Error('The dataOrCallback parameter was not an array or function');
4593
- }
4594
- const findUniqueObjectIds = (item, value) => {
4595
- let isMatch = true;
4596
- uniqueObjectIds.find(uniqueObjectId => {
4597
- if (value[uniqueObjectId] !== item[uniqueObjectId]) {
4598
- isMatch = false;
4599
- return true;
4600
- }
4601
- return false;
4602
- });
4603
- return isMatch;
4604
- };
4605
- const previousStateProperty = previousBootstrapState[stateKey];
4606
- let updatedData = newOrReplacementData?.map(value => {
4607
- return {
4608
- ...previousStateProperty?.find(previousValue => findUniqueObjectIds(previousValue, value)) || {},
4609
- ...value
4610
- };
4611
- }) ?? [];
4612
- switch (insertUpdateOrder) {
4613
- default:
4614
- throw Error('The insertUpdateOrder (eUpdateInsertMethod) was not implemented');
4615
- case exports.eUpdateInsertMethod.LAST:
4616
- return {
4617
- [stateKey]: null === newOrReplacementData ? null : [
4618
- ...updatedData,
4619
- ...(previousStateProperty?.filter(item => false === (updatedData?.find(value => findUniqueObjectIds(item, value)) || false)) ?? [])
4620
- ]
4621
- };
4622
- case exports.eUpdateInsertMethod.FIRST:
4623
- return {
4624
- [stateKey]: null === newOrReplacementData ? null : [
4625
- ...(previousStateProperty?.filter(item => false === (updatedData?.find(value => findUniqueObjectIds(item, value)) || false)) ?? []),
4626
- ...updatedData,
4627
- ]
4628
- };
4629
- case exports.eUpdateInsertMethod.REPLACE: {
4630
- return {
4631
- [stateKey]: [
4632
- ...(previousStateProperty?.map(oldObject => {
4633
- const index = updatedData.findIndex(item => findUniqueObjectIds(item, oldObject));
4634
- if (-1 === index) {
4635
- return oldObject;
4636
- }
4637
- return updatedData.splice(index, 1).pop();
4638
- }) ?? []),
4639
- ...updatedData
4640
- ]
4641
- };
4642
- }
4643
- }
4644
- }, callback);
4645
- }
4646
-
4647
4634
  // @link https://stackoverflow.com/questions/6735414/php-data-uri-to-file
4648
4635
  // @link https://www.tutorialspoint.com/convert-image-to-data-uri-with-javascript
4649
4636
  async function toDataURL(src, fileType, callback) {