@vuu-ui/vuu-utils 2.1.4 → 2.1.5

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.
Files changed (32) hide show
  1. package/cjs/packages/vuu-utils/src/data-editing/DataEditingProvider.js +8 -8
  2. package/cjs/packages/vuu-utils/src/data-editing/DataEditingProvider.js.map +1 -1
  3. package/cjs/packages/vuu-utils/src/data-editing/EditButtons.js +3 -3
  4. package/cjs/packages/vuu-utils/src/data-editing/EditButtons.js.map +1 -1
  5. package/cjs/packages/vuu-utils/src/data-editing/{EditTracker.js → EditSession.js} +9 -16
  6. package/cjs/packages/vuu-utils/src/data-editing/EditSession.js.map +1 -0
  7. package/cjs/packages/vuu-utils/src/data-editing/useEditableTable.js +21 -14
  8. package/cjs/packages/vuu-utils/src/data-editing/useEditableTable.js.map +1 -1
  9. package/cjs/packages/vuu-utils/src/form-utils.js +28 -1
  10. package/cjs/packages/vuu-utils/src/form-utils.js.map +1 -1
  11. package/cjs/packages/vuu-utils/src/index.js +4 -3
  12. package/cjs/packages/vuu-utils/src/index.js.map +1 -1
  13. package/esm/packages/vuu-utils/src/data-editing/DataEditingProvider.js +8 -8
  14. package/esm/packages/vuu-utils/src/data-editing/DataEditingProvider.js.map +1 -1
  15. package/esm/packages/vuu-utils/src/data-editing/EditButtons.js +3 -3
  16. package/esm/packages/vuu-utils/src/data-editing/EditButtons.js.map +1 -1
  17. package/esm/packages/vuu-utils/src/data-editing/{EditTracker.js → EditSession.js} +9 -16
  18. package/esm/packages/vuu-utils/src/data-editing/EditSession.js.map +1 -0
  19. package/esm/packages/vuu-utils/src/data-editing/useEditableTable.js +21 -14
  20. package/esm/packages/vuu-utils/src/data-editing/useEditableTable.js.map +1 -1
  21. package/esm/packages/vuu-utils/src/form-utils.js +28 -2
  22. package/esm/packages/vuu-utils/src/form-utils.js.map +1 -1
  23. package/esm/packages/vuu-utils/src/index.js +3 -3
  24. package/package.json +6 -6
  25. package/types/data-editing/DataEditingProvider.d.ts +5 -5
  26. package/types/data-editing/EditButtons.d.ts +3 -3
  27. package/types/data-editing/{EditTracker.d.ts → EditSession.d.ts} +3 -3
  28. package/types/data-editing/useEditableTable.d.ts +3 -3
  29. package/types/form-utils.d.ts +5 -0
  30. package/types/index.d.ts +2 -2
  31. package/cjs/packages/vuu-utils/src/data-editing/EditTracker.js.map +0 -1
  32. package/esm/packages/vuu-utils/src/data-editing/EditTracker.js.map +0 -1
@@ -6,23 +6,23 @@ var React = require('react');
6
6
  const DataEditingContext = React.createContext(void 0);
7
7
  const DataEditingProvider = ({
8
8
  children,
9
- editTracker
9
+ editSession
10
10
  }) => {
11
- return /* @__PURE__ */ jsxRuntime.jsx(DataEditingContext.Provider, { value: editTracker, children });
11
+ return /* @__PURE__ */ jsxRuntime.jsx(DataEditingContext.Provider, { value: editSession, children });
12
12
  };
13
- function useEditTracker(throwIfUnavailable = false) {
14
- const editTracker = React.useContext(DataEditingContext);
15
- if (editTracker === void 0) {
13
+ function useEditSession(throwIfUnavailable = false) {
14
+ const editSession = React.useContext(DataEditingContext);
15
+ if (editSession === void 0) {
16
16
  if (throwIfUnavailable) {
17
17
  throw Error(
18
- "[useEditTracker] no DataEditingContext in scope. You need to enclose editable component(s) with DataEditingProvider"
18
+ "[useEditSession] no DataEditingContext in scope. You need to enclose editable component(s) with DataEditingProvider"
19
19
  );
20
20
  }
21
21
  } else {
22
- return editTracker;
22
+ return editSession;
23
23
  }
24
24
  }
25
25
 
26
26
  exports.DataEditingProvider = DataEditingProvider;
27
- exports.useEditTracker = useEditTracker;
27
+ exports.useEditSession = useEditSession;
28
28
  //# sourceMappingURL=DataEditingProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataEditingProvider.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/DataEditingProvider.tsx"],"sourcesContent":["import { createContext, ReactNode, useContext } from \"react\";\nimport { EditTracker } from \"./EditTracker\";\n\nconst DataEditingContext = createContext<EditTracker | undefined>(undefined);\n\nexport const DataEditingProvider = ({\n children,\n editTracker,\n}: {\n children: ReactNode;\n editTracker: EditTracker;\n}) => {\n return (\n <DataEditingContext.Provider value={editTracker}>\n {children}\n </DataEditingContext.Provider>\n );\n};\n\nexport function useEditTracker(\n throwIfUnavailable?: false,\n): EditTracker | undefined;\nexport function useEditTracker(throwIfUnavailable: true): EditTracker;\nexport function useEditTracker(throwIfUnavailable = false) {\n const editTracker = useContext(DataEditingContext);\n if (editTracker === undefined) {\n if (throwIfUnavailable) {\n throw Error(\n \"[useEditTracker] no DataEditingContext in scope. You need to enclose editable component(s) with DataEditingProvider\",\n );\n }\n } else {\n return editTracker;\n }\n}\n"],"names":["createContext","useContext"],"mappings":";;;;;AAGA,MAAM,kBAAA,GAAqBA,oBAAuC,KAAS,CAAA,CAAA;AAEpE,MAAM,sBAAsB,CAAC;AAAA,EAClC,QAAA;AAAA,EACA;AACF,CAGM,KAAA;AACJ,EAAA,sCACG,kBAAmB,CAAA,QAAA,EAAnB,EAA4B,KAAA,EAAO,aACjC,QACH,EAAA,CAAA;AAEJ;AAMgB,SAAA,cAAA,CAAe,qBAAqB,KAAO,EAAA;AACzD,EAAM,MAAA,WAAA,GAAcC,iBAAW,kBAAkB,CAAA;AACjD,EAAA,IAAI,gBAAgB,KAAW,CAAA,EAAA;AAC7B,IAAA,IAAI,kBAAoB,EAAA;AACtB,MAAM,MAAA,KAAA;AAAA,QACJ;AAAA,OACF;AAAA;AACF,GACK,MAAA;AACL,IAAO,OAAA,WAAA;AAAA;AAEX;;;;;"}
1
+ {"version":3,"file":"DataEditingProvider.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/DataEditingProvider.tsx"],"sourcesContent":["import { createContext, ReactNode, useContext } from \"react\";\nimport { EditSession } from \"./EditSession\";\n\nconst DataEditingContext = createContext<EditSession | undefined>(undefined);\n\nexport const DataEditingProvider = ({\n children,\n editSession,\n}: {\n children: ReactNode;\n editSession: EditSession;\n}) => {\n return (\n <DataEditingContext.Provider value={editSession}>\n {children}\n </DataEditingContext.Provider>\n );\n};\n\nexport function useEditSession(\n throwIfUnavailable?: false,\n): EditSession | undefined;\nexport function useEditSession(throwIfUnavailable: true): EditSession;\nexport function useEditSession(throwIfUnavailable = false) {\n const editSession = useContext(DataEditingContext);\n if (editSession === undefined) {\n if (throwIfUnavailable) {\n throw Error(\n \"[useEditSession] no DataEditingContext in scope. You need to enclose editable component(s) with DataEditingProvider\",\n );\n }\n } else {\n return editSession;\n }\n}\n"],"names":["createContext","useContext"],"mappings":";;;;;AAGA,MAAM,kBAAA,GAAqBA,oBAAuC,KAAS,CAAA,CAAA;AAEpE,MAAM,sBAAsB,CAAC;AAAA,EAClC,QAAA;AAAA,EACA;AACF,CAGM,KAAA;AACJ,EAAA,sCACG,kBAAmB,CAAA,QAAA,EAAnB,EAA4B,KAAA,EAAO,aACjC,QACH,EAAA,CAAA;AAEJ;AAMgB,SAAA,cAAA,CAAe,qBAAqB,KAAO,EAAA;AACzD,EAAM,MAAA,WAAA,GAAcC,iBAAW,kBAAkB,CAAA;AACjD,EAAA,IAAI,gBAAgB,KAAW,CAAA,EAAA;AAC7B,IAAA,IAAI,kBAAoB,EAAA;AACtB,MAAM,MAAA,KAAA;AAAA,QACJ;AAAA,OACF;AAAA;AACF,GACK,MAAA;AACL,IAAO,OAAA,WAAA;AAAA;AAEX;;;;;"}
@@ -5,14 +5,14 @@ var core = require('@salt-ds/core');
5
5
  var React = require('react');
6
6
 
7
7
  const EditButtons = ({
8
- editTracker,
8
+ editSession,
9
9
  onCancel,
10
10
  onSave
11
11
  }) => {
12
12
  const [editState, setEditState] = React.useState("clean");
13
13
  React.useMemo(() => {
14
- editTracker?.on("editState", setEditState);
15
- }, [editTracker]);
14
+ editSession?.on("editState", setEditState);
15
+ }, [editSession]);
16
16
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
17
17
  /* @__PURE__ */ jsxRuntime.jsx(
18
18
  core.Button,
@@ -1 +1 @@
1
- {"version":3,"file":"EditButtons.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/EditButtons.tsx"],"sourcesContent":["import { Button } from \"@salt-ds/core\";\nimport { EditState, EditTracker } from \"./EditTracker\";\nimport { useMemo, useState } from \"react\";\n\nexport interface EditButtonProps {\n editTracker?: EditTracker;\n onCancel: () => void;\n onSave: () => void;\n}\n\nexport const EditButtons = ({\n editTracker,\n onCancel,\n onSave,\n}: EditButtonProps) => {\n const [editState, setEditState] = useState<EditState>(\"clean\");\n\n useMemo(() => {\n editTracker?.on(\"editState\", setEditState);\n }, [editTracker]);\n\n return (\n <>\n <Button\n disabled={editState === \"clean\"}\n onClick={onSave}\n sentiment=\"accented\"\n >\n Save\n </Button>\n <Button onClick={onCancel}>Cancel</Button>\n </>\n );\n};\n"],"names":["useState","useMemo","jsxs","Fragment","jsx","Button"],"mappings":";;;;;;AAUO,MAAM,cAAc,CAAC;AAAA,EAC1B,WAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAuB,KAAA;AACrB,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,eAAoB,OAAO,CAAA;AAE7D,EAAAC,aAAA,CAAQ,MAAM;AACZ,IAAa,WAAA,EAAA,EAAA,CAAG,aAAa,YAAY,CAAA;AAAA,GAC3C,EAAG,CAAC,WAAW,CAAC,CAAA;AAEhB,EAAA,uBAEIC,eAAA,CAAAC,mBAAA,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAAC,cAAA;AAAA,MAACC,WAAA;AAAA,MAAA;AAAA,QACC,UAAU,SAAc,KAAA,OAAA;AAAA,QACxB,OAAS,EAAA,MAAA;AAAA,QACT,SAAU,EAAA,UAAA;AAAA,QACX,QAAA,EAAA;AAAA;AAAA,KAED;AAAA,oBACCD,cAAA,CAAAC,WAAA,EAAA,EAAO,OAAS,EAAA,QAAA,EAAU,QAAM,EAAA,QAAA,EAAA;AAAA,GACnC,EAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"EditButtons.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/EditButtons.tsx"],"sourcesContent":["import { Button } from \"@salt-ds/core\";\nimport { EditState, EditSession } from \"./EditSession\";\nimport { useMemo, useState } from \"react\";\n\nexport interface EditButtonProps {\n editSession?: EditSession;\n onCancel: () => void;\n onSave: () => void;\n}\n\nexport const EditButtons = ({\n editSession,\n onCancel,\n onSave,\n}: EditButtonProps) => {\n const [editState, setEditState] = useState<EditState>(\"clean\");\n\n useMemo(() => {\n editSession?.on(\"editState\", setEditState);\n }, [editSession]);\n\n return (\n <>\n <Button\n disabled={editState === \"clean\"}\n onClick={onSave}\n sentiment=\"accented\"\n >\n Save\n </Button>\n <Button onClick={onCancel}>Cancel</Button>\n </>\n );\n};\n"],"names":["useState","useMemo","jsxs","Fragment","jsx","Button"],"mappings":";;;;;;AAUO,MAAM,cAAc,CAAC;AAAA,EAC1B,WAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAuB,KAAA;AACrB,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAIA,eAAoB,OAAO,CAAA;AAE7D,EAAAC,aAAA,CAAQ,MAAM;AACZ,IAAa,WAAA,EAAA,EAAA,CAAG,aAAa,YAAY,CAAA;AAAA,GAC3C,EAAG,CAAC,WAAW,CAAC,CAAA;AAEhB,EAAA,uBAEIC,eAAA,CAAAC,mBAAA,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAAC,cAAA;AAAA,MAACC,WAAA;AAAA,MAAA;AAAA,QACC,UAAU,SAAc,KAAA,OAAA;AAAA,QACxB,OAAS,EAAA,MAAA;AAAA,QACT,SAAU,EAAA,UAAA;AAAA,QACX,QAAA,EAAA;AAAA;AAAA,KAED;AAAA,oBACCD,cAAA,CAAAC,WAAA,EAAA,EAAO,OAAS,EAAA,QAAA,EAAU,QAAM,EAAA,QAAA,EAAA;AAAA,GACnC,EAAA,CAAA;AAEJ;;;;"}
@@ -11,7 +11,7 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
11
11
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
12
12
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
13
13
  var _active, _rowEdits, _editCount, _dataSource, _inEditMode;
