@vuu-ui/vuu-data-react 2.1.19-beta.2 → 2.1.19-beta.4
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/data-editing/EditForm.css.js +6 -0
- package/cjs/data-editing/EditForm.css.js.map +1 -0
- package/cjs/data-editing/EditForm.js +90 -0
- package/cjs/data-editing/EditForm.js.map +1 -0
- package/cjs/data-editing/UnsavedChangesReport.css.js +6 -0
- package/cjs/data-editing/UnsavedChangesReport.css.js.map +1 -0
- package/cjs/data-editing/UnsavedChangesReport.js +29 -0
- package/cjs/data-editing/UnsavedChangesReport.js.map +1 -0
- package/cjs/data-editing/edit-rule-validation-checker.js +41 -0
- package/cjs/data-editing/edit-rule-validation-checker.js.map +1 -0
- package/cjs/data-editing/edit-validation-rules.js +52 -0
- package/cjs/data-editing/edit-validation-rules.js.map +1 -0
- package/cjs/data-editing/form-edit-state.js +26 -0
- package/cjs/data-editing/form-edit-state.js.map +1 -0
- package/cjs/data-editing/get-data-item-edit-control.js +105 -0
- package/cjs/data-editing/get-data-item-edit-control.js.map +1 -0
- package/cjs/data-editing/useEditForm.js +258 -0
- package/cjs/data-editing/useEditForm.js.map +1 -0
- package/cjs/datasource-provider/VuuDataSourceProvider.js +34 -0
- package/cjs/datasource-provider/VuuDataSourceProvider.js.map +1 -0
- package/cjs/datasource-provider/useAutoLoginToVuuServer.js +52 -0
- package/cjs/datasource-provider/useAutoLoginToVuuServer.js.map +1 -0
- package/cjs/hooks/useLookupValues.js +100 -0
- package/cjs/hooks/useLookupValues.js.map +1 -0
- package/cjs/hooks/useSessionDataSource.js +58 -0
- package/cjs/hooks/useSessionDataSource.js.map +1 -0
- package/cjs/hooks/useTypeaheadSuggestions.js +57 -0
- package/cjs/hooks/useTypeaheadSuggestions.js.map +1 -0
- package/cjs/hooks/useVisualLinks.js +84 -0
- package/cjs/hooks/useVisualLinks.js.map +1 -0
- package/cjs/hooks/useVuuMenuActions.js +352 -0
- package/cjs/hooks/useVuuMenuActions.js.map +1 -0
- package/cjs/hooks/useVuuTables.js +38 -0
- package/cjs/hooks/useVuuTables.js.map +1 -0
- package/cjs/index.js +42 -0
- package/cjs/index.js.map +1 -0
- package/cjs/lost-connection-indicator/LostConnectionIndicator.css.js +6 -0
- package/cjs/lost-connection-indicator/LostConnectionIndicator.css.js.map +1 -0
- package/cjs/lost-connection-indicator/LostConnectionIndicator.js +24 -0
- package/cjs/lost-connection-indicator/LostConnectionIndicator.js.map +1 -0
- package/cjs/lost-connection-indicator/useLostConnection.js +34 -0
- package/cjs/lost-connection-indicator/useLostConnection.js.map +1 -0
- package/cjs/session-editing-form/SessionEditingForm.css.js +6 -0
- package/cjs/session-editing-form/SessionEditingForm.css.js.map +1 -0
- package/cjs/session-editing-form/SessionEditingForm.js +270 -0
- package/cjs/session-editing-form/SessionEditingForm.js.map +1 -0
- package/esm/data-editing/EditForm.css.js +4 -0
- package/esm/data-editing/EditForm.css.js.map +1 -0
- package/esm/data-editing/EditForm.js +88 -0
- package/esm/data-editing/EditForm.js.map +1 -0
- package/esm/data-editing/UnsavedChangesReport.css.js +4 -0
- package/esm/data-editing/UnsavedChangesReport.css.js.map +1 -0
- package/esm/data-editing/UnsavedChangesReport.js +27 -0
- package/esm/data-editing/UnsavedChangesReport.js.map +1 -0
- package/esm/data-editing/edit-rule-validation-checker.js +37 -0
- package/esm/data-editing/edit-rule-validation-checker.js.map +1 -0
- package/esm/data-editing/edit-validation-rules.js +50 -0
- package/esm/data-editing/edit-validation-rules.js.map +1 -0
- package/esm/data-editing/form-edit-state.js +23 -0
- package/esm/data-editing/form-edit-state.js.map +1 -0
- package/esm/data-editing/get-data-item-edit-control.js +103 -0
- package/esm/data-editing/get-data-item-edit-control.js.map +1 -0
- package/esm/data-editing/useEditForm.js +256 -0
- package/esm/data-editing/useEditForm.js.map +1 -0
- package/esm/datasource-provider/VuuDataSourceProvider.js +32 -0
- package/esm/datasource-provider/VuuDataSourceProvider.js.map +1 -0
- package/esm/datasource-provider/useAutoLoginToVuuServer.js +50 -0
- package/esm/datasource-provider/useAutoLoginToVuuServer.js.map +1 -0
- package/esm/hooks/useLookupValues.js +98 -0
- package/esm/hooks/useLookupValues.js.map +1 -0
- package/esm/hooks/useSessionDataSource.js +56 -0
- package/esm/hooks/useSessionDataSource.js.map +1 -0
- package/esm/hooks/useTypeaheadSuggestions.js +54 -0
- package/esm/hooks/useTypeaheadSuggestions.js.map +1 -0
- package/esm/hooks/useVisualLinks.js +82 -0
- package/esm/hooks/useVisualLinks.js.map +1 -0
- package/esm/hooks/useVuuMenuActions.js +348 -0
- package/esm/hooks/useVuuMenuActions.js.map +1 -0
- package/esm/hooks/useVuuTables.js +36 -0
- package/esm/hooks/useVuuTables.js.map +1 -0
- package/esm/index.js +16 -0
- package/esm/index.js.map +1 -0
- package/esm/lost-connection-indicator/LostConnectionIndicator.css.js +4 -0
- package/esm/lost-connection-indicator/LostConnectionIndicator.css.js.map +1 -0
- package/esm/lost-connection-indicator/LostConnectionIndicator.js +22 -0
- package/esm/lost-connection-indicator/LostConnectionIndicator.js.map +1 -0
- package/esm/lost-connection-indicator/useLostConnection.js +32 -0
- package/esm/lost-connection-indicator/useLostConnection.js.map +1 -0
- package/esm/session-editing-form/SessionEditingForm.css.js +4 -0
- package/esm/session-editing-form/SessionEditingForm.css.js.map +1 -0
- package/esm/session-editing-form/SessionEditingForm.js +268 -0
- package/esm/session-editing-form/SessionEditingForm.js.map +1 -0
- package/package.json +21 -18
- package/src/data-editing/EditForm.css.js +0 -53
- package/src/data-editing/EditForm.js +0 -82
- package/src/data-editing/UnsavedChangesReport.css.js +0 -27
- package/src/data-editing/UnsavedChangesReport.js +0 -41
- package/src/data-editing/edit-rule-validation-checker.js +0 -30
- package/src/data-editing/edit-validation-rules.js +0 -33
- package/src/data-editing/form-edit-state.js +0 -16
- package/src/data-editing/get-data-item-edit-control.js +0 -63
- package/src/data-editing/index.js +0 -6
- package/src/data-editing/useEditForm.js +0 -253
- package/src/datasource-provider/VuuDataSourceProvider.js +0 -20
- package/src/datasource-provider/index.js +0 -1
- package/src/datasource-provider/useAutoLoginToVuuServer.js +0 -42
- package/src/hooks/useLookupValues.js +0 -93
- package/src/hooks/useSessionDataSource.js +0 -37
- package/src/hooks/useTypeaheadSuggestions.js +0 -50
- package/src/hooks/useVisualLinks.js +0 -87
- package/src/hooks/useVuuMenuActions.js +0 -269
- package/src/hooks/useVuuTables.js +0 -32
- package/src/index.js +0 -10
- package/src/lost-connection-indicator/LostConnectionIndicator.css.js +0 -29
- package/src/lost-connection-indicator/LostConnectionIndicator.js +0 -30
- package/src/lost-connection-indicator/useLostConnection.js +0 -28
- package/src/session-editing-form/SessionEditingForm.css.js +0 -47
- package/src/session-editing-form/SessionEditingForm.js +0 -236
- package/src/session-editing-form/index.js +0 -1
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { useComponentCssInjection } from "@salt-ds/styles";
|
|
3
|
-
import { useWindow } from "@salt-ds/window";
|
|
4
|
-
import { buildFormEditState } from "./form-edit-state.js";
|
|
5
|
-
import UnsavedChangesReport from "./UnsavedChangesReport.css";
|
|
6
|
-
const classBase = "vuuUnsavedChanges";
|
|
7
|
-
const UnsavedChangesReport_UnsavedChangesReport = ({ entity, editedEntity })=>{
|
|
8
|
-
const targetWindow = useWindow();
|
|
9
|
-
useComponentCssInjection({
|
|
10
|
-
testId: "vuu-unsaved-changes-report",
|
|
11
|
-
css: UnsavedChangesReport,
|
|
12
|
-
window: targetWindow
|
|
13
|
-
});
|
|
14
|
-
const { editedFields } = buildFormEditState(entity, editedEntity);
|
|
15
|
-
return /*#__PURE__*/ jsx("div", {
|
|
16
|
-
className: classBase,
|
|
17
|
-
children: /*#__PURE__*/ jsx("table", {
|
|
18
|
-
className: `${classBase}-table`,
|
|
19
|
-
children: /*#__PURE__*/ jsx("tbody", {
|
|
20
|
-
children: editedFields.map((fieldName, i)=>/*#__PURE__*/ jsxs("tr", {
|
|
21
|
-
className: `${classBase}-row`,
|
|
22
|
-
children: [
|
|
23
|
-
/*#__PURE__*/ jsx("td", {
|
|
24
|
-
className: `${classBase}-fieldName`,
|
|
25
|
-
children: fieldName
|
|
26
|
-
}),
|
|
27
|
-
/*#__PURE__*/ jsx("td", {
|
|
28
|
-
className: `${classBase}-old`,
|
|
29
|
-
children: entity[fieldName]
|
|
30
|
-
}),
|
|
31
|
-
/*#__PURE__*/ jsx("td", {
|
|
32
|
-
className: `${classBase}-new`,
|
|
33
|
-
children: editedEntity[fieldName]
|
|
34
|
-
})
|
|
35
|
-
]
|
|
36
|
-
}, i))
|
|
37
|
-
})
|
|
38
|
-
})
|
|
39
|
-
});
|
|
40
|
-
};
|
|
41
|
-
export { UnsavedChangesReport_UnsavedChangesReport as UnsavedChangesReport };
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { getEditRuleValidator, isTypeDescriptor } from "@vuu-ui/vuu-utils";
|
|
2
|
-
const OK = {
|
|
3
|
-
ok: true
|
|
4
|
-
};
|
|
5
|
-
const NO_VALIDATION_RULES = [];
|
|
6
|
-
function getEditValidationRules(descriptor, editPhase) {
|
|
7
|
-
if (isTypeDescriptor(descriptor.type)) return "*" === editPhase ? descriptor.type.rules ?? [] : descriptor.type.rules?.filter(({ phase: a = "commit" })=>a === editPhase) ?? NO_VALIDATION_RULES;
|
|
8
|
-
return NO_VALIDATION_RULES;
|
|
9
|
-
}
|
|
10
|
-
const buildValidationChecker = (rules)=>(value, editPhase)=>applyRules(rules, value, editPhase);
|
|
11
|
-
function applyRules(rules, value, editPhase = "commit") {
|
|
12
|
-
const result = {
|
|
13
|
-
ok: true
|
|
14
|
-
};
|
|
15
|
-
for (const rule of rules){
|
|
16
|
-
const { phase = "commit" } = rule;
|
|
17
|
-
if ("*" === editPhase || phase === editPhase) {
|
|
18
|
-
const applyRuleToValue = getEditRuleValidator(rule.name);
|
|
19
|
-
if (applyRuleToValue) {
|
|
20
|
-
const res = applyRuleToValue(rule, value);
|
|
21
|
-
if (!res.ok) {
|
|
22
|
-
result.ok = false;
|
|
23
|
-
(result.messages ?? (result.messages = [])).push(res.message);
|
|
24
|
-
}
|
|
25
|
-
} else throw Error(`editable-utils applyRules, no validator registered for rule '${rule.name}'`);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
return result;
|
|
29
|
-
}
|
|
30
|
-
export { OK, buildValidationChecker, getEditValidationRules };
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { registerComponent } from "@vuu-ui/vuu-utils";
|
|
2
|
-
import { OK } from "./edit-rule-validation-checker.js";
|
|
3
|
-
const isString = (value)=>"string" == typeof value;
|
|
4
|
-
const NUMERIC = /^(?:[0-9]|\.)+$/;
|
|
5
|
-
const CharValidatorNumeric = (rule, value)=>{
|
|
6
|
-
if (isString(value)) {
|
|
7
|
-
if ("" === value.trim()) return OK;
|
|
8
|
-
else if (value.match(NUMERIC)) return OK;
|
|
9
|
-
}
|
|
10
|
-
return {
|
|
11
|
-
ok: false,
|
|
12
|
-
message: "only numeric characters are permitted"
|
|
13
|
-
};
|
|
14
|
-
};
|
|
15
|
-
const ValueValidatorInteger = (rule, value)=>{
|
|
16
|
-
if (isString(value)) if ("" === value.trim()) return OK;
|
|
17
|
-
else {
|
|
18
|
-
if (!value.match(NUMERIC)) return {
|
|
19
|
-
ok: false,
|
|
20
|
-
message: "value must be an integer, invalid character"
|
|
21
|
-
};
|
|
22
|
-
if (parseFloat(value) === parseInt(value)) return OK;
|
|
23
|
-
}
|
|
24
|
-
return {
|
|
25
|
-
ok: false,
|
|
26
|
-
message: "must be an integer value"
|
|
27
|
-
};
|
|
28
|
-
};
|
|
29
|
-
const registerRules = ()=>{
|
|
30
|
-
registerComponent("char-numeric", CharValidatorNumeric, "data-edit-validator", {});
|
|
31
|
-
registerComponent("value-integer", ValueValidatorInteger, "data-edit-validator", {});
|
|
32
|
-
};
|
|
33
|
-
export { registerRules };
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
const CLEAN_FORM = {
|
|
2
|
-
isClean: true,
|
|
3
|
-
editedFields: []
|
|
4
|
-
};
|
|
5
|
-
const buildFormEditState = (entity, newEntity)=>{
|
|
6
|
-
if (void 0 === entity) return CLEAN_FORM;
|
|
7
|
-
{
|
|
8
|
-
const editedFields = [];
|
|
9
|
-
for (const [fieldName, value] of Object.entries(entity))if (value !== newEntity[fieldName]) editedFields.push(fieldName);
|
|
10
|
-
return {
|
|
11
|
-
isClean: 0 === editedFields.length,
|
|
12
|
-
editedFields
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
|
-
};
|
|
16
|
-
export { CLEAN_FORM, buildFormEditState };
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { VuuDatePicker, VuuInput, VuuTimePicker, VuuTypeaheadInput } from "@vuu-ui/vuu-ui-controls";
|
|
3
|
-
import { asTimeString, isDateTimeDataValue, isTimeDataValue } from "@vuu-ui/vuu-utils";
|
|
4
|
-
import { ToggleFilter } from "@vuu-ui/vuu-filters";
|
|
5
|
-
const getDataItemEditControl = ({ InputProps, TypeaheadProps, className, commitOnBlur, commitWhenCleared, dataDescriptor, errorMessage, onCommit, table, values, variant })=>{
|
|
6
|
-
const handleCommitNumber = (evt, value)=>{
|
|
7
|
-
onCommit(evt, value.toString());
|
|
8
|
-
};
|
|
9
|
-
const dataVariant = variant && "toggle" !== variant ? variant : void 0;
|
|
10
|
-
if (false === dataDescriptor.editable) return /*#__PURE__*/ jsx(VuuInput, {
|
|
11
|
-
variant: "secondary",
|
|
12
|
-
...InputProps,
|
|
13
|
-
onCommit: onCommit,
|
|
14
|
-
readOnly: true,
|
|
15
|
-
"data-edit-control": true
|
|
16
|
-
});
|
|
17
|
-
if (isTimeDataValue(dataDescriptor)) {
|
|
18
|
-
if (InputProps?.inputProps) {
|
|
19
|
-
const { value, onChange } = InputProps.inputProps;
|
|
20
|
-
return /*#__PURE__*/ jsx(VuuTimePicker, {
|
|
21
|
-
className: className,
|
|
22
|
-
value: asTimeString(value, true),
|
|
23
|
-
onChange: onChange,
|
|
24
|
-
onCommit: onCommit,
|
|
25
|
-
"data-edit-control": true
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
} else if (isDateTimeDataValue(dataDescriptor)) return /*#__PURE__*/ jsx(VuuDatePicker, {
|
|
29
|
-
className: className,
|
|
30
|
-
onCommit: handleCommitNumber,
|
|
31
|
-
"data-edit-control": true
|
|
32
|
-
});
|
|
33
|
-
else if ("string" === dataDescriptor.serverDataType && table) if ("toggle" === variant && values?.length) return /*#__PURE__*/ jsx(ToggleFilter, {
|
|
34
|
-
className: className,
|
|
35
|
-
column: dataDescriptor.name,
|
|
36
|
-
"data-edit-control": true,
|
|
37
|
-
onCommit: onCommit,
|
|
38
|
-
table: table,
|
|
39
|
-
values: values,
|
|
40
|
-
value: InputProps?.inputProps?.value ?? "all"
|
|
41
|
-
});
|
|
42
|
-
else return /*#__PURE__*/ jsx(VuuTypeaheadInput, {
|
|
43
|
-
...InputProps,
|
|
44
|
-
...TypeaheadProps,
|
|
45
|
-
className: className,
|
|
46
|
-
column: dataDescriptor.name,
|
|
47
|
-
"data-edit-control": true,
|
|
48
|
-
"data-variant": dataVariant,
|
|
49
|
-
onCommit: onCommit,
|
|
50
|
-
table: table
|
|
51
|
-
});
|
|
52
|
-
return /*#__PURE__*/ jsx(VuuInput, {
|
|
53
|
-
variant: "secondary",
|
|
54
|
-
...InputProps,
|
|
55
|
-
className: className,
|
|
56
|
-
commitOnBlur: commitOnBlur,
|
|
57
|
-
commitWhenCleared: commitWhenCleared,
|
|
58
|
-
onCommit: onCommit,
|
|
59
|
-
errorMessage: errorMessage,
|
|
60
|
-
"data-edit-control": true
|
|
61
|
-
});
|
|
62
|
-
};
|
|
63
|
-
export { getDataItemEditControl };
|
|
@@ -1,253 +0,0 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { Range, buildColumnMap, dataSourceRowToEntity, messageHasDataRows, queryClosest } from "@vuu-ui/vuu-utils";
|
|
3
|
-
import { Button } from "@salt-ds/core";
|
|
4
|
-
import { useCallback, useMemo, useRef, useState } from "react";
|
|
5
|
-
import { UnsavedChangesReport } from "./UnsavedChangesReport.js";
|
|
6
|
-
import { buildValidationChecker, getEditValidationRules } from "./edit-rule-validation-checker.js";
|
|
7
|
-
import { CLEAN_FORM, buildFormEditState } from "./form-edit-state.js";
|
|
8
|
-
import { useModal } from "@vuu-ui/vuu-ui-controls";
|
|
9
|
-
const CLEAN_VALIDATION = {
|
|
10
|
-
ok: true,
|
|
11
|
-
messages: {}
|
|
12
|
-
};
|
|
13
|
-
const getValidationChecker = (descriptor, editPhase)=>{
|
|
14
|
-
const rules = getEditValidationRules(descriptor, editPhase) ?? [];
|
|
15
|
-
return buildValidationChecker(rules);
|
|
16
|
-
};
|
|
17
|
-
const nextValidationState = (state, dataDescriptor, value)=>{
|
|
18
|
-
const check = getValidationChecker(dataDescriptor, "change");
|
|
19
|
-
const result = check(value, "change");
|
|
20
|
-
const { name } = dataDescriptor;
|
|
21
|
-
const { ok: wasOk, messages: existingMessages } = state;
|
|
22
|
-
if (!result.ok) return {
|
|
23
|
-
ok: false,
|
|
24
|
-
messages: {
|
|
25
|
-
...existingMessages,
|
|
26
|
-
[name]: result.messages.join("\n")
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
if (!wasOk) {
|
|
30
|
-
const fieldsInError = Object.keys(existingMessages);
|
|
31
|
-
if (fieldsInError.includes(name)) if (1 === fieldsInError.length) return {
|
|
32
|
-
ok: true,
|
|
33
|
-
messages: {}
|
|
34
|
-
};
|
|
35
|
-
else {
|
|
36
|
-
const messages = {
|
|
37
|
-
...existingMessages
|
|
38
|
-
};
|
|
39
|
-
delete messages[name];
|
|
40
|
-
return {
|
|
41
|
-
ok: false,
|
|
42
|
-
messages
|
|
43
|
-
};
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return state;
|
|
47
|
-
};
|
|
48
|
-
function find(descriptors, fieldname) {
|
|
49
|
-
const d = descriptors.find(({ name })=>name === fieldname);
|
|
50
|
-
if (d) return d;
|
|
51
|
-
throw Error(`DataValueDescriptor not found for field ${fieldname}`);
|
|
52
|
-
}
|
|
53
|
-
const getField = (target)=>{
|
|
54
|
-
const fieldElement = queryClosest(target, "[data-field]");
|
|
55
|
-
if (fieldElement) return fieldElement.dataset.field;
|
|
56
|
-
throw Error("no field ");
|
|
57
|
-
};
|
|
58
|
-
const useEditForm = ({ dataSource, formFieldDescriptors, onSubmit })=>{
|
|
59
|
-
const { showDialog, closeDialog } = useModal();
|
|
60
|
-
const currentDataSource = useRef(void 0);
|
|
61
|
-
const formFieldsContainerRef = useRef(null);
|
|
62
|
-
const entityRef = useRef(void 0);
|
|
63
|
-
const focusedFieldRef = useRef("");
|
|
64
|
-
const originalEntityRef = useRef(void 0);
|
|
65
|
-
const formEditStateRef = useRef(CLEAN_FORM);
|
|
66
|
-
const validationStateRef = useRef({
|
|
67
|
-
ok: true,
|
|
68
|
-
messages: {}
|
|
69
|
-
});
|
|
70
|
-
const [entity, _setEntity] = useState();
|
|
71
|
-
const [, forceUpdate] = useState({});
|
|
72
|
-
const setFormEditState = useCallback((newState)=>{
|
|
73
|
-
formEditStateRef.current = newState;
|
|
74
|
-
}, []);
|
|
75
|
-
const setEntity = useCallback((newEntity)=>{
|
|
76
|
-
setFormEditState(buildFormEditState(originalEntityRef.current, newEntity));
|
|
77
|
-
entityRef.current = newEntity;
|
|
78
|
-
_setEntity(newEntity);
|
|
79
|
-
}, [
|
|
80
|
-
setFormEditState
|
|
81
|
-
]);
|
|
82
|
-
const submitChanges = useCallback(async ()=>{
|
|
83
|
-
const rpcResponse = await currentDataSource.current?.rpcRequest?.({
|
|
84
|
-
params: {},
|
|
85
|
-
rpcName: "VP_BULK_EDIT_SUBMIT_RPC",
|
|
86
|
-
type: "RPC_REQUEST"
|
|
87
|
-
});
|
|
88
|
-
console.log({
|
|
89
|
-
rpcResponse
|
|
90
|
-
});
|
|
91
|
-
}, []);
|
|
92
|
-
const showSaveOrDiscardPrompt = useCallback(async ()=>{
|
|
93
|
-
const { current: currentEntity } = entityRef;
|
|
94
|
-
const { current: originalEntity } = originalEntityRef;
|
|
95
|
-
let resolver;
|
|
96
|
-
const save = async ()=>{
|
|
97
|
-
await submitChanges();
|
|
98
|
-
closeDialog();
|
|
99
|
-
resolver?.("saved");
|
|
100
|
-
};
|
|
101
|
-
const discard = ()=>{
|
|
102
|
-
closeDialog();
|
|
103
|
-
resolver?.("discarded");
|
|
104
|
-
};
|
|
105
|
-
requestAnimationFrame(()=>{
|
|
106
|
-
showDialog(/*#__PURE__*/ jsx(UnsavedChangesReport, {
|
|
107
|
-
entity: originalEntity,
|
|
108
|
-
editedEntity: currentEntity
|
|
109
|
-
}), "Unsaved Changes", [
|
|
110
|
-
/*#__PURE__*/ jsx(Button, {
|
|
111
|
-
onClick: discard,
|
|
112
|
-
children: "Discard Changes"
|
|
113
|
-
}, "cancel"),
|
|
114
|
-
/*#__PURE__*/ jsx(Button, {
|
|
115
|
-
onClick: save,
|
|
116
|
-
children: "Save Changes"
|
|
117
|
-
}, "submit")
|
|
118
|
-
], true);
|
|
119
|
-
});
|
|
120
|
-
return new Promise((resolve)=>{
|
|
121
|
-
resolver = resolve;
|
|
122
|
-
});
|
|
123
|
-
}, [
|
|
124
|
-
closeDialog,
|
|
125
|
-
showDialog,
|
|
126
|
-
submitChanges
|
|
127
|
-
]);
|
|
128
|
-
useMemo(async ()=>{
|
|
129
|
-
if (dataSource) {
|
|
130
|
-
if (false === formEditStateRef.current.isClean) await showSaveOrDiscardPrompt();
|
|
131
|
-
currentDataSource.current = dataSource;
|
|
132
|
-
originalEntityRef.current = void 0;
|
|
133
|
-
const columnMap = buildColumnMap(dataSource.columns);
|
|
134
|
-
dataSource?.subscribe({
|
|
135
|
-
range: Range(0, 1)
|
|
136
|
-
}, (message)=>{
|
|
137
|
-
if (messageHasDataRows(message)) {
|
|
138
|
-
const [row] = message.rows;
|
|
139
|
-
if (row) {
|
|
140
|
-
const entity = dataSourceRowToEntity(row, columnMap);
|
|
141
|
-
if (void 0 === originalEntityRef.current) {
|
|
142
|
-
originalEntityRef.current = entity;
|
|
143
|
-
setEntity(entity);
|
|
144
|
-
}
|
|
145
|
-
const { editedFields } = buildFormEditState(entityRef.current, entity);
|
|
146
|
-
if (1 === editedFields.length) setEntity(entity);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
}, [
|
|
152
|
-
dataSource,
|
|
153
|
-
setEntity,
|
|
154
|
-
showSaveOrDiscardPrompt
|
|
155
|
-
]);
|
|
156
|
-
const setValidationState = useCallback((state)=>{
|
|
157
|
-
validationStateRef.current = state;
|
|
158
|
-
forceUpdate({});
|
|
159
|
-
}, []);
|
|
160
|
-
const handleFieldCommit = useCallback(async (_, value)=>{
|
|
161
|
-
const { current: fieldName } = focusedFieldRef;
|
|
162
|
-
const dataDescriptor = find(formFieldDescriptors, fieldName);
|
|
163
|
-
const { current: state } = validationStateRef;
|
|
164
|
-
const newState = nextValidationState(state, dataDescriptor, value);
|
|
165
|
-
if (newState !== state) setValidationState(newState);
|
|
166
|
-
if (newState.ok && dataSource?.tableSchema) {
|
|
167
|
-
const { key } = dataSource.tableSchema;
|
|
168
|
-
const keyValue = entity?.[key];
|
|
169
|
-
const response = await dataSource.rpcRequest?.({
|
|
170
|
-
params: {
|
|
171
|
-
column: fieldName,
|
|
172
|
-
data: value,
|
|
173
|
-
key: keyValue
|
|
174
|
-
},
|
|
175
|
-
rpcName: "editCell",
|
|
176
|
-
type: "RPC_REQUEST"
|
|
177
|
-
});
|
|
178
|
-
console.log({
|
|
179
|
-
response
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
}, [
|
|
183
|
-
dataSource,
|
|
184
|
-
entity,
|
|
185
|
-
formFieldDescriptors,
|
|
186
|
-
setValidationState
|
|
187
|
-
]);
|
|
188
|
-
const handleFieldChange = useCallback((evt)=>{
|
|
189
|
-
const { current: fieldName } = focusedFieldRef;
|
|
190
|
-
if (fieldName) {
|
|
191
|
-
const input = queryClosest(evt.target, "input", true);
|
|
192
|
-
const dataDescriptor = find(formFieldDescriptors, fieldName);
|
|
193
|
-
const value = input.value;
|
|
194
|
-
const { current: state } = validationStateRef;
|
|
195
|
-
const newState = nextValidationState(state, dataDescriptor, value);
|
|
196
|
-
if (newState !== state) setValidationState(newState);
|
|
197
|
-
setEntity({
|
|
198
|
-
...entity,
|
|
199
|
-
[fieldName]: value
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
}, [
|
|
203
|
-
entity,
|
|
204
|
-
formFieldDescriptors,
|
|
205
|
-
setEntity,
|
|
206
|
-
setValidationState
|
|
207
|
-
]);
|
|
208
|
-
const handleFormSubmit = useCallback(async ()=>{
|
|
209
|
-
submitChanges();
|
|
210
|
-
setFormEditState(CLEAN_FORM);
|
|
211
|
-
originalEntityRef.current = entity;
|
|
212
|
-
onSubmit?.();
|
|
213
|
-
forceUpdate({});
|
|
214
|
-
}, [
|
|
215
|
-
entity,
|
|
216
|
-
onSubmit,
|
|
217
|
-
setFormEditState,
|
|
218
|
-
submitChanges
|
|
219
|
-
]);
|
|
220
|
-
const handleFormCancel = useCallback(async ()=>{
|
|
221
|
-
setFormEditState(CLEAN_FORM);
|
|
222
|
-
setValidationState(CLEAN_VALIDATION);
|
|
223
|
-
setEntity(originalEntityRef.current);
|
|
224
|
-
}, [
|
|
225
|
-
setEntity,
|
|
226
|
-
setFormEditState,
|
|
227
|
-
setValidationState
|
|
228
|
-
]);
|
|
229
|
-
const handleFocus = useCallback((evt)=>{
|
|
230
|
-
if (formFieldsContainerRef.current?.contains(evt.target)) {
|
|
231
|
-
const fieldName = getField(evt.target);
|
|
232
|
-
if (fieldName) {
|
|
233
|
-
if (fieldName) focusedFieldRef.current = fieldName;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}, []);
|
|
237
|
-
const { current: { ok, messages: errorMessages } } = validationStateRef;
|
|
238
|
-
const { current: { isClean, editedFields } } = formEditStateRef;
|
|
239
|
-
return {
|
|
240
|
-
editedFields,
|
|
241
|
-
editEntity: entity,
|
|
242
|
-
errorMessages,
|
|
243
|
-
formFieldsContainerRef,
|
|
244
|
-
isClean,
|
|
245
|
-
ok,
|
|
246
|
-
onCancel: handleFormCancel,
|
|
247
|
-
onChange: handleFieldChange,
|
|
248
|
-
onCommit: handleFieldCommit,
|
|
249
|
-
onFocus: handleFocus,
|
|
250
|
-
onSubmit: handleFormSubmit
|
|
251
|
-
};
|
|
252
|
-
};
|
|
253
|
-
export { useEditForm };
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { ConnectionManager, VuuDataSource } from "@vuu-ui/vuu-data-remote";
|
|
3
|
-
import { DataProvider } from "@vuu-ui/vuu-utils";
|
|
4
|
-
import { useAutoLoginToVuuServer } from "./useAutoLoginToVuuServer.js";
|
|
5
|
-
const getServerAPI = ()=>ConnectionManager.serverAPI;
|
|
6
|
-
const VuuDataSourceProvider = ({ authenticate, autoConnect = false, autoLogin = false, children, websocketUrl })=>{
|
|
7
|
-
useAutoLoginToVuuServer({
|
|
8
|
-
authenticate,
|
|
9
|
-
autoConnect,
|
|
10
|
-
autoLogin,
|
|
11
|
-
websocketUrl
|
|
12
|
-
});
|
|
13
|
-
return /*#__PURE__*/ jsx(DataProvider, {
|
|
14
|
-
VuuDataSource: VuuDataSource,
|
|
15
|
-
getServerAPI: getServerAPI,
|
|
16
|
-
isLocalData: false,
|
|
17
|
-
children: children
|
|
18
|
-
});
|
|
19
|
-
};
|
|
20
|
-
export { VuuDataSourceProvider };
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./VuuDataSourceProvider.js";
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { jsx } from "react/jsx-runtime";
|
|
2
|
-
import { ConnectionManager, authenticate as vuu_data_remote_authenticate } from "@vuu-ui/vuu-data-remote";
|
|
3
|
-
import { useEffect, useState } from "react";
|
|
4
|
-
const useAutoLoginToVuuServer = ({ authenticate = true, autoConnect = true, secure = true, token: tokenProp = "no-token", user = "steve", websocketUrl } = {})=>{
|
|
5
|
-
const [errorMessage, setErrorMessage] = useState("");
|
|
6
|
-
useEffect(()=>{
|
|
7
|
-
const connect = async ()=>{
|
|
8
|
-
try {
|
|
9
|
-
let token = tokenProp;
|
|
10
|
-
if (authenticate) {
|
|
11
|
-
const response = await vuu_data_remote_authenticate(user, "xyz", "/api/authn");
|
|
12
|
-
token = response.token;
|
|
13
|
-
}
|
|
14
|
-
const url = websocketUrl ?? `${secure ? "wss" : "ws"}://localhost/8090/websocket`;
|
|
15
|
-
ConnectionManager.connect({
|
|
16
|
-
url,
|
|
17
|
-
token
|
|
18
|
-
});
|
|
19
|
-
} catch (e) {
|
|
20
|
-
if (e instanceof Error) {
|
|
21
|
-
console.error(e.message);
|
|
22
|
-
setErrorMessage(e.message);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
};
|
|
26
|
-
if (autoConnect) connect();
|
|
27
|
-
return ()=>{
|
|
28
|
-
if (autoConnect) ConnectionManager.disconnect();
|
|
29
|
-
};
|
|
30
|
-
}, [
|
|
31
|
-
authenticate,
|
|
32
|
-
autoConnect,
|
|
33
|
-
secure,
|
|
34
|
-
tokenProp,
|
|
35
|
-
user,
|
|
36
|
-
websocketUrl
|
|
37
|
-
]);
|
|
38
|
-
if (errorMessage) return /*#__PURE__*/ jsx("p", {
|
|
39
|
-
children: "Unable to authenticate against Vuu Server A Vuu Server instance must be running to show this example."
|
|
40
|
-
});
|
|
41
|
-
};
|
|
42
|
-
export { useAutoLoginToVuuServer };
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
import { VuuDataSource } from "@vuu-ui/vuu-data-remote";
|
|
2
|
-
import { Range, buildColumnMap, getSelectedOption, isLookupRenderer, isTypeDescriptor, isValueListRenderer, useShellContext } from "@vuu-ui/vuu-utils";
|
|
3
|
-
import { useMemo, useState } from "react";
|
|
4
|
-
const NO_VALUES = [];
|
|
5
|
-
const toListOption = (value)=>({
|
|
6
|
-
label: value,
|
|
7
|
-
value
|
|
8
|
-
});
|
|
9
|
-
const lookupValueMap = new Map();
|
|
10
|
-
const loadLookupValues = ({ labelColumn, table, valueColumn })=>{
|
|
11
|
-
const tableKey = `${table.module}:${table.table}`;
|
|
12
|
-
const lookupValues = lookupValueMap.get(tableKey);
|
|
13
|
-
if (lookupValues) return lookupValues;
|
|
14
|
-
{
|
|
15
|
-
const promise = new Promise((resolve)=>{
|
|
16
|
-
const columns = [
|
|
17
|
-
valueColumn,
|
|
18
|
-
labelColumn
|
|
19
|
-
];
|
|
20
|
-
const columnMap = buildColumnMap(columns);
|
|
21
|
-
const dataSource = new VuuDataSource({
|
|
22
|
-
bufferSize: 0,
|
|
23
|
-
table
|
|
24
|
-
});
|
|
25
|
-
dataSource.subscribe({
|
|
26
|
-
columns,
|
|
27
|
-
range: Range(0, 100)
|
|
28
|
-
}, (message)=>{
|
|
29
|
-
if ("viewport-update" === message.type) {
|
|
30
|
-
if (message.rows) {
|
|
31
|
-
const listOptions = message.rows.map((row)=>({
|
|
32
|
-
value: row[columnMap[valueColumn]],
|
|
33
|
-
label: row[columnMap[labelColumn]]
|
|
34
|
-
}));
|
|
35
|
-
resolve(listOptions);
|
|
36
|
-
dataSource.unsubscribe();
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
});
|
|
41
|
-
lookupValueMap.set(tableKey, promise);
|
|
42
|
-
return promise;
|
|
43
|
-
}
|
|
44
|
-
};
|
|
45
|
-
const getLookupDetails = ({ name, type })=>{
|
|
46
|
-
if (isTypeDescriptor(type) && isLookupRenderer(type.renderer)) return type.renderer.lookup;
|
|
47
|
-
throw Error(`useLookupValues column ${name} is not configured to use lookup values`);
|
|
48
|
-
};
|
|
49
|
-
const useLookupValues = (column, initialValueProp)=>{
|
|
50
|
-
const { type: columnType } = column;
|
|
51
|
-
const { getLookupValues } = useShellContext();
|
|
52
|
-
const initialState = useMemo(()=>{
|
|
53
|
-
if (isTypeDescriptor(columnType) && isValueListRenderer(columnType?.renderer)) {
|
|
54
|
-
const values = columnType.renderer.values.map(toListOption);
|
|
55
|
-
return {
|
|
56
|
-
initialValue: getSelectedOption(values, initialValueProp) ?? null,
|
|
57
|
-
values
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
{
|
|
61
|
-
const lookupDetails = getLookupDetails(column);
|
|
62
|
-
const values = getLookupValues?.(lookupDetails.table) ?? NO_VALUES;
|
|
63
|
-
return {
|
|
64
|
-
initialValue: getSelectedOption(values, initialValueProp) ?? null,
|
|
65
|
-
values
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
}, [
|
|
69
|
-
column,
|
|
70
|
-
columnType,
|
|
71
|
-
getLookupValues,
|
|
72
|
-
initialValueProp
|
|
73
|
-
]);
|
|
74
|
-
const [{ initialValue, values }, setLookupState] = useState(initialState);
|
|
75
|
-
useMemo(()=>{
|
|
76
|
-
if (values === NO_VALUES) {
|
|
77
|
-
const lookupDetails = getLookupDetails(column);
|
|
78
|
-
loadLookupValues(lookupDetails).then((values)=>setLookupState({
|
|
79
|
-
initialValue: getSelectedOption(values, initialValueProp) ?? null,
|
|
80
|
-
values
|
|
81
|
-
}));
|
|
82
|
-
}
|
|
83
|
-
}, [
|
|
84
|
-
values,
|
|
85
|
-
column,
|
|
86
|
-
initialValueProp
|
|
87
|
-
]);
|
|
88
|
-
return {
|
|
89
|
-
initialValue,
|
|
90
|
-
values
|
|
91
|
-
};
|
|
92
|
-
};
|
|
93
|
-
export { useLookupValues };
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { useData } from "@vuu-ui/vuu-utils";
|
|
2
|
-
import { useCallback, useRef } from "react";
|
|
3
|
-
const sessionState = new Map();
|
|
4
|
-
const useSessionDataSource = (props)=>{
|
|
5
|
-
const { VuuDataSource } = useData();
|
|
6
|
-
const dataSourceConfigRef = useRef(void 0);
|
|
7
|
-
const getDataSource = useCallback((sessionKey, dataSourceConstructorProps)=>{
|
|
8
|
-
let ds = sessionState.get(sessionKey);
|
|
9
|
-
if (ds) return ds;
|
|
10
|
-
if (dataSourceConstructorProps?.columns) {
|
|
11
|
-
ds = new VuuDataSource({
|
|
12
|
-
...dataSourceConstructorProps,
|
|
13
|
-
viewport: sessionKey,
|
|
14
|
-
...dataSourceConfigRef.current
|
|
15
|
-
});
|
|
16
|
-
if (props?.onConfigChange) ds.on("config", props.onConfigChange);
|
|
17
|
-
sessionState.set(sessionKey, ds);
|
|
18
|
-
return ds;
|
|
19
|
-
}
|
|
20
|
-
throw Error("[useSessionDataSource] unable to create new DataSource, columns have not been defined ");
|
|
21
|
-
}, [
|
|
22
|
-
VuuDataSource,
|
|
23
|
-
props?.onConfigChange
|
|
24
|
-
]);
|
|
25
|
-
const clearDataSource = useCallback((sessionKey, unsubscribe)=>{
|
|
26
|
-
const ds = sessionState.get(sessionKey);
|
|
27
|
-
if (ds) {
|
|
28
|
-
sessionState.delete(sessionKey);
|
|
29
|
-
if (true === unsubscribe) ds.unsubscribe();
|
|
30
|
-
} else console.warn(`[useSessionbDatasource] clearDataSource ${sessionKey} not found `);
|
|
31
|
-
}, []);
|
|
32
|
-
return {
|
|
33
|
-
clearDataSource,
|
|
34
|
-
getDataSource
|
|
35
|
-
};
|
|
36
|
-
};
|
|
37
|
-
export { useSessionDataSource };
|