@dxos/plugin-sheet 0.6.14-main.7bd9c89 → 0.6.14-staging.54a8bab
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/lib/browser/{SheetContainer-AKWROARP.mjs → SheetContainer-JZEKRM4Z.mjs} +83 -76
- package/dist/lib/browser/SheetContainer-JZEKRM4Z.mjs.map +7 -0
- package/dist/lib/browser/{chunk-BWN5DZWZ.mjs → chunk-BVUN7SHF.mjs} +6 -13
- package/dist/lib/browser/chunk-BVUN7SHF.mjs.map +7 -0
- package/dist/lib/browser/{chunk-FGMFOW6U.mjs → chunk-G2FUL6PK.mjs} +791 -690
- package/dist/lib/browser/chunk-G2FUL6PK.mjs.map +7 -0
- package/dist/lib/browser/{chunk-D3QTX46O.mjs → chunk-RABELMEQ.mjs} +3 -2
- package/dist/lib/browser/{chunk-D3QTX46O.mjs.map → chunk-RABELMEQ.mjs.map} +3 -3
- package/dist/lib/browser/{chunk-GSV5QNLD.mjs → chunk-VMSX6Z4X.mjs} +297 -44
- package/dist/lib/browser/chunk-VMSX6Z4X.mjs.map +7 -0
- package/dist/lib/browser/{graph-M4IQ76QX.mjs → compute-graph-GGWUX644.mjs} +4 -2
- package/dist/lib/browser/index.mjs +91 -21
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/browser/meta.mjs +1 -1
- package/dist/lib/browser/types.mjs +2 -2
- package/dist/lib/node/{SheetContainer-N5IQGEFL.cjs → SheetContainer-PJE74VO4.cjs} +81 -81
- package/dist/lib/node/SheetContainer-PJE74VO4.cjs.map +7 -0
- package/dist/lib/node/{chunk-QIFIGEKV.cjs → chunk-2ZVZI2KJ.cjs} +6 -5
- package/dist/lib/node/{chunk-QIFIGEKV.cjs.map → chunk-2ZVZI2KJ.cjs.map} +3 -3
- package/dist/lib/node/{chunk-NZARD7UP.cjs → chunk-AWKOWDMI.cjs} +10 -17
- package/dist/lib/node/chunk-AWKOWDMI.cjs.map +7 -0
- package/dist/lib/node/{chunk-5XPK2V4A.cjs → chunk-O7XR4R7Y.cjs} +306 -42
- package/dist/lib/node/chunk-O7XR4R7Y.cjs.map +7 -0
- package/dist/lib/node/{chunk-53BMSUIK.cjs → chunk-STZ7S7RF.cjs} +755 -668
- package/dist/lib/node/chunk-STZ7S7RF.cjs.map +7 -0
- package/dist/lib/node/{graph-Q3N2X26H.cjs → compute-graph-KGWA2QLE.cjs} +21 -19
- package/dist/lib/node/compute-graph-KGWA2QLE.cjs.map +7 -0
- package/dist/lib/node/index.cjs +109 -42
- package/dist/lib/node/index.cjs.map +4 -4
- package/dist/lib/node/meta.cjs +3 -3
- package/dist/lib/node/meta.cjs.map +1 -1
- package/dist/lib/node/meta.json +1 -1
- package/dist/lib/node/types.cjs +7 -7
- package/dist/lib/node/types.cjs.map +1 -1
- package/dist/lib/node-esm/{SheetContainer-46PBMF2E.mjs → SheetContainer-R73XEXHU.mjs} +83 -76
- package/dist/lib/node-esm/SheetContainer-R73XEXHU.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-VCYJWE3O.mjs → chunk-BM2Q3FFC.mjs} +3 -2
- package/dist/lib/node-esm/{chunk-VCYJWE3O.mjs.map → chunk-BM2Q3FFC.mjs.map} +3 -3
- package/dist/lib/node-esm/{chunk-5WPZCXNS.mjs → chunk-CR4K75EL.mjs} +296 -44
- package/dist/lib/node-esm/chunk-CR4K75EL.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-WFDTY3IC.mjs → chunk-UIBWRHW7.mjs} +6 -13
- package/dist/lib/node-esm/chunk-UIBWRHW7.mjs.map +7 -0
- package/dist/lib/node-esm/{chunk-T3PRH7QS.mjs → chunk-V5N3Y2O5.mjs} +791 -690
- package/dist/lib/node-esm/chunk-V5N3Y2O5.mjs.map +7 -0
- package/dist/lib/node-esm/{graph-SMPUMOV2.mjs → compute-graph-2SCZT7N5.mjs} +4 -2
- package/dist/lib/node-esm/index.mjs +91 -21
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/lib/node-esm/meta.mjs +1 -1
- package/dist/lib/node-esm/types.mjs +2 -2
- package/dist/types/src/SheetPlugin.d.ts.map +1 -1
- package/dist/types/src/components/ComputeGraph/ComputeGraphContextProvider.d.ts +3 -1
- package/dist/types/src/components/ComputeGraph/ComputeGraphContextProvider.d.ts.map +1 -1
- package/dist/types/src/components/GridSheet/GridSheet.d.ts.map +1 -1
- package/dist/types/src/components/GridSheet/GridSheet.stories.d.ts.map +1 -1
- package/dist/types/src/components/GridSheet/util.d.ts +1 -2
- package/dist/types/src/components/GridSheet/util.d.ts.map +1 -1
- package/dist/types/src/components/RangeList/RangeList.d.ts +7 -0
- package/dist/types/src/components/RangeList/RangeList.d.ts.map +1 -0
- package/dist/types/src/components/RangeList/index.d.ts +2 -0
- package/dist/types/src/components/RangeList/index.d.ts.map +1 -0
- package/dist/types/src/components/SheetContainer/SheetContainer.d.ts +6 -3
- package/dist/types/src/components/SheetContainer/SheetContainer.d.ts.map +1 -1
- package/dist/types/src/components/SheetContainer/SheetContainer.stories.d.ts.map +1 -1
- package/dist/types/src/components/SheetContext/SheetContext.d.ts +7 -5
- package/dist/types/src/components/SheetContext/SheetContext.d.ts.map +1 -1
- package/dist/types/src/components/Toolbar/Toolbar.d.ts +6 -3
- package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/types/src/components/index.d.ts +5 -2
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/compute-graph/compute-graph-registry.d.ts.map +1 -0
- package/dist/types/src/{graph → compute-graph}/compute-graph.d.ts +3 -3
- package/dist/types/src/compute-graph/compute-graph.d.ts.map +1 -0
- package/dist/types/src/compute-graph/compute-graph.stories.d.ts.map +1 -0
- package/dist/types/src/compute-graph/compute-graph.test.d.ts.map +1 -0
- package/dist/types/src/compute-graph/compute-node.d.ts.map +1 -0
- package/dist/types/src/compute-graph/functions/async-function.d.ts.map +1 -0
- package/dist/types/src/compute-graph/functions/edge-function.d.ts.map +1 -0
- package/dist/types/src/compute-graph/functions/function-defs.d.ts.map +1 -0
- package/dist/types/src/compute-graph/functions/index.d.ts.map +1 -0
- package/dist/types/src/compute-graph/hyperformula.test.d.ts.map +1 -0
- package/dist/types/src/compute-graph/index.d.ts.map +1 -0
- package/dist/types/src/compute-graph/testing/index.d.ts.map +1 -0
- package/dist/types/src/compute-graph/testing/test-builder.d.ts.map +1 -0
- package/dist/types/src/compute-graph/testing/test-plugin.d.ts.map +1 -0
- package/dist/types/src/compute-graph/util.d.ts.map +1 -0
- package/dist/types/src/defs/index.d.ts +1 -1
- package/dist/types/src/defs/index.d.ts.map +1 -1
- package/dist/types/src/defs/sheet-range-types.d.ts +2 -2
- package/dist/types/src/defs/sheet-range-types.d.ts.map +1 -1
- package/dist/types/src/defs/types.d.ts +6 -0
- package/dist/types/src/defs/types.d.ts.map +1 -1
- package/dist/types/src/defs/util.d.ts +3 -7
- package/dist/types/src/defs/util.d.ts.map +1 -1
- package/dist/types/src/extensions/compute.d.ts +1 -1
- package/dist/types/src/extensions/compute.d.ts.map +1 -1
- package/dist/types/src/extensions/editor/extension.d.ts +23 -3
- package/dist/types/src/extensions/editor/extension.d.ts.map +1 -1
- package/dist/types/src/index.d.ts +1 -1
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/integrations/index.d.ts +2 -0
- package/dist/types/src/integrations/index.d.ts.map +1 -0
- package/dist/types/src/integrations/thread-ranges.d.ts +7 -0
- package/dist/types/src/integrations/thread-ranges.d.ts.map +1 -0
- package/dist/types/src/meta.d.ts +1 -0
- package/dist/types/src/meta.d.ts.map +1 -1
- package/dist/types/src/model/index.d.ts +1 -1
- package/dist/types/src/model/index.d.ts.map +1 -1
- package/dist/types/src/model/sheet-model.d.ts +13 -6
- package/dist/types/src/model/sheet-model.d.ts.map +1 -1
- package/dist/types/src/{hooks → model}/useSheetModel.d.ts +1 -1
- package/dist/types/src/model/useSheetModel.d.ts.map +1 -0
- package/dist/types/src/serializer.d.ts +4 -0
- package/dist/types/src/serializer.d.ts.map +1 -0
- package/dist/types/src/testing/testing.d.ts +1 -1
- package/dist/types/src/testing/testing.d.ts.map +1 -1
- package/dist/types/src/translations.d.ts +18 -3
- package/dist/types/src/translations.d.ts.map +1 -1
- package/dist/types/src/types.d.ts +37 -33
- package/dist/types/src/types.d.ts.map +1 -1
- package/package.json +43 -50
- package/src/SheetPlugin.tsx +45 -12
- package/src/components/ComputeGraph/ComputeGraphContextProvider.tsx +19 -2
- package/src/components/FunctionEditor/FunctionEditor.tsx +5 -5
- package/src/components/GridSheet/GridSheet.stories.tsx +3 -1
- package/src/components/GridSheet/GridSheet.tsx +181 -24
- package/src/components/GridSheet/SheetCellEditor.stories.tsx +1 -1
- package/src/components/GridSheet/util.ts +34 -18
- package/src/components/RangeList/RangeList.tsx +53 -0
- package/src/components/RangeList/index.ts +5 -0
- package/src/components/SheetContainer/SheetContainer.stories.tsx +5 -3
- package/src/components/SheetContainer/SheetContainer.tsx +10 -4
- package/src/components/SheetContext/SheetContext.tsx +43 -20
- package/src/components/Toolbar/Toolbar.tsx +98 -74
- package/src/components/index.ts +1 -0
- package/src/{graph → compute-graph}/compute-graph.stories.tsx +2 -1
- package/src/{graph → compute-graph}/compute-graph.ts +27 -9
- package/src/{graph → compute-graph}/compute-node.ts +2 -3
- package/src/{graph → compute-graph}/functions/async-function.ts +1 -0
- package/src/{graph → compute-graph}/functions/edge-function.ts +5 -3
- package/src/defs/index.ts +1 -1
- package/src/defs/sheet-range-types.ts +9 -6
- package/src/defs/types.ts +6 -1
- package/src/defs/util.ts +4 -19
- package/src/extensions/compute.stories.tsx +2 -2
- package/src/extensions/compute.ts +2 -2
- package/src/extensions/editor/extension.test.ts +1 -1
- package/src/extensions/editor/extension.ts +48 -23
- package/src/index.ts +2 -2
- package/src/integrations/index.ts +5 -0
- package/src/integrations/thread-ranges.ts +101 -0
- package/src/meta.ts +1 -0
- package/src/model/index.ts +1 -1
- package/src/model/sheet-model.test.ts +6 -4
- package/src/model/sheet-model.ts +103 -26
- package/src/{hooks → model}/useSheetModel.ts +1 -1
- package/src/serializer.ts +27 -0
- package/src/testing/testing.tsx +1 -1
- package/src/translations.ts +18 -3
- package/src/types.ts +24 -2
- package/dist/lib/browser/SheetContainer-AKWROARP.mjs.map +0 -7
- package/dist/lib/browser/chunk-BWN5DZWZ.mjs.map +0 -7
- package/dist/lib/browser/chunk-FGMFOW6U.mjs.map +0 -7
- package/dist/lib/browser/chunk-GSV5QNLD.mjs.map +0 -7
- package/dist/lib/node/SheetContainer-N5IQGEFL.cjs.map +0 -7
- package/dist/lib/node/chunk-53BMSUIK.cjs.map +0 -7
- package/dist/lib/node/chunk-5XPK2V4A.cjs.map +0 -7
- package/dist/lib/node/chunk-NZARD7UP.cjs.map +0 -7
- package/dist/lib/node/graph-Q3N2X26H.cjs.map +0 -7
- package/dist/lib/node-esm/SheetContainer-46PBMF2E.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-5WPZCXNS.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-T3PRH7QS.mjs.map +0 -7
- package/dist/lib/node-esm/chunk-WFDTY3IC.mjs.map +0 -7
- package/dist/types/src/graph/compute-graph-registry.d.ts.map +0 -1
- package/dist/types/src/graph/compute-graph.d.ts.map +0 -1
- package/dist/types/src/graph/compute-graph.stories.d.ts.map +0 -1
- package/dist/types/src/graph/compute-graph.test.d.ts.map +0 -1
- package/dist/types/src/graph/compute-node.d.ts.map +0 -1
- package/dist/types/src/graph/functions/async-function.d.ts.map +0 -1
- package/dist/types/src/graph/functions/edge-function.d.ts.map +0 -1
- package/dist/types/src/graph/functions/function-defs.d.ts.map +0 -1
- package/dist/types/src/graph/functions/index.d.ts.map +0 -1
- package/dist/types/src/graph/hyperformula.test.d.ts.map +0 -1
- package/dist/types/src/graph/index.d.ts.map +0 -1
- package/dist/types/src/graph/testing/index.d.ts.map +0 -1
- package/dist/types/src/graph/testing/test-builder.d.ts.map +0 -1
- package/dist/types/src/graph/testing/test-plugin.d.ts.map +0 -1
- package/dist/types/src/graph/util.d.ts.map +0 -1
- package/dist/types/src/hooks/hooks.stories.d.ts +0 -6
- package/dist/types/src/hooks/hooks.stories.d.ts.map +0 -1
- package/dist/types/src/hooks/index.d.ts +0 -4
- package/dist/types/src/hooks/index.d.ts.map +0 -1
- package/dist/types/src/hooks/threads.d.ts +0 -8
- package/dist/types/src/hooks/threads.d.ts.map +0 -1
- package/dist/types/src/hooks/useComputeGraph.d.ts +0 -7
- package/dist/types/src/hooks/useComputeGraph.d.ts.map +0 -1
- package/dist/types/src/hooks/useSheetModel.d.ts.map +0 -1
- package/dist/types/src/model/decorations.d.ts +0 -26
- package/dist/types/src/model/decorations.d.ts.map +0 -1
- package/src/hooks/hooks.stories.tsx +0 -53
- package/src/hooks/index.ts +0 -7
- package/src/hooks/threads.ts +0 -147
- package/src/hooks/useComputeGraph.ts +0 -28
- package/src/model/decorations.ts +0 -66
- /package/dist/lib/browser/{graph-M4IQ76QX.mjs.map → compute-graph-GGWUX644.mjs.map} +0 -0
- /package/dist/lib/node-esm/{graph-SMPUMOV2.mjs.map → compute-graph-2SCZT7N5.mjs.map} +0 -0
- /package/dist/types/src/{graph → compute-graph}/compute-graph-registry.d.ts +0 -0
- /package/dist/types/src/{graph → compute-graph}/compute-graph.stories.d.ts +0 -0
- /package/dist/types/src/{graph → compute-graph}/compute-graph.test.d.ts +0 -0
- /package/dist/types/src/{graph → compute-graph}/compute-node.d.ts +0 -0
- /package/dist/types/src/{graph → compute-graph}/functions/async-function.d.ts +0 -0
- /package/dist/types/src/{graph → compute-graph}/functions/edge-function.d.ts +0 -0
- /package/dist/types/src/{graph → compute-graph}/functions/function-defs.d.ts +0 -0
- /package/dist/types/src/{graph → compute-graph}/functions/index.d.ts +0 -0
- /package/dist/types/src/{graph → compute-graph}/hyperformula.test.d.ts +0 -0
- /package/dist/types/src/{graph → compute-graph}/index.d.ts +0 -0
- /package/dist/types/src/{graph → compute-graph}/testing/index.d.ts +0 -0
- /package/dist/types/src/{graph → compute-graph}/testing/test-builder.d.ts +0 -0
- /package/dist/types/src/{graph → compute-graph}/testing/test-plugin.d.ts +0 -0
- /package/dist/types/src/{graph → compute-graph}/util.d.ts +0 -0
- /package/src/{graph → compute-graph}/compute-graph-registry.ts +0 -0
- /package/src/{graph → compute-graph}/compute-graph.test.ts +0 -0
- /package/src/{graph → compute-graph}/functions/function-defs.ts +0 -0
- /package/src/{graph → compute-graph}/functions/index.ts +0 -0
- /package/src/{graph → compute-graph}/hyperformula.test.ts +0 -0
- /package/src/{graph → compute-graph}/index.ts +0 -0
- /package/src/{graph → compute-graph}/testing/index.ts +0 -0
- /package/src/{graph → compute-graph}/testing/test-builder.ts +0 -0
- /package/src/{graph → compute-graph}/testing/test-plugin.ts +0 -0
- /package/src/{graph → compute-graph}/util.ts +0 -0
|
@@ -15,8 +15,9 @@ import { SyntaxHighlighter } from '@dxos/react-ui-syntax-highlighter';
|
|
|
15
15
|
import { withTheme } from '@dxos/storybook-utils';
|
|
16
16
|
|
|
17
17
|
import { testFunctionPlugins } from './testing';
|
|
18
|
+
import { useComputeGraph } from '../components';
|
|
18
19
|
import { createSheet } from '../defs';
|
|
19
|
-
import {
|
|
20
|
+
import { useSheetModel } from '../model';
|
|
20
21
|
import { withComputeGraphDecorator } from '../testing';
|
|
21
22
|
import { SheetType } from '../types';
|
|
22
23
|
|
|
@@ -6,6 +6,7 @@ import { type Listeners } from 'hyperformula/typings/Emitter';
|
|
|
6
6
|
|
|
7
7
|
import { Event } from '@dxos/async';
|
|
8
8
|
import { type Space, Filter, fullyQualifiedId } from '@dxos/client/echo';
|
|
9
|
+
import { FQ_ID_LENGTH } from '@dxos/client/echo';
|
|
9
10
|
import { Resource } from '@dxos/context';
|
|
10
11
|
import { getTypename } from '@dxos/echo-schema';
|
|
11
12
|
import { invariant } from '@dxos/invariant';
|
|
@@ -24,8 +25,9 @@ import {
|
|
|
24
25
|
EDGE_FUNCTION_NAME,
|
|
25
26
|
} from './functions';
|
|
26
27
|
|
|
27
|
-
// TODO(
|
|
28
|
-
|
|
28
|
+
// TODO(burdon): Factor out compute-graph.
|
|
29
|
+
|
|
30
|
+
const UNKNOWN_BINDING = '__UNKNOWN__';
|
|
29
31
|
|
|
30
32
|
// TODO(burdon): Factory.
|
|
31
33
|
// export type ComputeNodeGenerator = <T>(obj: T) => ComputeNode;
|
|
@@ -42,7 +44,7 @@ export const parseSheetName = (name: string): Partial<ObjectRef> => {
|
|
|
42
44
|
return id ? { type, id } : { id: type };
|
|
43
45
|
};
|
|
44
46
|
|
|
45
|
-
export type ComputeGraphEvent = 'functionsUpdated';
|
|
47
|
+
export type ComputeGraphEvent = 'functionsUpdated' | 'valuesUpdated';
|
|
46
48
|
|
|
47
49
|
/**
|
|
48
50
|
* Per-space compute and dependency graph.
|
|
@@ -62,7 +64,7 @@ export class ComputeGraph extends Resource {
|
|
|
62
64
|
public readonly update = new Event<{ type: ComputeGraphEvent }>();
|
|
63
65
|
|
|
64
66
|
// The context is passed to all functions.
|
|
65
|
-
public readonly context
|
|
67
|
+
public readonly context: FunctionContext;
|
|
66
68
|
|
|
67
69
|
constructor(
|
|
68
70
|
private readonly _hf: HyperFormula,
|
|
@@ -70,7 +72,17 @@ export class ComputeGraph extends Resource {
|
|
|
70
72
|
private readonly _options?: Partial<FunctionContextOptions>,
|
|
71
73
|
) {
|
|
72
74
|
super();
|
|
75
|
+
|
|
76
|
+
const contextOptions = {
|
|
77
|
+
...this._options,
|
|
78
|
+
onUpdate: (update) => {
|
|
79
|
+
this._options?.onUpdate?.(update);
|
|
80
|
+
this.update.emit({ type: 'valuesUpdated' });
|
|
81
|
+
},
|
|
82
|
+
} satisfies Partial<FunctionContextOptions>;
|
|
83
|
+
this.context = new FunctionContext(this._hf, this._space, contextOptions);
|
|
73
84
|
this._hf.updateConfig({ context: this.context });
|
|
85
|
+
|
|
74
86
|
// TODO(burdon): If debounce then aggregate changes.
|
|
75
87
|
const onValuesUpdate: Listeners['valuesUpdated'] = (changes) => {
|
|
76
88
|
for (const change of changes) {
|
|
@@ -116,7 +128,7 @@ export class ComputeGraph extends Resource {
|
|
|
116
128
|
getOrCreateNode(name: string): ComputeNode {
|
|
117
129
|
invariant(name.length);
|
|
118
130
|
if (!this._hf.doesSheetExist(name)) {
|
|
119
|
-
log
|
|
131
|
+
log('created node', { space: this._space?.id, sheet: name });
|
|
120
132
|
this._hf.addSheet(name);
|
|
121
133
|
}
|
|
122
134
|
|
|
@@ -130,7 +142,7 @@ export class ComputeGraph extends Resource {
|
|
|
130
142
|
|
|
131
143
|
/**
|
|
132
144
|
* Map bound value to custom function invocation.
|
|
133
|
-
* E.g., "HELLO(...args)" => "
|
|
145
|
+
* E.g., "HELLO(...args)" => "DX("HELLO", ...args)".
|
|
134
146
|
*/
|
|
135
147
|
mapFormulaToNative(formula: string): string {
|
|
136
148
|
return (
|
|
@@ -206,9 +218,9 @@ export class ComputeGraph extends Resource {
|
|
|
206
218
|
* E.g., spaceId:objectId() => HELLO()
|
|
207
219
|
*/
|
|
208
220
|
mapFunctionBindingFromId(formula: string) {
|
|
209
|
-
|
|
221
|
+
const binding = formula.replace(/(\w+):([a-zA-Z0-9]+)\((.*)\)/g, (match, spaceId, objectId, args) => {
|
|
210
222
|
const id = `${spaceId}:${objectId}`;
|
|
211
|
-
if (id.length !==
|
|
223
|
+
if (id.length !== FQ_ID_LENGTH) {
|
|
212
224
|
return match;
|
|
213
225
|
}
|
|
214
226
|
|
|
@@ -216,9 +228,15 @@ export class ComputeGraph extends Resource {
|
|
|
216
228
|
if (fn?.binding) {
|
|
217
229
|
return `${fn.binding}(${args})`;
|
|
218
230
|
} else {
|
|
219
|
-
return
|
|
231
|
+
return UNKNOWN_BINDING;
|
|
220
232
|
}
|
|
221
233
|
});
|
|
234
|
+
|
|
235
|
+
if (binding.startsWith(`=${UNKNOWN_BINDING}`)) {
|
|
236
|
+
return undefined;
|
|
237
|
+
} else {
|
|
238
|
+
return binding;
|
|
239
|
+
}
|
|
222
240
|
}
|
|
223
241
|
|
|
224
242
|
protected override async _open() {
|
|
@@ -10,7 +10,7 @@ import { Resource } from '@dxos/context';
|
|
|
10
10
|
|
|
11
11
|
import { DetailedCellError } from '#hyperformula';
|
|
12
12
|
import { type ComputeGraph } from './compute-graph';
|
|
13
|
-
import { type CellAddress } from '../defs';
|
|
13
|
+
import { type CellAddress, isFormula } from '../defs';
|
|
14
14
|
import { type CellScalarValue } from '../types';
|
|
15
15
|
|
|
16
16
|
export type ComputeNodeEvent = {
|
|
@@ -50,8 +50,7 @@ export class ComputeNode extends Resource {
|
|
|
50
50
|
}
|
|
51
51
|
|
|
52
52
|
setValue(cell: CellAddress, value: CellScalarValue) {
|
|
53
|
-
const mappedValue =
|
|
54
|
-
typeof value === 'string' && value.charAt(0) === '=' ? this._graph.mapFormulaToNative(value) : value;
|
|
53
|
+
const mappedValue = isFormula(value) ? this._graph.mapFormulaToNative(value) : value;
|
|
55
54
|
this._graph.hf.setCellContents({ sheet: this.sheetId, row: cell.row, col: cell.col }, [[mappedValue]]);
|
|
56
55
|
}
|
|
57
56
|
|
|
@@ -83,6 +83,7 @@ export class FunctionContext {
|
|
|
83
83
|
) {
|
|
84
84
|
this._options = defaultsDeep(_options ?? {}, defaultFunctionContextOptions);
|
|
85
85
|
this._onUpdate = debounce((update) => {
|
|
86
|
+
log('update', update);
|
|
86
87
|
// TODO(burdon): Better way to trigger recalculation? (NOTE: rebuildAndRecalculate resets the undo history.)
|
|
87
88
|
this._hf.resumeEvaluation();
|
|
88
89
|
this._options.onUpdate?.(update);
|
|
@@ -44,7 +44,7 @@ export class EdgeFunctionPlugin extends AsyncFunctionPlugin {
|
|
|
44
44
|
|
|
45
45
|
if (subscribe) {
|
|
46
46
|
const unsubscribe = effect(() => {
|
|
47
|
-
log
|
|
47
|
+
log('function changed', { fn });
|
|
48
48
|
const _ = fn?.version;
|
|
49
49
|
|
|
50
50
|
// TODO(wittjosiah): `ttl` should be 0 to force a recalculation when a new version is deployed.
|
|
@@ -56,13 +56,15 @@ export class EdgeFunctionPlugin extends AsyncFunctionPlugin {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
const path = getUserFunctionUrlInMetadata(getMeta(fn));
|
|
59
|
-
const
|
|
59
|
+
const response = await fetch(`${this.context.remoteFunctionUrl}${path}`, {
|
|
60
60
|
method: 'POST',
|
|
61
61
|
headers: { 'Content-Type': 'application/json' },
|
|
62
62
|
body: JSON.stringify({ args: args.filter(nonNullable) }),
|
|
63
63
|
});
|
|
64
|
+
const result = await response.text();
|
|
65
|
+
log('function executed', { result });
|
|
64
66
|
|
|
65
|
-
return
|
|
67
|
+
return result;
|
|
66
68
|
};
|
|
67
69
|
|
|
68
70
|
return this.runAsyncFunction(ast, state, handler(true), { ttl: FUNCTION_TTL });
|
package/src/defs/index.ts
CHANGED
|
@@ -6,7 +6,7 @@ import { type ClassNameValue } from '@dxos/react-ui';
|
|
|
6
6
|
|
|
7
7
|
import { type SheetType } from '../types';
|
|
8
8
|
|
|
9
|
-
export const alignKey = '
|
|
9
|
+
export const alignKey = 'alignment';
|
|
10
10
|
export type AlignKey = typeof alignKey;
|
|
11
11
|
export type AlignValue = 'start' | 'center' | 'end' | 'unset';
|
|
12
12
|
|
|
@@ -16,11 +16,12 @@ export type CommentValue = string;
|
|
|
16
16
|
|
|
17
17
|
export const styleKey = 'style';
|
|
18
18
|
export type StyleKey = typeof styleKey;
|
|
19
|
-
export type StyleValue = 'highlight' | '
|
|
19
|
+
export type StyleValue = 'highlight' | 'softwrap';
|
|
20
20
|
|
|
21
|
+
// TODO(burdon): Reconcile with plugin-table.
|
|
21
22
|
export const cellClassNameForRange = ({ key, value }: SheetType['ranges'][number]): ClassNameValue => {
|
|
22
23
|
switch (key) {
|
|
23
|
-
case
|
|
24
|
+
case alignKey:
|
|
24
25
|
switch (value) {
|
|
25
26
|
case 'start':
|
|
26
27
|
return 'text-start';
|
|
@@ -31,12 +32,14 @@ export const cellClassNameForRange = ({ key, value }: SheetType['ranges'][number
|
|
|
31
32
|
default:
|
|
32
33
|
return undefined;
|
|
33
34
|
}
|
|
34
|
-
case
|
|
35
|
+
case commentKey:
|
|
35
36
|
return 'bg-gridComment';
|
|
36
|
-
case
|
|
37
|
+
case styleKey:
|
|
37
38
|
switch (value) {
|
|
38
39
|
case 'highlight':
|
|
39
|
-
return 'bg-gridHighlight';
|
|
40
|
+
return '!bg-gridHighlight';
|
|
41
|
+
case 'softwrap':
|
|
42
|
+
return '!whitespace-normal';
|
|
40
43
|
default:
|
|
41
44
|
return undefined;
|
|
42
45
|
}
|
package/src/defs/types.ts
CHANGED
|
@@ -13,11 +13,16 @@ export const MAX_COLUMNS = 26 * 2;
|
|
|
13
13
|
export type CellAddress = { col: number; row: number };
|
|
14
14
|
|
|
15
15
|
export type CellRange = { from: CellAddress; to?: CellAddress };
|
|
16
|
+
export type CompleteCellRange = { from: CellAddress; to: CellAddress };
|
|
16
17
|
|
|
17
18
|
export type CellIndex = string;
|
|
18
19
|
|
|
19
20
|
export type CellContentValue = number | string | boolean | null;
|
|
20
21
|
|
|
22
|
+
export const RANGE_NOTATION = /^[A-Z]+[0-9]+(:[A-Z]+[0-9]+)?$/;
|
|
23
|
+
|
|
24
|
+
export const isFormula = (value: any): value is string => typeof value === 'string' && value.charAt(0) === '=';
|
|
25
|
+
|
|
21
26
|
export const posEquals = (a: CellAddress | undefined, b: CellAddress | undefined) => {
|
|
22
27
|
return a?.col === b?.col && a?.row === b?.row;
|
|
23
28
|
};
|
|
@@ -34,7 +39,7 @@ export const addressToA1Notation = ({ col, row }: CellAddress): string => {
|
|
|
34
39
|
return `${columnLetter(col)}${row + 1}`;
|
|
35
40
|
};
|
|
36
41
|
|
|
37
|
-
// TODO(burdon): See simpleCellAddressFromString
|
|
42
|
+
// TODO(burdon): See (HF) simpleCellAddressFromString.
|
|
38
43
|
export const addressFromA1Notation = (ref: string): CellAddress => {
|
|
39
44
|
const match = ref.match(/([A-Z]+)(\d+)/);
|
|
40
45
|
invariant(match, `Invalid notation: ${ref}`);
|
package/src/defs/util.ts
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
addressFromA1Notation,
|
|
10
10
|
type CellAddress,
|
|
11
11
|
type CellRange,
|
|
12
|
+
type CompleteCellRange,
|
|
12
13
|
DEFAULT_COLUMNS,
|
|
13
14
|
DEFAULT_ROWS,
|
|
14
15
|
MAX_COLUMNS,
|
|
@@ -46,6 +47,7 @@ export const insertIndices = (indices: string[], i: number, n: number, max: numb
|
|
|
46
47
|
|
|
47
48
|
const idx = createIndices(n);
|
|
48
49
|
indices.splice(i, 0, ...idx);
|
|
50
|
+
return idx;
|
|
49
51
|
};
|
|
50
52
|
|
|
51
53
|
export const initialize = (
|
|
@@ -69,6 +71,7 @@ export const createSheet = ({ name, cells, ...size }: CreateSheetOptions = {}):
|
|
|
69
71
|
rowMeta: {},
|
|
70
72
|
columnMeta: {},
|
|
71
73
|
ranges: [],
|
|
74
|
+
threads: [],
|
|
72
75
|
});
|
|
73
76
|
|
|
74
77
|
initialize(sheet, size);
|
|
@@ -111,29 +114,11 @@ export const rangeToIndex = (sheet: SheetType, range: CellRange): string => {
|
|
|
111
114
|
/**
|
|
112
115
|
* E.g., "CA2@CB3:CC4@CD5" => "A1:B2".
|
|
113
116
|
*/
|
|
114
|
-
export const rangeFromIndex = (sheet: SheetType, idx: string):
|
|
117
|
+
export const rangeFromIndex = (sheet: SheetType, idx: string): CompleteCellRange => {
|
|
115
118
|
const [from, to] = idx.split(':').map((index) => addressFromIndex(sheet, index));
|
|
116
119
|
return { from, to };
|
|
117
120
|
};
|
|
118
121
|
|
|
119
|
-
/**
|
|
120
|
-
* Find closest cell to cursor.
|
|
121
|
-
*/
|
|
122
|
-
export const closest = (cursor: CellAddress, cells: CellAddress[]): CellAddress | undefined => {
|
|
123
|
-
let closestCell: CellAddress | undefined;
|
|
124
|
-
let closestDistance = Number.MAX_SAFE_INTEGER;
|
|
125
|
-
|
|
126
|
-
for (const cell of cells) {
|
|
127
|
-
const distance = Math.abs(cell.row - cursor.row) + Math.abs(cell.col - cursor.col);
|
|
128
|
-
if (distance < closestDistance) {
|
|
129
|
-
closestCell = cell;
|
|
130
|
-
closestDistance = distance;
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return closestCell;
|
|
135
|
-
};
|
|
136
|
-
|
|
137
122
|
/**
|
|
138
123
|
* Compares the positions of two cell indexes in a sheet.
|
|
139
124
|
* Sorts primarily by row, then by column if rows are equal.
|
|
@@ -23,8 +23,8 @@ import { withTheme, withLayout } from '@dxos/storybook-utils';
|
|
|
23
23
|
import { nonNullable } from '@dxos/util';
|
|
24
24
|
|
|
25
25
|
import { compute, computeGraphFacet } from './compute';
|
|
26
|
-
import { GridSheet, SheetProvider } from '../components';
|
|
27
|
-
import {
|
|
26
|
+
import { GridSheet, SheetProvider, useComputeGraph } from '../components';
|
|
27
|
+
import { useSheetModel } from '../model';
|
|
28
28
|
import { useTestSheet, withComputeGraphDecorator } from '../testing';
|
|
29
29
|
import { SheetType } from '../types';
|
|
30
30
|
|
|
@@ -16,10 +16,10 @@ import { Decoration, EditorView, ViewPlugin, WidgetType } from '@codemirror/view
|
|
|
16
16
|
|
|
17
17
|
import { type UnsubscribeCallback, debounce } from '@dxos/async';
|
|
18
18
|
import { invariant } from '@dxos/invariant';
|
|
19
|
-
import { documentId, singleValueFacet } from '@dxos/react-ui-editor
|
|
19
|
+
import { documentId, singleValueFacet } from '@dxos/react-ui-editor';
|
|
20
20
|
|
|
21
|
+
import { type ComputeGraph, type ComputeNode, createSheetName } from '../compute-graph';
|
|
21
22
|
import { type CellAddress } from '../defs';
|
|
22
|
-
import { type ComputeGraph, type ComputeNode, createSheetName } from '../graph';
|
|
23
23
|
import { type CellScalarValue } from '../types';
|
|
24
24
|
|
|
25
25
|
const LANGUAGE_TAG = 'dx';
|
|
@@ -9,7 +9,7 @@ import { spreadsheet } from 'codemirror-lang-spreadsheet';
|
|
|
9
9
|
import { describe, expect, test } from 'vitest';
|
|
10
10
|
|
|
11
11
|
import { sheetExtension } from './extension';
|
|
12
|
-
import { defaultFunctions } from '../../graph';
|
|
12
|
+
import { defaultFunctions } from '../../compute-graph';
|
|
13
13
|
|
|
14
14
|
describe('formula parser', () => {
|
|
15
15
|
const {
|
|
@@ -18,10 +18,11 @@ import { type SyntaxNode } from '@lezer/common';
|
|
|
18
18
|
import { tags } from '@lezer/highlight';
|
|
19
19
|
import { spreadsheet } from 'codemirror-lang-spreadsheet';
|
|
20
20
|
|
|
21
|
-
import { singleValueFacet } from '@dxos/react-ui-editor
|
|
21
|
+
import { singleValueFacet } from '@dxos/react-ui-editor';
|
|
22
22
|
import { mx } from '@dxos/react-ui-theme';
|
|
23
23
|
|
|
24
|
-
import { type FunctionDefinition } from '../../graph';
|
|
24
|
+
import { type FunctionDefinition } from '../../compute-graph';
|
|
25
|
+
import { RANGE_NOTATION } from '../../defs';
|
|
25
26
|
|
|
26
27
|
/**
|
|
27
28
|
* https://codemirror.net/examples/styling
|
|
@@ -195,34 +196,53 @@ export const sheetExtension = ({ functions = [] }: SheetExtensionOptions): Exten
|
|
|
195
196
|
];
|
|
196
197
|
};
|
|
197
198
|
|
|
198
|
-
export type
|
|
199
|
-
|
|
200
|
-
|
|
199
|
+
export type SelectionRange = { from: number; to: number };
|
|
200
|
+
|
|
201
|
+
export interface RangeController {
|
|
202
|
+
setRange(range: string): void;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export type RangeExtensionOptions = {
|
|
206
|
+
/**
|
|
207
|
+
* Provides controller callback when extension is initialized.
|
|
208
|
+
*/
|
|
209
|
+
onInit?: (controller: RangeController) => void;
|
|
210
|
+
/**
|
|
211
|
+
* Called when the active range changes.
|
|
212
|
+
* @param state The current state.
|
|
213
|
+
* @param state.activeRange undefined if no range is active, otherwise a possibly partially defined range.
|
|
214
|
+
*/
|
|
215
|
+
onStateChange?: (state: { activeRange: string | undefined }) => void;
|
|
216
|
+
};
|
|
201
217
|
|
|
202
218
|
/**
|
|
203
219
|
* Tracks the currently active cell within a formula and provides a callback to modify it.
|
|
204
220
|
*/
|
|
205
|
-
export const rangeExtension = (onInit
|
|
221
|
+
export const rangeExtension = ({ onInit, onStateChange }: RangeExtensionOptions): Extension => {
|
|
206
222
|
let view: EditorView;
|
|
207
|
-
let activeRange:
|
|
208
|
-
const provider: CellRangeNotifier = (range: string) => {
|
|
209
|
-
if (activeRange) {
|
|
210
|
-
view.dispatch(
|
|
211
|
-
view.state.update({
|
|
212
|
-
changes: { ...activeRange, insert: range.toString() },
|
|
213
|
-
selection: { anchor: activeRange.from + range.length },
|
|
214
|
-
}),
|
|
215
|
-
);
|
|
216
|
-
}
|
|
223
|
+
let activeRange: SelectionRange | undefined;
|
|
217
224
|
|
|
218
|
-
|
|
225
|
+
// Called externally to provide current range.
|
|
226
|
+
const notifier: RangeController = {
|
|
227
|
+
setRange: (range: string) => {
|
|
228
|
+
if (activeRange) {
|
|
229
|
+
view.dispatch(
|
|
230
|
+
view.state.update({
|
|
231
|
+
changes: { ...activeRange, insert: range.toString() },
|
|
232
|
+
selection: { anchor: activeRange.from + range.length },
|
|
233
|
+
}),
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
view.focus();
|
|
238
|
+
},
|
|
219
239
|
};
|
|
220
240
|
|
|
221
241
|
return ViewPlugin.fromClass(
|
|
222
242
|
class {
|
|
223
243
|
constructor(_view: EditorView) {
|
|
224
244
|
view = _view;
|
|
225
|
-
onInit(
|
|
245
|
+
onInit?.(notifier);
|
|
226
246
|
}
|
|
227
247
|
|
|
228
248
|
update(view: ViewUpdate) {
|
|
@@ -235,17 +255,15 @@ export const rangeExtension = (onInit: (notifier: CellRangeNotifier) => void): E
|
|
|
235
255
|
visitTree(topNode, ({ type, from, to }) => {
|
|
236
256
|
if (from <= anchor && to >= anchor) {
|
|
237
257
|
switch (type.name) {
|
|
238
|
-
case 'Function':
|
|
258
|
+
case 'Function':
|
|
239
259
|
// Mark but keep looking.
|
|
240
260
|
activeRange = { from: to, to };
|
|
241
261
|
break;
|
|
242
|
-
}
|
|
243
262
|
|
|
244
|
-
case 'CloseParen':
|
|
263
|
+
case 'CloseParen':
|
|
245
264
|
// Mark but keep looking.
|
|
246
265
|
activeRange = { from, to: from };
|
|
247
266
|
break;
|
|
248
|
-
}
|
|
249
267
|
|
|
250
268
|
case 'RangeToken':
|
|
251
269
|
case 'CellToken':
|
|
@@ -259,8 +277,15 @@ export const rangeExtension = (onInit: (notifier: CellRangeNotifier) => void): E
|
|
|
259
277
|
|
|
260
278
|
// Allow start of formula.
|
|
261
279
|
if (!activeRange && view.state.doc.toString()[0] === '=') {
|
|
262
|
-
|
|
280
|
+
const str = view.state.doc.sliceString(1);
|
|
281
|
+
if (RANGE_NOTATION.test(str)) {
|
|
282
|
+
activeRange = { from: 1, to: str.length + 1 };
|
|
283
|
+
}
|
|
263
284
|
}
|
|
285
|
+
|
|
286
|
+
onStateChange?.({
|
|
287
|
+
activeRange: activeRange ? view.state.doc.sliceString(activeRange.from, activeRange.to) : undefined,
|
|
288
|
+
});
|
|
264
289
|
}
|
|
265
290
|
},
|
|
266
291
|
);
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { useCallback, useEffect, useMemo } from 'react';
|
|
6
|
+
|
|
7
|
+
import { type IntentResolver, LayoutAction, useIntentDispatcher, useIntentResolver } from '@dxos/app-framework';
|
|
8
|
+
import { debounce } from '@dxos/async';
|
|
9
|
+
import { fullyQualifiedId } from '@dxos/react-client/echo';
|
|
10
|
+
import { type DxGridElement, type DxGridPosition } from '@dxos/react-ui-grid';
|
|
11
|
+
|
|
12
|
+
import { useSheetContext } from '../components';
|
|
13
|
+
import { type CellAddress, type CompleteCellRange, inRange } from '../defs';
|
|
14
|
+
import { SHEET_PLUGIN } from '../meta';
|
|
15
|
+
|
|
16
|
+
export const completeCellRangeToThreadCursor = (range: CompleteCellRange): string => {
|
|
17
|
+
return `${range.from.col},${range.from.row},${range.to.col},${range.to.row}`;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
export const parseThreadAnchorAsCellRange = (cursor: string): CompleteCellRange | null => {
|
|
21
|
+
const coords = cursor.split(',');
|
|
22
|
+
if (coords.length !== 4) {
|
|
23
|
+
return null;
|
|
24
|
+
} else {
|
|
25
|
+
const [fromCol, fromRow, toCol, toRow] = coords;
|
|
26
|
+
return {
|
|
27
|
+
from: { col: parseInt(fromCol), row: parseInt(fromRow) },
|
|
28
|
+
to: { col: parseInt(toCol), row: parseInt(toRow) },
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export const useUpdateFocusedCellOnThreadSelection = (grid: DxGridElement | null) => {
|
|
34
|
+
const { model, setActiveRefs } = useSheetContext();
|
|
35
|
+
const handleScrollIntoView: IntentResolver = useCallback(
|
|
36
|
+
({ action, data }) => {
|
|
37
|
+
switch (action) {
|
|
38
|
+
case LayoutAction.SCROLL_INTO_VIEW: {
|
|
39
|
+
if (!data?.id || data?.cursor === undefined || data?.id !== fullyQualifiedId(model.sheet)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
setActiveRefs(data.thread);
|
|
43
|
+
// TODO(Zan): Everywhere we refer to the cursor in a thread context should change to `anchor`.
|
|
44
|
+
const range = parseThreadAnchorAsCellRange(data.cursor);
|
|
45
|
+
range && grid?.setFocus({ ...range.to, plane: 'grid' }, true);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
[model.sheet, setActiveRefs],
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
useIntentResolver(SHEET_PLUGIN, handleScrollIntoView);
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export const useSelectThreadOnCellFocus = () => {
|
|
56
|
+
const { model, cursor } = useSheetContext();
|
|
57
|
+
const dispatch = useIntentDispatcher();
|
|
58
|
+
|
|
59
|
+
const threads = useMemo(
|
|
60
|
+
() => model.sheet.threads?.filter((thread): thread is NonNullable<typeof thread> => !!thread) ?? [],
|
|
61
|
+
[
|
|
62
|
+
// TODO(thure): Surely we can find a better dependency for this…
|
|
63
|
+
JSON.stringify(model.sheet.threads),
|
|
64
|
+
],
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const selectClosestThread = useCallback(
|
|
68
|
+
(cellAddress: CellAddress) => {
|
|
69
|
+
if (!cellAddress || !threads) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const closestThread = threads?.find(({ anchor }) => {
|
|
74
|
+
if (anchor) {
|
|
75
|
+
const range = parseThreadAnchorAsCellRange(anchor);
|
|
76
|
+
return range ? inRange(range, cellAddress) : false;
|
|
77
|
+
} else {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
if (closestThread) {
|
|
83
|
+
void dispatch([
|
|
84
|
+
{ action: 'dxos.org/plugin/thread/action/select', data: { current: fullyQualifiedId(closestThread) } },
|
|
85
|
+
]);
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
[dispatch, threads],
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const debounced = useMemo(() => {
|
|
92
|
+
return debounce((cellCoords: DxGridPosition) => requestAnimationFrame(() => selectClosestThread(cellCoords)), 50);
|
|
93
|
+
}, [selectClosestThread]);
|
|
94
|
+
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
if (!cursor) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
debounced(cursor);
|
|
100
|
+
}, [cursor, debounced]);
|
|
101
|
+
};
|
package/src/meta.ts
CHANGED
package/src/model/index.ts
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { afterEach, beforeEach, describe, expect, test } from 'vitest';
|
|
5
|
+
import { afterEach, beforeEach, describe, expect, onTestFinished, test } from 'vitest';
|
|
6
6
|
|
|
7
7
|
import { Trigger } from '@dxos/async';
|
|
8
8
|
import { FunctionType } from '@dxos/plugin-script/types';
|
|
9
9
|
|
|
10
10
|
import { SheetModel } from './sheet-model';
|
|
11
|
+
import { TestBuilder, testFunctionPlugins } from '../compute-graph/testing';
|
|
11
12
|
import { addressFromA1Notation, createSheet } from '../defs';
|
|
12
|
-
import { TestBuilder, testFunctionPlugins } from '../graph/testing';
|
|
13
13
|
import { type CellScalarValue } from '../types';
|
|
14
14
|
|
|
15
15
|
describe('SheetModel', () => {
|
|
@@ -36,13 +36,15 @@ describe('SheetModel', () => {
|
|
|
36
36
|
// Trigger waits for function invocation.
|
|
37
37
|
const trigger = new Trigger<CellScalarValue>();
|
|
38
38
|
model.setValue(addressFromA1Notation('A1'), '=TEST(100)');
|
|
39
|
-
|
|
39
|
+
// TODO(wittjosiah): Currently this fires twice, once for the binding loading & once for the function invocation.
|
|
40
|
+
const unsubscribe = model.update.on((update) => {
|
|
40
41
|
const { type } = update;
|
|
41
42
|
if (type === 'valuesUpdated') {
|
|
42
43
|
const value = model.getValue(addressFromA1Notation('A1'));
|
|
43
|
-
trigger.wake(value);
|
|
44
|
+
value && trigger.wake(value);
|
|
44
45
|
}
|
|
45
46
|
});
|
|
47
|
+
onTestFinished(() => unsubscribe());
|
|
46
48
|
|
|
47
49
|
// Initial value will be null.
|
|
48
50
|
const v1 = model.getValue(addressFromA1Notation('A1'));
|