@vuu-ui/vuu-shell 0.7.0-debug → 0.7.1-debug
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/cjs/index.js +460 -117
- package/cjs/index.js.map +4 -4
- package/esm/index.js +464 -108
- package/esm/index.js.map +4 -4
- package/index.css +47 -0
- package/index.css.map +3 -3
- package/package.json +4 -4
- package/types/index.d.ts +1 -0
- package/types/layout-config/index.d.ts +1 -0
- package/types/layout-config/local-config.d.ts +4 -0
- package/types/layout-config/remote-config.d.ts +4 -0
- package/types/layout-config/use-layout-config.d.ts +15 -0
- package/types/session-editing-form/SessionEditingForm.d.ts +25 -0
- package/types/session-editing-form/index.d.ts +1 -0
- package/types/shell.d.ts +4 -1
- package/types/shellTypes.d.ts +1 -0
- package/types/use-layout-config.d.ts +0 -2
package/esm/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import React, { useEffect, useState } from "react";
|
|
|
3
3
|
import cx from "classnames";
|
|
4
4
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
5
5
|
var ConnectionStatusIcon = ({ connectionStatus, className, element = "span", ...props }) => {
|
|
6
|
-
const [
|
|
6
|
+
const [classBase6, setClassBase] = useState("vuuConnectingStatus");
|
|
7
7
|
useEffect(() => {
|
|
8
8
|
switch (connectionStatus) {
|
|
9
9
|
case "connected":
|
|
@@ -24,7 +24,7 @@ var ConnectionStatusIcon = ({ connectionStatus, className, element = "span", ...
|
|
|
24
24
|
element,
|
|
25
25
|
{
|
|
26
26
|
...props,
|
|
27
|
-
className: cx("vuuStatus vuuIcon",
|
|
27
|
+
className: cx("vuuStatus vuuIcon", classBase6, className)
|
|
28
28
|
}
|
|
29
29
|
);
|
|
30
30
|
return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs("div", { className: "vuuStatus-container salt-theme", children: [
|
|
@@ -65,7 +65,7 @@ var DensitySwitch = ({
|
|
|
65
65
|
};
|
|
66
66
|
|
|
67
67
|
// src/feature/Feature.tsx
|
|
68
|
-
import React3, { Suspense } from "react";
|
|
68
|
+
import React3, { Suspense, useEffect as useEffect2 } from "react";
|
|
69
69
|
import { registerComponent } from "@vuu-ui/vuu-layout";
|
|
70
70
|
|
|
71
71
|
// src/feature/ErrorBoundary.jsx
|
|
@@ -76,11 +76,11 @@ var ErrorBoundary = class extends React2.Component {
|
|
|
76
76
|
super(props);
|
|
77
77
|
this.state = { errorMessage: null };
|
|
78
78
|
}
|
|
79
|
-
static getDerivedStateFromError(
|
|
80
|
-
return { errorMessage:
|
|
79
|
+
static getDerivedStateFromError(error2) {
|
|
80
|
+
return { errorMessage: error2.message };
|
|
81
81
|
}
|
|
82
|
-
componentDidCatch(
|
|
83
|
-
console.log(
|
|
82
|
+
componentDidCatch(error2, errorInfo) {
|
|
83
|
+
console.log(error2, errorInfo);
|
|
84
84
|
}
|
|
85
85
|
render() {
|
|
86
86
|
if (this.state.errorMessage) {
|
|
@@ -99,18 +99,45 @@ var Loader = () => /* @__PURE__ */ jsx4("div", { className: "hwLoader", children
|
|
|
99
99
|
|
|
100
100
|
// src/feature/Feature.tsx
|
|
101
101
|
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
102
|
+
var componentsMap = /* @__PURE__ */ new Map();
|
|
103
|
+
var useCachedFeature = (url) => {
|
|
104
|
+
useEffect2(
|
|
105
|
+
() => () => {
|
|
106
|
+
componentsMap.delete(url);
|
|
107
|
+
},
|
|
108
|
+
[url]
|
|
109
|
+
);
|
|
110
|
+
if (!componentsMap.has(url)) {
|
|
111
|
+
componentsMap.set(
|
|
112
|
+
url,
|
|
113
|
+
React3.lazy(() => import(
|
|
114
|
+
/* @vite-ignore */
|
|
115
|
+
url
|
|
116
|
+
))
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
return componentsMap.get(url);
|
|
120
|
+
};
|
|
102
121
|
function RawFeature({
|
|
103
122
|
url,
|
|
104
123
|
css,
|
|
105
124
|
params,
|
|
106
125
|
...props
|
|
107
126
|
}) {
|
|
127
|
+
console.log("Feature render", { css, url, props });
|
|
128
|
+
useEffect2(() => {
|
|
129
|
+
console.log("%cFeature mount", "color: green;");
|
|
130
|
+
return () => {
|
|
131
|
+
console.log("%cFeature unmount", "color:red;");
|
|
132
|
+
};
|
|
133
|
+
}, []);
|
|
108
134
|
if (css) {
|
|
109
135
|
import(
|
|
110
136
|
/* @vite-ignore */
|
|
111
137
|
css
|
|
112
138
|
).then(
|
|
113
139
|
(cssModule) => {
|
|
140
|
+
console.log("%cInject Styles", "color: blue;font-weight: bold");
|
|
114
141
|
document.adoptedStyleSheets = [
|
|
115
142
|
...document.adoptedStyleSheets,
|
|
116
143
|
cssModule.default
|
|
@@ -118,10 +145,7 @@ function RawFeature({
|
|
|
118
145
|
}
|
|
119
146
|
);
|
|
120
147
|
}
|
|
121
|
-
const LazyFeature =
|
|
122
|
-
/* @vite-ignore */
|
|
123
|
-
url
|
|
124
|
-
));
|
|
148
|
+
const LazyFeature = useCachedFeature(url);
|
|
125
149
|
return /* @__PURE__ */ jsx5(ErrorBoundary, { children: /* @__PURE__ */ jsx5(Suspense, { fallback: /* @__PURE__ */ jsx5(Loader, {}), children: /* @__PURE__ */ jsx5(LazyFeature, { ...props, ...params }) }) });
|
|
126
150
|
}
|
|
127
151
|
var Feature = React3.memo(RawFeature);
|
|
@@ -187,19 +211,289 @@ var logout = (loginUrl) => {
|
|
|
187
211
|
redirectToLogin(loginUrl);
|
|
188
212
|
};
|
|
189
213
|
|
|
214
|
+
// src/session-editing-form/SessionEditingForm.tsx
|
|
215
|
+
import {
|
|
216
|
+
useCallback as useCallback2,
|
|
217
|
+
useEffect as useEffect3,
|
|
218
|
+
useMemo,
|
|
219
|
+
useRef,
|
|
220
|
+
useState as useState3
|
|
221
|
+
} from "react";
|
|
222
|
+
import cx3 from "classnames";
|
|
223
|
+
import { useIdMemo } from "@salt-ds/core";
|
|
224
|
+
import { Button as Button2 } from "@salt-ds/core";
|
|
225
|
+
import {
|
|
226
|
+
isErrorResponse,
|
|
227
|
+
RemoteDataSource
|
|
228
|
+
} from "@vuu-ui/vuu-data";
|
|
229
|
+
import {
|
|
230
|
+
buildColumnMap,
|
|
231
|
+
isValidNumber,
|
|
232
|
+
shallowEquals
|
|
233
|
+
} from "@vuu-ui/vuu-utils";
|
|
234
|
+
import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
235
|
+
var classBase3 = "vuuSessionEditingForm";
|
|
236
|
+
var getField = (fields, name) => {
|
|
237
|
+
const field = fields.find((f) => f.name === name);
|
|
238
|
+
if (field) {
|
|
239
|
+
return field;
|
|
240
|
+
} else {
|
|
241
|
+
throw Error(`SessionEditingForm, no field '${name}' found`);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
var getFieldNameAndValue = (evt) => {
|
|
245
|
+
const {
|
|
246
|
+
dataset: { field },
|
|
247
|
+
value
|
|
248
|
+
} = evt.target;
|
|
249
|
+
if (field === void 0) {
|
|
250
|
+
throw Error("SessionEditingForm, form field has no field name");
|
|
251
|
+
}
|
|
252
|
+
return [field, value];
|
|
253
|
+
};
|
|
254
|
+
var Status = {
|
|
255
|
+
uninitialised: 0,
|
|
256
|
+
unchanged: 1,
|
|
257
|
+
changed: 2,
|
|
258
|
+
invalid: 3
|
|
259
|
+
};
|
|
260
|
+
function getTypedValue(value, type, throwIfUndefined = false) {
|
|
261
|
+
switch (type) {
|
|
262
|
+
case "int":
|
|
263
|
+
case "long": {
|
|
264
|
+
const typedValue = parseInt(value, 10);
|
|
265
|
+
if (isValidNumber(typedValue)) {
|
|
266
|
+
return typedValue;
|
|
267
|
+
} else if (throwIfUndefined) {
|
|
268
|
+
throw Error("SessionEditingForm getTypedValue");
|
|
269
|
+
} else {
|
|
270
|
+
return void 0;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
case "double": {
|
|
274
|
+
const typedValue = parseFloat(value);
|
|
275
|
+
if (isValidNumber(typedValue)) {
|
|
276
|
+
return typedValue;
|
|
277
|
+
}
|
|
278
|
+
return void 0;
|
|
279
|
+
}
|
|
280
|
+
case "boolean":
|
|
281
|
+
return value === "true" ? true : false;
|
|
282
|
+
default:
|
|
283
|
+
return value;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
var getDataSource = (dataSource, schema) => {
|
|
287
|
+
if (dataSource) {
|
|
288
|
+
return dataSource;
|
|
289
|
+
} else if (schema) {
|
|
290
|
+
return new RemoteDataSource({
|
|
291
|
+
bufferSize: 0,
|
|
292
|
+
table: schema.table,
|
|
293
|
+
columns: schema.columns.map((col) => col.name)
|
|
294
|
+
});
|
|
295
|
+
} else {
|
|
296
|
+
throw Error(
|
|
297
|
+
"SessionEditingForm: either a DataSource or a TableSchema must be provided"
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
var SessionEditingForm = ({
|
|
302
|
+
className,
|
|
303
|
+
config: { fields, key: keyField },
|
|
304
|
+
dataSource: dataSourceProp,
|
|
305
|
+
id: idProp,
|
|
306
|
+
onClose,
|
|
307
|
+
schema,
|
|
308
|
+
...htmlAttributes
|
|
309
|
+
}) => {
|
|
310
|
+
const [values, setValues] = useState3();
|
|
311
|
+
const [errorMessage, setErrorMessage] = useState3("");
|
|
312
|
+
const formContentRef = useRef(null);
|
|
313
|
+
const initialDataRef = useRef();
|
|
314
|
+
const dataStatusRef = useRef(Status.uninitialised);
|
|
315
|
+
const dataSource = useMemo(() => {
|
|
316
|
+
const applyServerData = (data) => {
|
|
317
|
+
if (columnMap) {
|
|
318
|
+
const values2 = {};
|
|
319
|
+
for (const column of dataSource.columns) {
|
|
320
|
+
values2[column] = data[columnMap[column]];
|
|
321
|
+
}
|
|
322
|
+
if (dataStatusRef.current === Status.uninitialised) {
|
|
323
|
+
dataStatusRef.current = Status.unchanged;
|
|
324
|
+
initialDataRef.current = values2;
|
|
325
|
+
}
|
|
326
|
+
setValues(values2);
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
const ds = getDataSource(dataSourceProp, schema);
|
|
330
|
+
const columnMap = buildColumnMap(ds.columns);
|
|
331
|
+
ds.subscribe({ range: { from: 0, to: 5 } }, (message) => {
|
|
332
|
+
if (message.type === "viewport-update" && message.rows) {
|
|
333
|
+
if (dataStatusRef.current === Status.uninitialised) {
|
|
334
|
+
applyServerData(message.rows[0]);
|
|
335
|
+
} else {
|
|
336
|
+
console.log("what do we do with server updates");
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
return ds;
|
|
341
|
+
}, [dataSourceProp, schema]);
|
|
342
|
+
const id = useIdMemo(idProp);
|
|
343
|
+
const handleChange = useCallback2(
|
|
344
|
+
(evt) => {
|
|
345
|
+
const [field, value] = getFieldNameAndValue(evt);
|
|
346
|
+
const { type } = getField(fields, field);
|
|
347
|
+
const typedValue = getTypedValue(value, type);
|
|
348
|
+
setValues((values2 = {}) => {
|
|
349
|
+
const newValues = {
|
|
350
|
+
...values2,
|
|
351
|
+
[field]: typedValue
|
|
352
|
+
};
|
|
353
|
+
const notUpdated = shallowEquals(newValues, initialDataRef.current);
|
|
354
|
+
dataStatusRef.current = notUpdated ? Status.unchanged : typedValue !== void 0 ? Status.changed : Status.invalid;
|
|
355
|
+
return newValues;
|
|
356
|
+
});
|
|
357
|
+
},
|
|
358
|
+
[fields]
|
|
359
|
+
);
|
|
360
|
+
const handleBlur = useCallback2(
|
|
361
|
+
(evt) => {
|
|
362
|
+
const [field, value] = getFieldNameAndValue(evt);
|
|
363
|
+
const { type } = getField(fields, field);
|
|
364
|
+
console.log("BLUR", {
|
|
365
|
+
keyField
|
|
366
|
+
});
|
|
367
|
+
const rowKey = values == null ? void 0 : values[keyField];
|
|
368
|
+
const typedValue = getTypedValue(value, type, true);
|
|
369
|
+
if (typeof rowKey === "string") {
|
|
370
|
+
dataSource.menuRpcCall({
|
|
371
|
+
rowKey,
|
|
372
|
+
field,
|
|
373
|
+
value: typedValue,
|
|
374
|
+
type: "VP_EDIT_CELL_RPC"
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
[dataSource, fields, keyField, values]
|
|
379
|
+
);
|
|
380
|
+
const handleSubmit = useCallback2(async () => {
|
|
381
|
+
const response = await dataSource.menuRpcCall({
|
|
382
|
+
type: "VP_EDIT_SUBMIT_FORM_RPC"
|
|
383
|
+
});
|
|
384
|
+
if (isErrorResponse(response)) {
|
|
385
|
+
setErrorMessage(response.error);
|
|
386
|
+
}
|
|
387
|
+
}, [dataSource]);
|
|
388
|
+
const handleKeyDown = useCallback2(
|
|
389
|
+
(evt) => {
|
|
390
|
+
if (evt.key === "Enter" && dataStatusRef.current === Status.changed) {
|
|
391
|
+
handleSubmit();
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
[handleSubmit]
|
|
395
|
+
);
|
|
396
|
+
const handleCancel = useCallback2(() => {
|
|
397
|
+
onClose();
|
|
398
|
+
}, [onClose]);
|
|
399
|
+
const getFormControl = (field) => {
|
|
400
|
+
var _a;
|
|
401
|
+
const value = String((_a = values == null ? void 0 : values[field.name]) != null ? _a : "");
|
|
402
|
+
if (field.readonly || field.name === keyField) {
|
|
403
|
+
return /* @__PURE__ */ jsx7("div", { className: `${classBase3}-fieldValue vuuReadOnly`, children: value });
|
|
404
|
+
} else {
|
|
405
|
+
return /* @__PURE__ */ jsx7(
|
|
406
|
+
"input",
|
|
407
|
+
{
|
|
408
|
+
className: `${classBase3}-fieldValue`,
|
|
409
|
+
"data-field": field.name,
|
|
410
|
+
onBlur: handleBlur,
|
|
411
|
+
onChange: handleChange,
|
|
412
|
+
type: "text",
|
|
413
|
+
value,
|
|
414
|
+
id: `${id}-input-${field.name}`
|
|
415
|
+
}
|
|
416
|
+
);
|
|
417
|
+
}
|
|
418
|
+
};
|
|
419
|
+
useEffect3(() => {
|
|
420
|
+
if (formContentRef.current) {
|
|
421
|
+
const firstInput = formContentRef.current.querySelector(
|
|
422
|
+
"input"
|
|
423
|
+
);
|
|
424
|
+
if (firstInput) {
|
|
425
|
+
setTimeout(() => {
|
|
426
|
+
firstInput.focus();
|
|
427
|
+
console.log("select item");
|
|
428
|
+
firstInput.select();
|
|
429
|
+
}, 100);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}, []);
|
|
433
|
+
const isDirty = dataStatusRef.current === Status.changed;
|
|
434
|
+
return /* @__PURE__ */ jsxs4("div", { ...htmlAttributes, className: cx3(classBase3, className), children: [
|
|
435
|
+
errorMessage ? /* @__PURE__ */ jsx7(
|
|
436
|
+
"div",
|
|
437
|
+
{
|
|
438
|
+
className: `${classBase3}-errorBanner`,
|
|
439
|
+
"data-icon": "error",
|
|
440
|
+
title: errorMessage,
|
|
441
|
+
children: "Error, edit(s) not saved"
|
|
442
|
+
}
|
|
443
|
+
) : void 0,
|
|
444
|
+
/* @__PURE__ */ jsx7(
|
|
445
|
+
"div",
|
|
446
|
+
{
|
|
447
|
+
className: `${classBase3}-content`,
|
|
448
|
+
ref: formContentRef,
|
|
449
|
+
onKeyDown: handleKeyDown,
|
|
450
|
+
children: fields.map((field) => {
|
|
451
|
+
var _a;
|
|
452
|
+
return /* @__PURE__ */ jsxs4("div", { className: `${classBase3}-field`, children: [
|
|
453
|
+
/* @__PURE__ */ jsx7(
|
|
454
|
+
"label",
|
|
455
|
+
{
|
|
456
|
+
className: cx3(`${classBase3}-fieldLabel`, {
|
|
457
|
+
[`${classBase3}-required`]: field.required
|
|
458
|
+
}),
|
|
459
|
+
htmlFor: `${id}-input-${field.name}`,
|
|
460
|
+
children: (_a = field == null ? void 0 : field.label) != null ? _a : field.description
|
|
461
|
+
}
|
|
462
|
+
),
|
|
463
|
+
getFormControl(field)
|
|
464
|
+
] }, field.name);
|
|
465
|
+
})
|
|
466
|
+
}
|
|
467
|
+
),
|
|
468
|
+
/* @__PURE__ */ jsxs4("div", { className: `${classBase3}-buttonbar salt-theme salt-density-high`, children: [
|
|
469
|
+
/* @__PURE__ */ jsx7(
|
|
470
|
+
Button2,
|
|
471
|
+
{
|
|
472
|
+
type: "submit",
|
|
473
|
+
variant: "cta",
|
|
474
|
+
disabled: !isDirty,
|
|
475
|
+
onClick: handleSubmit,
|
|
476
|
+
children: "Submit"
|
|
477
|
+
}
|
|
478
|
+
),
|
|
479
|
+
/* @__PURE__ */ jsx7(Button2, { variant: "secondary", onClick: handleCancel, children: "Cancel" })
|
|
480
|
+
] })
|
|
481
|
+
] });
|
|
482
|
+
};
|
|
483
|
+
|
|
190
484
|
// src/shell.tsx
|
|
191
485
|
import { connectToServer } from "@vuu-ui/vuu-data";
|
|
192
|
-
import
|
|
486
|
+
import cx6 from "classnames";
|
|
193
487
|
import {
|
|
194
|
-
useCallback as
|
|
195
|
-
useEffect as
|
|
196
|
-
useRef,
|
|
197
|
-
useState as
|
|
488
|
+
useCallback as useCallback7,
|
|
489
|
+
useEffect as useEffect6,
|
|
490
|
+
useRef as useRef2,
|
|
491
|
+
useState as useState6
|
|
198
492
|
} from "react";
|
|
199
493
|
|
|
200
494
|
// src/ShellContextProvider.tsx
|
|
201
495
|
import { createContext, useContext } from "react";
|
|
202
|
-
import { jsx as
|
|
496
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
203
497
|
var defaultConfig = {};
|
|
204
498
|
var ShellContext = createContext(defaultConfig);
|
|
205
499
|
var Provider = ({
|
|
@@ -211,53 +505,106 @@ var Provider = ({
|
|
|
211
505
|
...inheritedContext,
|
|
212
506
|
...context
|
|
213
507
|
};
|
|
214
|
-
return /* @__PURE__ */
|
|
508
|
+
return /* @__PURE__ */ jsx8(ShellContext.Provider, { value: mergedContext, children });
|
|
215
509
|
};
|
|
216
510
|
var ShellContextProvider = ({
|
|
217
511
|
children,
|
|
218
512
|
value
|
|
219
513
|
}) => {
|
|
220
|
-
return /* @__PURE__ */
|
|
514
|
+
return /* @__PURE__ */ jsx8(ShellContext.Consumer, { children: (context) => /* @__PURE__ */ jsx8(Provider, { context: value, inheritedContext: context, children }) });
|
|
221
515
|
};
|
|
222
516
|
var useShellContext = () => {
|
|
223
517
|
return useContext(ShellContext);
|
|
224
518
|
};
|
|
225
519
|
|
|
226
|
-
// src/use-layout-config.
|
|
227
|
-
import { useCallback as
|
|
228
|
-
|
|
229
|
-
|
|
520
|
+
// src/layout-config/use-layout-config.ts
|
|
521
|
+
import { useCallback as useCallback3, useEffect as useEffect4, useState as useState4 } from "react";
|
|
522
|
+
|
|
523
|
+
// src/layout-config/local-config.ts
|
|
524
|
+
var loadLocalConfig = (saveUrl, user, id = "latest") => new Promise((resolve, reject) => {
|
|
525
|
+
console.log(
|
|
526
|
+
`load local config at ${saveUrl} for user ${user.username}, id ${id}`
|
|
527
|
+
);
|
|
528
|
+
const data = localStorage.getItem(saveUrl);
|
|
529
|
+
if (data) {
|
|
530
|
+
const layout = JSON.parse(data);
|
|
531
|
+
resolve(layout);
|
|
532
|
+
} else {
|
|
533
|
+
reject();
|
|
534
|
+
}
|
|
535
|
+
});
|
|
536
|
+
var saveLocalConfig = (saveUrl, user, data) => new Promise((resolve, reject) => {
|
|
537
|
+
try {
|
|
538
|
+
localStorage.setItem(saveUrl, JSON.stringify(data));
|
|
539
|
+
resolve(void 0);
|
|
540
|
+
} catch {
|
|
541
|
+
reject();
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
// src/layout-config/remote-config.ts
|
|
546
|
+
var loadRemoteConfig = (saveUrl, user, id = "latest") => new Promise((resolve, reject) => {
|
|
547
|
+
fetch(`${saveUrl}/${user.username}/${id}`, {}).then((response) => {
|
|
548
|
+
if (response.ok) {
|
|
549
|
+
resolve(response.json());
|
|
550
|
+
} else {
|
|
551
|
+
reject(void 0);
|
|
552
|
+
}
|
|
553
|
+
}).catch(() => {
|
|
554
|
+
reject(void 0);
|
|
555
|
+
});
|
|
556
|
+
});
|
|
557
|
+
var saveRemoteConfig = (saveUrl, user, data) => new Promise((resolve, reject) => {
|
|
558
|
+
fetch(`${saveUrl}/${user.username}`, {
|
|
559
|
+
method: "POST",
|
|
560
|
+
headers: {
|
|
561
|
+
"Content-Type": "application/json"
|
|
562
|
+
},
|
|
563
|
+
body: JSON.stringify(data)
|
|
564
|
+
}).then((response) => {
|
|
565
|
+
if (response.ok) {
|
|
566
|
+
resolve(void 0);
|
|
567
|
+
} else {
|
|
568
|
+
reject();
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
});
|
|
572
|
+
|
|
573
|
+
// src/layout-config/use-layout-config.ts
|
|
574
|
+
var useLayoutConfig = ({
|
|
575
|
+
saveLocation,
|
|
576
|
+
saveUrl = "api/vui",
|
|
577
|
+
user,
|
|
578
|
+
defaultLayout
|
|
579
|
+
}) => {
|
|
580
|
+
const [layout, _setLayout] = useState4(defaultLayout);
|
|
581
|
+
const usingRemote = saveLocation === "remote";
|
|
582
|
+
const loadConfig = usingRemote ? loadRemoteConfig : loadLocalConfig;
|
|
583
|
+
const saveConfig = usingRemote ? saveRemoteConfig : saveLocalConfig;
|
|
230
584
|
const setLayout = (layout2) => {
|
|
231
585
|
_setLayout(layout2);
|
|
232
586
|
};
|
|
233
|
-
const load =
|
|
587
|
+
const load = useCallback3(
|
|
234
588
|
async (id = "latest") => {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
589
|
+
try {
|
|
590
|
+
const layout2 = await loadConfig(saveUrl, user, id);
|
|
591
|
+
setLayout(layout2);
|
|
592
|
+
} catch {
|
|
238
593
|
setLayout(defaultLayout);
|
|
239
|
-
}
|
|
594
|
+
}
|
|
240
595
|
},
|
|
241
|
-
[defaultLayout, user
|
|
596
|
+
[defaultLayout, loadConfig, saveUrl, user]
|
|
242
597
|
);
|
|
243
|
-
|
|
598
|
+
useEffect4(() => {
|
|
244
599
|
load();
|
|
245
600
|
}, [load]);
|
|
246
|
-
const saveData =
|
|
601
|
+
const saveData = useCallback3(
|
|
247
602
|
(data) => {
|
|
248
|
-
|
|
249
|
-
method: "POST",
|
|
250
|
-
headers: {
|
|
251
|
-
"Content-Type": "application/json"
|
|
252
|
-
},
|
|
253
|
-
body: JSON.stringify(data)
|
|
254
|
-
}).then((response) => {
|
|
255
|
-
return response.ok ? response.json() : defaultLayout;
|
|
256
|
-
});
|
|
603
|
+
saveConfig(saveUrl, user, data);
|
|
257
604
|
},
|
|
258
|
-
[
|
|
605
|
+
[saveConfig, saveUrl, user]
|
|
259
606
|
);
|
|
260
|
-
const loadLayoutById =
|
|
607
|
+
const loadLayoutById = useCallback3(
|
|
261
608
|
(id) => {
|
|
262
609
|
load(id);
|
|
263
610
|
},
|
|
@@ -265,7 +612,6 @@ var useLayoutConfig = (user, defaultLayout) => {
|
|
|
265
612
|
);
|
|
266
613
|
return [layout, saveData, loadLayoutById];
|
|
267
614
|
};
|
|
268
|
-
var use_layout_config_default = useLayoutConfig;
|
|
269
615
|
|
|
270
616
|
// src/shell.tsx
|
|
271
617
|
import {
|
|
@@ -278,23 +624,23 @@ import {
|
|
|
278
624
|
} from "@vuu-ui/vuu-layout";
|
|
279
625
|
|
|
280
626
|
// src/app-header/AppHeader.tsx
|
|
281
|
-
import { useCallback as
|
|
627
|
+
import { useCallback as useCallback6 } from "react";
|
|
282
628
|
|
|
283
629
|
// src/user-profile/UserProfile.tsx
|
|
284
|
-
import { Button as
|
|
630
|
+
import { Button as Button4 } from "@salt-ds/core";
|
|
285
631
|
import { DropdownBase } from "@heswell/salt-lab";
|
|
286
632
|
import { UserSolidIcon } from "@salt-ds/icons";
|
|
287
633
|
|
|
288
634
|
// src/user-profile/UserPanel.tsx
|
|
289
635
|
import { formatDate } from "@vuu-ui/vuu-utils";
|
|
290
636
|
import { List, ListItem } from "@heswell/salt-lab";
|
|
291
|
-
import { Button as
|
|
637
|
+
import { Button as Button3 } from "@salt-ds/core";
|
|
292
638
|
import { ExportIcon } from "@salt-ds/icons";
|
|
293
639
|
import {
|
|
294
640
|
forwardRef,
|
|
295
|
-
useCallback as
|
|
296
|
-
useEffect as
|
|
297
|
-
useState as
|
|
641
|
+
useCallback as useCallback4,
|
|
642
|
+
useEffect as useEffect5,
|
|
643
|
+
useState as useState5
|
|
298
644
|
} from "react";
|
|
299
645
|
|
|
300
646
|
// src/get-layout-history.ts
|
|
@@ -308,16 +654,16 @@ var getLayoutHistory = async (user) => {
|
|
|
308
654
|
};
|
|
309
655
|
|
|
310
656
|
// src/user-profile/UserPanel.tsx
|
|
311
|
-
import { jsx as
|
|
657
|
+
import { jsx as jsx9, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
312
658
|
var byLastUpdate = ({ lastUpdate: l1 }, { lastUpdate: l2 }) => {
|
|
313
659
|
return l2 === l1 ? 0 : l2 < l1 ? -1 : 1;
|
|
314
660
|
};
|
|
315
661
|
var HistoryListItem = (props) => {
|
|
316
|
-
return /* @__PURE__ */
|
|
662
|
+
return /* @__PURE__ */ jsx9(ListItem, { ...props });
|
|
317
663
|
};
|
|
318
664
|
var UserPanel = forwardRef(function UserPanel2({ loginUrl, onNavigate, user, layoutId = "latest" }, forwardedRef) {
|
|
319
|
-
const [history, setHistory] =
|
|
320
|
-
|
|
665
|
+
const [history, setHistory] = useState5([]);
|
|
666
|
+
useEffect5(() => {
|
|
321
667
|
async function getHistory() {
|
|
322
668
|
const history2 = await getLayoutHistory(user);
|
|
323
669
|
const sortedHistory = history2.filter((item) => item.id !== "latest").sort(byLastUpdate).map(({ id, lastUpdate }) => ({
|
|
@@ -330,7 +676,7 @@ var UserPanel = forwardRef(function UserPanel2({ loginUrl, onNavigate, user, lay
|
|
|
330
676
|
}
|
|
331
677
|
getHistory();
|
|
332
678
|
}, [user]);
|
|
333
|
-
const handleHisorySelected =
|
|
679
|
+
const handleHisorySelected = useCallback4(
|
|
334
680
|
(evt, selected2) => {
|
|
335
681
|
if (selected2) {
|
|
336
682
|
onNavigate(selected2.id);
|
|
@@ -338,12 +684,12 @@ var UserPanel = forwardRef(function UserPanel2({ loginUrl, onNavigate, user, lay
|
|
|
338
684
|
},
|
|
339
685
|
[onNavigate]
|
|
340
686
|
);
|
|
341
|
-
const handleLogout =
|
|
687
|
+
const handleLogout = useCallback4(() => {
|
|
342
688
|
logout(loginUrl);
|
|
343
689
|
}, [loginUrl]);
|
|
344
690
|
const selected = history.length === 0 ? null : layoutId === "latest" ? history[0] : history.find((i) => i.id === layoutId);
|
|
345
|
-
return /* @__PURE__ */
|
|
346
|
-
/* @__PURE__ */
|
|
691
|
+
return /* @__PURE__ */ jsxs5("div", { className: "vuuUserPanel", ref: forwardedRef, children: [
|
|
692
|
+
/* @__PURE__ */ jsx9(
|
|
347
693
|
List,
|
|
348
694
|
{
|
|
349
695
|
ListItem: HistoryListItem,
|
|
@@ -353,15 +699,15 @@ var UserPanel = forwardRef(function UserPanel2({ loginUrl, onNavigate, user, lay
|
|
|
353
699
|
source: history
|
|
354
700
|
}
|
|
355
701
|
),
|
|
356
|
-
/* @__PURE__ */
|
|
357
|
-
/* @__PURE__ */
|
|
702
|
+
/* @__PURE__ */ jsx9("div", { className: "vuuUserPanel-buttonBar", children: /* @__PURE__ */ jsxs5(Button3, { "aria-label": "logout", onClick: handleLogout, children: [
|
|
703
|
+
/* @__PURE__ */ jsx9(ExportIcon, {}),
|
|
358
704
|
" Logout"
|
|
359
705
|
] }) })
|
|
360
706
|
] });
|
|
361
707
|
});
|
|
362
708
|
|
|
363
709
|
// src/user-profile/UserProfile.tsx
|
|
364
|
-
import { jsx as
|
|
710
|
+
import { jsx as jsx10, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
365
711
|
var UserProfile = ({
|
|
366
712
|
layoutId,
|
|
367
713
|
loginUrl,
|
|
@@ -371,9 +717,9 @@ var UserProfile = ({
|
|
|
371
717
|
const handleNavigate = (id) => {
|
|
372
718
|
onNavigate(id);
|
|
373
719
|
};
|
|
374
|
-
return /* @__PURE__ */
|
|
375
|
-
/* @__PURE__ */
|
|
376
|
-
/* @__PURE__ */
|
|
720
|
+
return /* @__PURE__ */ jsxs6(DropdownBase, { className: "vuuUserProfile", placement: "bottom-end", children: [
|
|
721
|
+
/* @__PURE__ */ jsx10(Button4, { variant: "secondary", children: /* @__PURE__ */ jsx10(UserSolidIcon, {}) }),
|
|
722
|
+
/* @__PURE__ */ jsx10(
|
|
377
723
|
UserPanel,
|
|
378
724
|
{
|
|
379
725
|
layoutId,
|
|
@@ -390,11 +736,11 @@ import {
|
|
|
390
736
|
ToggleButton,
|
|
391
737
|
ToggleButtonGroup
|
|
392
738
|
} from "@heswell/salt-lab";
|
|
393
|
-
import
|
|
739
|
+
import cx4 from "classnames";
|
|
394
740
|
import { useControlled } from "@salt-ds/core";
|
|
395
|
-
import { useCallback as
|
|
396
|
-
import { jsx as
|
|
397
|
-
var
|
|
741
|
+
import { useCallback as useCallback5 } from "react";
|
|
742
|
+
import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
743
|
+
var classBase4 = "vuuThemeSwitch";
|
|
398
744
|
var modes = ["light", "dark"];
|
|
399
745
|
var ThemeSwitch = ({
|
|
400
746
|
className: classNameProp,
|
|
@@ -410,7 +756,7 @@ var ThemeSwitch = ({
|
|
|
410
756
|
state: "mode"
|
|
411
757
|
});
|
|
412
758
|
const selectedIndex = modes.indexOf(mode);
|
|
413
|
-
const handleChangeSecondary =
|
|
759
|
+
const handleChangeSecondary = useCallback5(
|
|
414
760
|
(_evt, index) => {
|
|
415
761
|
const mode2 = modes[index];
|
|
416
762
|
setMode(mode2);
|
|
@@ -418,8 +764,8 @@ var ThemeSwitch = ({
|
|
|
418
764
|
},
|
|
419
765
|
[onChange, setMode]
|
|
420
766
|
);
|
|
421
|
-
const className =
|
|
422
|
-
return /* @__PURE__ */
|
|
767
|
+
const className = cx4(classBase4, classNameProp);
|
|
768
|
+
return /* @__PURE__ */ jsxs7(
|
|
423
769
|
ToggleButtonGroup,
|
|
424
770
|
{
|
|
425
771
|
className,
|
|
@@ -427,7 +773,7 @@ var ThemeSwitch = ({
|
|
|
427
773
|
onChange: handleChangeSecondary,
|
|
428
774
|
selectedIndex,
|
|
429
775
|
children: [
|
|
430
|
-
/* @__PURE__ */
|
|
776
|
+
/* @__PURE__ */ jsx11(
|
|
431
777
|
ToggleButton,
|
|
432
778
|
{
|
|
433
779
|
"aria-label": "alert",
|
|
@@ -435,7 +781,7 @@ var ThemeSwitch = ({
|
|
|
435
781
|
"data-icon": "light"
|
|
436
782
|
}
|
|
437
783
|
),
|
|
438
|
-
/* @__PURE__ */
|
|
784
|
+
/* @__PURE__ */ jsx11(
|
|
439
785
|
ToggleButton,
|
|
440
786
|
{
|
|
441
787
|
"aria-label": "home",
|
|
@@ -449,9 +795,9 @@ var ThemeSwitch = ({
|
|
|
449
795
|
};
|
|
450
796
|
|
|
451
797
|
// src/app-header/AppHeader.tsx
|
|
452
|
-
import
|
|
453
|
-
import { jsx as
|
|
454
|
-
var
|
|
798
|
+
import cx5 from "classnames";
|
|
799
|
+
import { jsx as jsx12, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
800
|
+
var classBase5 = "vuuAppHeader";
|
|
455
801
|
var AppHeader = ({
|
|
456
802
|
className: classNameProp,
|
|
457
803
|
layoutId,
|
|
@@ -462,14 +808,14 @@ var AppHeader = ({
|
|
|
462
808
|
user,
|
|
463
809
|
...htmlAttributes
|
|
464
810
|
}) => {
|
|
465
|
-
const className =
|
|
466
|
-
const handleSwitchTheme =
|
|
811
|
+
const className = cx5(classBase5, classNameProp);
|
|
812
|
+
const handleSwitchTheme = useCallback6(
|
|
467
813
|
(mode) => onSwitchTheme == null ? void 0 : onSwitchTheme(mode),
|
|
468
814
|
[onSwitchTheme]
|
|
469
815
|
);
|
|
470
|
-
return /* @__PURE__ */
|
|
471
|
-
/* @__PURE__ */
|
|
472
|
-
/* @__PURE__ */
|
|
816
|
+
return /* @__PURE__ */ jsxs8("header", { className, ...htmlAttributes, children: [
|
|
817
|
+
/* @__PURE__ */ jsx12(ThemeSwitch, { defaultMode: themeMode, onChange: handleSwitchTheme }),
|
|
818
|
+
/* @__PURE__ */ jsx12(
|
|
473
819
|
UserProfile,
|
|
474
820
|
{
|
|
475
821
|
layoutId,
|
|
@@ -482,7 +828,9 @@ var AppHeader = ({
|
|
|
482
828
|
};
|
|
483
829
|
|
|
484
830
|
// src/shell.tsx
|
|
485
|
-
import {
|
|
831
|
+
import { logger } from "@vuu-ui/vuu-utils";
|
|
832
|
+
import { jsx as jsx13, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
833
|
+
var { error } = logger("Shell");
|
|
486
834
|
var warningLayout = {
|
|
487
835
|
type: "View",
|
|
488
836
|
props: {
|
|
@@ -503,25 +851,32 @@ var Shell = ({
|
|
|
503
851
|
defaultLayout = warningLayout,
|
|
504
852
|
leftSidePanel,
|
|
505
853
|
loginUrl,
|
|
854
|
+
saveLocation = "remote",
|
|
855
|
+
saveUrl,
|
|
506
856
|
serverUrl,
|
|
507
857
|
user,
|
|
508
858
|
...htmlAttributes
|
|
509
859
|
}) => {
|
|
510
|
-
const rootRef =
|
|
511
|
-
const paletteView =
|
|
512
|
-
const [open, setOpen] =
|
|
513
|
-
const layoutId =
|
|
514
|
-
const [layout,
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
860
|
+
const rootRef = useRef2(null);
|
|
861
|
+
const paletteView = useRef2(null);
|
|
862
|
+
const [open, setOpen] = useState6(false);
|
|
863
|
+
const layoutId = useRef2("latest");
|
|
864
|
+
const [layout, saveLayoutConfig, loadLayoutById] = useLayoutConfig({
|
|
865
|
+
defaultLayout,
|
|
866
|
+
saveLocation,
|
|
867
|
+
user
|
|
868
|
+
});
|
|
869
|
+
const handleLayoutChange = useCallback7(
|
|
519
870
|
(layout2) => {
|
|
520
|
-
|
|
871
|
+
try {
|
|
872
|
+
saveLayoutConfig(layout2);
|
|
873
|
+
} catch {
|
|
874
|
+
error == null ? void 0 : error("Failed to save layout");
|
|
875
|
+
}
|
|
521
876
|
},
|
|
522
|
-
[
|
|
877
|
+
[saveLayoutConfig]
|
|
523
878
|
);
|
|
524
|
-
const handleSwitchTheme =
|
|
879
|
+
const handleSwitchTheme = useCallback7((mode) => {
|
|
525
880
|
if (rootRef.current) {
|
|
526
881
|
rootRef.current.dataset.mode = mode;
|
|
527
882
|
}
|
|
@@ -533,14 +888,14 @@ var Shell = ({
|
|
|
533
888
|
setOpen(!open);
|
|
534
889
|
}
|
|
535
890
|
};
|
|
536
|
-
const handleNavigate =
|
|
891
|
+
const handleNavigate = useCallback7(
|
|
537
892
|
(id) => {
|
|
538
893
|
layoutId.current = id;
|
|
539
894
|
loadLayoutById(id);
|
|
540
895
|
},
|
|
541
896
|
[loadLayoutById]
|
|
542
897
|
);
|
|
543
|
-
|
|
898
|
+
useEffect6(() => {
|
|
544
899
|
if (serverUrl && user.token) {
|
|
545
900
|
connectToServer({
|
|
546
901
|
authToken: user.token,
|
|
@@ -553,7 +908,7 @@ var Shell = ({
|
|
|
553
908
|
const drawers = [];
|
|
554
909
|
if (leftSidePanel) {
|
|
555
910
|
drawers.push(
|
|
556
|
-
/* @__PURE__ */
|
|
911
|
+
/* @__PURE__ */ jsx13(
|
|
557
912
|
Drawer,
|
|
558
913
|
{
|
|
559
914
|
onClick: handleDrawerClick,
|
|
@@ -563,7 +918,7 @@ var Shell = ({
|
|
|
563
918
|
peekaboo: true,
|
|
564
919
|
sizeOpen: 200,
|
|
565
920
|
toggleButton: "end",
|
|
566
|
-
children: /* @__PURE__ */
|
|
921
|
+
children: /* @__PURE__ */ jsx13(
|
|
567
922
|
View,
|
|
568
923
|
{
|
|
569
924
|
className: "vuuShell-palette",
|
|
@@ -581,7 +936,7 @@ var Shell = ({
|
|
|
581
936
|
}
|
|
582
937
|
return drawers;
|
|
583
938
|
};
|
|
584
|
-
const className =
|
|
939
|
+
const className = cx6(
|
|
585
940
|
"vuuShell",
|
|
586
941
|
classNameProp,
|
|
587
942
|
"salt-theme",
|
|
@@ -589,21 +944,21 @@ var Shell = ({
|
|
|
589
944
|
);
|
|
590
945
|
return (
|
|
591
946
|
// ShellContext TBD
|
|
592
|
-
/* @__PURE__ */
|
|
593
|
-
/* @__PURE__ */
|
|
947
|
+
/* @__PURE__ */ jsxs9(ShellContextProvider, { value: void 0, children: [
|
|
948
|
+
/* @__PURE__ */ jsx13(LayoutProvider, { layout, onLayoutChange: handleLayoutChange, children: /* @__PURE__ */ jsx13(
|
|
594
949
|
DraggableLayout,
|
|
595
950
|
{
|
|
596
951
|
className,
|
|
597
952
|
"data-mode": "light",
|
|
598
953
|
ref: rootRef,
|
|
599
954
|
...htmlAttributes,
|
|
600
|
-
children: /* @__PURE__ */
|
|
955
|
+
children: /* @__PURE__ */ jsxs9(
|
|
601
956
|
Flexbox,
|
|
602
957
|
{
|
|
603
958
|
className: "App",
|
|
604
959
|
style: { flexDirection: "column", height: "100%", width: "100%" },
|
|
605
960
|
children: [
|
|
606
|
-
/* @__PURE__ */
|
|
961
|
+
/* @__PURE__ */ jsx13(
|
|
607
962
|
AppHeader,
|
|
608
963
|
{
|
|
609
964
|
layoutId: layoutId.current,
|
|
@@ -613,8 +968,8 @@ var Shell = ({
|
|
|
613
968
|
onSwitchTheme: handleSwitchTheme
|
|
614
969
|
}
|
|
615
970
|
),
|
|
616
|
-
/* @__PURE__ */
|
|
617
|
-
/* @__PURE__ */
|
|
971
|
+
/* @__PURE__ */ jsx13(DockLayout, { style: { flex: 1 }, children: getDrawers().concat(
|
|
972
|
+
/* @__PURE__ */ jsx13(
|
|
618
973
|
DraggableLayout,
|
|
619
974
|
{
|
|
620
975
|
dropTarget: true,
|
|
@@ -640,8 +995,8 @@ import {
|
|
|
640
995
|
cloneElement,
|
|
641
996
|
useContext as useContext2
|
|
642
997
|
} from "react";
|
|
643
|
-
import
|
|
644
|
-
import { jsx as
|
|
998
|
+
import cx7 from "classnames";
|
|
999
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
645
1000
|
var DEFAULT_DENSITY2 = "medium";
|
|
646
1001
|
var DEFAULT_THEME = "salt-theme";
|
|
647
1002
|
var DEFAULT_THEME_MODE = "light";
|
|
@@ -654,7 +1009,7 @@ var createThemedChildren = (children, theme, themeMode, density) => {
|
|
|
654
1009
|
var _a;
|
|
655
1010
|
if (isValidElement(children)) {
|
|
656
1011
|
return cloneElement(children, {
|
|
657
|
-
className:
|
|
1012
|
+
className: cx7(
|
|
658
1013
|
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
|
659
1014
|
(_a = children.props) == null ? void 0 : _a.className,
|
|
660
1015
|
theme,
|
|
@@ -694,7 +1049,7 @@ var ThemeProvider = ({
|
|
|
694
1049
|
themeMode,
|
|
695
1050
|
density
|
|
696
1051
|
);
|
|
697
|
-
return /* @__PURE__ */
|
|
1052
|
+
return /* @__PURE__ */ jsx14(ThemeContext.Provider, { value: { themeMode, density, theme }, children: themedChildren });
|
|
698
1053
|
};
|
|
699
1054
|
ThemeProvider.displayName = "ThemeProvider";
|
|
700
1055
|
export {
|
|
@@ -705,6 +1060,7 @@ export {
|
|
|
705
1060
|
DensitySwitch,
|
|
706
1061
|
Feature,
|
|
707
1062
|
LoginPanel,
|
|
1063
|
+
SessionEditingForm,
|
|
708
1064
|
Shell,
|
|
709
1065
|
ShellContextProvider,
|
|
710
1066
|
ThemeContext,
|