@revisium/schema-toolkit-ui 0.2.2 → 0.3.0
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/README.md +55 -0
- package/dist/index.cjs +1976 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +252 -43
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +252 -43
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +1972 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -3
package/dist/index.mjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import * as mobx from "mobx";
|
|
2
2
|
import { makeAutoObservable, observable, reaction, runInAction } from "mobx";
|
|
3
|
-
import { FIELD_NAME_ERROR_MESSAGE,
|
|
3
|
+
import { FIELD_NAME_ERROR_MESSAGE, SystemSchemaIds, createRowModel, createTableModel, fileSchema, generateDefaultValue, isForeignKeyValueNode, isValidFieldName, jsonPointerToSimplePath, rowCreatedAtSchema, rowCreatedIdSchema, rowHashSchema, rowIdSchema, rowPublishedAtSchema, rowSchemaHashSchema, rowUpdatedAtSchema, rowVersionIdSchema, validateFormulaAgainstSchema } from "@revisium/schema-toolkit";
|
|
4
4
|
import { createMobxProvider, setReactivityProvider } from "@revisium/schema-toolkit/core";
|
|
5
|
-
import { Badge, Box, Button, Flex, Icon, IconButton, Input, Menu, Popover, Portal, SegmentGroup, Text, Textarea, Tooltip as Tooltip$1, VStack } from "@chakra-ui/react";
|
|
5
|
+
import { Badge, Box, Button, Flex, HStack, HoverCard, Icon, IconButton, Image, Input, Menu, Popover, Portal, SegmentGroup, Spinner, Text, Textarea, Tooltip as Tooltip$1, VStack } from "@chakra-ui/react";
|
|
6
6
|
import { observer } from "mobx-react-lite";
|
|
7
7
|
import * as React$1 from "react";
|
|
8
8
|
import React, { Fragment, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
9
|
-
import { PiArrowCounterClockwiseBold, PiArrowRight, PiArrowsLeftRightLight, PiBracketsCurlyThin, PiCaretDownLight, PiCaretLeft, PiCaretRight, PiCopy, PiDotOutlineFill, PiDotsSixVerticalBold, PiEquals, PiFunction, PiGear, PiLinkThin, PiMinusLight, PiPencilSimpleLight, PiPlusBold, PiPlusLight, PiTextT, PiTrash, PiTreeViewThin, PiWarning, PiWarningCircle, PiX } from "react-icons/pi";
|
|
9
|
+
import { PiArrowCounterClockwiseBold, PiArrowRight, PiArrowSquareUpRightThin, PiArrowsLeftRightLight, PiBracketsCurlyThin, PiCaretDownLight, PiCaretLeft, PiCaretRight, PiCopy, PiDotOutlineFill, PiDotsSixVerticalBold, PiDotsThreeVerticalBold, PiEquals, PiFile, PiFunction, PiFunctionLight, PiGear, PiInfo, PiLinkThin, PiMagnifyingGlassBold, PiMinusLight, PiPencilSimpleLight, PiPlusBold, PiPlusLight, PiTextT, PiTrash, PiTreeViewThin, PiUploadThin, PiWarning, PiWarningCircle, PiX, PiXBold } from "react-icons/pi";
|
|
10
10
|
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
11
11
|
import { githubLight } from "@uiw/codemirror-theme-github";
|
|
12
12
|
import CodeMirror, { EditorView } from "@uiw/react-codemirror";
|
|
@@ -16,6 +16,9 @@ import { Menu as Menu$1 } from "@chakra-ui/react/menu";
|
|
|
16
16
|
import { LuChevronRight } from "react-icons/lu";
|
|
17
17
|
import { draggable, dropTargetForElements, monitorForElements } from "@atlaskit/drag-and-drop/adapter/element";
|
|
18
18
|
import { DialogBackdrop, DialogBody, DialogCloseTrigger, DialogContent, DialogFooter, DialogHeader, DialogPositioner, DialogRoot, DialogTitle } from "@chakra-ui/react/dialog";
|
|
19
|
+
import { Virtuoso } from "react-virtuoso";
|
|
20
|
+
|
|
21
|
+
export * from "@revisium/schema-toolkit"
|
|
19
22
|
|
|
20
23
|
//#region src/schema-editor/model/state/TreeState.ts
|
|
21
24
|
var TreeState = class {
|
|
@@ -1680,7 +1683,7 @@ var SchemaEditorCore = class {
|
|
|
1680
1683
|
keyboard;
|
|
1681
1684
|
constructor(jsonSchema, options = {}, accessorFactory = new NodeAccessorFactory()) {
|
|
1682
1685
|
ensureReactivityProvider();
|
|
1683
|
-
this._tableModel = createTableModel
|
|
1686
|
+
this._tableModel = createTableModel({
|
|
1684
1687
|
tableId: options.tableId ?? "",
|
|
1685
1688
|
schema: jsonSchema,
|
|
1686
1689
|
refSchemas: options.refSchemas ?? defaultRefSchemas
|
|
@@ -4585,5 +4588,1969 @@ const UpdatingSchemaEditor = observer(({ vm }) => {
|
|
|
4585
4588
|
});
|
|
4586
4589
|
|
|
4587
4590
|
//#endregion
|
|
4588
|
-
|
|
4591
|
+
//#region src/row-editor/vm/flattenNodes.ts
|
|
4592
|
+
function traverse(node, result) {
|
|
4593
|
+
result.push({
|
|
4594
|
+
type: "node",
|
|
4595
|
+
node
|
|
4596
|
+
});
|
|
4597
|
+
if (node.showChildren) for (const child of node.childNodes) traverse(child, result);
|
|
4598
|
+
if (node.isArray() && node.showAddButton) result.push({
|
|
4599
|
+
type: "add-button",
|
|
4600
|
+
array: node,
|
|
4601
|
+
guides: [...node.guides, false]
|
|
4602
|
+
});
|
|
4603
|
+
}
|
|
4604
|
+
function flattenNodes(root) {
|
|
4605
|
+
const result = [];
|
|
4606
|
+
if (root.isObject()) for (const child of root.children) traverse(child, result);
|
|
4607
|
+
else traverse(root, result);
|
|
4608
|
+
return result;
|
|
4609
|
+
}
|
|
4610
|
+
|
|
4611
|
+
//#endregion
|
|
4612
|
+
//#region src/row-editor/vm/state/RowTreeState.ts
|
|
4613
|
+
var RowTreeState = class {
|
|
4614
|
+
_expanded = observable.map();
|
|
4615
|
+
_focused = observable.map();
|
|
4616
|
+
constructor() {
|
|
4617
|
+
makeAutoObservable(this, {}, { autoBind: true });
|
|
4618
|
+
}
|
|
4619
|
+
isExpanded(nodeId) {
|
|
4620
|
+
return this._expanded.get(nodeId) ?? true;
|
|
4621
|
+
}
|
|
4622
|
+
setExpanded(nodeId, value) {
|
|
4623
|
+
this._expanded.set(nodeId, value);
|
|
4624
|
+
}
|
|
4625
|
+
toggleExpanded(nodeId) {
|
|
4626
|
+
this._expanded.set(nodeId, !this.isExpanded(nodeId));
|
|
4627
|
+
}
|
|
4628
|
+
isFocused(nodeId) {
|
|
4629
|
+
return this._focused.get(nodeId) ?? false;
|
|
4630
|
+
}
|
|
4631
|
+
setFocused(nodeId, value) {
|
|
4632
|
+
this._focused.set(nodeId, value);
|
|
4633
|
+
}
|
|
4634
|
+
expandAll(nodeIds) {
|
|
4635
|
+
for (const nodeId of nodeIds) this._expanded.set(nodeId, true);
|
|
4636
|
+
}
|
|
4637
|
+
collapseAll(nodeIds) {
|
|
4638
|
+
for (const nodeId of nodeIds) this._expanded.set(nodeId, false);
|
|
4639
|
+
}
|
|
4640
|
+
reset() {
|
|
4641
|
+
this._expanded.clear();
|
|
4642
|
+
this._focused.clear();
|
|
4643
|
+
}
|
|
4644
|
+
};
|
|
4645
|
+
|
|
4646
|
+
//#endregion
|
|
4647
|
+
//#region src/row-editor/vm/accessor/RowNodeAccessor.ts
|
|
4648
|
+
var RowNodeAccessor = class {
|
|
4649
|
+
_menu;
|
|
4650
|
+
_layout;
|
|
4651
|
+
constructor(node, parent, _state, _tree, editorContext, _childResolver) {
|
|
4652
|
+
this.node = node;
|
|
4653
|
+
this.parent = parent;
|
|
4654
|
+
this._state = _state;
|
|
4655
|
+
this._tree = _tree;
|
|
4656
|
+
this.editorContext = editorContext;
|
|
4657
|
+
this._childResolver = _childResolver;
|
|
4658
|
+
makeAutoObservable(this, {}, { autoBind: true });
|
|
4659
|
+
}
|
|
4660
|
+
setMenu(menu) {
|
|
4661
|
+
this._menu = menu;
|
|
4662
|
+
}
|
|
4663
|
+
setLayout(layout) {
|
|
4664
|
+
this._layout = layout;
|
|
4665
|
+
}
|
|
4666
|
+
get id() {
|
|
4667
|
+
return this.node.id;
|
|
4668
|
+
}
|
|
4669
|
+
get name() {
|
|
4670
|
+
return this.node.name;
|
|
4671
|
+
}
|
|
4672
|
+
get displayName() {
|
|
4673
|
+
if (this.parent) return this.node.name;
|
|
4674
|
+
return this._rootDisplayName();
|
|
4675
|
+
}
|
|
4676
|
+
get testId() {
|
|
4677
|
+
if (!this.parent) return "root";
|
|
4678
|
+
const parentId = this.parent.testId;
|
|
4679
|
+
if (parentId === "root" && this.parent.isObject()) return this.name;
|
|
4680
|
+
return `${parentId}-${this.name}`;
|
|
4681
|
+
}
|
|
4682
|
+
isPrimitive() {
|
|
4683
|
+
return this.node.isPrimitive();
|
|
4684
|
+
}
|
|
4685
|
+
isObject() {
|
|
4686
|
+
return this.node.isObject();
|
|
4687
|
+
}
|
|
4688
|
+
isArray() {
|
|
4689
|
+
return this.node.isArray();
|
|
4690
|
+
}
|
|
4691
|
+
get isExpanded() {
|
|
4692
|
+
return this._state.isExpanded;
|
|
4693
|
+
}
|
|
4694
|
+
set isExpanded(value) {
|
|
4695
|
+
this._state.setExpanded(value);
|
|
4696
|
+
}
|
|
4697
|
+
get isFocused() {
|
|
4698
|
+
return this._state.isFocused;
|
|
4699
|
+
}
|
|
4700
|
+
expand() {
|
|
4701
|
+
this._state.setExpanded(true);
|
|
4702
|
+
}
|
|
4703
|
+
collapse() {
|
|
4704
|
+
this._state.setExpanded(false);
|
|
4705
|
+
}
|
|
4706
|
+
toggleExpanded() {
|
|
4707
|
+
this._state.toggleExpanded();
|
|
4708
|
+
}
|
|
4709
|
+
setFocused(focused) {
|
|
4710
|
+
this._state.setFocused(focused);
|
|
4711
|
+
}
|
|
4712
|
+
get depth() {
|
|
4713
|
+
return this._layout.depth;
|
|
4714
|
+
}
|
|
4715
|
+
get guides() {
|
|
4716
|
+
return this._layout.guides;
|
|
4717
|
+
}
|
|
4718
|
+
get isCollapsible() {
|
|
4719
|
+
return this._layout.isCollapsible;
|
|
4720
|
+
}
|
|
4721
|
+
get isCollapsibleTree() {
|
|
4722
|
+
return this._layout.isCollapsibleTree;
|
|
4723
|
+
}
|
|
4724
|
+
get rendererType() {
|
|
4725
|
+
return this._layout.rendererType;
|
|
4726
|
+
}
|
|
4727
|
+
get isContainer() {
|
|
4728
|
+
return this._layout.isContainer;
|
|
4729
|
+
}
|
|
4730
|
+
get childNodes() {
|
|
4731
|
+
return this._childResolver.getChildren(this);
|
|
4732
|
+
}
|
|
4733
|
+
get showChildren() {
|
|
4734
|
+
return this._layout.showChildren;
|
|
4735
|
+
}
|
|
4736
|
+
get collapsedLabel() {
|
|
4737
|
+
return this._layout.collapsedLabel;
|
|
4738
|
+
}
|
|
4739
|
+
get isLongText() {
|
|
4740
|
+
return this._layout.isLongText;
|
|
4741
|
+
}
|
|
4742
|
+
expandAll() {
|
|
4743
|
+
this._layout.expandAll();
|
|
4744
|
+
}
|
|
4745
|
+
collapseAll() {
|
|
4746
|
+
this._layout.collapseAll();
|
|
4747
|
+
}
|
|
4748
|
+
get menu() {
|
|
4749
|
+
return this._menu.menu;
|
|
4750
|
+
}
|
|
4751
|
+
get formula() {
|
|
4752
|
+
if (this.node.isPrimitive()) return this.node.formula?.expression;
|
|
4753
|
+
}
|
|
4754
|
+
get isEditorReadOnly() {
|
|
4755
|
+
return this.editorContext?.isReadOnly ?? false;
|
|
4756
|
+
}
|
|
4757
|
+
get path() {
|
|
4758
|
+
return this._tree.pathOf(this.node).asString();
|
|
4759
|
+
}
|
|
4760
|
+
get isDirty() {
|
|
4761
|
+
return this.node.isDirty;
|
|
4762
|
+
}
|
|
4763
|
+
get value() {
|
|
4764
|
+
return this.node.value;
|
|
4765
|
+
}
|
|
4766
|
+
get defaultValue() {
|
|
4767
|
+
return this.node.defaultValue;
|
|
4768
|
+
}
|
|
4769
|
+
get isReadOnly() {
|
|
4770
|
+
return this.node.isReadOnly;
|
|
4771
|
+
}
|
|
4772
|
+
get isFieldReadOnly() {
|
|
4773
|
+
return this.isReadOnly || this.isEditorReadOnly;
|
|
4774
|
+
}
|
|
4775
|
+
setValue(value) {
|
|
4776
|
+
this.node.setValue(value);
|
|
4777
|
+
}
|
|
4778
|
+
get children() {
|
|
4779
|
+
if (!this.node.isObject()) return [];
|
|
4780
|
+
return this._childResolver.getChildren(this);
|
|
4781
|
+
}
|
|
4782
|
+
child(name) {
|
|
4783
|
+
return this.children.find((c) => c.name === name);
|
|
4784
|
+
}
|
|
4785
|
+
get items() {
|
|
4786
|
+
if (!this.node.isArray()) return [];
|
|
4787
|
+
return this._childResolver.getChildren(this);
|
|
4788
|
+
}
|
|
4789
|
+
get length() {
|
|
4790
|
+
if (!this.node.isArray()) return 0;
|
|
4791
|
+
return this.node.length;
|
|
4792
|
+
}
|
|
4793
|
+
at(index) {
|
|
4794
|
+
const allItems = this.items;
|
|
4795
|
+
if (index < 0 || index >= allItems.length) return;
|
|
4796
|
+
return allItems[index];
|
|
4797
|
+
}
|
|
4798
|
+
pushValue(value) {
|
|
4799
|
+
this.node.pushValue(value);
|
|
4800
|
+
}
|
|
4801
|
+
removeAt(index) {
|
|
4802
|
+
this.node.removeAt(index);
|
|
4803
|
+
}
|
|
4804
|
+
move(fromIndex, toIndex) {
|
|
4805
|
+
this.node.move(fromIndex, toIndex);
|
|
4806
|
+
}
|
|
4807
|
+
insertAt(index) {
|
|
4808
|
+
this.node.pushValue(null);
|
|
4809
|
+
const lastIndex = this.length - 1;
|
|
4810
|
+
if (index < lastIndex) this.node.move(lastIndex, index);
|
|
4811
|
+
}
|
|
4812
|
+
get showAddButton() {
|
|
4813
|
+
return this.isExpanded && !this.isEditorReadOnly;
|
|
4814
|
+
}
|
|
4815
|
+
isForeignKey() {
|
|
4816
|
+
return isForeignKeyValueNode(this.node);
|
|
4817
|
+
}
|
|
4818
|
+
get foreignKeyTableId() {
|
|
4819
|
+
return this.node.foreignKey;
|
|
4820
|
+
}
|
|
4821
|
+
isFile() {
|
|
4822
|
+
return this.rendererType === "file";
|
|
4823
|
+
}
|
|
4824
|
+
get fileStatus() {
|
|
4825
|
+
return this._getFileChildValue("status", "");
|
|
4826
|
+
}
|
|
4827
|
+
get fileId() {
|
|
4828
|
+
return this._getFileChildValue("fileId", "");
|
|
4829
|
+
}
|
|
4830
|
+
get fileUrl() {
|
|
4831
|
+
return this._getFileChildValue("url", "");
|
|
4832
|
+
}
|
|
4833
|
+
get fileMimeType() {
|
|
4834
|
+
return this._getFileChildValue("mimeType", "");
|
|
4835
|
+
}
|
|
4836
|
+
get fileWidth() {
|
|
4837
|
+
return this._getFileChildNumericValue("width");
|
|
4838
|
+
}
|
|
4839
|
+
get fileHeight() {
|
|
4840
|
+
return this._getFileChildNumericValue("height");
|
|
4841
|
+
}
|
|
4842
|
+
get callbacks() {
|
|
4843
|
+
return this.editorContext?.callbacks ?? null;
|
|
4844
|
+
}
|
|
4845
|
+
getChildAccessors() {
|
|
4846
|
+
return this._childResolver.getChildren(this);
|
|
4847
|
+
}
|
|
4848
|
+
_getFileChildValue(name, fallback) {
|
|
4849
|
+
if (!this.node.isObject()) return fallback;
|
|
4850
|
+
const child = this.node.child(name);
|
|
4851
|
+
if (child?.isPrimitive()) return String(child.value);
|
|
4852
|
+
return fallback;
|
|
4853
|
+
}
|
|
4854
|
+
_rootDisplayName() {
|
|
4855
|
+
const schema = this.node.schema;
|
|
4856
|
+
if (!("type" in schema)) return this.node.name;
|
|
4857
|
+
return `<${schema.type}>`;
|
|
4858
|
+
}
|
|
4859
|
+
_getFileChildNumericValue(name) {
|
|
4860
|
+
if (!this.node.isObject()) return 0;
|
|
4861
|
+
const child = this.node.child(name);
|
|
4862
|
+
if (child?.isPrimitive()) return Number(child.value) || 0;
|
|
4863
|
+
return 0;
|
|
4864
|
+
}
|
|
4865
|
+
};
|
|
4866
|
+
|
|
4867
|
+
//#endregion
|
|
4868
|
+
//#region src/row-editor/vm/accessor/RowNodeState.ts
|
|
4869
|
+
var RowNodeState = class {
|
|
4870
|
+
constructor(_nodeId, _treeState) {
|
|
4871
|
+
this._nodeId = _nodeId;
|
|
4872
|
+
this._treeState = _treeState;
|
|
4873
|
+
makeAutoObservable(this, {}, { autoBind: true });
|
|
4874
|
+
}
|
|
4875
|
+
get isExpanded() {
|
|
4876
|
+
return this._treeState.isExpanded(this._nodeId);
|
|
4877
|
+
}
|
|
4878
|
+
setExpanded(value) {
|
|
4879
|
+
this._treeState.setExpanded(this._nodeId, value);
|
|
4880
|
+
}
|
|
4881
|
+
toggleExpanded() {
|
|
4882
|
+
this._treeState.toggleExpanded(this._nodeId);
|
|
4883
|
+
}
|
|
4884
|
+
get isFocused() {
|
|
4885
|
+
return this._treeState.isFocused(this._nodeId);
|
|
4886
|
+
}
|
|
4887
|
+
setFocused(value) {
|
|
4888
|
+
this._treeState.setFocused(this._nodeId, value);
|
|
4889
|
+
}
|
|
4890
|
+
};
|
|
4891
|
+
|
|
4892
|
+
//#endregion
|
|
4893
|
+
//#region src/row-editor/vm/accessor/RowNodeMenu.ts
|
|
4894
|
+
var RowNodeMenu = class {
|
|
4895
|
+
constructor(_accessor) {
|
|
4896
|
+
this._accessor = _accessor;
|
|
4897
|
+
makeAutoObservable(this, {}, { autoBind: true });
|
|
4898
|
+
}
|
|
4899
|
+
get menu() {
|
|
4900
|
+
return [
|
|
4901
|
+
...this.topMenu,
|
|
4902
|
+
...this.arrayOwnMenu,
|
|
4903
|
+
...this.arrayItemMenu,
|
|
4904
|
+
...this.bottomMenu
|
|
4905
|
+
];
|
|
4906
|
+
}
|
|
4907
|
+
get arrayItemContext() {
|
|
4908
|
+
const parent = this._accessor.parent;
|
|
4909
|
+
if (!parent || !parent.node.isArray()) return null;
|
|
4910
|
+
const arrayNode = parent.node;
|
|
4911
|
+
const index = arrayNode.value.indexOf(this._accessor.node);
|
|
4912
|
+
if (index === -1) return null;
|
|
4913
|
+
return {
|
|
4914
|
+
index,
|
|
4915
|
+
arrayLength: arrayNode.value.length,
|
|
4916
|
+
insertAt: (i) => parent.insertAt(i),
|
|
4917
|
+
removeAt: (i) => parent.removeAt(i),
|
|
4918
|
+
move: (from, to) => parent.move(from, to)
|
|
4919
|
+
};
|
|
4920
|
+
}
|
|
4921
|
+
get topMenu() {
|
|
4922
|
+
if (!this._accessor.isCollapsibleTree) return [];
|
|
4923
|
+
return [{
|
|
4924
|
+
value: "expand",
|
|
4925
|
+
label: "Expand",
|
|
4926
|
+
handler: () => this._accessor.expandAll()
|
|
4927
|
+
}, {
|
|
4928
|
+
value: "collapse",
|
|
4929
|
+
label: "Collapse",
|
|
4930
|
+
handler: () => this._accessor.collapseAll(),
|
|
4931
|
+
afterSeparator: true
|
|
4932
|
+
}];
|
|
4933
|
+
}
|
|
4934
|
+
get arrayOwnMenu() {
|
|
4935
|
+
if (!this._accessor.node.isArray()) return [];
|
|
4936
|
+
return [{
|
|
4937
|
+
value: "array",
|
|
4938
|
+
label: "Array",
|
|
4939
|
+
children: [...this._accessor.length > 0 ? [{
|
|
4940
|
+
value: "add-first",
|
|
4941
|
+
label: "Add item to start",
|
|
4942
|
+
handler: () => this._accessor.insertAt(0)
|
|
4943
|
+
}] : [], {
|
|
4944
|
+
value: "add-last",
|
|
4945
|
+
label: "Add item to end",
|
|
4946
|
+
handler: () => this._accessor.pushValue(null)
|
|
4947
|
+
}]
|
|
4948
|
+
}];
|
|
4949
|
+
}
|
|
4950
|
+
get arrayItemMenu() {
|
|
4951
|
+
const ctx = this.arrayItemContext;
|
|
4952
|
+
if (!ctx) return [];
|
|
4953
|
+
const moveMenuItem = ctx.arrayLength > 1 ? this.buildMoveMenuItem(ctx) : null;
|
|
4954
|
+
return [
|
|
4955
|
+
...moveMenuItem ? [moveMenuItem] : [],
|
|
4956
|
+
{
|
|
4957
|
+
value: "item",
|
|
4958
|
+
label: "Item",
|
|
4959
|
+
children: [{
|
|
4960
|
+
value: "add-before",
|
|
4961
|
+
label: "Add before",
|
|
4962
|
+
handler: () => ctx.insertAt(ctx.index)
|
|
4963
|
+
}, {
|
|
4964
|
+
value: "add-after",
|
|
4965
|
+
label: "Add after",
|
|
4966
|
+
handler: () => ctx.insertAt(ctx.index + 1)
|
|
4967
|
+
}]
|
|
4968
|
+
},
|
|
4969
|
+
{
|
|
4970
|
+
value: "delete",
|
|
4971
|
+
label: "Delete",
|
|
4972
|
+
handler: () => ctx.removeAt(ctx.index),
|
|
4973
|
+
afterSeparator: true
|
|
4974
|
+
}
|
|
4975
|
+
];
|
|
4976
|
+
}
|
|
4977
|
+
buildMoveMenuItem(ctx) {
|
|
4978
|
+
const { index, arrayLength } = ctx;
|
|
4979
|
+
const isFirst = index === 0;
|
|
4980
|
+
const isLast = index === arrayLength - 1;
|
|
4981
|
+
return {
|
|
4982
|
+
value: "move",
|
|
4983
|
+
label: "Move",
|
|
4984
|
+
children: [
|
|
4985
|
+
...arrayLength > 2 && index > 1 ? [{
|
|
4986
|
+
value: "move-to-start",
|
|
4987
|
+
label: "to start",
|
|
4988
|
+
handler: () => ctx.move(index, 0)
|
|
4989
|
+
}] : [],
|
|
4990
|
+
...!isFirst ? [{
|
|
4991
|
+
value: "move-up",
|
|
4992
|
+
label: "up",
|
|
4993
|
+
handler: () => ctx.move(index, index - 1)
|
|
4994
|
+
}] : [],
|
|
4995
|
+
...!isLast ? [{
|
|
4996
|
+
value: "move-down",
|
|
4997
|
+
label: "down",
|
|
4998
|
+
handler: () => ctx.move(index, index + 1)
|
|
4999
|
+
}] : [],
|
|
5000
|
+
...arrayLength > 2 && index < arrayLength - 2 ? [{
|
|
5001
|
+
value: "move-to-end",
|
|
5002
|
+
label: "to end",
|
|
5003
|
+
handler: () => ctx.move(index, arrayLength - 1)
|
|
5004
|
+
}] : []
|
|
5005
|
+
]
|
|
5006
|
+
};
|
|
5007
|
+
}
|
|
5008
|
+
get bottomMenu() {
|
|
5009
|
+
const copyChildren = [{
|
|
5010
|
+
value: "json",
|
|
5011
|
+
label: "json",
|
|
5012
|
+
handler: () => this.copyJson()
|
|
5013
|
+
}];
|
|
5014
|
+
if (this._accessor.path) copyChildren.push({
|
|
5015
|
+
value: "path",
|
|
5016
|
+
label: "path",
|
|
5017
|
+
handler: () => this.copyPath()
|
|
5018
|
+
});
|
|
5019
|
+
return [{
|
|
5020
|
+
value: "copy",
|
|
5021
|
+
label: "Copy",
|
|
5022
|
+
children: copyChildren
|
|
5023
|
+
}];
|
|
5024
|
+
}
|
|
5025
|
+
async copyJson() {
|
|
5026
|
+
const json = JSON.stringify(this._accessor.node.getPlainValue(), null, 2);
|
|
5027
|
+
await navigator.clipboard.writeText(json);
|
|
5028
|
+
}
|
|
5029
|
+
async copyPath() {
|
|
5030
|
+
await navigator.clipboard.writeText(this._accessor.path);
|
|
5031
|
+
}
|
|
5032
|
+
};
|
|
5033
|
+
|
|
5034
|
+
//#endregion
|
|
5035
|
+
//#region src/row-editor/vm/accessor/RowNodeLayout.ts
|
|
5036
|
+
const STRING_COLLAPSE_THRESHOLD = 64;
|
|
5037
|
+
var RowNodeLayout = class {
|
|
5038
|
+
constructor(_accessor) {
|
|
5039
|
+
this._accessor = _accessor;
|
|
5040
|
+
makeAutoObservable(this, {}, { autoBind: true });
|
|
5041
|
+
}
|
|
5042
|
+
get depth() {
|
|
5043
|
+
let d = 0;
|
|
5044
|
+
let current = this._accessor.parent;
|
|
5045
|
+
while (current) {
|
|
5046
|
+
d++;
|
|
5047
|
+
current = current.parent;
|
|
5048
|
+
}
|
|
5049
|
+
return d;
|
|
5050
|
+
}
|
|
5051
|
+
get guides() {
|
|
5052
|
+
const result = [];
|
|
5053
|
+
let current = this._accessor.parent;
|
|
5054
|
+
while (current) {
|
|
5055
|
+
if (current.parent) {
|
|
5056
|
+
const isLastSibling = current.parent.getChildAccessors().at(-1)?.id === current.id;
|
|
5057
|
+
result.unshift(!isLastSibling);
|
|
5058
|
+
} else if (!current.isObject()) result.unshift(false);
|
|
5059
|
+
current = current.parent;
|
|
5060
|
+
}
|
|
5061
|
+
return result;
|
|
5062
|
+
}
|
|
5063
|
+
get isCollapsible() {
|
|
5064
|
+
return this._accessor.getChildAccessors().length > 0;
|
|
5065
|
+
}
|
|
5066
|
+
get isCollapsibleTree() {
|
|
5067
|
+
return this.isCollapsible || this._accessor.getChildAccessors().some((c) => c.isCollapsible);
|
|
5068
|
+
}
|
|
5069
|
+
get rendererType() {
|
|
5070
|
+
if (this._accessor.node.isObject()) {
|
|
5071
|
+
const schema = this._accessor.node.schema;
|
|
5072
|
+
if ("$ref" in schema && schema.$ref === SystemSchemaIds.File) return "file";
|
|
5073
|
+
return "container";
|
|
5074
|
+
}
|
|
5075
|
+
if (this._accessor.node.isArray()) return "container";
|
|
5076
|
+
if (isForeignKeyValueNode(this._accessor.node)) return "foreignKey";
|
|
5077
|
+
if (this._accessor.node.isPrimitive()) {
|
|
5078
|
+
const v = this._accessor.value;
|
|
5079
|
+
if (typeof v === "boolean") return "boolean";
|
|
5080
|
+
if (typeof v === "number") return "number";
|
|
5081
|
+
}
|
|
5082
|
+
return "string";
|
|
5083
|
+
}
|
|
5084
|
+
get isContainer() {
|
|
5085
|
+
return this._accessor.node.isObject() || this._accessor.node.isArray();
|
|
5086
|
+
}
|
|
5087
|
+
get isRefNode() {
|
|
5088
|
+
return "$ref" in this._accessor.node.schema && this.isContainer;
|
|
5089
|
+
}
|
|
5090
|
+
get showChildren() {
|
|
5091
|
+
return this.isContainer && this._accessor.isExpanded && this._accessor.getChildAccessors().length > 0;
|
|
5092
|
+
}
|
|
5093
|
+
get collapsedLabel() {
|
|
5094
|
+
if (this._accessor.node.isPrimitive()) return this.primitiveCollapsedLabel;
|
|
5095
|
+
if (this._accessor.node.isObject()) return formatCount(this._accessor.children.length, "key", "keys");
|
|
5096
|
+
if (this._accessor.node.isArray()) return formatCount(this._accessor.length, "item", "items");
|
|
5097
|
+
return "";
|
|
5098
|
+
}
|
|
5099
|
+
get primitiveCollapsedLabel() {
|
|
5100
|
+
const v = this._accessor.value;
|
|
5101
|
+
if (typeof v !== "string") return "";
|
|
5102
|
+
if (!v.trim()) return "<empty text>";
|
|
5103
|
+
const wordCount = v.trim().split(/\s+/).length;
|
|
5104
|
+
return formatCount(wordCount, "word", "words", "text: ");
|
|
5105
|
+
}
|
|
5106
|
+
get isLongText() {
|
|
5107
|
+
const v = this._accessor.value;
|
|
5108
|
+
return typeof v === "string" && v.length > STRING_COLLAPSE_THRESHOLD;
|
|
5109
|
+
}
|
|
5110
|
+
expandAll() {
|
|
5111
|
+
this._accessor.expand();
|
|
5112
|
+
for (const child of this._accessor.getChildAccessors()) if (child.isCollapsible) child.expandAll();
|
|
5113
|
+
}
|
|
5114
|
+
collapseAll() {
|
|
5115
|
+
this._accessor.collapse();
|
|
5116
|
+
for (const child of this._accessor.getChildAccessors()) if (child.isCollapsible) child.collapseAll();
|
|
5117
|
+
}
|
|
5118
|
+
};
|
|
5119
|
+
function formatCount(count, singular, plural, prefix = "") {
|
|
5120
|
+
return `<${prefix}${count} ${count === 1 ? singular : plural}>`;
|
|
5121
|
+
}
|
|
5122
|
+
|
|
5123
|
+
//#endregion
|
|
5124
|
+
//#region src/row-editor/vm/accessor/RowAccessorFactory.ts
|
|
5125
|
+
var RowAccessorFactory = class {
|
|
5126
|
+
constructor(_tree, _treeState, _editorContext) {
|
|
5127
|
+
this._tree = _tree;
|
|
5128
|
+
this._treeState = _treeState;
|
|
5129
|
+
this._editorContext = _editorContext;
|
|
5130
|
+
}
|
|
5131
|
+
create(node, parent, childResolver) {
|
|
5132
|
+
const accessor = new RowNodeAccessor(node, parent, new RowNodeState(node.id, this._treeState), this._tree, this._editorContext, childResolver);
|
|
5133
|
+
const layout = new RowNodeLayout(accessor);
|
|
5134
|
+
const menu = new RowNodeMenu(accessor);
|
|
5135
|
+
accessor.setLayout(layout);
|
|
5136
|
+
accessor.setMenu(menu);
|
|
5137
|
+
if (layout.isRefNode) this._treeState.setExpanded(node.id, false);
|
|
5138
|
+
return accessor;
|
|
5139
|
+
}
|
|
5140
|
+
};
|
|
5141
|
+
|
|
5142
|
+
//#endregion
|
|
5143
|
+
//#region src/row-editor/vm/accessor/RowAccessorCache.ts
|
|
5144
|
+
var RowAccessorCache = class {
|
|
5145
|
+
_cache = observable.map();
|
|
5146
|
+
constructor(_factory) {
|
|
5147
|
+
this._factory = _factory;
|
|
5148
|
+
}
|
|
5149
|
+
getOrCreate(node, parent) {
|
|
5150
|
+
const cached = this._cache.get(node.id);
|
|
5151
|
+
if (cached) return cached;
|
|
5152
|
+
const accessor = this._factory.create(node, parent, this);
|
|
5153
|
+
this._cache.set(node.id, accessor);
|
|
5154
|
+
return accessor;
|
|
5155
|
+
}
|
|
5156
|
+
getChildren(accessor) {
|
|
5157
|
+
const node = accessor.node;
|
|
5158
|
+
if (node.isObject()) return node.children.map((childNode) => this.getOrCreate(childNode, accessor));
|
|
5159
|
+
if (node.isArray()) return node.value.map((itemNode) => this.getOrCreate(itemNode, accessor));
|
|
5160
|
+
return [];
|
|
5161
|
+
}
|
|
5162
|
+
clear() {
|
|
5163
|
+
this._cache.clear();
|
|
5164
|
+
}
|
|
5165
|
+
};
|
|
5166
|
+
|
|
5167
|
+
//#endregion
|
|
5168
|
+
//#region src/row-editor/vm/RowEditorCore.ts
|
|
5169
|
+
var RowEditorCore = class {
|
|
5170
|
+
treeState = new RowTreeState();
|
|
5171
|
+
_cache;
|
|
5172
|
+
_root;
|
|
5173
|
+
constructor(tree, editorContext, options) {
|
|
5174
|
+
this._cache = new RowAccessorCache(new RowAccessorFactory(tree, this.treeState, editorContext));
|
|
5175
|
+
this._root = this._cache.getOrCreate(tree.root, null);
|
|
5176
|
+
if (options?.collapseComplexity) this._collapseIfComplex(options.collapseComplexity);
|
|
5177
|
+
makeAutoObservable(this, { treeState: false }, { autoBind: true });
|
|
5178
|
+
}
|
|
5179
|
+
get root() {
|
|
5180
|
+
return this._root;
|
|
5181
|
+
}
|
|
5182
|
+
get flattenedNodes() {
|
|
5183
|
+
return flattenNodes(this._root);
|
|
5184
|
+
}
|
|
5185
|
+
dispose() {
|
|
5186
|
+
this._cache.clear();
|
|
5187
|
+
this.treeState.reset();
|
|
5188
|
+
}
|
|
5189
|
+
_collapseIfComplex(threshold) {
|
|
5190
|
+
const nodeIds = this._collectAllNodeIds(this._root);
|
|
5191
|
+
if (nodeIds.length >= threshold) {
|
|
5192
|
+
this.treeState.collapseAll(nodeIds);
|
|
5193
|
+
this.treeState.setExpanded(this._root.id, true);
|
|
5194
|
+
}
|
|
5195
|
+
}
|
|
5196
|
+
_collectAllNodeIds(accessor, ids = []) {
|
|
5197
|
+
ids.push(accessor.id);
|
|
5198
|
+
for (const child of accessor.getChildAccessors()) this._collectAllNodeIds(child, ids);
|
|
5199
|
+
return ids;
|
|
5200
|
+
}
|
|
5201
|
+
};
|
|
5202
|
+
|
|
5203
|
+
//#endregion
|
|
5204
|
+
//#region src/row-editor/vm/RowEditorVM.ts
|
|
5205
|
+
var RowEditorVM = class {
|
|
5206
|
+
_rowModel;
|
|
5207
|
+
_core;
|
|
5208
|
+
_mode;
|
|
5209
|
+
_callbacks;
|
|
5210
|
+
_onChange;
|
|
5211
|
+
_onSave;
|
|
5212
|
+
_onCancel;
|
|
5213
|
+
_disposeReaction;
|
|
5214
|
+
_prevPatchCount = 0;
|
|
5215
|
+
_rowId;
|
|
5216
|
+
_initialRowId;
|
|
5217
|
+
constructor(schema, initialValue, options) {
|
|
5218
|
+
ensureReactivityProvider();
|
|
5219
|
+
this._mode = options?.mode ?? "editing";
|
|
5220
|
+
this._rowId = options?.rowId ?? "";
|
|
5221
|
+
this._initialRowId = this._rowId;
|
|
5222
|
+
this._callbacks = options?.callbacks ?? null;
|
|
5223
|
+
this._onChange = options?.onChange ?? null;
|
|
5224
|
+
this._onSave = options?.onSave ?? null;
|
|
5225
|
+
this._onCancel = options?.onCancel ?? null;
|
|
5226
|
+
this._rowModel = createRowModel({
|
|
5227
|
+
rowId: "editor",
|
|
5228
|
+
schema,
|
|
5229
|
+
data: initialValue,
|
|
5230
|
+
refSchemas: options?.refSchemas
|
|
5231
|
+
});
|
|
5232
|
+
this._core = new RowEditorCore(this._rowModel.tree, this, { collapseComplexity: options?.collapseComplexity });
|
|
5233
|
+
makeAutoObservable(this, {}, { autoBind: true });
|
|
5234
|
+
this._disposeReaction = this._onChange ? reaction(() => this.patches, () => this._emitChange()) : null;
|
|
5235
|
+
}
|
|
5236
|
+
get root() {
|
|
5237
|
+
return this._core.root;
|
|
5238
|
+
}
|
|
5239
|
+
get flattenedNodes() {
|
|
5240
|
+
return this._core.flattenedNodes;
|
|
5241
|
+
}
|
|
5242
|
+
get rowModel() {
|
|
5243
|
+
return this._rowModel;
|
|
5244
|
+
}
|
|
5245
|
+
get mode() {
|
|
5246
|
+
return this._mode;
|
|
5247
|
+
}
|
|
5248
|
+
get rowId() {
|
|
5249
|
+
return this._rowId;
|
|
5250
|
+
}
|
|
5251
|
+
get initialRowId() {
|
|
5252
|
+
return this._initialRowId;
|
|
5253
|
+
}
|
|
5254
|
+
get isRowIdChanged() {
|
|
5255
|
+
return this._rowId !== this._initialRowId;
|
|
5256
|
+
}
|
|
5257
|
+
setRowId(value) {
|
|
5258
|
+
this._rowId = value;
|
|
5259
|
+
}
|
|
5260
|
+
get isDirty() {
|
|
5261
|
+
return this._rowModel.isDirty;
|
|
5262
|
+
}
|
|
5263
|
+
get hasChanges() {
|
|
5264
|
+
return this.isDirty || this.isRowIdChanged;
|
|
5265
|
+
}
|
|
5266
|
+
get isValid() {
|
|
5267
|
+
return this._rowModel.isValid;
|
|
5268
|
+
}
|
|
5269
|
+
get errors() {
|
|
5270
|
+
return this._rowModel.errors;
|
|
5271
|
+
}
|
|
5272
|
+
get isReadOnly() {
|
|
5273
|
+
return this._mode === "reading";
|
|
5274
|
+
}
|
|
5275
|
+
get callbacks() {
|
|
5276
|
+
return this._callbacks;
|
|
5277
|
+
}
|
|
5278
|
+
get patches() {
|
|
5279
|
+
return this._rowModel.patches;
|
|
5280
|
+
}
|
|
5281
|
+
getValue() {
|
|
5282
|
+
return this._rowModel.getPlainValue();
|
|
5283
|
+
}
|
|
5284
|
+
save() {
|
|
5285
|
+
const value = this.getValue();
|
|
5286
|
+
const patches = this.patches;
|
|
5287
|
+
this.commit();
|
|
5288
|
+
this._onSave?.(this._rowId, value, patches);
|
|
5289
|
+
}
|
|
5290
|
+
markAsSaved() {
|
|
5291
|
+
this.commit();
|
|
5292
|
+
}
|
|
5293
|
+
cancel() {
|
|
5294
|
+
this._onCancel?.();
|
|
5295
|
+
}
|
|
5296
|
+
commit() {
|
|
5297
|
+
this._rowModel.commit();
|
|
5298
|
+
this._prevPatchCount = 0;
|
|
5299
|
+
this._initialRowId = this._rowId;
|
|
5300
|
+
}
|
|
5301
|
+
revert() {
|
|
5302
|
+
this._rowModel.revert();
|
|
5303
|
+
this._prevPatchCount = 0;
|
|
5304
|
+
}
|
|
5305
|
+
dispose() {
|
|
5306
|
+
this._disposeReaction?.();
|
|
5307
|
+
this._core.dispose();
|
|
5308
|
+
this._rowModel.dispose();
|
|
5309
|
+
}
|
|
5310
|
+
_emitChange() {
|
|
5311
|
+
if (!this._onChange || !this.isValid) return;
|
|
5312
|
+
const all = this.patches;
|
|
5313
|
+
const newPatches = all.slice(this._prevPatchCount);
|
|
5314
|
+
this._prevPatchCount = all.length;
|
|
5315
|
+
if (newPatches.length > 0) this._onChange(newPatches);
|
|
5316
|
+
}
|
|
5317
|
+
};
|
|
5318
|
+
|
|
5319
|
+
//#endregion
|
|
5320
|
+
//#region src/row-editor/ui/components/Guides.tsx
|
|
5321
|
+
function toGuideItems(guides) {
|
|
5322
|
+
return guides.map((showLine, i) => ({
|
|
5323
|
+
key: `d${i}`,
|
|
5324
|
+
showLine
|
|
5325
|
+
}));
|
|
5326
|
+
}
|
|
5327
|
+
const Guides = ({ guides }) => {
|
|
5328
|
+
const items = toGuideItems(guides);
|
|
5329
|
+
return /* @__PURE__ */ jsxs(Flex, {
|
|
5330
|
+
position: "relative",
|
|
5331
|
+
alignItems: "center",
|
|
5332
|
+
children: [/* @__PURE__ */ jsx(Box, {
|
|
5333
|
+
left: "-48px",
|
|
5334
|
+
width: "48px",
|
|
5335
|
+
height: "100%",
|
|
5336
|
+
position: "absolute"
|
|
5337
|
+
}), items.map((item) => /* @__PURE__ */ jsx(Box, {
|
|
5338
|
+
position: "relative",
|
|
5339
|
+
width: "24px",
|
|
5340
|
+
height: "100%",
|
|
5341
|
+
_before: item.showLine ? {
|
|
5342
|
+
content: "\"\"",
|
|
5343
|
+
position: "absolute",
|
|
5344
|
+
left: "8px",
|
|
5345
|
+
top: 0,
|
|
5346
|
+
bottom: 0,
|
|
5347
|
+
width: "1px",
|
|
5348
|
+
backgroundColor: "blackAlpha.200"
|
|
5349
|
+
} : void 0
|
|
5350
|
+
}, item.key))]
|
|
5351
|
+
});
|
|
5352
|
+
};
|
|
5353
|
+
|
|
5354
|
+
//#endregion
|
|
5355
|
+
//#region src/row-editor/ui/components/Dot.tsx
|
|
5356
|
+
const getDotTestId = (testId, isCollapsed) => {
|
|
5357
|
+
if (!testId) return;
|
|
5358
|
+
return isCollapsed ? `${testId}-expand` : `${testId}-collapse`;
|
|
5359
|
+
};
|
|
5360
|
+
const Dot = ({ isCollapsed, isCollapsible, toggleCollapsed, testId }) => {
|
|
5361
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [!isCollapsed && /* @__PURE__ */ jsx(Flex, {
|
|
5362
|
+
color: "gray.300",
|
|
5363
|
+
width: "16px",
|
|
5364
|
+
height: "28px",
|
|
5365
|
+
_groupHover: { display: isCollapsible ? "none" : "flex" },
|
|
5366
|
+
alignItems: "center",
|
|
5367
|
+
justifyContent: "center",
|
|
5368
|
+
children: /* @__PURE__ */ jsx(PiDotOutlineFill, {})
|
|
5369
|
+
}), isCollapsible && /* @__PURE__ */ jsx(Flex, {
|
|
5370
|
+
_groupHover: {
|
|
5371
|
+
display: "inline-flex",
|
|
5372
|
+
color: "gray.500"
|
|
5373
|
+
},
|
|
5374
|
+
display: isCollapsed ? "inline-flex" : "none",
|
|
5375
|
+
_hover: { backgroundColor: "transparent" },
|
|
5376
|
+
color: "gray.400",
|
|
5377
|
+
onClick: toggleCollapsed,
|
|
5378
|
+
width: "16px",
|
|
5379
|
+
height: "28px",
|
|
5380
|
+
alignItems: "center",
|
|
5381
|
+
justifyContent: "center",
|
|
5382
|
+
cursor: "pointer",
|
|
5383
|
+
"data-testid": getDotTestId(testId, isCollapsed),
|
|
5384
|
+
children: /* @__PURE__ */ jsx(Box, {
|
|
5385
|
+
transform: isCollapsed ? "rotate(0deg)" : "rotate(90deg)",
|
|
5386
|
+
children: /* @__PURE__ */ jsx(MdOutlineChevronRight, { size: 16 })
|
|
5387
|
+
})
|
|
5388
|
+
})] });
|
|
5389
|
+
};
|
|
5390
|
+
|
|
5391
|
+
//#endregion
|
|
5392
|
+
//#region src/row-editor/ui/components/Field.tsx
|
|
5393
|
+
const Field = ({ name, formula, description, isDeprecated }) => {
|
|
5394
|
+
const getTooltipContent = () => {
|
|
5395
|
+
if (formula && description) return /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsxs(Flex, {
|
|
5396
|
+
alignItems: "center",
|
|
5397
|
+
gap: "4px",
|
|
5398
|
+
marginBottom: "4px",
|
|
5399
|
+
fontWeight: "medium",
|
|
5400
|
+
children: [/* @__PURE__ */ jsx(PiFunctionLight, { size: 14 }), /* @__PURE__ */ jsx("span", { children: formula })]
|
|
5401
|
+
}), /* @__PURE__ */ jsx(Box, {
|
|
5402
|
+
color: "gray.300",
|
|
5403
|
+
children: description
|
|
5404
|
+
})] });
|
|
5405
|
+
if (formula) return /* @__PURE__ */ jsxs(Flex, {
|
|
5406
|
+
alignItems: "center",
|
|
5407
|
+
gap: "4px",
|
|
5408
|
+
children: [/* @__PURE__ */ jsx(PiFunctionLight, { size: 14 }), /* @__PURE__ */ jsx("span", { children: formula })]
|
|
5409
|
+
});
|
|
5410
|
+
if (description) return description;
|
|
5411
|
+
return null;
|
|
5412
|
+
};
|
|
5413
|
+
const tooltipContent = getTooltipContent();
|
|
5414
|
+
const fieldContent = /* @__PURE__ */ jsxs(Flex, {
|
|
5415
|
+
alignItems: "center",
|
|
5416
|
+
gap: "4px",
|
|
5417
|
+
color: "gray.400",
|
|
5418
|
+
children: [/* @__PURE__ */ jsxs(Text, {
|
|
5419
|
+
textDecoration: isDeprecated ? "line-through" : void 0,
|
|
5420
|
+
children: [name, ":"]
|
|
5421
|
+
}), formula && /* @__PURE__ */ jsx(PiFunctionLight, { size: 14 })]
|
|
5422
|
+
});
|
|
5423
|
+
return /* @__PURE__ */ jsx(Flex, {
|
|
5424
|
+
height: "28px",
|
|
5425
|
+
alignItems: "center",
|
|
5426
|
+
children: tooltipContent ? /* @__PURE__ */ jsx(Tooltip, {
|
|
5427
|
+
openDelay: 350,
|
|
5428
|
+
content: tooltipContent,
|
|
5429
|
+
positioning: { placement: "right-end" },
|
|
5430
|
+
showArrow: true,
|
|
5431
|
+
children: fieldContent
|
|
5432
|
+
}) : fieldContent
|
|
5433
|
+
});
|
|
5434
|
+
};
|
|
5435
|
+
|
|
5436
|
+
//#endregion
|
|
5437
|
+
//#region src/row-editor/ui/components/More.tsx
|
|
5438
|
+
const More = ({ onClick, label }) => {
|
|
5439
|
+
return /* @__PURE__ */ jsx(Text, {
|
|
5440
|
+
ml: "8px",
|
|
5441
|
+
color: "gray.300",
|
|
5442
|
+
onClick,
|
|
5443
|
+
cursor: "pointer",
|
|
5444
|
+
children: label
|
|
5445
|
+
});
|
|
5446
|
+
};
|
|
5447
|
+
|
|
5448
|
+
//#endregion
|
|
5449
|
+
//#region src/row-editor/ui/components/NodeMenu/NodeMenu.tsx
|
|
5450
|
+
const NodeMenu = observer(({ node }) => {
|
|
5451
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
5452
|
+
if (node.menu.length === 0) return null;
|
|
5453
|
+
return /* @__PURE__ */ jsxs(Menu.Root, {
|
|
5454
|
+
lazyMount: true,
|
|
5455
|
+
unmountOnExit: true,
|
|
5456
|
+
onOpenChange: ({ open }) => setIsOpen(open),
|
|
5457
|
+
children: [/* @__PURE__ */ jsx(Menu.Trigger, {
|
|
5458
|
+
asChild: true,
|
|
5459
|
+
children: /* @__PURE__ */ jsx(Flex, {
|
|
5460
|
+
width: "24px",
|
|
5461
|
+
left: "-24px",
|
|
5462
|
+
position: "absolute",
|
|
5463
|
+
zIndex: 1,
|
|
5464
|
+
alignItems: "center",
|
|
5465
|
+
justifyContent: "center",
|
|
5466
|
+
cursor: "pointer",
|
|
5467
|
+
children: /* @__PURE__ */ jsx(Flex, {
|
|
5468
|
+
alignItems: "center",
|
|
5469
|
+
justifyContent: "center",
|
|
5470
|
+
mt: "2px",
|
|
5471
|
+
height: "24px",
|
|
5472
|
+
width: "12px",
|
|
5473
|
+
borderRadius: "4px",
|
|
5474
|
+
bg: "blackAlpha.50",
|
|
5475
|
+
backdropFilter: "blur(4px)",
|
|
5476
|
+
boxShadow: "0 0 0 1px rgba(0,0,0,0.06), 0 1px 1px rgba(0,0,0,0.08)",
|
|
5477
|
+
opacity: isOpen ? 1 : 0,
|
|
5478
|
+
transition: isOpen ? "opacity 1s ease 0s" : void 0,
|
|
5479
|
+
_groupHover: {
|
|
5480
|
+
opacity: 1,
|
|
5481
|
+
transition: "opacity 0.5s ease 0s"
|
|
5482
|
+
},
|
|
5483
|
+
_hover: { boxShadow: "0 0 0 1px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.1)" },
|
|
5484
|
+
children: /* @__PURE__ */ jsx(Icon, {
|
|
5485
|
+
size: "md",
|
|
5486
|
+
color: "gray.400",
|
|
5487
|
+
as: PiDotsThreeVerticalBold
|
|
5488
|
+
})
|
|
5489
|
+
})
|
|
5490
|
+
})
|
|
5491
|
+
}), /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, { children: /* @__PURE__ */ jsx(Menu.Content, { children: node.menu.map((item) => item.children ? /* @__PURE__ */ jsxs(Menu.Root, {
|
|
5492
|
+
positioning: {
|
|
5493
|
+
placement: "right-start",
|
|
5494
|
+
gutter: 2
|
|
5495
|
+
},
|
|
5496
|
+
children: [
|
|
5497
|
+
item.beforeSeparator && /* @__PURE__ */ jsx(Menu.Separator, {}),
|
|
5498
|
+
/* @__PURE__ */ jsxs(Menu.TriggerItem, {
|
|
5499
|
+
width: "100%",
|
|
5500
|
+
justifyContent: "space-between",
|
|
5501
|
+
children: [
|
|
5502
|
+
item.label,
|
|
5503
|
+
" ",
|
|
5504
|
+
/* @__PURE__ */ jsx(LuChevronRight, {})
|
|
5505
|
+
]
|
|
5506
|
+
}),
|
|
5507
|
+
item.afterSeparator && /* @__PURE__ */ jsx(Menu.Separator, {}),
|
|
5508
|
+
/* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Menu.Positioner, { children: /* @__PURE__ */ jsx(Menu.Content, { children: item.children.map((childItem) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5509
|
+
childItem.beforeSeparator && /* @__PURE__ */ jsx(Menu.Separator, {}),
|
|
5510
|
+
/* @__PURE__ */ jsx(Menu.Item, {
|
|
5511
|
+
value: childItem.value,
|
|
5512
|
+
onClick: childItem.handler,
|
|
5513
|
+
children: /* @__PURE__ */ jsx(Box, {
|
|
5514
|
+
flex: 1,
|
|
5515
|
+
children: childItem.label
|
|
5516
|
+
})
|
|
5517
|
+
}),
|
|
5518
|
+
childItem.afterSeparator && /* @__PURE__ */ jsx(Menu.Separator, {})
|
|
5519
|
+
] }, childItem.value)) }) }) })
|
|
5520
|
+
]
|
|
5521
|
+
}, item.value) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
5522
|
+
item.beforeSeparator && /* @__PURE__ */ jsx(Menu.Separator, {}),
|
|
5523
|
+
/* @__PURE__ */ jsx(Menu.Item, {
|
|
5524
|
+
value: item.value,
|
|
5525
|
+
onClick: item.handler,
|
|
5526
|
+
children: /* @__PURE__ */ jsx(Box, {
|
|
5527
|
+
flex: 1,
|
|
5528
|
+
children: item.label
|
|
5529
|
+
})
|
|
5530
|
+
}),
|
|
5531
|
+
item.afterSeparator && /* @__PURE__ */ jsx(Menu.Separator, {})
|
|
5532
|
+
] }, item.value)) }) }) })]
|
|
5533
|
+
});
|
|
5534
|
+
});
|
|
5535
|
+
|
|
5536
|
+
//#endregion
|
|
5537
|
+
//#region src/row-editor/ui/components/Row.tsx
|
|
5538
|
+
const Row = ({ node, name, guides, isCollapsible = false, isExpanded = true, onToggle, formula, description, isDeprecated, skipDot, skipField, skipMore, collapsedLabel, isReadOnly, testId, onMouseEnter, onMouseLeave, children }) => {
|
|
5539
|
+
const isCollapsed = isCollapsible && !isExpanded;
|
|
5540
|
+
const showMenu = node && !isReadOnly;
|
|
5541
|
+
return /* @__PURE__ */ jsxs(Flex, {
|
|
5542
|
+
width: "100%",
|
|
5543
|
+
onMouseEnter,
|
|
5544
|
+
onMouseLeave,
|
|
5545
|
+
position: "relative",
|
|
5546
|
+
className: "group",
|
|
5547
|
+
"data-testid": testId,
|
|
5548
|
+
children: [
|
|
5549
|
+
/* @__PURE__ */ jsx(Guides, { guides }),
|
|
5550
|
+
showMenu && /* @__PURE__ */ jsx(NodeMenu, { node }),
|
|
5551
|
+
/* @__PURE__ */ jsxs(Flex, {
|
|
5552
|
+
width: "100%",
|
|
5553
|
+
alignItems: "center",
|
|
5554
|
+
children: [/* @__PURE__ */ jsxs(Flex, { children: [
|
|
5555
|
+
!skipDot && /* @__PURE__ */ jsx(Dot, {
|
|
5556
|
+
isCollapsed,
|
|
5557
|
+
isCollapsible,
|
|
5558
|
+
toggleCollapsed: onToggle,
|
|
5559
|
+
testId
|
|
5560
|
+
}),
|
|
5561
|
+
!skipField && /* @__PURE__ */ jsx(Field, {
|
|
5562
|
+
name,
|
|
5563
|
+
formula,
|
|
5564
|
+
description,
|
|
5565
|
+
isDeprecated
|
|
5566
|
+
}),
|
|
5567
|
+
children
|
|
5568
|
+
] }), !skipMore && isCollapsed && collapsedLabel && /* @__PURE__ */ jsx(More, {
|
|
5569
|
+
onClick: onToggle,
|
|
5570
|
+
label: collapsedLabel
|
|
5571
|
+
})]
|
|
5572
|
+
})
|
|
5573
|
+
]
|
|
5574
|
+
});
|
|
5575
|
+
};
|
|
5576
|
+
|
|
5577
|
+
//#endregion
|
|
5578
|
+
//#region src/row-editor/ui/renderers/ContainerRenderer.tsx
|
|
5579
|
+
const ContainerRendererComponent = observer(({ node }) => {
|
|
5580
|
+
const handleToggle = useCallback(() => {
|
|
5581
|
+
node.toggleExpanded();
|
|
5582
|
+
}, [node]);
|
|
5583
|
+
return /* @__PURE__ */ jsx(Row, {
|
|
5584
|
+
node,
|
|
5585
|
+
name: node.displayName,
|
|
5586
|
+
guides: node.guides,
|
|
5587
|
+
isCollapsible: node.isCollapsible,
|
|
5588
|
+
isExpanded: node.isExpanded,
|
|
5589
|
+
onToggle: handleToggle,
|
|
5590
|
+
collapsedLabel: node.collapsedLabel,
|
|
5591
|
+
isReadOnly: node.isEditorReadOnly,
|
|
5592
|
+
testId: node.testId
|
|
5593
|
+
});
|
|
5594
|
+
});
|
|
5595
|
+
|
|
5596
|
+
//#endregion
|
|
5597
|
+
//#region src/row-editor/ui/editors/PrimitiveBox.tsx
|
|
5598
|
+
const PrimitiveBox = observer(({ value, readonly, prefix = "", postfix = "", restrict, dataTestId, onChange, onFocus, onBlur }) => {
|
|
5599
|
+
const [focused, setFocused] = useState(false);
|
|
5600
|
+
const handleFocus = useCallback(() => {
|
|
5601
|
+
setFocused(true);
|
|
5602
|
+
onFocus?.();
|
|
5603
|
+
}, [onFocus]);
|
|
5604
|
+
const handleBlur = useCallback(() => {
|
|
5605
|
+
setFocused(false);
|
|
5606
|
+
onBlur?.();
|
|
5607
|
+
}, [onBlur]);
|
|
5608
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
5609
|
+
borderRadius: "4px",
|
|
5610
|
+
bgColor: focused ? "gray.100" : void 0,
|
|
5611
|
+
_hover: { bgColor: readonly ? void 0 : "gray.100" },
|
|
5612
|
+
mt: "2px",
|
|
5613
|
+
ml: "2px",
|
|
5614
|
+
pl: "4px",
|
|
5615
|
+
pr: "4px",
|
|
5616
|
+
minHeight: "24px",
|
|
5617
|
+
minWidth: "15px",
|
|
5618
|
+
cursor: readonly ? "text" : void 0,
|
|
5619
|
+
children: readonly ? `${prefix}${value}${postfix}` : /* @__PURE__ */ jsx(ContentEditable, {
|
|
5620
|
+
dataTestId,
|
|
5621
|
+
prefix,
|
|
5622
|
+
postfix,
|
|
5623
|
+
initValue: value,
|
|
5624
|
+
onChange,
|
|
5625
|
+
onFocus: handleFocus,
|
|
5626
|
+
onBlur: handleBlur,
|
|
5627
|
+
restrict
|
|
5628
|
+
})
|
|
5629
|
+
});
|
|
5630
|
+
});
|
|
5631
|
+
|
|
5632
|
+
//#endregion
|
|
5633
|
+
//#region src/row-editor/ui/editors/StringEditor.tsx
|
|
5634
|
+
const StringEditor = ({ value, setValue, readonly, dataTestId }) => {
|
|
5635
|
+
const [internalValue, setInternalValue] = useState(value);
|
|
5636
|
+
useEffect(() => {
|
|
5637
|
+
setInternalValue(value);
|
|
5638
|
+
}, [value]);
|
|
5639
|
+
const handleChange = useCallback((newValue) => {
|
|
5640
|
+
setInternalValue(newValue);
|
|
5641
|
+
}, []);
|
|
5642
|
+
const handleBlur = useCallback(() => {
|
|
5643
|
+
setValue(internalValue);
|
|
5644
|
+
}, [internalValue, setValue]);
|
|
5645
|
+
const prefix = internalValue ? "" : "\"";
|
|
5646
|
+
return /* @__PURE__ */ jsx(PrimitiveBox, {
|
|
5647
|
+
prefix,
|
|
5648
|
+
postfix: prefix,
|
|
5649
|
+
value: internalValue,
|
|
5650
|
+
readonly,
|
|
5651
|
+
dataTestId,
|
|
5652
|
+
onChange: handleChange,
|
|
5653
|
+
onBlur: handleBlur
|
|
5654
|
+
});
|
|
5655
|
+
};
|
|
5656
|
+
|
|
5657
|
+
//#endregion
|
|
5658
|
+
//#region src/row-editor/ui/renderers/StringRenderer.tsx
|
|
5659
|
+
const StringRendererComponent = observer(({ node }) => {
|
|
5660
|
+
const value = String(node.value);
|
|
5661
|
+
const handleSetValue = useCallback((newValue) => {
|
|
5662
|
+
node.setValue(newValue);
|
|
5663
|
+
}, [node]);
|
|
5664
|
+
const handleToggle = useCallback(() => {
|
|
5665
|
+
node.toggleExpanded();
|
|
5666
|
+
}, [node]);
|
|
5667
|
+
if (node.isLongText) return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Row, {
|
|
5668
|
+
node,
|
|
5669
|
+
name: node.displayName,
|
|
5670
|
+
guides: node.guides,
|
|
5671
|
+
formula: node.formula,
|
|
5672
|
+
isCollapsible: true,
|
|
5673
|
+
isExpanded: node.isExpanded,
|
|
5674
|
+
onToggle: handleToggle,
|
|
5675
|
+
collapsedLabel: node.collapsedLabel,
|
|
5676
|
+
isReadOnly: node.isEditorReadOnly,
|
|
5677
|
+
testId: node.testId
|
|
5678
|
+
}), node.isExpanded && /* @__PURE__ */ jsx(Row, {
|
|
5679
|
+
name: "",
|
|
5680
|
+
guides: [...node.guides, true],
|
|
5681
|
+
skipDot: true,
|
|
5682
|
+
skipField: true,
|
|
5683
|
+
children: /* @__PURE__ */ jsx(StringEditor, {
|
|
5684
|
+
value,
|
|
5685
|
+
setValue: handleSetValue,
|
|
5686
|
+
readonly: node.isFieldReadOnly,
|
|
5687
|
+
dataTestId: `${node.testId}-editor`
|
|
5688
|
+
})
|
|
5689
|
+
})] });
|
|
5690
|
+
return /* @__PURE__ */ jsx(Row, {
|
|
5691
|
+
node,
|
|
5692
|
+
name: node.displayName,
|
|
5693
|
+
guides: node.guides,
|
|
5694
|
+
formula: node.formula,
|
|
5695
|
+
isReadOnly: node.isEditorReadOnly,
|
|
5696
|
+
testId: node.testId,
|
|
5697
|
+
children: /* @__PURE__ */ jsx(StringEditor, {
|
|
5698
|
+
value,
|
|
5699
|
+
setValue: handleSetValue,
|
|
5700
|
+
readonly: node.isFieldReadOnly,
|
|
5701
|
+
dataTestId: `${node.testId}-editor`
|
|
5702
|
+
})
|
|
5703
|
+
});
|
|
5704
|
+
});
|
|
5705
|
+
|
|
5706
|
+
//#endregion
|
|
5707
|
+
//#region src/row-editor/ui/editors/NumberEditor.tsx
|
|
5708
|
+
const NUMERIC_CHARS = /^[\d.eE+-]+$/;
|
|
5709
|
+
const NumberEditor = ({ value, setValue, readonly, dataTestId }) => {
|
|
5710
|
+
const stringValue = value.toString();
|
|
5711
|
+
const lastValidValue = useRef(stringValue);
|
|
5712
|
+
const [state, setState] = useState(stringValue);
|
|
5713
|
+
useEffect(() => {
|
|
5714
|
+
setState(stringValue);
|
|
5715
|
+
lastValidValue.current = stringValue;
|
|
5716
|
+
}, [stringValue]);
|
|
5717
|
+
return /* @__PURE__ */ jsx(PrimitiveBox, {
|
|
5718
|
+
value: state,
|
|
5719
|
+
readonly,
|
|
5720
|
+
dataTestId,
|
|
5721
|
+
onChange: useCallback((newValue) => {
|
|
5722
|
+
setState(newValue);
|
|
5723
|
+
}, []),
|
|
5724
|
+
onBlur: useCallback(() => {
|
|
5725
|
+
const trimmed = state.trim();
|
|
5726
|
+
const parsedValue = Number(trimmed);
|
|
5727
|
+
if (trimmed !== "" && Number.isFinite(parsedValue)) {
|
|
5728
|
+
setValue(parsedValue);
|
|
5729
|
+
setState(parsedValue.toString());
|
|
5730
|
+
lastValidValue.current = parsedValue.toString();
|
|
5731
|
+
} else setState(lastValidValue.current);
|
|
5732
|
+
}, [setValue, state]),
|
|
5733
|
+
restrict: NUMERIC_CHARS
|
|
5734
|
+
});
|
|
5735
|
+
};
|
|
5736
|
+
|
|
5737
|
+
//#endregion
|
|
5738
|
+
//#region src/row-editor/ui/renderers/NumberRenderer.tsx
|
|
5739
|
+
const NumberRendererComponent = observer(({ node }) => {
|
|
5740
|
+
const handleSetValue = useCallback((value) => {
|
|
5741
|
+
node.setValue(value);
|
|
5742
|
+
}, [node]);
|
|
5743
|
+
return /* @__PURE__ */ jsx(Row, {
|
|
5744
|
+
node,
|
|
5745
|
+
name: node.displayName,
|
|
5746
|
+
guides: node.guides,
|
|
5747
|
+
formula: node.formula,
|
|
5748
|
+
isReadOnly: node.isEditorReadOnly,
|
|
5749
|
+
testId: node.testId,
|
|
5750
|
+
children: /* @__PURE__ */ jsx(NumberEditor, {
|
|
5751
|
+
value: Number(node.value),
|
|
5752
|
+
setValue: handleSetValue,
|
|
5753
|
+
readonly: node.isFieldReadOnly,
|
|
5754
|
+
dataTestId: `${node.testId}-editor`
|
|
5755
|
+
})
|
|
5756
|
+
});
|
|
5757
|
+
});
|
|
5758
|
+
|
|
5759
|
+
//#endregion
|
|
5760
|
+
//#region src/row-editor/ui/editors/FocusPopover.tsx
|
|
5761
|
+
const FocusPopover = ({ isOpen, setIsOpen, trigger, children, disabled, width }) => {
|
|
5762
|
+
const triggerRef = useRef(null);
|
|
5763
|
+
const lastRectRef = useRef(null);
|
|
5764
|
+
const getAnchorRect = useCallback(() => {
|
|
5765
|
+
const rect = triggerRef.current?.getBoundingClientRect();
|
|
5766
|
+
if (rect && rect.width > 0) lastRectRef.current = rect;
|
|
5767
|
+
return lastRectRef.current;
|
|
5768
|
+
}, []);
|
|
5769
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Box, {
|
|
5770
|
+
ref: triggerRef,
|
|
5771
|
+
onFocus: useCallback(() => {
|
|
5772
|
+
if (!disabled) setIsOpen(true);
|
|
5773
|
+
}, [disabled, setIsOpen]),
|
|
5774
|
+
children: trigger
|
|
5775
|
+
}), !disabled && /* @__PURE__ */ jsx(Popover.Root, {
|
|
5776
|
+
lazyMount: true,
|
|
5777
|
+
unmountOnExit: true,
|
|
5778
|
+
open: isOpen,
|
|
5779
|
+
onOpenChange: ({ open }) => setIsOpen(open),
|
|
5780
|
+
autoFocus: false,
|
|
5781
|
+
closeOnInteractOutside: true,
|
|
5782
|
+
modal: false,
|
|
5783
|
+
positioning: {
|
|
5784
|
+
placement: "bottom-start",
|
|
5785
|
+
getAnchorRect
|
|
5786
|
+
},
|
|
5787
|
+
children: /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, { children: /* @__PURE__ */ jsx(Popover.Content, {
|
|
5788
|
+
width,
|
|
5789
|
+
p: 1,
|
|
5790
|
+
children
|
|
5791
|
+
}) }) })
|
|
5792
|
+
})] });
|
|
5793
|
+
};
|
|
5794
|
+
|
|
5795
|
+
//#endregion
|
|
5796
|
+
//#region src/row-editor/ui/editors/FocusPopoverItem.tsx
|
|
5797
|
+
const FocusPopoverItem = ({ children, onClick }) => {
|
|
5798
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
5799
|
+
px: 2,
|
|
5800
|
+
py: 1.5,
|
|
5801
|
+
cursor: "pointer",
|
|
5802
|
+
borderRadius: "md",
|
|
5803
|
+
fontSize: "sm",
|
|
5804
|
+
_hover: { bg: "gray.100" },
|
|
5805
|
+
onClick,
|
|
5806
|
+
children
|
|
5807
|
+
});
|
|
5808
|
+
};
|
|
5809
|
+
|
|
5810
|
+
//#endregion
|
|
5811
|
+
//#region src/row-editor/ui/editors/BooleanMenu.tsx
|
|
5812
|
+
const BooleanMenu = ({ children, onChange, disabled }) => {
|
|
5813
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
5814
|
+
const handleSelect = useCallback((value) => {
|
|
5815
|
+
onChange(value === "true");
|
|
5816
|
+
setIsOpen(false);
|
|
5817
|
+
}, [onChange]);
|
|
5818
|
+
return /* @__PURE__ */ jsxs(FocusPopover, {
|
|
5819
|
+
width: "60px",
|
|
5820
|
+
isOpen,
|
|
5821
|
+
setIsOpen,
|
|
5822
|
+
trigger: children,
|
|
5823
|
+
disabled,
|
|
5824
|
+
children: [/* @__PURE__ */ jsx(FocusPopoverItem, {
|
|
5825
|
+
onClick: () => handleSelect("true"),
|
|
5826
|
+
children: "true"
|
|
5827
|
+
}), /* @__PURE__ */ jsx(FocusPopoverItem, {
|
|
5828
|
+
onClick: () => handleSelect("false"),
|
|
5829
|
+
children: "false"
|
|
5830
|
+
})]
|
|
5831
|
+
});
|
|
5832
|
+
};
|
|
5833
|
+
|
|
5834
|
+
//#endregion
|
|
5835
|
+
//#region src/row-editor/ui/editors/BooleanEditor.tsx
|
|
5836
|
+
const BooleanEditor = ({ value, setValue, readonly, dataTestId }) => {
|
|
5837
|
+
const stringValue = value.toString();
|
|
5838
|
+
const [state, setState] = useState(stringValue);
|
|
5839
|
+
useEffect(() => {
|
|
5840
|
+
setState(stringValue);
|
|
5841
|
+
}, [stringValue]);
|
|
5842
|
+
const handleChange = useCallback((value) => {
|
|
5843
|
+
setState(value);
|
|
5844
|
+
}, []);
|
|
5845
|
+
const handleBlur = useCallback(() => {
|
|
5846
|
+
const trimmed = state.trim();
|
|
5847
|
+
const boolValue = trimmed.toLowerCase() === "false" || trimmed === "0" ? false : Boolean(trimmed);
|
|
5848
|
+
setState(boolValue.toString());
|
|
5849
|
+
setValue(boolValue);
|
|
5850
|
+
}, [setValue, state]);
|
|
5851
|
+
return /* @__PURE__ */ jsx(BooleanMenu, {
|
|
5852
|
+
onChange: useCallback((boolValue) => {
|
|
5853
|
+
setState(boolValue.toString());
|
|
5854
|
+
setValue(boolValue);
|
|
5855
|
+
}, [setValue]),
|
|
5856
|
+
disabled: readonly,
|
|
5857
|
+
children: /* @__PURE__ */ jsx(PrimitiveBox, {
|
|
5858
|
+
value: state,
|
|
5859
|
+
readonly,
|
|
5860
|
+
dataTestId,
|
|
5861
|
+
onChange: handleChange,
|
|
5862
|
+
onBlur: handleBlur
|
|
5863
|
+
})
|
|
5864
|
+
});
|
|
5865
|
+
};
|
|
5866
|
+
|
|
5867
|
+
//#endregion
|
|
5868
|
+
//#region src/row-editor/ui/renderers/BooleanRenderer.tsx
|
|
5869
|
+
const BooleanRendererComponent = observer(({ node }) => {
|
|
5870
|
+
const handleSetValue = useCallback((value) => {
|
|
5871
|
+
node.setValue(value);
|
|
5872
|
+
}, [node]);
|
|
5873
|
+
return /* @__PURE__ */ jsx(Row, {
|
|
5874
|
+
node,
|
|
5875
|
+
name: node.displayName,
|
|
5876
|
+
guides: node.guides,
|
|
5877
|
+
formula: node.formula,
|
|
5878
|
+
isReadOnly: node.isEditorReadOnly,
|
|
5879
|
+
testId: node.testId,
|
|
5880
|
+
children: /* @__PURE__ */ jsx(BooleanEditor, {
|
|
5881
|
+
value: Boolean(node.value),
|
|
5882
|
+
setValue: handleSetValue,
|
|
5883
|
+
readonly: node.isFieldReadOnly,
|
|
5884
|
+
dataTestId: `${node.testId}-editor`
|
|
5885
|
+
})
|
|
5886
|
+
});
|
|
5887
|
+
});
|
|
5888
|
+
|
|
5889
|
+
//#endregion
|
|
5890
|
+
//#region src/row-editor/ui/editors/ForeignKeyActions.tsx
|
|
5891
|
+
const ForeignKeyActions = observer(({ node }) => {
|
|
5892
|
+
const value = String(node.value);
|
|
5893
|
+
const showNavigate = Boolean(value) && Boolean(node.callbacks?.onNavigateToForeignKey);
|
|
5894
|
+
const showWarning = !value && !node.isEditorReadOnly;
|
|
5895
|
+
const handleNavigate = useCallback(() => {
|
|
5896
|
+
node.callbacks?.onNavigateToForeignKey?.(node.foreignKeyTableId, value);
|
|
5897
|
+
}, [node, value]);
|
|
5898
|
+
return /* @__PURE__ */ jsxs(Flex, {
|
|
5899
|
+
alignItems: "center",
|
|
5900
|
+
gap: "4px",
|
|
5901
|
+
children: [showNavigate && /* @__PURE__ */ jsx(IconButton, {
|
|
5902
|
+
"aria-label": "Navigate to foreign key",
|
|
5903
|
+
variant: "ghost",
|
|
5904
|
+
size: "2xs",
|
|
5905
|
+
color: "gray.500",
|
|
5906
|
+
_hover: {
|
|
5907
|
+
color: "black",
|
|
5908
|
+
bg: "gray.100"
|
|
5909
|
+
},
|
|
5910
|
+
onClick: handleNavigate,
|
|
5911
|
+
"data-testid": `${node.testId}-fk-navigate`,
|
|
5912
|
+
children: /* @__PURE__ */ jsx(PiArrowSquareUpRightThin, {})
|
|
5913
|
+
}), showWarning && /* @__PURE__ */ jsx(Tooltip, {
|
|
5914
|
+
openDelay: 50,
|
|
5915
|
+
closeDelay: 50,
|
|
5916
|
+
content: "This field requires a valid foreign key ID",
|
|
5917
|
+
children: /* @__PURE__ */ jsx(Flex, {
|
|
5918
|
+
width: "24px",
|
|
5919
|
+
height: "24px",
|
|
5920
|
+
alignItems: "center",
|
|
5921
|
+
justifyContent: "center",
|
|
5922
|
+
color: "gray.400",
|
|
5923
|
+
children: /* @__PURE__ */ jsx(PiInfo, {})
|
|
5924
|
+
})
|
|
5925
|
+
})]
|
|
5926
|
+
});
|
|
5927
|
+
});
|
|
5928
|
+
|
|
5929
|
+
//#endregion
|
|
5930
|
+
//#region src/lib/Debounce.ts
|
|
5931
|
+
var Debounce = class {
|
|
5932
|
+
_timer = null;
|
|
5933
|
+
constructor(_delay) {
|
|
5934
|
+
this._delay = _delay;
|
|
5935
|
+
}
|
|
5936
|
+
schedule(fn) {
|
|
5937
|
+
if (this._timer) clearTimeout(this._timer);
|
|
5938
|
+
this._timer = setTimeout(fn, this._delay);
|
|
5939
|
+
}
|
|
5940
|
+
dispose() {
|
|
5941
|
+
if (this._timer) {
|
|
5942
|
+
clearTimeout(this._timer);
|
|
5943
|
+
this._timer = null;
|
|
5944
|
+
}
|
|
5945
|
+
}
|
|
5946
|
+
};
|
|
5947
|
+
|
|
5948
|
+
//#endregion
|
|
5949
|
+
//#region src/search-foreign-key/vm/SearchForeignKeyVM.ts
|
|
5950
|
+
var SearchForeignKeyVM = class {
|
|
5951
|
+
_search = "";
|
|
5952
|
+
_state = "loading";
|
|
5953
|
+
_ids = [];
|
|
5954
|
+
_hasMore = false;
|
|
5955
|
+
_initialized = false;
|
|
5956
|
+
_disposeReaction = null;
|
|
5957
|
+
_debounce = new Debounce(300);
|
|
5958
|
+
constructor(_tableId, _onSearch) {
|
|
5959
|
+
this._tableId = _tableId;
|
|
5960
|
+
this._onSearch = _onSearch;
|
|
5961
|
+
makeAutoObservable(this, {}, { autoBind: true });
|
|
5962
|
+
}
|
|
5963
|
+
get search() {
|
|
5964
|
+
return this._search;
|
|
5965
|
+
}
|
|
5966
|
+
get state() {
|
|
5967
|
+
return this._state;
|
|
5968
|
+
}
|
|
5969
|
+
get ids() {
|
|
5970
|
+
return this._ids;
|
|
5971
|
+
}
|
|
5972
|
+
get hasMore() {
|
|
5973
|
+
return this._hasMore;
|
|
5974
|
+
}
|
|
5975
|
+
get showInput() {
|
|
5976
|
+
return this._state === "list" || this._state === "notFound" || this._state === "loading" && this._initialized;
|
|
5977
|
+
}
|
|
5978
|
+
get showFooter() {
|
|
5979
|
+
return this._state === "list" || this._state === "notFound" || this._state === "error" || this._state === "empty";
|
|
5980
|
+
}
|
|
5981
|
+
get showLoading() {
|
|
5982
|
+
return this._state === "loading";
|
|
5983
|
+
}
|
|
5984
|
+
get showNotFound() {
|
|
5985
|
+
return this._state === "notFound";
|
|
5986
|
+
}
|
|
5987
|
+
get showError() {
|
|
5988
|
+
return this._state === "error";
|
|
5989
|
+
}
|
|
5990
|
+
get showEmpty() {
|
|
5991
|
+
return this._state === "empty";
|
|
5992
|
+
}
|
|
5993
|
+
get showList() {
|
|
5994
|
+
return this._state === "list";
|
|
5995
|
+
}
|
|
5996
|
+
get tableId() {
|
|
5997
|
+
return this._tableId;
|
|
5998
|
+
}
|
|
5999
|
+
init() {
|
|
6000
|
+
this._performSearch();
|
|
6001
|
+
this._disposeReaction = reaction(() => this._search, () => this._debouncedSearch());
|
|
6002
|
+
}
|
|
6003
|
+
setSearch(value) {
|
|
6004
|
+
this._search = value;
|
|
6005
|
+
}
|
|
6006
|
+
dispose() {
|
|
6007
|
+
this._disposeReaction?.();
|
|
6008
|
+
this._disposeReaction = null;
|
|
6009
|
+
this._debounce.dispose();
|
|
6010
|
+
}
|
|
6011
|
+
_debouncedSearch() {
|
|
6012
|
+
this._debounce.schedule(() => {
|
|
6013
|
+
this._performSearch();
|
|
6014
|
+
});
|
|
6015
|
+
}
|
|
6016
|
+
_resolveState(ids, search) {
|
|
6017
|
+
if (ids.length === 0 && !search) return "empty";
|
|
6018
|
+
if (ids.length === 0) return "notFound";
|
|
6019
|
+
return "list";
|
|
6020
|
+
}
|
|
6021
|
+
async _performSearch() {
|
|
6022
|
+
if (!this._onSearch) {
|
|
6023
|
+
this._state = "error";
|
|
6024
|
+
return;
|
|
6025
|
+
}
|
|
6026
|
+
const searchTerm = this._search;
|
|
6027
|
+
try {
|
|
6028
|
+
this._state = "loading";
|
|
6029
|
+
const result = await this._onSearch(this._tableId, searchTerm);
|
|
6030
|
+
runInAction(() => {
|
|
6031
|
+
if (this._search !== searchTerm) return;
|
|
6032
|
+
this._initialized = true;
|
|
6033
|
+
this._ids = result.ids;
|
|
6034
|
+
this._hasMore = result.hasMore;
|
|
6035
|
+
this._state = this._resolveState(result.ids, searchTerm);
|
|
6036
|
+
});
|
|
6037
|
+
} catch {
|
|
6038
|
+
runInAction(() => {
|
|
6039
|
+
if (this._search !== searchTerm) return;
|
|
6040
|
+
this._state = "error";
|
|
6041
|
+
});
|
|
6042
|
+
}
|
|
6043
|
+
}
|
|
6044
|
+
};
|
|
6045
|
+
|
|
6046
|
+
//#endregion
|
|
6047
|
+
//#region src/search-foreign-key/ui/Header.tsx
|
|
6048
|
+
const Header = ({ tableId, onClose }) => {
|
|
6049
|
+
return /* @__PURE__ */ jsxs(Flex, {
|
|
6050
|
+
p: "4px",
|
|
6051
|
+
alignItems: "center",
|
|
6052
|
+
justifyContent: "space-between",
|
|
6053
|
+
children: [/* @__PURE__ */ jsxs(Text, {
|
|
6054
|
+
fontSize: "xs",
|
|
6055
|
+
color: "gray.600",
|
|
6056
|
+
fontWeight: "medium",
|
|
6057
|
+
children: [
|
|
6058
|
+
"Select from \"",
|
|
6059
|
+
tableId,
|
|
6060
|
+
"\""
|
|
6061
|
+
]
|
|
6062
|
+
}), onClose && /* @__PURE__ */ jsx(IconButton, {
|
|
6063
|
+
"aria-label": "Close",
|
|
6064
|
+
variant: "ghost",
|
|
6065
|
+
size: "2xs",
|
|
6066
|
+
color: "gray.500",
|
|
6067
|
+
_hover: { color: "black" },
|
|
6068
|
+
onClick: onClose,
|
|
6069
|
+
children: /* @__PURE__ */ jsx(PiXBold, {})
|
|
6070
|
+
})]
|
|
6071
|
+
});
|
|
6072
|
+
};
|
|
6073
|
+
|
|
6074
|
+
//#endregion
|
|
6075
|
+
//#region src/search-foreign-key/ui/SearchInput.tsx
|
|
6076
|
+
const SearchInput = ({ value, onChange }) => {
|
|
6077
|
+
const handleChange = useCallback((e) => {
|
|
6078
|
+
onChange(e.target.value);
|
|
6079
|
+
}, [onChange]);
|
|
6080
|
+
const handleClear = useCallback(() => {
|
|
6081
|
+
onChange("");
|
|
6082
|
+
}, [onChange]);
|
|
6083
|
+
return /* @__PURE__ */ jsxs(Box, {
|
|
6084
|
+
px: "4px",
|
|
6085
|
+
pb: "4px",
|
|
6086
|
+
position: "relative",
|
|
6087
|
+
children: [/* @__PURE__ */ jsx(Input, {
|
|
6088
|
+
value,
|
|
6089
|
+
onChange: handleChange,
|
|
6090
|
+
placeholder: "Search by ID...",
|
|
6091
|
+
size: "sm",
|
|
6092
|
+
"data-testid": "fk-search-input",
|
|
6093
|
+
autoFocus: true
|
|
6094
|
+
}), value && /* @__PURE__ */ jsx(IconButton, {
|
|
6095
|
+
"aria-label": "Clear",
|
|
6096
|
+
variant: "ghost",
|
|
6097
|
+
size: "2xs",
|
|
6098
|
+
position: "absolute",
|
|
6099
|
+
right: "8px",
|
|
6100
|
+
top: "50%",
|
|
6101
|
+
transform: "translateY(-50%)",
|
|
6102
|
+
onClick: handleClear,
|
|
6103
|
+
color: "gray.400",
|
|
6104
|
+
_hover: { color: "black" },
|
|
6105
|
+
children: /* @__PURE__ */ jsx(PiXBold, {})
|
|
6106
|
+
})]
|
|
6107
|
+
});
|
|
6108
|
+
};
|
|
6109
|
+
|
|
6110
|
+
//#endregion
|
|
6111
|
+
//#region src/search-foreign-key/ui/Item.tsx
|
|
6112
|
+
const Item = ({ id, onSelect }) => {
|
|
6113
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
6114
|
+
px: 2,
|
|
6115
|
+
py: 1.5,
|
|
6116
|
+
mr: "12px",
|
|
6117
|
+
cursor: "pointer",
|
|
6118
|
+
borderRadius: "md",
|
|
6119
|
+
fontSize: "sm",
|
|
6120
|
+
_hover: { bg: "gray.100" },
|
|
6121
|
+
onClick: useCallback(() => {
|
|
6122
|
+
onSelect(id);
|
|
6123
|
+
}, [id, onSelect]),
|
|
6124
|
+
"data-testid": `fk-item-${id}`,
|
|
6125
|
+
children: id
|
|
6126
|
+
});
|
|
6127
|
+
};
|
|
6128
|
+
|
|
6129
|
+
//#endregion
|
|
6130
|
+
//#region src/search-foreign-key/ui/List.tsx
|
|
6131
|
+
const List = ({ ids, onSelect }) => {
|
|
6132
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
6133
|
+
flex: 1,
|
|
6134
|
+
overflowY: "auto",
|
|
6135
|
+
"data-testid": "fk-list",
|
|
6136
|
+
children: ids.map((id) => /* @__PURE__ */ jsx(Item, {
|
|
6137
|
+
id,
|
|
6138
|
+
onSelect
|
|
6139
|
+
}, id))
|
|
6140
|
+
});
|
|
6141
|
+
};
|
|
6142
|
+
|
|
6143
|
+
//#endregion
|
|
6144
|
+
//#region src/search-foreign-key/ui/Empty.tsx
|
|
6145
|
+
const Empty = () => {
|
|
6146
|
+
return /* @__PURE__ */ jsx(Flex, {
|
|
6147
|
+
flex: 1,
|
|
6148
|
+
justifyContent: "center",
|
|
6149
|
+
alignItems: "center",
|
|
6150
|
+
"data-testid": "fk-empty",
|
|
6151
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
6152
|
+
fontSize: "sm",
|
|
6153
|
+
color: "gray.500",
|
|
6154
|
+
children: "No rows found in this table"
|
|
6155
|
+
})
|
|
6156
|
+
});
|
|
6157
|
+
};
|
|
6158
|
+
|
|
6159
|
+
//#endregion
|
|
6160
|
+
//#region src/search-foreign-key/ui/Footer.tsx
|
|
6161
|
+
const Footer = ({ onOpenTableSearch, onCreateAndConnect }) => {
|
|
6162
|
+
if (!(onOpenTableSearch || onCreateAndConnect)) return null;
|
|
6163
|
+
return /* @__PURE__ */ jsxs(HStack, {
|
|
6164
|
+
mt: "4px",
|
|
6165
|
+
p: "4px",
|
|
6166
|
+
gap: 2,
|
|
6167
|
+
borderTopWidth: "1px",
|
|
6168
|
+
borderColor: "gray.200",
|
|
6169
|
+
children: [onOpenTableSearch && /* @__PURE__ */ jsxs(Button, {
|
|
6170
|
+
size: "xs",
|
|
6171
|
+
variant: "ghost",
|
|
6172
|
+
color: "gray.500",
|
|
6173
|
+
onClick: onOpenTableSearch,
|
|
6174
|
+
"data-testid": "fk-open-table-search",
|
|
6175
|
+
children: [/* @__PURE__ */ jsx(PiMagnifyingGlassBold, {}), "Open Table Search"]
|
|
6176
|
+
}), onCreateAndConnect && /* @__PURE__ */ jsxs(Button, {
|
|
6177
|
+
size: "xs",
|
|
6178
|
+
variant: "ghost",
|
|
6179
|
+
color: "gray.500",
|
|
6180
|
+
onClick: onCreateAndConnect,
|
|
6181
|
+
"data-testid": "fk-create-and-connect",
|
|
6182
|
+
children: [/* @__PURE__ */ jsx(PiPlusBold, {}), "Create & Connect"]
|
|
6183
|
+
})]
|
|
6184
|
+
});
|
|
6185
|
+
};
|
|
6186
|
+
|
|
6187
|
+
//#endregion
|
|
6188
|
+
//#region src/search-foreign-key/ui/SearchForeignKey.tsx
|
|
6189
|
+
const SearchForeignKey = observer(({ tableId, onSearch, onSelect, onClose, onOpenTableSearch, onCreateAndConnect }) => {
|
|
6190
|
+
const [model] = useState(() => new SearchForeignKeyVM(tableId, onSearch));
|
|
6191
|
+
useEffect(() => {
|
|
6192
|
+
model.init();
|
|
6193
|
+
return () => model.dispose();
|
|
6194
|
+
}, [model]);
|
|
6195
|
+
return /* @__PURE__ */ jsxs(Flex, {
|
|
6196
|
+
flexDirection: "column",
|
|
6197
|
+
height: "290px",
|
|
6198
|
+
width: "100%",
|
|
6199
|
+
"data-testid": "fk-picker",
|
|
6200
|
+
children: [
|
|
6201
|
+
/* @__PURE__ */ jsx(Header, {
|
|
6202
|
+
tableId,
|
|
6203
|
+
onClose
|
|
6204
|
+
}),
|
|
6205
|
+
model.showInput && /* @__PURE__ */ jsx(SearchInput, {
|
|
6206
|
+
value: model.search,
|
|
6207
|
+
onChange: model.setSearch
|
|
6208
|
+
}),
|
|
6209
|
+
model.showLoading && /* @__PURE__ */ jsx(Flex, {
|
|
6210
|
+
flex: 1,
|
|
6211
|
+
justifyContent: "center",
|
|
6212
|
+
alignItems: "center",
|
|
6213
|
+
children: /* @__PURE__ */ jsx(Spinner, {
|
|
6214
|
+
size: "sm",
|
|
6215
|
+
color: "gray.400"
|
|
6216
|
+
})
|
|
6217
|
+
}),
|
|
6218
|
+
model.showNotFound && /* @__PURE__ */ jsx(Flex, {
|
|
6219
|
+
flex: 1,
|
|
6220
|
+
justifyContent: "center",
|
|
6221
|
+
alignItems: "center",
|
|
6222
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
6223
|
+
fontSize: "sm",
|
|
6224
|
+
color: "gray.500",
|
|
6225
|
+
children: "No results found"
|
|
6226
|
+
})
|
|
6227
|
+
}),
|
|
6228
|
+
model.showError && /* @__PURE__ */ jsx(Flex, {
|
|
6229
|
+
flex: 1,
|
|
6230
|
+
justifyContent: "center",
|
|
6231
|
+
alignItems: "center",
|
|
6232
|
+
children: /* @__PURE__ */ jsx(Text, {
|
|
6233
|
+
fontSize: "sm",
|
|
6234
|
+
color: "gray.500",
|
|
6235
|
+
children: "Could not load data"
|
|
6236
|
+
})
|
|
6237
|
+
}),
|
|
6238
|
+
model.showEmpty && /* @__PURE__ */ jsx(Empty, {}),
|
|
6239
|
+
model.showList && /* @__PURE__ */ jsx(List, {
|
|
6240
|
+
ids: model.ids,
|
|
6241
|
+
onSelect
|
|
6242
|
+
}),
|
|
6243
|
+
model.showFooter && /* @__PURE__ */ jsx(Footer, {
|
|
6244
|
+
onOpenTableSearch,
|
|
6245
|
+
onCreateAndConnect
|
|
6246
|
+
})
|
|
6247
|
+
]
|
|
6248
|
+
});
|
|
6249
|
+
});
|
|
6250
|
+
|
|
6251
|
+
//#endregion
|
|
6252
|
+
//#region src/row-editor/ui/editors/ForeignKeyMenu.tsx
|
|
6253
|
+
const ForeignKeyMenu = ({ node, onSelect, disabled, children }) => {
|
|
6254
|
+
const [isOpen, setIsOpen] = useState(false);
|
|
6255
|
+
const onSearchForeignKey = node.callbacks?.onSearchForeignKey;
|
|
6256
|
+
const handleSelect = useCallback((id) => {
|
|
6257
|
+
onSelect(id);
|
|
6258
|
+
setIsOpen(false);
|
|
6259
|
+
}, [onSelect]);
|
|
6260
|
+
const handleClose = useCallback(() => {
|
|
6261
|
+
setIsOpen(false);
|
|
6262
|
+
}, []);
|
|
6263
|
+
const handleOpenTableSearch = useCallback(async () => {
|
|
6264
|
+
if (!node.callbacks?.onOpenTableSearch) return;
|
|
6265
|
+
const selectedId = await node.callbacks.onOpenTableSearch(node.foreignKeyTableId);
|
|
6266
|
+
if (selectedId) handleSelect(selectedId);
|
|
6267
|
+
}, [
|
|
6268
|
+
node.callbacks,
|
|
6269
|
+
node.foreignKeyTableId,
|
|
6270
|
+
handleSelect
|
|
6271
|
+
]);
|
|
6272
|
+
const handleCreateAndConnect = useCallback(async () => {
|
|
6273
|
+
if (!node.callbacks?.onCreateAndConnect) return;
|
|
6274
|
+
const createdId = await node.callbacks.onCreateAndConnect(node.foreignKeyTableId);
|
|
6275
|
+
if (createdId) handleSelect(createdId);
|
|
6276
|
+
}, [
|
|
6277
|
+
node.callbacks,
|
|
6278
|
+
node.foreignKeyTableId,
|
|
6279
|
+
handleSelect
|
|
6280
|
+
]);
|
|
6281
|
+
if (!onSearchForeignKey) return /* @__PURE__ */ jsx(Fragment$1, { children });
|
|
6282
|
+
return /* @__PURE__ */ jsx(FocusPopover, {
|
|
6283
|
+
isOpen,
|
|
6284
|
+
setIsOpen,
|
|
6285
|
+
trigger: children,
|
|
6286
|
+
disabled,
|
|
6287
|
+
width: "320px",
|
|
6288
|
+
children: /* @__PURE__ */ jsx(SearchForeignKey, {
|
|
6289
|
+
tableId: node.foreignKeyTableId,
|
|
6290
|
+
onSearch: onSearchForeignKey,
|
|
6291
|
+
onSelect: handleSelect,
|
|
6292
|
+
onClose: handleClose,
|
|
6293
|
+
onOpenTableSearch: node.callbacks?.onOpenTableSearch ? handleOpenTableSearch : void 0,
|
|
6294
|
+
onCreateAndConnect: node.callbacks?.onCreateAndConnect ? handleCreateAndConnect : void 0
|
|
6295
|
+
})
|
|
6296
|
+
});
|
|
6297
|
+
};
|
|
6298
|
+
|
|
6299
|
+
//#endregion
|
|
6300
|
+
//#region src/row-editor/ui/renderers/ForeignKeyRenderer.tsx
|
|
6301
|
+
const ForeignKeyRendererComponent = observer(({ node }) => {
|
|
6302
|
+
const value = String(node.value);
|
|
6303
|
+
const handleSetValue = useCallback((newValue) => {
|
|
6304
|
+
node.setValue(newValue);
|
|
6305
|
+
}, [node]);
|
|
6306
|
+
const handleSelect = useCallback((id) => {
|
|
6307
|
+
node.setValue(id);
|
|
6308
|
+
}, [node]);
|
|
6309
|
+
return /* @__PURE__ */ jsx(Row, {
|
|
6310
|
+
node,
|
|
6311
|
+
name: node.displayName,
|
|
6312
|
+
guides: node.guides,
|
|
6313
|
+
formula: node.formula,
|
|
6314
|
+
isReadOnly: node.isEditorReadOnly,
|
|
6315
|
+
testId: node.testId,
|
|
6316
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
6317
|
+
alignItems: "center",
|
|
6318
|
+
gap: "2px",
|
|
6319
|
+
children: [/* @__PURE__ */ jsx(ForeignKeyMenu, {
|
|
6320
|
+
node,
|
|
6321
|
+
onSelect: handleSelect,
|
|
6322
|
+
disabled: node.isFieldReadOnly,
|
|
6323
|
+
children: /* @__PURE__ */ jsx(StringEditor, {
|
|
6324
|
+
value,
|
|
6325
|
+
setValue: handleSetValue,
|
|
6326
|
+
readonly: node.isFieldReadOnly,
|
|
6327
|
+
dataTestId: `${node.testId}-editor`
|
|
6328
|
+
})
|
|
6329
|
+
}), /* @__PURE__ */ jsx(ForeignKeyActions, { node })]
|
|
6330
|
+
})
|
|
6331
|
+
});
|
|
6332
|
+
});
|
|
6333
|
+
|
|
6334
|
+
//#endregion
|
|
6335
|
+
//#region src/row-editor/ui/editors/FileHoverCard.tsx
|
|
6336
|
+
const FileIcon = ({ onClick, dataTestId }) => {
|
|
6337
|
+
return /* @__PURE__ */ jsx(IconButton, {
|
|
6338
|
+
"data-testid": dataTestId,
|
|
6339
|
+
"aria-label": "Open file",
|
|
6340
|
+
variant: "ghost",
|
|
6341
|
+
size: "2xs",
|
|
6342
|
+
color: "gray.400",
|
|
6343
|
+
_hover: {
|
|
6344
|
+
bg: "gray.100",
|
|
6345
|
+
color: "black"
|
|
6346
|
+
},
|
|
6347
|
+
onClick,
|
|
6348
|
+
children: /* @__PURE__ */ jsx(PiFile, {})
|
|
6349
|
+
});
|
|
6350
|
+
};
|
|
6351
|
+
const FileHoverCard = ({ url, availablePreview, width, height, onClick, dataTestId }) => {
|
|
6352
|
+
if (!availablePreview) return /* @__PURE__ */ jsx(FileIcon, {
|
|
6353
|
+
onClick,
|
|
6354
|
+
dataTestId
|
|
6355
|
+
});
|
|
6356
|
+
return /* @__PURE__ */ jsxs(HoverCard.Root, {
|
|
6357
|
+
lazyMount: true,
|
|
6358
|
+
unmountOnExit: true,
|
|
6359
|
+
openDelay: 350,
|
|
6360
|
+
closeDelay: 100,
|
|
6361
|
+
positioning: { gutter: 16 },
|
|
6362
|
+
children: [/* @__PURE__ */ jsx(HoverCard.Trigger, {
|
|
6363
|
+
asChild: true,
|
|
6364
|
+
children: /* @__PURE__ */ jsx("span", { children: /* @__PURE__ */ jsx(FileIcon, {
|
|
6365
|
+
onClick,
|
|
6366
|
+
dataTestId
|
|
6367
|
+
}) })
|
|
6368
|
+
}), /* @__PURE__ */ jsx(Portal, { children: /* @__PURE__ */ jsx(HoverCard.Positioner, { children: /* @__PURE__ */ jsxs(HoverCard.Content, { children: [/* @__PURE__ */ jsx(HoverCard.Arrow, { children: /* @__PURE__ */ jsx(HoverCard.ArrowTip, {}) }), /* @__PURE__ */ jsx(Image, {
|
|
6369
|
+
aspectRatio: height > 0 ? width / height : 1,
|
|
6370
|
+
width: "400px",
|
|
6371
|
+
src: url,
|
|
6372
|
+
alt: "File preview"
|
|
6373
|
+
})] }) }) })]
|
|
6374
|
+
});
|
|
6375
|
+
};
|
|
6376
|
+
|
|
6377
|
+
//#endregion
|
|
6378
|
+
//#region src/row-editor/ui/editors/FileActions.tsx
|
|
6379
|
+
const FileActions = observer(({ node }) => {
|
|
6380
|
+
const fileInputRef = useRef(null);
|
|
6381
|
+
const url = node.fileUrl;
|
|
6382
|
+
const fileId = node.fileId;
|
|
6383
|
+
const status = node.fileStatus;
|
|
6384
|
+
const mimeType = node.fileMimeType;
|
|
6385
|
+
const width = node.fileWidth;
|
|
6386
|
+
const height = node.fileHeight;
|
|
6387
|
+
const readonly = node.isEditorReadOnly;
|
|
6388
|
+
const availablePreview = mimeType.startsWith("image/");
|
|
6389
|
+
const showViewFile = Boolean(url);
|
|
6390
|
+
const showUploadFile = !readonly && Boolean(node.callbacks?.onUploadFile) && (status === "ready" || status === "uploaded");
|
|
6391
|
+
const showInfo = !showViewFile && !showUploadFile;
|
|
6392
|
+
const handleFileChange = useCallback(async (event) => {
|
|
6393
|
+
const file = event.target.files?.[0];
|
|
6394
|
+
if (!file) return;
|
|
6395
|
+
event.target.value = "";
|
|
6396
|
+
await node.callbacks?.onUploadFile?.(fileId, file);
|
|
6397
|
+
}, [node, fileId]);
|
|
6398
|
+
const handleOpenFile = useCallback(() => {
|
|
6399
|
+
if (node.callbacks?.onOpenFile) node.callbacks.onOpenFile(url);
|
|
6400
|
+
else window.open(url, "_blank", "noopener,noreferrer");
|
|
6401
|
+
}, [node, url]);
|
|
6402
|
+
const handleUploadClick = useCallback(() => {
|
|
6403
|
+
fileInputRef.current?.click();
|
|
6404
|
+
}, []);
|
|
6405
|
+
return /* @__PURE__ */ jsxs(Flex, {
|
|
6406
|
+
alignItems: "center",
|
|
6407
|
+
children: [
|
|
6408
|
+
showInfo && /* @__PURE__ */ jsx(Tooltip, {
|
|
6409
|
+
openDelay: 50,
|
|
6410
|
+
closeDelay: 50,
|
|
6411
|
+
content: readonly ? "The file was not uploaded in this revision" : "Save the row first, then upload the file",
|
|
6412
|
+
children: /* @__PURE__ */ jsx(Flex, {
|
|
6413
|
+
width: "24px",
|
|
6414
|
+
height: "24px",
|
|
6415
|
+
alignItems: "center",
|
|
6416
|
+
justifyContent: "center",
|
|
6417
|
+
color: "gray.400",
|
|
6418
|
+
children: /* @__PURE__ */ jsx(PiInfo, {})
|
|
6419
|
+
})
|
|
6420
|
+
}),
|
|
6421
|
+
showViewFile && /* @__PURE__ */ jsx(FileHoverCard, {
|
|
6422
|
+
url,
|
|
6423
|
+
availablePreview,
|
|
6424
|
+
width,
|
|
6425
|
+
height,
|
|
6426
|
+
onClick: handleOpenFile,
|
|
6427
|
+
dataTestId: `${node.testId}-open-file`
|
|
6428
|
+
}),
|
|
6429
|
+
showUploadFile && /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsx("input", {
|
|
6430
|
+
ref: fileInputRef,
|
|
6431
|
+
type: "file",
|
|
6432
|
+
onChange: handleFileChange,
|
|
6433
|
+
style: { display: "none" },
|
|
6434
|
+
"data-testid": `${node.testId}-file-input`
|
|
6435
|
+
}), /* @__PURE__ */ jsx(IconButton, {
|
|
6436
|
+
"aria-label": "Upload file",
|
|
6437
|
+
variant: "ghost",
|
|
6438
|
+
size: "2xs",
|
|
6439
|
+
color: showViewFile ? "gray.300" : "gray.500",
|
|
6440
|
+
_hover: {
|
|
6441
|
+
bg: "gray.100",
|
|
6442
|
+
color: "black"
|
|
6443
|
+
},
|
|
6444
|
+
onClick: handleUploadClick,
|
|
6445
|
+
"data-testid": `${node.testId}-upload-file`,
|
|
6446
|
+
children: /* @__PURE__ */ jsx(PiUploadThin, {})
|
|
6447
|
+
})] })
|
|
6448
|
+
]
|
|
6449
|
+
});
|
|
6450
|
+
});
|
|
6451
|
+
|
|
6452
|
+
//#endregion
|
|
6453
|
+
//#region src/row-editor/ui/renderers/FileRenderer.tsx
|
|
6454
|
+
const FileRendererComponent = observer(({ node }) => {
|
|
6455
|
+
const handleToggle = useCallback(() => {
|
|
6456
|
+
node.toggleExpanded();
|
|
6457
|
+
}, [node]);
|
|
6458
|
+
return /* @__PURE__ */ jsx(Row, {
|
|
6459
|
+
node,
|
|
6460
|
+
name: node.displayName,
|
|
6461
|
+
guides: node.guides,
|
|
6462
|
+
isCollapsible: node.isCollapsible,
|
|
6463
|
+
isExpanded: node.isExpanded,
|
|
6464
|
+
onToggle: handleToggle,
|
|
6465
|
+
collapsedLabel: node.collapsedLabel,
|
|
6466
|
+
isReadOnly: node.isEditorReadOnly,
|
|
6467
|
+
testId: node.testId,
|
|
6468
|
+
skipMore: true,
|
|
6469
|
+
children: /* @__PURE__ */ jsx(FileActions, { node })
|
|
6470
|
+
});
|
|
6471
|
+
});
|
|
6472
|
+
|
|
6473
|
+
//#endregion
|
|
6474
|
+
//#region src/row-editor/ui/renderers/NodeRenderers.ts
|
|
6475
|
+
const NODE_RENDERERS = {
|
|
6476
|
+
container: ContainerRendererComponent,
|
|
6477
|
+
string: StringRendererComponent,
|
|
6478
|
+
number: NumberRendererComponent,
|
|
6479
|
+
boolean: BooleanRendererComponent,
|
|
6480
|
+
foreignKey: ForeignKeyRendererComponent,
|
|
6481
|
+
file: FileRendererComponent
|
|
6482
|
+
};
|
|
6483
|
+
|
|
6484
|
+
//#endregion
|
|
6485
|
+
//#region src/row-editor/ui/RowEditor/FlatItemView.tsx
|
|
6486
|
+
const FlatItemView = observer(({ item }) => {
|
|
6487
|
+
if (item.type === "node") {
|
|
6488
|
+
const Renderer = NODE_RENDERERS[item.node.rendererType];
|
|
6489
|
+
return /* @__PURE__ */ jsx(Renderer, { node: item.node });
|
|
6490
|
+
}
|
|
6491
|
+
const handleAddItem = () => {
|
|
6492
|
+
item.array.pushValue(null);
|
|
6493
|
+
};
|
|
6494
|
+
return /* @__PURE__ */ jsx(Row, {
|
|
6495
|
+
name: "",
|
|
6496
|
+
guides: item.guides,
|
|
6497
|
+
skipDot: true,
|
|
6498
|
+
skipField: true,
|
|
6499
|
+
skipMore: true,
|
|
6500
|
+
children: /* @__PURE__ */ jsx(CreateButton, {
|
|
6501
|
+
title: "Item",
|
|
6502
|
+
onClick: handleAddItem,
|
|
6503
|
+
dataTestId: `${item.array.testId}-add-button`
|
|
6504
|
+
})
|
|
6505
|
+
});
|
|
6506
|
+
});
|
|
6507
|
+
|
|
6508
|
+
//#endregion
|
|
6509
|
+
//#region src/row-editor/ui/RowEditor/RowEditor.tsx
|
|
6510
|
+
const RowEditor = observer(({ viewModel }) => {
|
|
6511
|
+
const itemContent = useCallback((_index, item) => /* @__PURE__ */ jsx(FlatItemView, { item }), []);
|
|
6512
|
+
return /* @__PURE__ */ jsx(Virtuoso, {
|
|
6513
|
+
data: viewModel.flattenedNodes,
|
|
6514
|
+
itemContent,
|
|
6515
|
+
useWindowScroll: true,
|
|
6516
|
+
style: {
|
|
6517
|
+
width: "100%",
|
|
6518
|
+
height: "100%"
|
|
6519
|
+
}
|
|
6520
|
+
});
|
|
6521
|
+
});
|
|
6522
|
+
|
|
6523
|
+
//#endregion
|
|
6524
|
+
//#region src/row-editor/ui/NodeView/NodeView.tsx
|
|
6525
|
+
const NodeView = observer(({ viewModel }) => {
|
|
6526
|
+
const Renderer = NODE_RENDERERS[viewModel.rendererType];
|
|
6527
|
+
const { showChildren, childNodes } = viewModel;
|
|
6528
|
+
const showAddButton = viewModel.isArray() && viewModel.showAddButton;
|
|
6529
|
+
const handleAddItem = useCallback(() => {
|
|
6530
|
+
if (viewModel.isArray()) viewModel.pushValue(null);
|
|
6531
|
+
}, [viewModel]);
|
|
6532
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
6533
|
+
/* @__PURE__ */ jsx(Renderer, { node: viewModel }),
|
|
6534
|
+
showChildren && /* @__PURE__ */ jsx(VStack, {
|
|
6535
|
+
align: "stretch",
|
|
6536
|
+
gap: 0,
|
|
6537
|
+
children: childNodes.map((child) => /* @__PURE__ */ jsx(NodeView, { viewModel: child }, child.id))
|
|
6538
|
+
}),
|
|
6539
|
+
showAddButton && /* @__PURE__ */ jsx(Row, {
|
|
6540
|
+
name: "",
|
|
6541
|
+
guides: [...viewModel.guides, false],
|
|
6542
|
+
skipDot: true,
|
|
6543
|
+
skipField: true,
|
|
6544
|
+
skipMore: true,
|
|
6545
|
+
children: /* @__PURE__ */ jsx(CreateButton, {
|
|
6546
|
+
title: "Item",
|
|
6547
|
+
onClick: handleAddItem,
|
|
6548
|
+
dataTestId: `${viewModel.testId}-add-button`
|
|
6549
|
+
})
|
|
6550
|
+
})
|
|
6551
|
+
] });
|
|
6552
|
+
});
|
|
6553
|
+
|
|
6554
|
+
//#endregion
|
|
6555
|
+
export { BackButton, CloseButton, ContentEditable, CopyButton, CreateButton, CreatingEditorVM, CreatingSchemaEditor, GrayButton, JsonCard, RowEditor, RowEditorVM, SchemaEditorCore, SchemaTypeIds, SearchForeignKey, SearchForeignKeyVM, SettingsButton, Tooltip, UpdatingEditorVM, UpdatingSchemaEditor, ViewerSwitcher, ViewerSwitcherMode, ensureReactivityProvider, getLabelByRef, typeMenuGroups, useContentEditable };
|
|
4589
6556
|
//# sourceMappingURL=index.mjs.map
|