14
- class EditTracker extends eventEmitter.EventEmitter {
14
+ class EditSession extends eventEmitter.EventEmitter {
15
15
  constructor() {
16
16
  super(...arguments);
17
17
  __privateAdd(this, _active, false);
@@ -52,11 +52,8 @@ class EditTracker extends eventEmitter.EventEmitter {
52
52
  }
53
53
  async enterEditMode() {
54
54
  __privateSet(this, _inEditMode, true);
55
- const rpcResponse = await __privateGet(this, _dataSource)?.rpcRequest?.({
56
- type: "RPC_REQUEST",
57
- rpcName: "ENTER_EDIT_MODE",
58
- params: {}
59
- });
55
+ const rpcResponse = await __privateGet(this, _dataSource)?.beginEditSession?.();
56
+ console.log({ rpcResponse });
60
57
  if (protocolMessageUtils.isRpcSuccess(rpcResponse)) {
61
58
  const { table: sessionTable } = rpcResponse.data;
62
59
  return sessionTable;
@@ -73,7 +70,7 @@ class EditTracker extends eventEmitter.EventEmitter {
73
70
  async cancelChanges() {
74
71
  const rpcResponse = await __privateGet(this, _dataSource)?.rpcRequest?.({
75
72
  type: "RPC_REQUEST",
76
- rpcName: "EXIT_EDIT_MODE",
73
+ rpcName: "endEditSession",
77
74
  params: {}
78
75
  });
79
76
  this.clear();
@@ -82,7 +79,7 @@ class EditTracker extends eventEmitter.EventEmitter {
82
79
  async saveChanges() {
83
80
  const rpcResponse = await __privateGet(this, _dataSource)?.rpcRequest?.({
84
81
  type: "RPC_REQUEST",
85
- rpcName: "EXIT_EDIT_MODE",
82
+ rpcName: "endEditSession",
86
83
  params: { save: true }
87
84
  });
88
85
  this.clear();
@@ -121,22 +118,18 @@ class EditTracker extends eventEmitter.EventEmitter {
121
118
  this.editCount = __privateGet(this, _editCount) + 1;
122
119
  }
123
120
  }
124
- //TODO alow a shortcut commit that allows a value, bypassing need
125
- // for edit. Thids caters for boolean values, dropdown list etc
126
- // that have no intermediate edit phase
127
- async commit(key, columnName) {
121
+ async commit(key, columnName, typedValue) {
128
122
  const rowEditDetails = __privateGet(this, _rowEdits).get(key);
129
123
  if (rowEditDetails) {
130
124
  const { cellEdits } = rowEditDetails;
131
125
  const cellEditValues = cellEdits.get(columnName);
132
126
  if (cellEditValues) {
133
- const { editedValue } = cellEditValues;
134
127
  const rpcResponse = await __privateGet(this, _dataSource)?.rpcRequest?.({
135
128
  type: "RPC_REQUEST",
136
129
  rpcName: "editCell",
137
130
  params: {
138
131
  column: columnName,
139
- data: editedValue,
132
+ data: typedValue,
140
133
  key
141
134
  }
142
135
  });
@@ -156,5 +149,5 @@ _editCount = new WeakMap();
156
149
  _dataSource = new WeakMap();
157
150
  _inEditMode = new WeakMap();
158
151
 
159
- exports.EditTracker = EditTracker;
160
- //# sourceMappingURL=EditTracker.js.map
152
+ exports.EditSession = EditSession;
153
+ //# sourceMappingURL=EditSession.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditSession.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/EditSession.tsx"],"sourcesContent":["import { DataSource } from \"@vuu-ui/vuu-data-types\";\nimport type {\n RpcResultError,\n VuuRowDataItemType,\n VuuTable,\n} from \"@vuu-ui/vuu-protocol-types\";\nimport { EventEmitter } from \"../event-emitter\";\nimport { isRpcSuccess } from \"../protocol-message-utils\";\n\nexport type EditState = \"clean\" | \"dirty\";\n\ntype CellEdit = {\n originalValue: VuuRowDataItemType;\n editedValue: VuuRowDataItemType;\n};\n\ntype RowEditDetails = {\n /**\n * Column name => cell edit details\n */\n cellEdits: Map<string, CellEdit>;\n};\n\ntype EditSessionEvents = {\n editState: (editState: EditState) => void;\n};\n\nexport class EditSession extends EventEmitter<EditSessionEvents> {\n #active = false;\n /**\n * Row key => row edits\n */\n #rowEdits = new Map<string, RowEditDetails>();\n #editCount = 0;\n #dataSource?: DataSource;\n #inEditMode = false;\n\n get active() {\n return this.#active;\n }\n set active(isActive: boolean) {\n this.#active = isActive;\n }\n get editCount() {\n return this.#editCount;\n }\n\n set editCount(val: number) {\n if (val !== this.#editCount) {\n const oldCount = this.#editCount;\n this.#editCount = val;\n if (val === 0) {\n this.emit(\"editState\", \"clean\");\n } else if (oldCount === 0) {\n this.emit(\"editState\", \"dirty\");\n }\n }\n }\n\n set dataSource(ds: DataSource) {\n this.#dataSource = ds;\n }\n\n clear() {\n this.#rowEdits.clear();\n this.#editCount = 0;\n }\n\n async enterEditMode() {\n this.#inEditMode = true;\n\n const rpcResponse = await this.#dataSource?.beginEditSession?.();\n\n console.log({ rpcResponse });\n\n if (isRpcSuccess(rpcResponse)) {\n const { table: sessionTable } = rpcResponse.data as { table: VuuTable };\n return sessionTable;\n } else {\n console.log(\"fail\");\n }\n }\n\n get inEditMode() {\n return this.#inEditMode;\n }\n\n get editState(): EditState {\n return this.editCount === 0 ? \"clean\" : \"dirty\";\n }\n\n async cancelChanges() {\n const rpcResponse = await this.#dataSource?.rpcRequest?.({\n type: \"RPC_REQUEST\",\n rpcName: \"endEditSession\",\n params: {},\n });\n this.clear();\n return rpcResponse;\n }\n\n async saveChanges() {\n const rpcResponse = await this.#dataSource?.rpcRequest?.({\n type: \"RPC_REQUEST\",\n rpcName: \"endEditSession\",\n params: { save: true },\n });\n this.clear();\n return rpcResponse;\n }\n\n // TODO how do we deal with the '_edited' pattern\n edit(\n key: string,\n columnName: string,\n originalValue: VuuRowDataItemType,\n newValue: VuuRowDataItemType,\n ) {\n const rowEditDetails = this.#rowEdits.get(key);\n if (rowEditDetails) {\n const { cellEdits } = rowEditDetails;\n const cellEdit = cellEdits.get(columnName);\n if (cellEdit) {\n if (newValue === cellEdit.originalValue) {\n if (cellEdits.size === 1) {\n this.#rowEdits.delete(key);\n } else {\n // re-editing a cell had removed the edit\n cellEdits.delete(columnName);\n }\n this.editCount = this.#editCount - 1;\n } else {\n cellEdit.editedValue = newValue;\n }\n } else {\n // row has already been edited, but this column has not\n cellEdits.set(columnName, {\n originalValue,\n editedValue: newValue,\n });\n this.editCount = this.#editCount + 1;\n }\n } else {\n this.#rowEdits.set(key, {\n cellEdits: new Map([\n [columnName, { originalValue, editedValue: newValue }],\n ]),\n });\n this.editCount = this.#editCount + 1;\n }\n }\n\n async commit(\n key: string,\n columnName: string,\n typedValue: string | number | boolean,\n ) {\n const rowEditDetails = this.#rowEdits.get(key);\n if (rowEditDetails) {\n const { cellEdits } = rowEditDetails;\n const cellEditValues = cellEdits.get(columnName);\n if (cellEditValues) {\n const rpcResponse = await this.#dataSource?.rpcRequest?.({\n type: \"RPC_REQUEST\",\n rpcName: \"editCell\",\n params: {\n column: columnName,\n data: typedValue,\n key,\n },\n });\n\n return rpcResponse;\n }\n } else {\n return {\n errorMessage: \"CHANGE_REVERTED\",\n type: \"ERROR_RESULT\",\n } as RpcResultError;\n }\n }\n}\n"],"names":["EventEmitter","isRpcSuccess"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  var React = require('react');
4
- var EditTracker = require('./EditTracker.js');
4
+ var EditSession = require('./EditSession.js');
5
5
  var DataProvider = require('../context-definitions/DataProvider.js');
6
6
  var protocolMessageUtils = require('../protocol-message-utils.js');
7
7
  var useLayoutEffectSkipFirst = require('../useLayoutEffectSkipFirst.js');
@@ -26,47 +26,54 @@ const useEditableTable = ({
26
26
  console.warn(`[useEditableTable] columns and or table changed`);
27
27
  }, [columns, table]);
28
28
  const dataSource = React.useMemo(() => {
29
- return dataSourceProp ?? new VuuDataSource({ columns, table });
29
+ if (dataSourceProp) {
30
+ return dataSourceProp;
31
+ } else if (table) {
32
+ return new VuuDataSource({ columns, table });
33
+ } else {
34
+ throw Error(
35
+ `useEditableTable unable to provide DataSource, neither dataSource nor table available as props`
36
+ );
37
+ }
30
38
  }, [VuuDataSource, columns, dataSourceProp, table]);
31
- const editTracker = React.useMemo(() => new EditTracker.EditTracker(), []);
39
+ const editSession = React.useMemo(() => new EditSession.EditSession(), []);
32
40
  React.useMemo(() => {
33
41
  if (dataSource) {
34
- editTracker.dataSource = dataSource;
42
+ editSession.dataSource = dataSource;
35
43
  }
36
- }, [dataSource, editTracker]);
44
+ }, [dataSource, editSession]);
37
45
  const handleCancel = React.useCallback(() => {
38
- editTracker.cancelChanges();
46
+ editSession.cancelChanges();
39
47
  onCancel();
40
48
  clearSessionDataSource();
41
49
  dataSource.resume?.();
42
- }, [clearSessionDataSource, dataSource, editTracker, onCancel]);
50
+ }, [clearSessionDataSource, dataSource, editSession, onCancel]);
43
51
  const handleSave = React.useCallback(async () => {
44
52
  dataSource.resume?.();
45
- const response = await editTracker.saveChanges();
53
+ const response = await editSession.saveChanges();
46
54
  if (protocolMessageUtils.isRpcSuccess(response)) {
47
55
  onSave();
48
56
  clearSessionDataSource();
49
57
  }
50
- }, [clearSessionDataSource, dataSource, editTracker, onSave]);
58
+ }, [clearSessionDataSource, dataSource, editSession, onSave]);
51
59
  React.useMemo(async () => {
52
60
  if (isEditMode) {
53
- const sessionTable = await editTracker.enterEditMode();
61
+ const sessionTable = await editSession.enterEditMode();
54
62
  if (sessionTable && dataSource.tableSchema) {
55
- dataSource.suspend?.(false);
56
63
  const sessionDataSource2 = new VuuDataSource({
57
64
  columns: dataSource.columns,
58
65
  table: sessionTable,
59
66
  viewport: sessionTable.table
60
67
  });
61
68
  setSessionDataSource(sessionDataSource2);
62
- editTracker.dataSource = sessionDataSource2;
69
+ editSession.dataSource = sessionDataSource2;
63
70
  }
64
71
  }
65
- }, [VuuDataSource, dataSource, editTracker, isEditMode]);
72
+ }, [VuuDataSource, dataSource, editSession, isEditMode]);
66
73
  return {
67
74
  // DO we need to reset the dataSource or could useDataSOurce detect the sessiondataSOurce from the editSession ?
68
75
  dataSource: sessionDataSource ?? dataSource,
69
- editTracker,
76
+ editSession,
70
77
  onCancel: handleCancel,
71
78
  onSave: handleSave
72
79
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useEditableTable.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/useEditableTable.ts"],"sourcesContent":["import { VuuTable } from \"@vuu-ui/vuu-protocol-types\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { EditTracker } from \"./EditTracker\";\nimport { useData } from \"../context-definitions/DataProvider\";\nimport { DataSource } from \"@vuu-ui/vuu-data-types\";\nimport { isRpcSuccess } from \"../protocol-message-utils\";\nimport { useLayoutEffectSkipFirst } from \"../useLayoutEffectSkipFirst\";\n\nexport type EditMode = \"edit\" | \"view\";\n\nexport interface EditableTableHookProps {\n /**\n * columns to be included in subscription. If not provided,\n * default will be '*'. Ignored if dataSource prop present.\n */\n columns?: string[];\n dataSource?: DataSource;\n isEditMode: boolean;\n onCancel: () => void;\n onSave: () => void;\n /**\n * If dataSource not provided, new DataSource\n * will be created using table and columns\n */\n table: VuuTable;\n}\n\nexport const useEditableTable = ({\n columns,\n dataSource: dataSourceProp,\n isEditMode,\n onCancel,\n onSave,\n table,\n}: EditableTableHookProps) => {\n const { VuuDataSource } = useData();\n const [sessionDataSource, setSessionDataSource] = useState<\n DataSource | undefined\n >(undefined);\n\n const clearSessionDataSource = useCallback(() => {\n setSessionDataSource((dataSource) => {\n dataSource?.unsubscribe();\n return undefined;\n });\n }, []);\n\n useLayoutEffectSkipFirst(() => {\n console.warn(`[useEditableTable] columns and or table changed`);\n }, [columns, table]);\n\n const dataSource = useMemo(() => {\n return dataSourceProp ?? new VuuDataSource({ columns, table });\n }, [VuuDataSource, columns, dataSourceProp, table]);\n\n const editTracker = useMemo(() => new EditTracker(), []);\n\n useMemo(() => {\n if (dataSource) {\n editTracker.dataSource = dataSource;\n }\n }, [dataSource, editTracker]);\n\n const handleCancel = useCallback(() => {\n // editTracker.dataSource = dataSource;\n editTracker.cancelChanges();\n onCancel();\n clearSessionDataSource();\n dataSource.resume?.();\n }, [clearSessionDataSource, dataSource, editTracker, onCancel]);\n\n const handleSave = useCallback(async () => {\n dataSource.resume?.();\n const response = await editTracker.saveChanges();\n if (isRpcSuccess(response)) {\n onSave();\n clearSessionDataSource();\n }\n }, [clearSessionDataSource, dataSource, editTracker, onSave]);\n\n useMemo(async () => {\n if (isEditMode) {\n const sessionTable = await editTracker.enterEditMode();\n if (sessionTable && dataSource.tableSchema) {\n dataSource.suspend?.(false);\n const sessionDataSource = new VuuDataSource({\n columns: dataSource.columns,\n table: sessionTable,\n viewport: sessionTable.table,\n });\n setSessionDataSource(sessionDataSource);\n editTracker.dataSource = sessionDataSource;\n }\n }\n }, [VuuDataSource, dataSource, editTracker, isEditMode]);\n\n return {\n // DO we need to reset the dataSource or could useDataSOurce detect the sessiondataSOurce from the editSession ?\n dataSource: sessionDataSource ?? dataSource,\n editTracker,\n onCancel: handleCancel,\n onSave: handleSave,\n };\n};\n"],"names":["useData","useState","useCallback","dataSource","useLayoutEffectSkipFirst","useMemo","EditTracker","isRpcSuccess","sessionDataSource"],"mappings":"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"}
1
+ {"version":3,"file":"useEditableTable.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/useEditableTable.ts"],"sourcesContent":["import { VuuTable } from \"@vuu-ui/vuu-protocol-types\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { EditSession } from \"./EditSession\";\nimport { useData } from \"../context-definitions/DataProvider\";\nimport { DataSource } from \"@vuu-ui/vuu-data-types\";\nimport { isRpcSuccess } from \"../protocol-message-utils\";\nimport { useLayoutEffectSkipFirst } from \"../useLayoutEffectSkipFirst\";\n\nexport type EditMode = \"edit\" | \"view\";\n\nexport interface EditableTableHookProps {\n /**\n * columns to be included in subscription. If not provided,\n * default will be '*'. Ignored if dataSource prop present.\n */\n columns?: string[];\n dataSource?: DataSource;\n isEditMode: boolean;\n onCancel: () => void;\n onSave: () => void;\n /**\n * If dataSource not provided, new DataSource\n * will be created using table and columns\n */\n table?: VuuTable;\n}\n\nexport const useEditableTable = ({\n columns,\n dataSource: dataSourceProp,\n isEditMode,\n onCancel,\n onSave,\n table,\n}: EditableTableHookProps) => {\n const { VuuDataSource } = useData();\n const [sessionDataSource, setSessionDataSource] = useState<\n DataSource | undefined\n >(undefined);\n\n const clearSessionDataSource = useCallback(() => {\n setSessionDataSource((dataSource) => {\n dataSource?.unsubscribe();\n return undefined;\n });\n }, []);\n\n useLayoutEffectSkipFirst(() => {\n console.warn(`[useEditableTable] columns and or table changed`);\n }, [columns, table]);\n\n const dataSource = useMemo(() => {\n // The dataSource would normally be managed by client and passed in, but for\n // simple use cases we can create it here.\n if (dataSourceProp) {\n return dataSourceProp;\n } else if (table) {\n return new VuuDataSource({ columns, table });\n } else {\n throw Error(\n `useEditableTable unable to provide DataSource, neither dataSource nor table available as props`,\n );\n }\n }, [VuuDataSource, columns, dataSourceProp, table]);\n\n // The editSession will be made available to all the edit controls in scope by\n // wrapping the edit component with a DataEditingProvider.\n const editSession = useMemo(() => new EditSession(), []);\n\n useMemo(() => {\n if (dataSource) {\n editSession.dataSource = dataSource;\n }\n }, [dataSource, editSession]);\n\n const handleCancel = useCallback(() => {\n // editTracker.dataSource = dataSource;\n editSession.cancelChanges();\n onCancel();\n clearSessionDataSource();\n dataSource.resume?.();\n }, [clearSessionDataSource, dataSource, editSession, onCancel]);\n\n const handleSave = useCallback(async () => {\n dataSource.resume?.();\n const response = await editSession.saveChanges();\n if (isRpcSuccess(response)) {\n onSave();\n clearSessionDataSource();\n }\n }, [clearSessionDataSource, dataSource, editSession, onSave]);\n\n useMemo(async () => {\n if (isEditMode) {\n const sessionTable = await editSession.enterEditMode();\n if (sessionTable && dataSource.tableSchema) {\n // dataSource.suspend?.(false);\n const sessionDataSource = new VuuDataSource({\n columns: dataSource.columns,\n table: sessionTable,\n viewport: sessionTable.table,\n });\n setSessionDataSource(sessionDataSource);\n editSession.dataSource = sessionDataSource;\n }\n }\n }, [VuuDataSource, dataSource, editSession, isEditMode]);\n\n return {\n // DO we need to reset the dataSource or could useDataSOurce detect the sessiondataSOurce from the editSession ?\n dataSource: sessionDataSource ?? dataSource,\n editSession,\n onCancel: handleCancel,\n onSave: handleSave,\n };\n};\n"],"names":["useData","useState","useCallback","dataSource","useLayoutEffectSkipFirst","useMemo","EditSession","isRpcSuccess","sessionDataSource"],"mappings":"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"}
@@ -7,6 +7,18 @@ require('@internationalized/date');
7
7
  var htmlUtils = require('./html-utils.js');
8
8
  var ScaledDecimal = require('./ScaledDecimal.js');
9
9
 
10
+ var __defProp = Object.defineProperty;
11
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
12
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
13
+ class DataValidationError extends Error {
14
+ constructor(message, expectedType, actualType) {
15
+ super(message);
16
+ __publicField(this, "actualType");
17
+ __publicField(this, "expectedType");
18
+ this.actualType = actualType;
19
+ this.expectedType = expectedType;
20
+ }
21
+ }
10
22
  const getFieldName = (target) => {
11
23
  const saltFormField = htmlUtils.queryClosest(target, "[data-field]");
12
24
  const fieldName = saltFormField?.dataset.field;
@@ -29,6 +41,16 @@ function getTypedRange([value1, value2], dataType, options) {
29
41
  getTypedValue(value2, dataType, false, options)
30
42
  ];
31
43
  }
44
+ const getActualType = (value) => {
45
+ if (typeof value === "boolean") {
46
+ return "boolean";
47
+ } else if (typeof value === "number") {
48
+ return "number";
49
+ } else if (typeof value === "string") {
50
+ return "string";
51
+ }
52
+ return "string";
53
+ };
32
54
  function getTypedValue(value, type, throwIfInvalid = false, options) {
33
55
  switch (type) {
34
56
  case "int":
@@ -56,7 +78,11 @@ function getTypedValue(value, type, throwIfInvalid = false, options) {
56
78
  if (dataUtils.stringIsValidDecimal(value)) {
57
79
  return parseFloat(value);
58
80
  } else if (throwIfInvalid) {
59
- throw Error(`value ${value} is not a valid ${type}`);
81
+ throw new DataValidationError(
82
+ `value ${value} is not a valid ${type}`,
83
+ "decimal",
84
+ getActualType(value)
85
+ );
60
86
  } else {
61
87
  return void 0;
62
88
  }
@@ -82,6 +108,7 @@ function getTypedValue(value, type, throwIfInvalid = false, options) {
82
108
  }
83
109
  }
84
110
 
111
+ exports.DataValidationError = DataValidationError;
85
112
  exports.getFieldName = getFieldName;
86
113
  exports.getTypedRange = getTypedRange;
87
114
  exports.getTypedValue = getTypedValue;
@@ -1 +1 @@
1
- {"version":3,"file":"form-utils.js","sources":["../../../../../../packages/vuu-utils/src/form-utils.ts"],"sourcesContent":["import { DataValueTypeSimple } from \"@vuu-ui/vuu-data-types\";\nimport {\n VuuColumnDataType,\n VuuRowDataItemType,\n} from \"@vuu-ui/vuu-protocol-types\";\nimport { KeyboardEvent, SyntheticEvent } from \"react\";\nimport { stringIsValidDecimal, stringIsValidInt } from \"./data-utils\";\nimport { isValidTimeString, Time } from \"./date\";\nimport { queryClosest } from \"./html-utils\";\nimport { ExtendedFilterOptions } from \"@vuu-ui/vuu-filter-types\";\nimport {\n type ScaledDecimal,\n ScaledDecimal2,\n ScaledDecimal4,\n ScaledDecimal6,\n ScaledDecimal8,\n} from \"./ScaledDecimal\";\n\n/**\n * Use with the following convention:\n *\n * <FormField data-field=\"my-field-name\">\n */\nexport const getFieldName = (target: EventTarget | HTMLElement): string => {\n const saltFormField = queryClosest(target, \"[data-field]\") as HTMLElement;\n const fieldName = saltFormField?.dataset.field;\n if (fieldName) {\n return fieldName;\n } else {\n throw Error(\"named form field not found\");\n }\n};\n\nexport type InputSource = \"typeahead-suggestion\" | \"text-input\";\n\nexport const isNumber = (\n type: string,\n value: VuuRowDataItemType,\n): value is number => type === \"number\";\n\nexport type CommitHandler<\n E extends HTMLElement = HTMLInputElement,\n T = VuuRowDataItemType,\n> = (\n evt: SyntheticEvent<E> | KeyboardEvent<E>,\n value: T,\n source?: InputSource,\n) => void;\n\nexport const isValidRange = <T>([val1, val2]: [T, T]) => {\n if (isValidTimeString(val1) && isValidTimeString(val2)) {\n return val2 > val1;\n }\n return true;\n};\n\n/**\n * Convert a pair of string values to the type appropriate for the\n * associated column or form field. Can be used when processing a string value\n * from an input used for user editing.\n *\n */\nexport function getTypedRange(\n [value1, value2]: [string, string],\n dataType: VuuColumnDataType | DataValueTypeSimple,\n options?: ExtendedFilterOptions,\n) {\n return [\n getTypedValue(value1, dataType, false, options),\n getTypedValue(value2, dataType, false, options),\n ];\n}\n\n/**\n * Convert a string value to the type appropriate for the associated\n * column or form field. Can be used when processing a string value\n * from an input used for user editing.\n *\n * @param value\n * @param type\n * @param throwIfInvalid\n */\nexport function getTypedValue(\n value: string,\n type: VuuColumnDataType | DataValueTypeSimple,\n throwIfInvalid?: false,\n options?: ExtendedFilterOptions,\n): VuuRowDataItemType | undefined;\nexport function getTypedValue(\n value: string,\n type: VuuColumnDataType | DataValueTypeSimple,\n throwIfInvalid: true,\n options?: ExtendedFilterOptions,\n): VuuRowDataItemType;\nexport function getTypedValue(\n value: string,\n type: VuuColumnDataType | DataValueTypeSimple,\n throwIfInvalid = false,\n options?: ExtendedFilterOptions,\n): VuuRowDataItemType | ScaledDecimal | undefined {\n switch (type) {\n case \"int\":\n case \"long\": {\n if (stringIsValidInt(value)) {\n return parseInt(value, 10);\n } else if (isValidTimeString(value)) {\n //TOCHECK\n return value;\n } else if (throwIfInvalid) {\n throw Error(`value ${value} is not a valid ${type}`);\n } else {\n return undefined;\n }\n }\n\n case \"scaleddecimal2\":\n return ScaledDecimal2(value);\n case \"scaleddecimal4\":\n return ScaledDecimal4(value);\n case \"scaleddecimal6\":\n return ScaledDecimal6(value);\n case \"scaleddecimal8\":\n return ScaledDecimal8(value);\n case \"double\":\n case \"number\": {\n if (stringIsValidDecimal(value)) {\n return parseFloat(value);\n } else if (throwIfInvalid) {\n throw Error(`value ${value} is not a valid ${type}`);\n } else {\n return undefined;\n }\n }\n\n case \"boolean\":\n return value === \"true\" ? true : false;\n\n case \"time\":\n if (isValidTimeString(value)) {\n // We don't manipulate the values of 'extended' filters, the\n // ExtendedFilter impementation will do that.\n if (options?.type === \"TimeString\") {\n return value;\n } else {\n return +Time(value).asDate();\n }\n } else if (value.length > 0 && Time.isDateInMillis(value)) {\n //if value previously converted\n return Number(value);\n } else if (throwIfInvalid) {\n throw Error(`value ${value} is not a valid ${type}`);\n } else {\n return undefined;\n }\n default:\n return value;\n }\n}\n"],"names":["queryClosest","isValidTimeString","stringIsValidInt","ScaledDecimal2","ScaledDecimal4","ScaledDecimal6","ScaledDecimal8","stringIsValidDecimal","Time"],"mappings":"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"}
1
+ {"version":3,"file":"form-utils.js","sources":["../../../../../../packages/vuu-utils/src/form-utils.ts"],"sourcesContent":["import { DataValueTypeSimple } from \"@vuu-ui/vuu-data-types\";\nimport {\n VuuColumnDataType,\n VuuRowDataItemType,\n} from \"@vuu-ui/vuu-protocol-types\";\nimport { KeyboardEvent, SyntheticEvent } from \"react\";\nimport { stringIsValidDecimal, stringIsValidInt } from \"./data-utils\";\nimport { isValidTimeString, Time } from \"./date\";\nimport { queryClosest } from \"./html-utils\";\nimport { ExtendedFilterOptions } from \"@vuu-ui/vuu-filter-types\";\nimport {\n type ScaledDecimal,\n ScaledDecimal2,\n ScaledDecimal4,\n ScaledDecimal6,\n ScaledDecimal8,\n} from \"./ScaledDecimal\";\n\nexport class DataValidationError extends Error {\n actualType: string;\n expectedType: string;\n constructor(message: string, expectedType: string, actualType: string) {\n super(message);\n this.actualType = actualType;\n this.expectedType = expectedType;\n }\n}\n\n/**\n * Use with the following convention:\n *\n * <FormField data-field=\"my-field-name\">\n */\nexport const getFieldName = (target: EventTarget | HTMLElement): string => {\n const saltFormField = queryClosest(target, \"[data-field]\") as HTMLElement;\n const fieldName = saltFormField?.dataset.field;\n if (fieldName) {\n return fieldName;\n } else {\n throw Error(\"named form field not found\");\n }\n};\n\nexport type InputSource = \"typeahead-suggestion\" | \"text-input\";\n\nexport const isNumber = (\n type: string,\n value: VuuRowDataItemType,\n): value is number => type === \"number\";\n\nexport type CommitHandler<\n E extends HTMLElement = HTMLInputElement,\n T = VuuRowDataItemType,\n> = (\n evt: SyntheticEvent<E> | KeyboardEvent<E>,\n value: T,\n source?: InputSource,\n) => void;\n\nexport const isValidRange = <T>([val1, val2]: [T, T]) => {\n if (isValidTimeString(val1) && isValidTimeString(val2)) {\n return val2 > val1;\n }\n return true;\n};\n\n/**\n * Convert a pair of string values to the type appropriate for the\n * associated column or form field. Can be used when processing a string value\n * from an input used for user editing.\n *\n */\nexport function getTypedRange(\n [value1, value2]: [string, string],\n dataType: VuuColumnDataType | DataValueTypeSimple,\n options?: ExtendedFilterOptions,\n) {\n return [\n getTypedValue(value1, dataType, false, options),\n getTypedValue(value2, dataType, false, options),\n ];\n}\n\nconst getActualType = (\n value: string | number | boolean,\n): \"string\" | \"number\" | \"boolean\" => {\n if (typeof value === \"boolean\") {\n return \"boolean\";\n } else if (typeof value === \"number\") {\n return \"number\";\n } else if (typeof value === \"string\") {\n return \"string\";\n }\n return \"string\";\n};\n\n/**\n * Convert a string value to the type appropriate for the associated\n * column or form field. Can be used when processing a string value\n * from an input used for user editing.\n *\n * @param value\n * @param type\n * @param throwIfInvalid\n */\nexport function getTypedValue(\n value: string,\n type: VuuColumnDataType | DataValueTypeSimple,\n throwIfInvalid?: false,\n options?: ExtendedFilterOptions,\n): VuuRowDataItemType | undefined;\nexport function getTypedValue(\n value: string,\n type: VuuColumnDataType | DataValueTypeSimple,\n throwIfInvalid: true,\n options?: ExtendedFilterOptions,\n): VuuRowDataItemType;\nexport function getTypedValue(\n value: string,\n type: VuuColumnDataType | DataValueTypeSimple,\n throwIfInvalid = false,\n options?: ExtendedFilterOptions,\n): VuuRowDataItemType | ScaledDecimal | undefined {\n switch (type) {\n case \"int\":\n case \"long\": {\n if (stringIsValidInt(value)) {\n return parseInt(value, 10);\n } else if (isValidTimeString(value)) {\n //TOCHECK\n return value;\n } else if (throwIfInvalid) {\n throw Error(`value ${value} is not a valid ${type}`);\n } else {\n return undefined;\n }\n }\n\n case \"scaleddecimal2\":\n return ScaledDecimal2(value);\n case \"scaleddecimal4\":\n return ScaledDecimal4(value);\n case \"scaleddecimal6\":\n return ScaledDecimal6(value);\n case \"scaleddecimal8\":\n return ScaledDecimal8(value);\n case \"double\":\n case \"number\": {\n if (stringIsValidDecimal(value)) {\n return parseFloat(value);\n } else if (throwIfInvalid) {\n throw new DataValidationError(\n `value ${value} is not a valid ${type}`,\n \"decimal\",\n getActualType(value),\n );\n } else {\n return undefined;\n }\n }\n\n case \"boolean\":\n return value === \"true\" ? true : false;\n\n case \"time\":\n if (isValidTimeString(value)) {\n // We don't manipulate the values of 'extended' filters, the\n // ExtendedFilter impementation will do that.\n if (options?.type === \"TimeString\") {\n return value;\n } else {\n return +Time(value).asDate();\n }\n } else if (value.length > 0 && Time.isDateInMillis(value)) {\n //if value previously converted\n return Number(value);\n } else if (throwIfInvalid) {\n throw Error(`value ${value} is not a valid ${type}`);\n } else {\n return undefined;\n }\n default:\n return value;\n }\n}\n"],"names":["queryClosest","isValidTimeString","stringIsValidInt","ScaledDecimal2","ScaledDecimal4","ScaledDecimal6","ScaledDecimal8","stringIsValidDecimal","Time"],"mappings":"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"}
@@ -14,7 +14,7 @@ var cookieUtils = require('./cookie-utils.js');
14
14
  var cssUtils = require('./css-utils.js');
15
15
  var EditButtons = require('./data-editing/EditButtons.js');
16
16
  var DataEditingProvider = require('./data-editing/DataEditingProvider.js');
17
- var EditTracker = require('./data-editing/EditTracker.js');
17
+ var EditSession = require('./data-editing/EditSession.js');
18
18
  var useEditableTable = require('./data-editing/useEditableTable.js');
19
19
  var dataUtils = require('./data-utils.js');
20
20
  var BaseDataSource = require('./datasource/BaseDataSource.js');
@@ -205,8 +205,8 @@ exports.setCookieValue = cookieUtils.setCookieValue;
205
205
  exports.importCSS = cssUtils.importCSS;
206
206
  exports.EditButtons = EditButtons.EditButtons;
207
207
  exports.DataEditingProvider = DataEditingProvider.DataEditingProvider;
208
- exports.useEditTracker = DataEditingProvider.useEditTracker;
209
- exports.EditTracker = EditTracker.EditTracker;
208
+ exports.useEditSession = DataEditingProvider.useEditSession;
209
+ exports.EditSession = EditSession.EditSession;
210
210
  exports.useEditableTable = useEditableTable.useEditableTable;
211
211
  exports.DOWN1 = dataUtils.DOWN1;
212
212
  exports.DOWN2 = dataUtils.DOWN2;
@@ -310,6 +310,7 @@ exports.stripFilterFromColumns = filterUtils.stripFilterFromColumns;
310
310
  exports.ONE_DAY_IN_MILLIS = filterAsQuery.ONE_DAY_IN_MILLIS;
311
311
  exports.dateFilterAsQuery = filterAsQuery.dateFilterAsQuery;
312
312
  exports.filterAsQuery = filterAsQuery.filterAsQuery;
313
+ exports.DataValidationError = formUtils.DataValidationError;
313
314
  exports.getFieldName = formUtils.getFieldName;
314
315
  exports.getTypedRange = formUtils.getTypedRange;
315
316
  exports.getTypedValue = formUtils.getTypedValue;
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -4,22 +4,22 @@ import { createContext, useContext } from 'react';
4
4
  const DataEditingContext = createContext(void 0);
5
5
  const DataEditingProvider = ({
6
6
  children,
7
- editTracker
7
+ editSession
8
8
  }) => {
9
- return /* @__PURE__ */ jsx(DataEditingContext.Provider, { value: editTracker, children });
9
+ return /* @__PURE__ */ jsx(DataEditingContext.Provider, { value: editSession, children });
10
10
  };
11
- function useEditTracker(throwIfUnavailable = false) {
12
- const editTracker = useContext(DataEditingContext);
13
- if (editTracker === void 0) {
11
+ function useEditSession(throwIfUnavailable = false) {
12
+ const editSession = useContext(DataEditingContext);
13
+ if (editSession === void 0) {
14
14
  if (throwIfUnavailable) {
15
15
  throw Error(
16
- "[useEditTracker] no DataEditingContext in scope. You need to enclose editable component(s) with DataEditingProvider"
16
+ "[useEditSession] no DataEditingContext in scope. You need to enclose editable component(s) with DataEditingProvider"
17
17
  );
18
18
  }
19
19
  } else {
20
- return editTracker;
20
+ return editSession;
21
21
  }
22
22
  }
23
23
 
24
- export { DataEditingProvider, useEditTracker };
24
+ export { DataEditingProvider, useEditSession };
25
25
  //# sourceMappingURL=DataEditingProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"DataEditingProvider.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/DataEditingProvider.tsx"],"sourcesContent":["import { createContext, ReactNode, useContext } from \"react\";\nimport { EditTracker } from \"./EditTracker\";\n\nconst DataEditingContext = createContext<EditTracker | undefined>(undefined);\n\nexport const DataEditingProvider = ({\n children,\n editTracker,\n}: {\n children: ReactNode;\n editTracker: EditTracker;\n}) => {\n return (\n <DataEditingContext.Provider value={editTracker}>\n {children}\n </DataEditingContext.Provider>\n );\n};\n\nexport function useEditTracker(\n throwIfUnavailable?: false,\n): EditTracker | undefined;\nexport function useEditTracker(throwIfUnavailable: true): EditTracker;\nexport function useEditTracker(throwIfUnavailable = false) {\n const editTracker = useContext(DataEditingContext);\n if (editTracker === undefined) {\n if (throwIfUnavailable) {\n throw Error(\n \"[useEditTracker] no DataEditingContext in scope. You need to enclose editable component(s) with DataEditingProvider\",\n );\n }\n } else {\n return editTracker;\n }\n}\n"],"names":[],"mappings":";;;AAGA,MAAM,kBAAA,GAAqB,cAAuC,KAAS,CAAA,CAAA;AAEpE,MAAM,sBAAsB,CAAC;AAAA,EAClC,QAAA;AAAA,EACA;AACF,CAGM,KAAA;AACJ,EAAA,2BACG,kBAAmB,CAAA,QAAA,EAAnB,EAA4B,KAAA,EAAO,aACjC,QACH,EAAA,CAAA;AAEJ;AAMgB,SAAA,cAAA,CAAe,qBAAqB,KAAO,EAAA;AACzD,EAAM,MAAA,WAAA,GAAc,WAAW,kBAAkB,CAAA;AACjD,EAAA,IAAI,gBAAgB,KAAW,CAAA,EAAA;AAC7B,IAAA,IAAI,kBAAoB,EAAA;AACtB,MAAM,MAAA,KAAA;AAAA,QACJ;AAAA,OACF;AAAA;AACF,GACK,MAAA;AACL,IAAO,OAAA,WAAA;AAAA;AAEX;;;;"}
1
+ {"version":3,"file":"DataEditingProvider.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/DataEditingProvider.tsx"],"sourcesContent":["import { createContext, ReactNode, useContext } from \"react\";\nimport { EditSession } from \"./EditSession\";\n\nconst DataEditingContext = createContext<EditSession | undefined>(undefined);\n\nexport const DataEditingProvider = ({\n children,\n editSession,\n}: {\n children: ReactNode;\n editSession: EditSession;\n}) => {\n return (\n <DataEditingContext.Provider value={editSession}>\n {children}\n </DataEditingContext.Provider>\n );\n};\n\nexport function useEditSession(\n throwIfUnavailable?: false,\n): EditSession | undefined;\nexport function useEditSession(throwIfUnavailable: true): EditSession;\nexport function useEditSession(throwIfUnavailable = false) {\n const editSession = useContext(DataEditingContext);\n if (editSession === undefined) {\n if (throwIfUnavailable) {\n throw Error(\n \"[useEditSession] no DataEditingContext in scope. You need to enclose editable component(s) with DataEditingProvider\",\n );\n }\n } else {\n return editSession;\n }\n}\n"],"names":[],"mappings":";;;AAGA,MAAM,kBAAA,GAAqB,cAAuC,KAAS,CAAA,CAAA;AAEpE,MAAM,sBAAsB,CAAC;AAAA,EAClC,QAAA;AAAA,EACA;AACF,CAGM,KAAA;AACJ,EAAA,2BACG,kBAAmB,CAAA,QAAA,EAAnB,EAA4B,KAAA,EAAO,aACjC,QACH,EAAA,CAAA;AAEJ;AAMgB,SAAA,cAAA,CAAe,qBAAqB,KAAO,EAAA;AACzD,EAAM,MAAA,WAAA,GAAc,WAAW,kBAAkB,CAAA;AACjD,EAAA,IAAI,gBAAgB,KAAW,CAAA,EAAA;AAC7B,IAAA,IAAI,kBAAoB,EAAA;AACtB,MAAM,MAAA,KAAA;AAAA,QACJ;AAAA,OACF;AAAA;AACF,GACK,MAAA;AACL,IAAO,OAAA,WAAA;AAAA;AAEX;;;;"}
@@ -3,14 +3,14 @@ import { Button } from '@salt-ds/core';
3
3
  import { useState, useMemo } from 'react';
4
4
 
5
5
  const EditButtons = ({
6
- editTracker,
6
+ editSession,
7
7
  onCancel,
8
8
  onSave
9
9
  }) => {
10
10
  const [editState, setEditState] = useState("clean");
11
11
  useMemo(() => {
12
- editTracker?.on("editState", setEditState);
13
- }, [editTracker]);
12
+ editSession?.on("editState", setEditState);
13
+ }, [editSession]);
14
14
  return /* @__PURE__ */ jsxs(Fragment, { children: [
15
15
  /* @__PURE__ */ jsx(
16
16
  Button,
@@ -1 +1 @@
1
- {"version":3,"file":"EditButtons.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/EditButtons.tsx"],"sourcesContent":["import { Button } from \"@salt-ds/core\";\nimport { EditState, EditTracker } from \"./EditTracker\";\nimport { useMemo, useState } from \"react\";\n\nexport interface EditButtonProps {\n editTracker?: EditTracker;\n onCancel: () => void;\n onSave: () => void;\n}\n\nexport const EditButtons = ({\n editTracker,\n onCancel,\n onSave,\n}: EditButtonProps) => {\n const [editState, setEditState] = useState<EditState>(\"clean\");\n\n useMemo(() => {\n editTracker?.on(\"editState\", setEditState);\n }, [editTracker]);\n\n return (\n <>\n <Button\n disabled={editState === \"clean\"}\n onClick={onSave}\n sentiment=\"accented\"\n >\n Save\n </Button>\n <Button onClick={onCancel}>Cancel</Button>\n </>\n );\n};\n"],"names":[],"mappings":";;;;AAUO,MAAM,cAAc,CAAC;AAAA,EAC1B,WAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAuB,KAAA;AACrB,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAoB,OAAO,CAAA;AAE7D,EAAA,OAAA,CAAQ,MAAM;AACZ,IAAa,WAAA,EAAA,EAAA,CAAG,aAAa,YAAY,CAAA;AAAA,GAC3C,EAAG,CAAC,WAAW,CAAC,CAAA;AAEhB,EAAA,uBAEI,IAAA,CAAA,QAAA,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,UAAU,SAAc,KAAA,OAAA;AAAA,QACxB,OAAS,EAAA,MAAA;AAAA,QACT,SAAU,EAAA,UAAA;AAAA,QACX,QAAA,EAAA;AAAA;AAAA,KAED;AAAA,oBACC,GAAA,CAAA,MAAA,EAAA,EAAO,OAAS,EAAA,QAAA,EAAU,QAAM,EAAA,QAAA,EAAA;AAAA,GACnC,EAAA,CAAA;AAEJ;;;;"}
1
+ {"version":3,"file":"EditButtons.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/EditButtons.tsx"],"sourcesContent":["import { Button } from \"@salt-ds/core\";\nimport { EditState, EditSession } from \"./EditSession\";\nimport { useMemo, useState } from \"react\";\n\nexport interface EditButtonProps {\n editSession?: EditSession;\n onCancel: () => void;\n onSave: () => void;\n}\n\nexport const EditButtons = ({\n editSession,\n onCancel,\n onSave,\n}: EditButtonProps) => {\n const [editState, setEditState] = useState<EditState>(\"clean\");\n\n useMemo(() => {\n editSession?.on(\"editState\", setEditState);\n }, [editSession]);\n\n return (\n <>\n <Button\n disabled={editState === \"clean\"}\n onClick={onSave}\n sentiment=\"accented\"\n >\n Save\n </Button>\n <Button onClick={onCancel}>Cancel</Button>\n </>\n );\n};\n"],"names":[],"mappings":";;;;AAUO,MAAM,cAAc,CAAC;AAAA,EAC1B,WAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAuB,KAAA;AACrB,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAI,SAAoB,OAAO,CAAA;AAE7D,EAAA,OAAA,CAAQ,MAAM;AACZ,IAAa,WAAA,EAAA,EAAA,CAAG,aAAa,YAAY,CAAA;AAAA,GAC3C,EAAG,CAAC,WAAW,CAAC,CAAA;AAEhB,EAAA,uBAEI,IAAA,CAAA,QAAA,EAAA,EAAA,QAAA,EAAA;AAAA,oBAAA,GAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,UAAU,SAAc,KAAA,OAAA;AAAA,QACxB,OAAS,EAAA,MAAA;AAAA,QACT,SAAU,EAAA,UAAA;AAAA,QACX,QAAA,EAAA;AAAA;AAAA,KAED;AAAA,oBACC,GAAA,CAAA,MAAA,EAAA,EAAO,OAAS,EAAA,QAAA,EAAU,QAAM,EAAA,QAAA,EAAA;AAAA,GACnC,EAAA,CAAA;AAEJ;;;;"}
@@ -9,7 +9,7 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
9
9
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
10
10
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), member.set(obj, value), value);
11
11
  var _active, _rowEdits, _editCount, _dataSource, _inEditMode;
12
- class EditTracker extends EventEmitter {
12
+ class EditSession extends EventEmitter {
13
13
  constructor() {
14
14
  super(...arguments);
15
15
  __privateAdd(this, _active, false);
@@ -50,11 +50,8 @@ class EditTracker extends EventEmitter {
50
50
  }
51
51
  async enterEditMode() {
52
52
  __privateSet(this, _inEditMode, true);
53
- const rpcResponse = await __privateGet(this, _dataSource)?.rpcRequest?.({
54
- type: "RPC_REQUEST",
55
- rpcName: "ENTER_EDIT_MODE",
56
- params: {}
57
- });
53
+ const rpcResponse = await __privateGet(this, _dataSource)?.beginEditSession?.();
54
+ console.log({ rpcResponse });
58
55
  if (isRpcSuccess(rpcResponse)) {
59
56
  const { table: sessionTable } = rpcResponse.data;
60
57
  return sessionTable;
@@ -71,7 +68,7 @@ class EditTracker extends EventEmitter {
71
68
  async cancelChanges() {
72
69
  const rpcResponse = await __privateGet(this, _dataSource)?.rpcRequest?.({
73
70
  type: "RPC_REQUEST",
74
- rpcName: "EXIT_EDIT_MODE",
71
+ rpcName: "endEditSession",
75
72
  params: {}
76
73
  });
77
74
  this.clear();
@@ -80,7 +77,7 @@ class EditTracker extends EventEmitter {
80
77
  async saveChanges() {
81
78
  const rpcResponse = await __privateGet(this, _dataSource)?.rpcRequest?.({
82
79
  type: "RPC_REQUEST",
83
- rpcName: "EXIT_EDIT_MODE",
80
+ rpcName: "endEditSession",
84
81
  params: { save: true }
85
82
  });
86
83
  this.clear();
@@ -119,22 +116,18 @@ class EditTracker extends EventEmitter {
119
116
  this.editCount = __privateGet(this, _editCount) + 1;
120
117
  }
121
118
  }
122
- //TODO alow a shortcut commit that allows a value, bypassing need
123
- // for edit. Thids caters for boolean values, dropdown list etc
124
- // that have no intermediate edit phase
125
- async commit(key, columnName) {
119
+ async commit(key, columnName, typedValue) {
126
120
  const rowEditDetails = __privateGet(this, _rowEdits).get(key);
127
121
  if (rowEditDetails) {
128
122
  const { cellEdits } = rowEditDetails;
129
123
  const cellEditValues = cellEdits.get(columnName);
130
124
  if (cellEditValues) {
131
- const { editedValue } = cellEditValues;
132
125
  const rpcResponse = await __privateGet(this, _dataSource)?.rpcRequest?.({
133
126
  type: "RPC_REQUEST",
134
127
  rpcName: "editCell",
135
128
  params: {
136
129
  column: columnName,
137
- data: editedValue,
130
+ data: typedValue,
138
131
  key
139
132
  }
140
133
  });
@@ -154,5 +147,5 @@ _editCount = new WeakMap();
154
147
  _dataSource = new WeakMap();
155
148
  _inEditMode = new WeakMap();
156
149
 
157
- export { EditTracker };
158
- //# sourceMappingURL=EditTracker.js.map
150
+ export { EditSession };
151
+ //# sourceMappingURL=EditSession.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"EditSession.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/EditSession.tsx"],"sourcesContent":["import { DataSource } from \"@vuu-ui/vuu-data-types\";\nimport type {\n RpcResultError,\n VuuRowDataItemType,\n VuuTable,\n} from \"@vuu-ui/vuu-protocol-types\";\nimport { EventEmitter } from \"../event-emitter\";\nimport { isRpcSuccess } from \"../protocol-message-utils\";\n\nexport type EditState = \"clean\" | \"dirty\";\n\ntype CellEdit = {\n originalValue: VuuRowDataItemType;\n editedValue: VuuRowDataItemType;\n};\n\ntype RowEditDetails = {\n /**\n * Column name => cell edit details\n */\n cellEdits: Map<string, CellEdit>;\n};\n\ntype EditSessionEvents = {\n editState: (editState: EditState) => void;\n};\n\nexport class EditSession extends EventEmitter<EditSessionEvents> {\n #active = false;\n /**\n * Row key => row edits\n */\n #rowEdits = new Map<string, RowEditDetails>();\n #editCount = 0;\n #dataSource?: DataSource;\n #inEditMode = false;\n\n get active() {\n return this.#active;\n }\n set active(isActive: boolean) {\n this.#active = isActive;\n }\n get editCount() {\n return this.#editCount;\n }\n\n set editCount(val: number) {\n if (val !== this.#editCount) {\n const oldCount = this.#editCount;\n this.#editCount = val;\n if (val === 0) {\n this.emit(\"editState\", \"clean\");\n } else if (oldCount === 0) {\n this.emit(\"editState\", \"dirty\");\n }\n }\n }\n\n set dataSource(ds: DataSource) {\n this.#dataSource = ds;\n }\n\n clear() {\n this.#rowEdits.clear();\n this.#editCount = 0;\n }\n\n async enterEditMode() {\n this.#inEditMode = true;\n\n const rpcResponse = await this.#dataSource?.beginEditSession?.();\n\n console.log({ rpcResponse });\n\n if (isRpcSuccess(rpcResponse)) {\n const { table: sessionTable } = rpcResponse.data as { table: VuuTable };\n return sessionTable;\n } else {\n console.log(\"fail\");\n }\n }\n\n get inEditMode() {\n return this.#inEditMode;\n }\n\n get editState(): EditState {\n return this.editCount === 0 ? \"clean\" : \"dirty\";\n }\n\n async cancelChanges() {\n const rpcResponse = await this.#dataSource?.rpcRequest?.({\n type: \"RPC_REQUEST\",\n rpcName: \"endEditSession\",\n params: {},\n });\n this.clear();\n return rpcResponse;\n }\n\n async saveChanges() {\n const rpcResponse = await this.#dataSource?.rpcRequest?.({\n type: \"RPC_REQUEST\",\n rpcName: \"endEditSession\",\n params: { save: true },\n });\n this.clear();\n return rpcResponse;\n }\n\n // TODO how do we deal with the '_edited' pattern\n edit(\n key: string,\n columnName: string,\n originalValue: VuuRowDataItemType,\n newValue: VuuRowDataItemType,\n ) {\n const rowEditDetails = this.#rowEdits.get(key);\n if (rowEditDetails) {\n const { cellEdits } = rowEditDetails;\n const cellEdit = cellEdits.get(columnName);\n if (cellEdit) {\n if (newValue === cellEdit.originalValue) {\n if (cellEdits.size === 1) {\n this.#rowEdits.delete(key);\n } else {\n // re-editing a cell had removed the edit\n cellEdits.delete(columnName);\n }\n this.editCount = this.#editCount - 1;\n } else {\n cellEdit.editedValue = newValue;\n }\n } else {\n // row has already been edited, but this column has not\n cellEdits.set(columnName, {\n originalValue,\n editedValue: newValue,\n });\n this.editCount = this.#editCount + 1;\n }\n } else {\n this.#rowEdits.set(key, {\n cellEdits: new Map([\n [columnName, { originalValue, editedValue: newValue }],\n ]),\n });\n this.editCount = this.#editCount + 1;\n }\n }\n\n async commit(\n key: string,\n columnName: string,\n typedValue: string | number | boolean,\n ) {\n const rowEditDetails = this.#rowEdits.get(key);\n if (rowEditDetails) {\n const { cellEdits } = rowEditDetails;\n const cellEditValues = cellEdits.get(columnName);\n if (cellEditValues) {\n const rpcResponse = await this.#dataSource?.rpcRequest?.({\n type: \"RPC_REQUEST\",\n rpcName: \"editCell\",\n params: {\n column: columnName,\n data: typedValue,\n key,\n },\n });\n\n return rpcResponse;\n }\n } else {\n return {\n errorMessage: \"CHANGE_REVERTED\",\n type: \"ERROR_RESULT\",\n } as RpcResultError;\n }\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { useState, useCallback, useMemo } from 'react';
2
- import { EditTracker } from './EditTracker.js';
2
+ import { EditSession } from './EditSession.js';
3
3
  import { useData } from '../context-definitions/DataProvider.js';
4
4
  import { isRpcSuccess } from '../protocol-message-utils.js';
5
5
  import { useLayoutEffectSkipFirst } from '../useLayoutEffectSkipFirst.js';
@@ -24,47 +24,54 @@ const useEditableTable = ({
24
24
  console.warn(`[useEditableTable] columns and or table changed`);
25
25
  }, [columns, table]);
26
26
  const dataSource = useMemo(() => {
27
- return dataSourceProp ?? new VuuDataSource({ columns, table });
27
+ if (dataSourceProp) {
28
+ return dataSourceProp;
29
+ } else if (table) {
30
+ return new VuuDataSource({ columns, table });
31
+ } else {
32
+ throw Error(
33
+ `useEditableTable unable to provide DataSource, neither dataSource nor table available as props`
34
+ );
35
+ }
28
36
  }, [VuuDataSource, columns, dataSourceProp, table]);
29
- const editTracker = useMemo(() => new EditTracker(), []);
37
+ const editSession = useMemo(() => new EditSession(), []);
30
38
  useMemo(() => {
31
39
  if (dataSource) {
32
- editTracker.dataSource = dataSource;
40
+ editSession.dataSource = dataSource;
33
41
  }
34
- }, [dataSource, editTracker]);
42
+ }, [dataSource, editSession]);
35
43
  const handleCancel = useCallback(() => {
36
- editTracker.cancelChanges();
44
+ editSession.cancelChanges();
37
45
  onCancel();
38
46
  clearSessionDataSource();
39
47
  dataSource.resume?.();
40
- }, [clearSessionDataSource, dataSource, editTracker, onCancel]);
48
+ }, [clearSessionDataSource, dataSource, editSession, onCancel]);
41
49
  const handleSave = useCallback(async () => {
42
50
  dataSource.resume?.();
43
- const response = await editTracker.saveChanges();
51
+ const response = await editSession.saveChanges();
44
52
  if (isRpcSuccess(response)) {
45
53
  onSave();
46
54
  clearSessionDataSource();
47
55
  }
48
- }, [clearSessionDataSource, dataSource, editTracker, onSave]);
56
+ }, [clearSessionDataSource, dataSource, editSession, onSave]);
49
57
  useMemo(async () => {
50
58
  if (isEditMode) {
51
- const sessionTable = await editTracker.enterEditMode();
59
+ const sessionTable = await editSession.enterEditMode();
52
60
  if (sessionTable && dataSource.tableSchema) {
53
- dataSource.suspend?.(false);
54
61
  const sessionDataSource2 = new VuuDataSource({
55
62
  columns: dataSource.columns,
56
63
  table: sessionTable,
57
64
  viewport: sessionTable.table
58
65
  });
59
66
  setSessionDataSource(sessionDataSource2);
60
- editTracker.dataSource = sessionDataSource2;
67
+ editSession.dataSource = sessionDataSource2;
61
68
  }
62
69
  }
63
- }, [VuuDataSource, dataSource, editTracker, isEditMode]);
70
+ }, [VuuDataSource, dataSource, editSession, isEditMode]);
64
71
  return {
65
72
  // DO we need to reset the dataSource or could useDataSOurce detect the sessiondataSOurce from the editSession ?
66
73
  dataSource: sessionDataSource ?? dataSource,
67
- editTracker,
74
+ editSession,
68
75
  onCancel: handleCancel,
69
76
  onSave: handleSave
70
77
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useEditableTable.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/useEditableTable.ts"],"sourcesContent":["import { VuuTable } from \"@vuu-ui/vuu-protocol-types\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { EditTracker } from \"./EditTracker\";\nimport { useData } from \"../context-definitions/DataProvider\";\nimport { DataSource } from \"@vuu-ui/vuu-data-types\";\nimport { isRpcSuccess } from \"../protocol-message-utils\";\nimport { useLayoutEffectSkipFirst } from \"../useLayoutEffectSkipFirst\";\n\nexport type EditMode = \"edit\" | \"view\";\n\nexport interface EditableTableHookProps {\n /**\n * columns to be included in subscription. If not provided,\n * default will be '*'. Ignored if dataSource prop present.\n */\n columns?: string[];\n dataSource?: DataSource;\n isEditMode: boolean;\n onCancel: () => void;\n onSave: () => void;\n /**\n * If dataSource not provided, new DataSource\n * will be created using table and columns\n */\n table: VuuTable;\n}\n\nexport const useEditableTable = ({\n columns,\n dataSource: dataSourceProp,\n isEditMode,\n onCancel,\n onSave,\n table,\n}: EditableTableHookProps) => {\n const { VuuDataSource } = useData();\n const [sessionDataSource, setSessionDataSource] = useState<\n DataSource | undefined\n >(undefined);\n\n const clearSessionDataSource = useCallback(() => {\n setSessionDataSource((dataSource) => {\n dataSource?.unsubscribe();\n return undefined;\n });\n }, []);\n\n useLayoutEffectSkipFirst(() => {\n console.warn(`[useEditableTable] columns and or table changed`);\n }, [columns, table]);\n\n const dataSource = useMemo(() => {\n return dataSourceProp ?? new VuuDataSource({ columns, table });\n }, [VuuDataSource, columns, dataSourceProp, table]);\n\n const editTracker = useMemo(() => new EditTracker(), []);\n\n useMemo(() => {\n if (dataSource) {\n editTracker.dataSource = dataSource;\n }\n }, [dataSource, editTracker]);\n\n const handleCancel = useCallback(() => {\n // editTracker.dataSource = dataSource;\n editTracker.cancelChanges();\n onCancel();\n clearSessionDataSource();\n dataSource.resume?.();\n }, [clearSessionDataSource, dataSource, editTracker, onCancel]);\n\n const handleSave = useCallback(async () => {\n dataSource.resume?.();\n const response = await editTracker.saveChanges();\n if (isRpcSuccess(response)) {\n onSave();\n clearSessionDataSource();\n }\n }, [clearSessionDataSource, dataSource, editTracker, onSave]);\n\n useMemo(async () => {\n if (isEditMode) {\n const sessionTable = await editTracker.enterEditMode();\n if (sessionTable && dataSource.tableSchema) {\n dataSource.suspend?.(false);\n const sessionDataSource = new VuuDataSource({\n columns: dataSource.columns,\n table: sessionTable,\n viewport: sessionTable.table,\n });\n setSessionDataSource(sessionDataSource);\n editTracker.dataSource = sessionDataSource;\n }\n }\n }, [VuuDataSource, dataSource, editTracker, isEditMode]);\n\n return {\n // DO we need to reset the dataSource or could useDataSOurce detect the sessiondataSOurce from the editSession ?\n dataSource: sessionDataSource ?? dataSource,\n editTracker,\n onCancel: handleCancel,\n onSave: handleSave,\n };\n};\n"],"names":["dataSource","sessionDataSource"],"mappings":";;;;;;AA2BO,MAAM,mBAAmB,CAAC;AAAA,EAC/B,OAAA;AAAA,EACA,UAAY,EAAA,cAAA;AAAA,EACZ,UAAA;AAAA,EACA,QAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAA8B,KAAA;AAC5B,EAAM,MAAA,EAAE,aAAc,EAAA,GAAI,OAAQ,EAAA;AAClC,EAAA,MAAM,CAAC,iBAAA,EAAmB,oBAAoB,CAAA,GAAI,SAEhD,KAAS,CAAA,CAAA;AAEX,EAAM,MAAA,sBAAA,GAAyB,YAAY,MAAM;AAC/C,IAAA,oBAAA,CAAqB,CAACA,WAAe,KAAA;AACnC,MAAAA,aAAY,WAAY,EAAA;AACxB,MAAO,OAAA,KAAA,CAAA;AAAA,KACR,CAAA;AAAA,GACH,EAAG,EAAE,CAAA;AAEL,EAAA,wBAAA,CAAyB,MAAM;AAC7B,IAAA,OAAA,CAAQ,KAAK,CAAiD,+CAAA,CAAA,CAAA;AAAA,GAC7D,EAAA,CAAC,OAAS,EAAA,KAAK,CAAC,CAAA;AAEnB,EAAM,MAAA,UAAA,GAAa,QAAQ,MAAM;AAC/B,IAAA,OAAO,kBAAkB,IAAI,aAAA,CAAc,EAAE,OAAA,EAAS,OAAO,CAAA;AAAA,KAC5D,CAAC,aAAA,EAAe,OAAS,EAAA,cAAA,EAAgB,KAAK,CAAC,CAAA;AAElD,EAAA,MAAM,cAAc,OAAQ,CAAA,MAAM,IAAI,WAAY,EAAA,EAAG,EAAE,CAAA;AAEvD,EAAA,OAAA,CAAQ,MAAM;AACZ,IAAA,IAAI,UAAY,EAAA;AACd,MAAA,WAAA,CAAY,UAAa,GAAA,UAAA;AAAA;AAC3B,GACC,EAAA,CAAC,UAAY,EAAA,WAAW,CAAC,CAAA;AAE5B,EAAM,MAAA,YAAA,GAAe,YAAY,MAAM;AAErC,IAAA,WAAA,CAAY,aAAc,EAAA;AAC1B,IAAS,QAAA,EAAA;AACT,IAAuB,sBAAA,EAAA;AACvB,IAAA,UAAA,CAAW,MAAS,IAAA;AAAA,KACnB,CAAC,sBAAA,EAAwB,UAAY,EAAA,WAAA,EAAa,QAAQ,CAAC,CAAA;AAE9D,EAAM,MAAA,UAAA,GAAa,YAAY,YAAY;AACzC,IAAA,UAAA,CAAW,MAAS,IAAA;AACpB,IAAM,MAAA,QAAA,GAAW,MAAM,WAAA,CAAY,WAAY,EAAA;AAC/C,IAAI,IAAA,YAAA,CAAa,QAAQ,CAAG,EAAA;AAC1B,MAAO,MAAA,EAAA;AACP,MAAuB,sBAAA,EAAA;AAAA;AACzB,KACC,CAAC,sBAAA,EAAwB,UAAY,EAAA,WAAA,EAAa,MAAM,CAAC,CAAA;AAE5D,EAAA,OAAA,CAAQ,YAAY;AAClB,IAAA,IAAI,UAAY,EAAA;AACd,MAAM,MAAA,YAAA,GAAe,MAAM,WAAA,CAAY,aAAc,EAAA;AACrD,MAAI,IAAA,YAAA,IAAgB,WAAW,WAAa,EAAA;AAC1C,QAAA,UAAA,CAAW,UAAU,KAAK,CAAA;AAC1B,QAAMC,MAAAA,kBAAAA,GAAoB,IAAI,aAAc,CAAA;AAAA,UAC1C,SAAS,UAAW,CAAA,OAAA;AAAA,UACpB,KAAO,EAAA,YAAA;AAAA,UACP,UAAU,YAAa,CAAA;AAAA,SACxB,CAAA;AACD,QAAA,oBAAA,CAAqBA,kBAAiB,CAAA;AACtC,QAAA,WAAA,CAAY,UAAaA,GAAAA,kBAAAA;AAAA;AAC3B;AACF,KACC,CAAC,aAAA,EAAe,UAAY,EAAA,WAAA,EAAa,UAAU,CAAC,CAAA;AAEvD,EAAO,OAAA;AAAA;AAAA,IAEL,YAAY,iBAAqB,IAAA,UAAA;AAAA,IACjC,WAAA;AAAA,IACA,QAAU,EAAA,YAAA;AAAA,IACV,MAAQ,EAAA;AAAA,GACV;AACF;;;;"}
1
+ {"version":3,"file":"useEditableTable.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/useEditableTable.ts"],"sourcesContent":["import { VuuTable } from \"@vuu-ui/vuu-protocol-types\";\nimport { useCallback, useMemo, useState } from \"react\";\nimport { EditSession } from \"./EditSession\";\nimport { useData } from \"../context-definitions/DataProvider\";\nimport { DataSource } from \"@vuu-ui/vuu-data-types\";\nimport { isRpcSuccess } from \"../protocol-message-utils\";\nimport { useLayoutEffectSkipFirst } from \"../useLayoutEffectSkipFirst\";\n\nexport type EditMode = \"edit\" | \"view\";\n\nexport interface EditableTableHookProps {\n /**\n * columns to be included in subscription. If not provided,\n * default will be '*'. Ignored if dataSource prop present.\n */\n columns?: string[];\n dataSource?: DataSource;\n isEditMode: boolean;\n onCancel: () => void;\n onSave: () => void;\n /**\n * If dataSource not provided, new DataSource\n * will be created using table and columns\n */\n table?: VuuTable;\n}\n\nexport const useEditableTable = ({\n columns,\n dataSource: dataSourceProp,\n isEditMode,\n onCancel,\n onSave,\n table,\n}: EditableTableHookProps) => {\n const { VuuDataSource } = useData();\n const [sessionDataSource, setSessionDataSource] = useState<\n DataSource | undefined\n >(undefined);\n\n const clearSessionDataSource = useCallback(() => {\n setSessionDataSource((dataSource) => {\n dataSource?.unsubscribe();\n return undefined;\n });\n }, []);\n\n useLayoutEffectSkipFirst(() => {\n console.warn(`[useEditableTable] columns and or table changed`);\n }, [columns, table]);\n\n const dataSource = useMemo(() => {\n // The dataSource would normally be managed by client and passed in, but for\n // simple use cases we can create it here.\n if (dataSourceProp) {\n return dataSourceProp;\n } else if (table) {\n return new VuuDataSource({ columns, table });\n } else {\n throw Error(\n `useEditableTable unable to provide DataSource, neither dataSource nor table available as props`,\n );\n }\n }, [VuuDataSource, columns, dataSourceProp, table]);\n\n // The editSession will be made available to all the edit controls in scope by\n // wrapping the edit component with a DataEditingProvider.\n const editSession = useMemo(() => new EditSession(), []);\n\n useMemo(() => {\n if (dataSource) {\n editSession.dataSource = dataSource;\n }\n }, [dataSource, editSession]);\n\n const handleCancel = useCallback(() => {\n // editTracker.dataSource = dataSource;\n editSession.cancelChanges();\n onCancel();\n clearSessionDataSource();\n dataSource.resume?.();\n }, [clearSessionDataSource, dataSource, editSession, onCancel]);\n\n const handleSave = useCallback(async () => {\n dataSource.resume?.();\n const response = await editSession.saveChanges();\n if (isRpcSuccess(response)) {\n onSave();\n clearSessionDataSource();\n }\n }, [clearSessionDataSource, dataSource, editSession, onSave]);\n\n useMemo(async () => {\n if (isEditMode) {\n const sessionTable = await editSession.enterEditMode();\n if (sessionTable && dataSource.tableSchema) {\n // dataSource.suspend?.(false);\n const sessionDataSource = new VuuDataSource({\n columns: dataSource.columns,\n table: sessionTable,\n viewport: sessionTable.table,\n });\n setSessionDataSource(sessionDataSource);\n editSession.dataSource = sessionDataSource;\n }\n }\n }, [VuuDataSource, dataSource, editSession, isEditMode]);\n\n return {\n // DO we need to reset the dataSource or could useDataSOurce detect the sessiondataSOurce from the editSession ?\n dataSource: sessionDataSource ?? dataSource,\n editSession,\n onCancel: handleCancel,\n onSave: handleSave,\n };\n};\n"],"names":["dataSource","sessionDataSource"],"mappings":"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"}
@@ -5,6 +5,18 @@ import '@internationalized/date';
5
5
  import { queryClosest } from './html-utils.js';
6
6
  import { ScaledDecimal8, ScaledDecimal6, ScaledDecimal4, ScaledDecimal2 } from './ScaledDecimal.js';
7
7
 
8
+ var __defProp = Object.defineProperty;
9
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
10
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
11
+ class DataValidationError extends Error {
12
+ constructor(message, expectedType, actualType) {
13
+ super(message);
14
+ __publicField(this, "actualType");
15
+ __publicField(this, "expectedType");
16
+ this.actualType = actualType;
17
+ this.expectedType = expectedType;
18
+ }
19
+ }
8
20
  const getFieldName = (target) => {
9
21
  const saltFormField = queryClosest(target, "[data-field]");
10
22
  const fieldName = saltFormField?.dataset.field;
@@ -27,6 +39,16 @@ function getTypedRange([value1, value2], dataType, options) {
27
39
  getTypedValue(value2, dataType, false, options)
28
40
  ];
29
41
  }
42
+ const getActualType = (value) => {
43
+ if (typeof value === "boolean") {
44
+ return "boolean";
45
+ } else if (typeof value === "number") {
46
+ return "number";
47
+ } else if (typeof value === "string") {
48
+ return "string";
49
+ }
50
+ return "string";
51
+ };
30
52
  function getTypedValue(value, type, throwIfInvalid = false, options) {
31
53
  switch (type) {
32
54
  case "int":
@@ -54,7 +76,11 @@ function getTypedValue(value, type, throwIfInvalid = false, options) {
54
76
  if (stringIsValidDecimal(value)) {
55
77
  return parseFloat(value);
56
78
  } else if (throwIfInvalid) {
57
- throw Error(`value ${value} is not a valid ${type}`);
79
+ throw new DataValidationError(
80
+ `value ${value} is not a valid ${type}`,
81
+ "decimal",
82
+ getActualType(value)
83
+ );
58
84
  } else {
59
85
  return void 0;
60
86
  }
@@ -80,5 +106,5 @@ function getTypedValue(value, type, throwIfInvalid = false, options) {
80
106
  }
81
107
  }
82
108
 
83
- export { getFieldName, getTypedRange, getTypedValue, isNumber, isValidRange };
109
+ export { DataValidationError, getFieldName, getTypedRange, getTypedValue, isNumber, isValidRange };
84
110
  //# sourceMappingURL=form-utils.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"form-utils.js","sources":["../../../../../../packages/vuu-utils/src/form-utils.ts"],"sourcesContent":["import { DataValueTypeSimple } from \"@vuu-ui/vuu-data-types\";\nimport {\n VuuColumnDataType,\n VuuRowDataItemType,\n} from \"@vuu-ui/vuu-protocol-types\";\nimport { KeyboardEvent, SyntheticEvent } from \"react\";\nimport { stringIsValidDecimal, stringIsValidInt } from \"./data-utils\";\nimport { isValidTimeString, Time } from \"./date\";\nimport { queryClosest } from \"./html-utils\";\nimport { ExtendedFilterOptions } from \"@vuu-ui/vuu-filter-types\";\nimport {\n type ScaledDecimal,\n ScaledDecimal2,\n ScaledDecimal4,\n ScaledDecimal6,\n ScaledDecimal8,\n} from \"./ScaledDecimal\";\n\n/**\n * Use with the following convention:\n *\n * <FormField data-field=\"my-field-name\">\n */\nexport const getFieldName = (target: EventTarget | HTMLElement): string => {\n const saltFormField = queryClosest(target, \"[data-field]\") as HTMLElement;\n const fieldName = saltFormField?.dataset.field;\n if (fieldName) {\n return fieldName;\n } else {\n throw Error(\"named form field not found\");\n }\n};\n\nexport type InputSource = \"typeahead-suggestion\" | \"text-input\";\n\nexport const isNumber = (\n type: string,\n value: VuuRowDataItemType,\n): value is number => type === \"number\";\n\nexport type CommitHandler<\n E extends HTMLElement = HTMLInputElement,\n T = VuuRowDataItemType,\n> = (\n evt: SyntheticEvent<E> | KeyboardEvent<E>,\n value: T,\n source?: InputSource,\n) => void;\n\nexport const isValidRange = <T>([val1, val2]: [T, T]) => {\n if (isValidTimeString(val1) && isValidTimeString(val2)) {\n return val2 > val1;\n }\n return true;\n};\n\n/**\n * Convert a pair of string values to the type appropriate for the\n * associated column or form field. Can be used when processing a string value\n * from an input used for user editing.\n *\n */\nexport function getTypedRange(\n [value1, value2]: [string, string],\n dataType: VuuColumnDataType | DataValueTypeSimple,\n options?: ExtendedFilterOptions,\n) {\n return [\n getTypedValue(value1, dataType, false, options),\n getTypedValue(value2, dataType, false, options),\n ];\n}\n\n/**\n * Convert a string value to the type appropriate for the associated\n * column or form field. Can be used when processing a string value\n * from an input used for user editing.\n *\n * @param value\n * @param type\n * @param throwIfInvalid\n */\nexport function getTypedValue(\n value: string,\n type: VuuColumnDataType | DataValueTypeSimple,\n throwIfInvalid?: false,\n options?: ExtendedFilterOptions,\n): VuuRowDataItemType | undefined;\nexport function getTypedValue(\n value: string,\n type: VuuColumnDataType | DataValueTypeSimple,\n throwIfInvalid: true,\n options?: ExtendedFilterOptions,\n): VuuRowDataItemType;\nexport function getTypedValue(\n value: string,\n type: VuuColumnDataType | DataValueTypeSimple,\n throwIfInvalid = false,\n options?: ExtendedFilterOptions,\n): VuuRowDataItemType | ScaledDecimal | undefined {\n switch (type) {\n case \"int\":\n case \"long\": {\n if (stringIsValidInt(value)) {\n return parseInt(value, 10);\n } else if (isValidTimeString(value)) {\n //TOCHECK\n return value;\n } else if (throwIfInvalid) {\n throw Error(`value ${value} is not a valid ${type}`);\n } else {\n return undefined;\n }\n }\n\n case \"scaleddecimal2\":\n return ScaledDecimal2(value);\n case \"scaleddecimal4\":\n return ScaledDecimal4(value);\n case \"scaleddecimal6\":\n return ScaledDecimal6(value);\n case \"scaleddecimal8\":\n return ScaledDecimal8(value);\n case \"double\":\n case \"number\": {\n if (stringIsValidDecimal(value)) {\n return parseFloat(value);\n } else if (throwIfInvalid) {\n throw Error(`value ${value} is not a valid ${type}`);\n } else {\n return undefined;\n }\n }\n\n case \"boolean\":\n return value === \"true\" ? true : false;\n\n case \"time\":\n if (isValidTimeString(value)) {\n // We don't manipulate the values of 'extended' filters, the\n // ExtendedFilter impementation will do that.\n if (options?.type === \"TimeString\") {\n return value;\n } else {\n return +Time(value).asDate();\n }\n } else if (value.length > 0 && Time.isDateInMillis(value)) {\n //if value previously converted\n return Number(value);\n } else if (throwIfInvalid) {\n throw Error(`value ${value} is not a valid ${type}`);\n } else {\n return undefined;\n }\n default:\n return value;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"form-utils.js","sources":["../../../../../../packages/vuu-utils/src/form-utils.ts"],"sourcesContent":["import { DataValueTypeSimple } from \"@vuu-ui/vuu-data-types\";\nimport {\n VuuColumnDataType,\n VuuRowDataItemType,\n} from \"@vuu-ui/vuu-protocol-types\";\nimport { KeyboardEvent, SyntheticEvent } from \"react\";\nimport { stringIsValidDecimal, stringIsValidInt } from \"./data-utils\";\nimport { isValidTimeString, Time } from \"./date\";\nimport { queryClosest } from \"./html-utils\";\nimport { ExtendedFilterOptions } from \"@vuu-ui/vuu-filter-types\";\nimport {\n type ScaledDecimal,\n ScaledDecimal2,\n ScaledDecimal4,\n ScaledDecimal6,\n ScaledDecimal8,\n} from \"./ScaledDecimal\";\n\nexport class DataValidationError extends Error {\n actualType: string;\n expectedType: string;\n constructor(message: string, expectedType: string, actualType: string) {\n super(message);\n this.actualType = actualType;\n this.expectedType = expectedType;\n }\n}\n\n/**\n * Use with the following convention:\n *\n * <FormField data-field=\"my-field-name\">\n */\nexport const getFieldName = (target: EventTarget | HTMLElement): string => {\n const saltFormField = queryClosest(target, \"[data-field]\") as HTMLElement;\n const fieldName = saltFormField?.dataset.field;\n if (fieldName) {\n return fieldName;\n } else {\n throw Error(\"named form field not found\");\n }\n};\n\nexport type InputSource = \"typeahead-suggestion\" | \"text-input\";\n\nexport const isNumber = (\n type: string,\n value: VuuRowDataItemType,\n): value is number => type === \"number\";\n\nexport type CommitHandler<\n E extends HTMLElement = HTMLInputElement,\n T = VuuRowDataItemType,\n> = (\n evt: SyntheticEvent<E> | KeyboardEvent<E>,\n value: T,\n source?: InputSource,\n) => void;\n\nexport const isValidRange = <T>([val1, val2]: [T, T]) => {\n if (isValidTimeString(val1) && isValidTimeString(val2)) {\n return val2 > val1;\n }\n return true;\n};\n\n/**\n * Convert a pair of string values to the type appropriate for the\n * associated column or form field. Can be used when processing a string value\n * from an input used for user editing.\n *\n */\nexport function getTypedRange(\n [value1, value2]: [string, string],\n dataType: VuuColumnDataType | DataValueTypeSimple,\n options?: ExtendedFilterOptions,\n) {\n return [\n getTypedValue(value1, dataType, false, options),\n getTypedValue(value2, dataType, false, options),\n ];\n}\n\nconst getActualType = (\n value: string | number | boolean,\n): \"string\" | \"number\" | \"boolean\" => {\n if (typeof value === \"boolean\") {\n return \"boolean\";\n } else if (typeof value === \"number\") {\n return \"number\";\n } else if (typeof value === \"string\") {\n return \"string\";\n }\n return \"string\";\n};\n\n/**\n * Convert a string value to the type appropriate for the associated\n * column or form field. Can be used when processing a string value\n * from an input used for user editing.\n *\n * @param value\n * @param type\n * @param throwIfInvalid\n */\nexport function getTypedValue(\n value: string,\n type: VuuColumnDataType | DataValueTypeSimple,\n throwIfInvalid?: false,\n options?: ExtendedFilterOptions,\n): VuuRowDataItemType | undefined;\nexport function getTypedValue(\n value: string,\n type: VuuColumnDataType | DataValueTypeSimple,\n throwIfInvalid: true,\n options?: ExtendedFilterOptions,\n): VuuRowDataItemType;\nexport function getTypedValue(\n value: string,\n type: VuuColumnDataType | DataValueTypeSimple,\n throwIfInvalid = false,\n options?: ExtendedFilterOptions,\n): VuuRowDataItemType | ScaledDecimal | undefined {\n switch (type) {\n case \"int\":\n case \"long\": {\n if (stringIsValidInt(value)) {\n return parseInt(value, 10);\n } else if (isValidTimeString(value)) {\n //TOCHECK\n return value;\n } else if (throwIfInvalid) {\n throw Error(`value ${value} is not a valid ${type}`);\n } else {\n return undefined;\n }\n }\n\n case \"scaleddecimal2\":\n return ScaledDecimal2(value);\n case \"scaleddecimal4\":\n return ScaledDecimal4(value);\n case \"scaleddecimal6\":\n return ScaledDecimal6(value);\n case \"scaleddecimal8\":\n return ScaledDecimal8(value);\n case \"double\":\n case \"number\": {\n if (stringIsValidDecimal(value)) {\n return parseFloat(value);\n } else if (throwIfInvalid) {\n throw new DataValidationError(\n `value ${value} is not a valid ${type}`,\n \"decimal\",\n getActualType(value),\n );\n } else {\n return undefined;\n }\n }\n\n case \"boolean\":\n return value === \"true\" ? true : false;\n\n case \"time\":\n if (isValidTimeString(value)) {\n // We don't manipulate the values of 'extended' filters, the\n // ExtendedFilter impementation will do that.\n if (options?.type === \"TimeString\") {\n return value;\n } else {\n return +Time(value).asDate();\n }\n } else if (value.length > 0 && Time.isDateInMillis(value)) {\n //if value previously converted\n return Number(value);\n } else if (throwIfInvalid) {\n throw Error(`value ${value} is not a valid ${type}`);\n } else {\n return undefined;\n }\n default:\n return value;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -11,8 +11,8 @@ export { getCellConfigPanelRenderer, getCellRenderer, getCellRendererOptions, ge
11
11
  export { getCookieValue, setCookieValue } from './cookie-utils.js';
12
12
  export { importCSS } from './css-utils.js';
13
13
  export { EditButtons } from './data-editing/EditButtons.js';
14
- export { DataEditingProvider, useEditTracker } from './data-editing/DataEditingProvider.js';
15
- export { EditTracker } from './data-editing/EditTracker.js';
14
+ export { DataEditingProvider, useEditSession } from './data-editing/DataEditingProvider.js';
15
+ export { EditSession } from './data-editing/EditSession.js';
16
16
  export { useEditableTable } from './data-editing/useEditableTable.js';
17
17
  export { DOWN1, DOWN2, UP1, UP2, asInteger, dataDescriptorTypeToVuuRowDataItemType, getMovingValueDirection, isValidNumber, numericTypeOfStringValue, shallowEquals, stringIsValidDecimal, stringIsValidInt, stringIsValidNumber } from './data-utils.js';
18
18
  export { BaseDataSource, defaultSuspenseProps } from './datasource/BaseDataSource.js';
@@ -28,7 +28,7 @@ export { EventEmitter } from './event-emitter.js';
28
28
  export { assertComponentRegistered, assertComponentsRegistered, byModule, env, featureFromJson, getCustomAndTableFeatures, getFilterTableFeatures, hasFilterTableFeatureProps, isCustomFeature, isSameTable, isStaticFeatures, isVuuTables, isWildcardSchema } from './feature-utils.js';
29
29
  export { applyFilterToColumns, extractFilterForColumn, filtersAreEqual, getColumnValueFromFilter, isAndFilter, isBetweenFilter, isBetweenOperator, isCompleteFilter, isExtendedFilter, isFilter, isFilterClause, isFilteredColumn, isInFilter, isMultiClauseFilter, isMultiValueFilter, isNamedFilter, isOrFilter, isScaledDecimalFilterClause, isSerializableFilter, isSingleValueFilter, isValidFilterClauseOp, stripFilterFromColumns } from './filters/filter-utils.js';
30
30
  export { ONE_DAY_IN_MILLIS, dateFilterAsQuery, filterAsQuery } from './filters/filterAsQuery.js';
31
- export { getFieldName, getTypedRange, getTypedValue, isNumber, isValidRange } from './form-utils.js';
31
+ export { DataValidationError, getFieldName, getTypedRange, getTypedValue, isNumber, isValidRange } from './form-utils.js';
32
32
  export { defaultValueFormatter, getValueFormatter, lowerCase, numericFormatter } from './formatting-utils.js';
33
33
  export { getUniqueId } from './getUniqueId.js';
34
34
  export { addGroupColumn, getGroupStatus, removeGroupColumn } from './group-utils.js';
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2.1.4",
2
+ "version": "2.1.5",
3
3
  "author": "heswell",
4
4
  "license": "Apache-2.0",
5
5
  "types": "types/index.d.ts",
@@ -7,14 +7,14 @@
7
7
  "@salt-ds/core": "1.54.1"
8
8
  },
9
9
  "devDependencies": {
10
- "@vuu-ui/vuu-data-types": "2.1.4",
11
- "@vuu-ui/vuu-table-types": "2.1.4",
12
- "@vuu-ui/vuu-filter-types": "2.1.4",
13
- "@vuu-ui/vuu-protocol-types": "2.1.4"
10
+ "@vuu-ui/vuu-data-types": "2.1.5",
11
+ "@vuu-ui/vuu-table-types": "2.1.5",
12
+ "@vuu-ui/vuu-filter-types": "2.1.5",
13
+ "@vuu-ui/vuu-protocol-types": "2.1.5"
14
14
  },
15
15
  "peerDependencies": {
16
16
  "@internationalized/date": "^3.0.0",
17
- "@vuu-ui/vuu-filter-parser": "2.1.4",
17
+ "@vuu-ui/vuu-filter-parser": "2.1.5",
18
18
  "clsx": "^2.0.0",
19
19
  "react": "^19.2.3",
20
20
  "react-dom": "^19.2.3"
@@ -1,8 +1,8 @@
1
1
  import { ReactNode } from "react";
2
- import { EditTracker } from "./EditTracker";
3
- export declare const DataEditingProvider: ({ children, editTracker, }: {
2
+ import { EditSession } from "./EditSession";
3
+ export declare const DataEditingProvider: ({ children, editSession, }: {
4
4
  children: ReactNode;
5
- editTracker: EditTracker;
5
+ editSession: EditSession;
6
6
  }) => import("react/jsx-runtime").JSX.Element;
7
- export declare function useEditTracker(throwIfUnavailable?: false): EditTracker | undefined;
8
- export declare function useEditTracker(throwIfUnavailable: true): EditTracker;
7
+ export declare function useEditSession(throwIfUnavailable?: false): EditSession | undefined;
8
+ export declare function useEditSession(throwIfUnavailable: true): EditSession;
@@ -1,7 +1,7 @@
1
- import { EditTracker } from "./EditTracker";
1
+ import { EditSession } from "./EditSession";
2
2
  export interface EditButtonProps {
3
- editTracker?: EditTracker;
3
+ editSession?: EditSession;
4
4
  onCancel: () => void;
5
5
  onSave: () => void;
6
6
  }
7
- export declare const EditButtons: ({ editTracker, onCancel, onSave, }: EditButtonProps) => import("react/jsx-runtime").JSX.Element;
7
+ export declare const EditButtons: ({ editSession, onCancel, onSave, }: EditButtonProps) => import("react/jsx-runtime").JSX.Element;
@@ -2,10 +2,10 @@ import { DataSource } from "@vuu-ui/vuu-data-types";
2
2
  import type { RpcResultError, VuuRowDataItemType, VuuTable } from "@vuu-ui/vuu-protocol-types";
3
3
  import { EventEmitter } from "../event-emitter";
4
4
  export type EditState = "clean" | "dirty";
5
- type EditTrackerEvents = {
5
+ type EditSessionEvents = {
6
6
  editState: (editState: EditState) => void;
7
7
  };
8
- export declare class EditTracker extends EventEmitter<EditTrackerEvents> {
8
+ export declare class EditSession extends EventEmitter<EditSessionEvents> {
9
9
  #private;
10
10
  get active(): boolean;
11
11
  set active(isActive: boolean);
@@ -19,6 +19,6 @@ export declare class EditTracker extends EventEmitter<EditTrackerEvents> {
19
19
  cancelChanges(): Promise<import("@vuu-ui/vuu-protocol-types").RpcResultSuccess | RpcResultError | undefined>;
20
20
  saveChanges(): Promise<import("@vuu-ui/vuu-protocol-types").RpcResultSuccess | RpcResultError | undefined>;
21
21
  edit(key: string, columnName: string, originalValue: VuuRowDataItemType, newValue: VuuRowDataItemType): void;
22
- commit(key: string, columnName: string): Promise<import("@vuu-ui/vuu-protocol-types").RpcResultSuccess | RpcResultError | undefined>;
22
+ commit(key: string, columnName: string, typedValue: string | number | boolean): Promise<import("@vuu-ui/vuu-protocol-types").RpcResultSuccess | RpcResultError | undefined>;
23
23
  }
24
24
  export {};
@@ -1,5 +1,5 @@
1
1
  import { VuuTable } from "@vuu-ui/vuu-protocol-types";
2
- import { EditTracker } from "./EditTracker";
2
+ import { EditSession } from "./EditSession";
3
3
  import { DataSource } from "@vuu-ui/vuu-data-types";
4
4
  export type EditMode = "edit" | "view";
5
5
  export interface EditableTableHookProps {
@@ -16,11 +16,11 @@ export interface EditableTableHookProps {
16
16
  * If dataSource not provided, new DataSource
17
17
  * will be created using table and columns
18
18
  */
19
- table: VuuTable;
19
+ table?: VuuTable;
20
20
  }
21
21
  export declare const useEditableTable: ({ columns, dataSource: dataSourceProp, isEditMode, onCancel, onSave, table, }: EditableTableHookProps) => {
22
22
  dataSource: DataSource;
23
- editTracker: EditTracker;
23
+ editSession: EditSession;
24
24
  onCancel: () => void;
25
25
  onSave: () => Promise<void>;
26
26
  };
@@ -2,6 +2,11 @@ import { DataValueTypeSimple } from "@vuu-ui/vuu-data-types";
2
2
  import { VuuColumnDataType, VuuRowDataItemType } from "@vuu-ui/vuu-protocol-types";
3
3
  import { KeyboardEvent, SyntheticEvent } from "react";
4
4
  import { ExtendedFilterOptions } from "@vuu-ui/vuu-filter-types";
5
+ export declare class DataValidationError extends Error {
6
+ actualType: string;
7
+ expectedType: string;
8
+ constructor(message: string, expectedType: string, actualType: string);
9
+ }
5
10
  /**
6
11
  * Use with the following convention:
7
12
  *
package/types/index.d.ts CHANGED
@@ -13,8 +13,8 @@ export * from "./component-registry";
13
13
  export * from "./cookie-utils";
14
14
  export * from "./css-utils";
15
15
  export { EditButtons, type EditButtonProps } from "./data-editing/EditButtons";
16
- export { DataEditingProvider, useEditTracker, } from "./data-editing/DataEditingProvider";
17
- export { EditTracker, type EditState } from "./data-editing/EditTracker";
16
+ export { DataEditingProvider, useEditSession, } from "./data-editing/DataEditingProvider";
17
+ export { EditSession, type EditState } from "./data-editing/EditSession";
18
18
  export { useEditableTable } from "./data-editing/useEditableTable";
19
19
  export * from "./data-utils";
20
20
  export * from "./datasource/BaseDataSource";
@@ -1 +0,0 @@
1
- {"version":3,"file":"EditTracker.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/EditTracker.tsx"],"sourcesContent":["import { DataSource } from \"@vuu-ui/vuu-data-types\";\nimport type {\n RpcResultError,\n VuuRowDataItemType,\n VuuTable,\n} from \"@vuu-ui/vuu-protocol-types\";\nimport { EventEmitter } from \"../event-emitter\";\nimport { isRpcSuccess } from \"../protocol-message-utils\";\n\nexport type EditState = \"clean\" | \"dirty\";\n\ntype CellEdit = {\n originalValue: VuuRowDataItemType;\n editedValue: VuuRowDataItemType;\n};\n\ntype RowEditDetails = {\n /**\n * Column name => cell edit details\n */\n cellEdits: Map<string, CellEdit>;\n};\n\ntype EditTrackerEvents = {\n editState: (editState: EditState) => void;\n};\n\nexport class EditTracker extends EventEmitter<EditTrackerEvents> {\n #active = false;\n /**\n * Row key => row edits\n */\n #rowEdits = new Map<string, RowEditDetails>();\n #editCount = 0;\n #dataSource?: DataSource;\n #inEditMode = false;\n\n get active() {\n return this.#active;\n }\n set active(isActive: boolean) {\n this.#active = isActive;\n }\n get editCount() {\n return this.#editCount;\n }\n\n set editCount(val: number) {\n if (val !== this.#editCount) {\n const oldCount = this.#editCount;\n this.#editCount = val;\n if (val === 0) {\n this.emit(\"editState\", \"clean\");\n } else if (oldCount === 0) {\n this.emit(\"editState\", \"dirty\");\n }\n }\n }\n\n set dataSource(ds: DataSource) {\n this.#dataSource = ds;\n }\n\n clear() {\n this.#rowEdits.clear();\n this.#editCount = 0;\n }\n\n async enterEditMode() {\n this.#inEditMode = true;\n\n const rpcResponse = await this.#dataSource?.rpcRequest?.({\n type: \"RPC_REQUEST\",\n rpcName: \"ENTER_EDIT_MODE\",\n params: {},\n });\n\n if (isRpcSuccess(rpcResponse)) {\n const { table: sessionTable } = rpcResponse.data as { table: VuuTable };\n return sessionTable;\n } else {\n console.log(\"fail\");\n }\n }\n\n get inEditMode() {\n return this.#inEditMode;\n }\n\n get editState(): EditState {\n return this.editCount === 0 ? \"clean\" : \"dirty\";\n }\n\n async cancelChanges() {\n const rpcResponse = await this.#dataSource?.rpcRequest?.({\n type: \"RPC_REQUEST\",\n rpcName: \"EXIT_EDIT_MODE\",\n params: {},\n });\n this.clear();\n return rpcResponse;\n }\n\n async saveChanges() {\n const rpcResponse = await this.#dataSource?.rpcRequest?.({\n type: \"RPC_REQUEST\",\n rpcName: \"EXIT_EDIT_MODE\",\n params: { save: true },\n });\n this.clear();\n return rpcResponse;\n }\n\n // TODO how do we deal with the '_edited' pattern\n edit(\n key: string,\n columnName: string,\n originalValue: VuuRowDataItemType,\n newValue: VuuRowDataItemType,\n ) {\n const rowEditDetails = this.#rowEdits.get(key);\n if (rowEditDetails) {\n const { cellEdits } = rowEditDetails;\n const cellEdit = cellEdits.get(columnName);\n if (cellEdit) {\n if (newValue === cellEdit.originalValue) {\n if (cellEdits.size === 1) {\n this.#rowEdits.delete(key);\n } else {\n // re-editing a cell had removed the edit\n cellEdits.delete(columnName);\n }\n this.editCount = this.#editCount - 1;\n } else {\n cellEdit.editedValue = newValue;\n }\n } else {\n // row has already been edited, but this column has not\n cellEdits.set(columnName, {\n originalValue,\n editedValue: newValue,\n });\n this.editCount = this.#editCount + 1;\n }\n } else {\n this.#rowEdits.set(key, {\n cellEdits: new Map([\n [columnName, { originalValue, editedValue: newValue }],\n ]),\n });\n this.editCount = this.#editCount + 1;\n }\n }\n\n //TODO alow a shortcut commit that allows a value, bypassing need\n // for edit. Thids caters for boolean values, dropdown list etc\n // that have no intermediate edit phase\n async commit(key: string, columnName: string) {\n const rowEditDetails = this.#rowEdits.get(key);\n if (rowEditDetails) {\n const { cellEdits } = rowEditDetails;\n const cellEditValues = cellEdits.get(columnName);\n if (cellEditValues) {\n const { editedValue } = cellEditValues;\n const rpcResponse = await this.#dataSource?.rpcRequest?.({\n type: \"RPC_REQUEST\",\n rpcName: \"editCell\",\n params: {\n column: columnName,\n data: editedValue,\n key,\n },\n });\n\n return rpcResponse;\n }\n } else {\n return {\n errorMessage: \"CHANGE_REVERTED\",\n type: \"ERROR_RESULT\",\n } as RpcResultError;\n }\n }\n}\n"],"names":["EventEmitter","isRpcSuccess"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"EditTracker.js","sources":["../../../../../../../packages/vuu-utils/src/data-editing/EditTracker.tsx"],"sourcesContent":["import { DataSource } from \"@vuu-ui/vuu-data-types\";\nimport type {\n RpcResultError,\n VuuRowDataItemType,\n VuuTable,\n} from \"@vuu-ui/vuu-protocol-types\";\nimport { EventEmitter } from \"../event-emitter\";\nimport { isRpcSuccess } from \"../protocol-message-utils\";\n\nexport type EditState = \"clean\" | \"dirty\";\n\ntype CellEdit = {\n originalValue: VuuRowDataItemType;\n editedValue: VuuRowDataItemType;\n};\n\ntype RowEditDetails = {\n /**\n * Column name => cell edit details\n */\n cellEdits: Map<string, CellEdit>;\n};\n\ntype EditTrackerEvents = {\n editState: (editState: EditState) => void;\n};\n\nexport class EditTracker extends EventEmitter<EditTrackerEvents> {\n #active = false;\n /**\n * Row key => row edits\n */\n #rowEdits = new Map<string, RowEditDetails>();\n #editCount = 0;\n #dataSource?: DataSource;\n #inEditMode = false;\n\n get active() {\n return this.#active;\n }\n set active(isActive: boolean) {\n this.#active = isActive;\n }\n get editCount() {\n return this.#editCount;\n }\n\n set editCount(val: number) {\n if (val !== this.#editCount) {\n const oldCount = this.#editCount;\n this.#editCount = val;\n if (val === 0) {\n this.emit(\"editState\", \"clean\");\n } else if (oldCount === 0) {\n this.emit(\"editState\", \"dirty\");\n }\n }\n }\n\n set dataSource(ds: DataSource) {\n this.#dataSource = ds;\n }\n\n clear() {\n this.#rowEdits.clear();\n this.#editCount = 0;\n }\n\n async enterEditMode() {\n this.#inEditMode = true;\n\n const rpcResponse = await this.#dataSource?.rpcRequest?.({\n type: \"RPC_REQUEST\",\n rpcName: \"ENTER_EDIT_MODE\",\n params: {},\n });\n\n if (isRpcSuccess(rpcResponse)) {\n const { table: sessionTable } = rpcResponse.data as { table: VuuTable };\n return sessionTable;\n } else {\n console.log(\"fail\");\n }\n }\n\n get inEditMode() {\n return this.#inEditMode;\n }\n\n get editState(): EditState {\n return this.editCount === 0 ? \"clean\" : \"dirty\";\n }\n\n async cancelChanges() {\n const rpcResponse = await this.#dataSource?.rpcRequest?.({\n type: \"RPC_REQUEST\",\n rpcName: \"EXIT_EDIT_MODE\",\n params: {},\n });\n this.clear();\n return rpcResponse;\n }\n\n async saveChanges() {\n const rpcResponse = await this.#dataSource?.rpcRequest?.({\n type: \"RPC_REQUEST\",\n rpcName: \"EXIT_EDIT_MODE\",\n params: { save: true },\n });\n this.clear();\n return rpcResponse;\n }\n\n // TODO how do we deal with the '_edited' pattern\n edit(\n key: string,\n columnName: string,\n originalValue: VuuRowDataItemType,\n newValue: VuuRowDataItemType,\n ) {\n const rowEditDetails = this.#rowEdits.get(key);\n if (rowEditDetails) {\n const { cellEdits } = rowEditDetails;\n const cellEdit = cellEdits.get(columnName);\n if (cellEdit) {\n if (newValue === cellEdit.originalValue) {\n if (cellEdits.size === 1) {\n this.#rowEdits.delete(key);\n } else {\n // re-editing a cell had removed the edit\n cellEdits.delete(columnName);\n }\n this.editCount = this.#editCount - 1;\n } else {\n cellEdit.editedValue = newValue;\n }\n } else {\n // row has already been edited, but this column has not\n cellEdits.set(columnName, {\n originalValue,\n editedValue: newValue,\n });\n this.editCount = this.#editCount + 1;\n }\n } else {\n this.#rowEdits.set(key, {\n cellEdits: new Map([\n [columnName, { originalValue, editedValue: newValue }],\n ]),\n });\n this.editCount = this.#editCount + 1;\n }\n }\n\n //TODO alow a shortcut commit that allows a value, bypassing need\n // for edit. Thids caters for boolean values, dropdown list etc\n // that have no intermediate edit phase\n async commit(key: string, columnName: string) {\n const rowEditDetails = this.#rowEdits.get(key);\n if (rowEditDetails) {\n const { cellEdits } = rowEditDetails;\n const cellEditValues = cellEdits.get(columnName);\n if (cellEditValues) {\n const { editedValue } = cellEditValues;\n const rpcResponse = await this.#dataSource?.rpcRequest?.({\n type: \"RPC_REQUEST\",\n rpcName: \"editCell\",\n params: {\n column: columnName,\n data: editedValue,\n key,\n },\n });\n\n return rpcResponse;\n }\n } else {\n return {\n errorMessage: \"CHANGE_REVERTED\",\n type: \"ERROR_RESULT\",\n } as RpcResultError;\n }\n }\n}\n"],"names":[],"mappings":"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"}