@arronqzy/react-view 1.0.5 → 1.0.7
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/styles.css +519 -9
- package/package.json +12 -4
- package/src/core/template.tsx +12 -2
- package/src/panel/ReactViewOnlinePreview.tsx +18 -8
- package/src/panel/ReactViewPanel.tsx +386 -170
- package/src/panel/ai/AssistantChatPanel.tsx +895 -0
- package/src/panel/ai/AssistantMarkdown.tsx +256 -0
- package/src/panel/ai/applyAssistantAction.ts +652 -0
- package/src/panel/ai/revealConfigField.ts +137 -0
- package/src/panel/components/ConfigHintIcon.tsx +6 -2
- package/src/panel/components/ElementsLayer.tsx +37 -18
- package/src/panel/components/MaterialSidebar.tsx +157 -109
- package/src/panel/components/MoveableLayer.tsx +7 -6
- package/src/panel/components/PanelConfigSidebar.tsx +434 -389
- package/src/panel/components/ViewElementScopePanel.tsx +9 -5
- package/src/panel/components/WorkspaceConfigSidebar.tsx +5 -2
- package/src/panel/components/WorkspaceProjectNav.tsx +25 -14
- package/src/panel/components/WorkspaceStageSplit.tsx +3 -1
- package/src/panel/components/scope-config/ScopeTemplatePreviewHost.tsx +11 -7
- package/src/panel/components/scope-config/ScopeTemplateUsageHint.tsx +6 -18
- package/src/panel/components/scope-config/ScopeTemplateWarningsPanel.tsx +5 -2
- package/src/panel/components/table/ConditionEditor.tsx +205 -0
- package/src/panel/components/table/JsonCodeEditor.tsx +115 -0
- package/src/panel/components/table/PanelConfigTableSection.tsx +2192 -0
- package/src/panel/components/table/TableNodeContent.tsx +544 -0
- package/src/panel/constants/messages.ts +76 -34
- package/src/panel/hooks/usePanelElements.ts +64 -52
- package/src/panel/hooks/useWorkspaceProjects.ts +11 -8
- package/src/panel/types.ts +4 -0
- package/src/panel/utils/panelElementDefaults.ts +69 -39
- package/src/panel/utils/scope-field-labels.ts +51 -38
- package/src/panel/utils/scope-template-preview.ts +10 -6
- package/src/panel/utils/scope-template-spread.ts +44 -21
- package/src/panel/utils/scope-template-warnings.ts +28 -16
- package/src/panel/utils/scope-template.ts +82 -2
- package/src/tailwind.css +17 -9
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useSyncExternalStore } from "react";
|
|
2
2
|
import { store, type Node, type State } from "@arronqzy/rx-store";
|
|
3
|
+
import { useI18nOptional } from "@arronqzy/i18n/react";
|
|
3
4
|
import type {
|
|
4
5
|
PanelActionResult,
|
|
5
6
|
PanelElement,
|
|
@@ -7,11 +8,14 @@ import type {
|
|
|
7
8
|
PanelLayer,
|
|
8
9
|
ReferenceCopyMode,
|
|
9
10
|
} from "../types";
|
|
11
|
+
import { getPanelMessages } from "../constants/messages";
|
|
10
12
|
import {
|
|
11
13
|
DEFAULT_LAYER,
|
|
12
14
|
DEFAULT_LAYER_ID,
|
|
13
15
|
getDefaultChartConfig,
|
|
16
|
+
getDefaultTableConfig,
|
|
14
17
|
getDefaultGridConfig,
|
|
18
|
+
getDefaultLayer,
|
|
15
19
|
getDefaultNodeName,
|
|
16
20
|
getDefaultSizeByMaterial,
|
|
17
21
|
getDefaultTextContent,
|
|
@@ -44,6 +48,10 @@ import {
|
|
|
44
48
|
export type { PanelActionResult, PanelHistoryItem, PanelLayer } from "../types";
|
|
45
49
|
|
|
46
50
|
export function usePanelElements() {
|
|
51
|
+
const { t } = useI18nOptional();
|
|
52
|
+
const messages = useMemo(() => getPanelMessages(t), [t]);
|
|
53
|
+
const defaultLayer = useMemo(() => getDefaultLayer(t), [t]);
|
|
54
|
+
|
|
47
55
|
const state = useSyncExternalStore(
|
|
48
56
|
(cb) => {
|
|
49
57
|
const sub = store.select().subscribe(cb);
|
|
@@ -52,7 +60,7 @@ export function usePanelElements() {
|
|
|
52
60
|
() => store.getState(),
|
|
53
61
|
() => store.getState()
|
|
54
62
|
) as State;
|
|
55
|
-
const rawLayers = (state.variables?.layers as PanelLayer[] | undefined) ?? [
|
|
63
|
+
const rawLayers = (state.variables?.layers as PanelLayer[] | undefined) ?? [defaultLayer];
|
|
56
64
|
const layers = useMemo(() => normalizePrimaryLayer(rawLayers), [rawLayers]);
|
|
57
65
|
const activeLayerId =
|
|
58
66
|
(state.variables?.activeLayerId as string | undefined) ?? DEFAULT_LAYER_ID;
|
|
@@ -70,8 +78,8 @@ export function usePanelElements() {
|
|
|
70
78
|
store.update((draft) => {
|
|
71
79
|
draft.variables = draft.variables ?? {};
|
|
72
80
|
draft.variables.layers = hasLayers
|
|
73
|
-
? normalizePrimaryLayer((draft.variables.layers as PanelLayer[] | undefined) ?? [
|
|
74
|
-
: [
|
|
81
|
+
? normalizePrimaryLayer((draft.variables.layers as PanelLayer[] | undefined) ?? [defaultLayer])
|
|
82
|
+
: [defaultLayer];
|
|
75
83
|
draft.variables.activeLayerId = hasActive
|
|
76
84
|
? draft.variables.activeLayerId
|
|
77
85
|
: DEFAULT_LAYER_ID;
|
|
@@ -565,14 +573,14 @@ export function usePanelElements() {
|
|
|
565
573
|
[]
|
|
566
574
|
);
|
|
567
575
|
|
|
568
|
-
const addElementFromMaterial = useCallback((materialType: string, x: number, y: number) => {
|
|
576
|
+
const addElementFromMaterial = useCallback((materialType: string, x: number, y: number): string | null => {
|
|
569
577
|
const current = store.getState();
|
|
570
578
|
const currentLayers =
|
|
571
579
|
(current.variables?.layers as PanelLayer[] | undefined) ?? [DEFAULT_LAYER];
|
|
572
580
|
const currentLayerId =
|
|
573
581
|
(current.variables?.activeLayerId as string | undefined) ?? DEFAULT_LAYER_ID;
|
|
574
582
|
const layer = currentLayers.find((l) => l.id === currentLayerId);
|
|
575
|
-
if (!layer || layer.locked) return;
|
|
583
|
+
if (!layer || layer.locked) return null;
|
|
576
584
|
|
|
577
585
|
const size = getDefaultSizeByMaterial(materialType);
|
|
578
586
|
const id = randomId("el");
|
|
@@ -581,11 +589,12 @@ export function usePanelElements() {
|
|
|
581
589
|
layerId: currentLayerId,
|
|
582
590
|
zIndex: 1,
|
|
583
591
|
materialType,
|
|
584
|
-
name: getDefaultNodeName(materialType),
|
|
585
|
-
...getDefaultTextContent(materialType),
|
|
592
|
+
name: getDefaultNodeName(materialType, t),
|
|
593
|
+
...getDefaultTextContent(materialType, t),
|
|
586
594
|
...getDefaultGridConfig(materialType),
|
|
587
595
|
refCopyMode: materialType === "reference" ? "shallow" : undefined,
|
|
588
|
-
chart: getDefaultChartConfig(materialType),
|
|
596
|
+
chart: getDefaultChartConfig(materialType, t),
|
|
597
|
+
table: getDefaultTableConfig(materialType, t),
|
|
589
598
|
geometryShape: materialType === "geometry" ? "rect" : undefined,
|
|
590
599
|
geometryColor: materialType === "geometry" ? "#3b82f6" : undefined,
|
|
591
600
|
geometryScript: undefined,
|
|
@@ -662,7 +671,7 @@ export function usePanelElements() {
|
|
|
662
671
|
},
|
|
663
672
|
{ meta: { type: "node.add", materialType, id: sourceId } }
|
|
664
673
|
);
|
|
665
|
-
return;
|
|
674
|
+
return sourceId;
|
|
666
675
|
}
|
|
667
676
|
store.update(
|
|
668
677
|
(draft) => {
|
|
@@ -676,7 +685,8 @@ export function usePanelElements() {
|
|
|
676
685
|
},
|
|
677
686
|
{ meta: { type: "node.add", materialType, id } }
|
|
678
687
|
);
|
|
679
|
-
|
|
688
|
+
return id;
|
|
689
|
+
}, [t]);
|
|
680
690
|
|
|
681
691
|
const setReferenceCopyMode = useCallback(
|
|
682
692
|
(id: string, mode: ReferenceCopyMode) => {
|
|
@@ -727,7 +737,7 @@ export function usePanelElements() {
|
|
|
727
737
|
const nextId = randomId("layer");
|
|
728
738
|
const next: PanelLayer = {
|
|
729
739
|
id: nextId,
|
|
730
|
-
name:
|
|
740
|
+
name: t("panel.defaults.layerN", { n: list.length + 1 }),
|
|
731
741
|
locked: false,
|
|
732
742
|
editable: true,
|
|
733
743
|
isPrimary: false,
|
|
@@ -740,11 +750,11 @@ export function usePanelElements() {
|
|
|
740
750
|
},
|
|
741
751
|
{ meta: { type: "layer.add" } }
|
|
742
752
|
);
|
|
743
|
-
}, []);
|
|
753
|
+
}, [t]);
|
|
744
754
|
|
|
745
755
|
const openElementsInNewLayer = useCallback((ids: string[]): PanelActionResult => {
|
|
746
756
|
const filtered = ids.filter(Boolean);
|
|
747
|
-
if (filtered.length === 0) return { ok: false, reason:
|
|
757
|
+
if (filtered.length === 0) return { ok: false, reason: messages.noNodesSelected };
|
|
748
758
|
const current = store.getState();
|
|
749
759
|
const currentLayers =
|
|
750
760
|
(current.variables?.layers as PanelLayer[] | undefined) ?? [DEFAULT_LAYER];
|
|
@@ -757,14 +767,14 @@ export function usePanelElements() {
|
|
|
757
767
|
const selected = expandedIds
|
|
758
768
|
.map((id) => nodeById.get(id))
|
|
759
769
|
.filter((el): el is PanelElement => !!el);
|
|
760
|
-
if (selected.length === 0) return { ok: false, reason:
|
|
770
|
+
if (selected.length === 0) return { ok: false, reason: messages.noMigratableNodes };
|
|
761
771
|
const anchorEl = nodeById.get(filtered[0]!) ?? selected[0];
|
|
762
772
|
const hasLocked = selected.some((el) => {
|
|
763
773
|
if (el.locked) return true;
|
|
764
774
|
const layer = currentLayers.find((l) => l.id === el.layerId);
|
|
765
775
|
return !!layer?.locked;
|
|
766
776
|
});
|
|
767
|
-
if (hasLocked) return { ok: false, reason:
|
|
777
|
+
if (hasLocked) return { ok: false, reason: messages.lockedCannotOpenMapping };
|
|
768
778
|
|
|
769
779
|
const selectedSet = new Set(selected.map((el) => el.id));
|
|
770
780
|
const idMap = new Map<string, string>();
|
|
@@ -772,7 +782,7 @@ export function usePanelElements() {
|
|
|
772
782
|
const nextLayerId = randomId("layer");
|
|
773
783
|
const nextLayer: PanelLayer = {
|
|
774
784
|
id: nextLayerId,
|
|
775
|
-
name:
|
|
785
|
+
name: t("panel.defaults.mappingLayerN", { n: currentLayers.length + 1 }),
|
|
776
786
|
locked: false,
|
|
777
787
|
editable: true,
|
|
778
788
|
isPrimary: false,
|
|
@@ -826,7 +836,7 @@ export function usePanelElements() {
|
|
|
826
836
|
}
|
|
827
837
|
);
|
|
828
838
|
return { ok: true };
|
|
829
|
-
}, []);
|
|
839
|
+
}, [messages, t]);
|
|
830
840
|
|
|
831
841
|
const renameLayer = useCallback((layerId: string, name: string) => {
|
|
832
842
|
store.update(
|
|
@@ -862,16 +872,16 @@ export function usePanelElements() {
|
|
|
862
872
|
const current = store.getState();
|
|
863
873
|
const list = (current.variables?.layers as PanelLayer[] | undefined) ?? [];
|
|
864
874
|
const target = list.find((l) => l.id === layerId);
|
|
865
|
-
if (!target) return { ok: false, reason:
|
|
866
|
-
if (!target.editable) return { ok: false, reason:
|
|
867
|
-
if (target.locked) return { ok: false, reason:
|
|
875
|
+
if (!target) return { ok: false, reason: messages.layerNotFound };
|
|
876
|
+
if (!target.editable) return { ok: false, reason: messages.defaultLayerCannotDelete };
|
|
877
|
+
if (target.locked) return { ok: false, reason: messages.lockedLayerCannotDelete };
|
|
868
878
|
if (mode === "move" && !targetLayerId) {
|
|
869
|
-
return { ok: false, reason:
|
|
879
|
+
return { ok: false, reason: messages.selectTargetLayer };
|
|
870
880
|
}
|
|
871
881
|
const remainingLayers = list.filter((l) => l.id !== layerId);
|
|
872
882
|
const moveTarget = remainingLayers.find((l) => l.id === targetLayerId);
|
|
873
883
|
if (mode === "move" && !moveTarget) {
|
|
874
|
-
return { ok: false, reason:
|
|
884
|
+
return { ok: false, reason: messages.targetLayerNotFound };
|
|
875
885
|
}
|
|
876
886
|
const allElements = (current.root.children ?? [])
|
|
877
887
|
.filter((n) => isPanelElementNode(n) && n.props)
|
|
@@ -885,7 +895,7 @@ export function usePanelElements() {
|
|
|
885
895
|
return (el.refCopyMode ?? "shallow") !== "deep";
|
|
886
896
|
});
|
|
887
897
|
if (hasBlockingRef) {
|
|
888
|
-
return { ok: false, reason:
|
|
898
|
+
return { ok: false, reason: messages.shallowRefBlockingDelete };
|
|
889
899
|
}
|
|
890
900
|
|
|
891
901
|
store.update(
|
|
@@ -924,7 +934,7 @@ export function usePanelElements() {
|
|
|
924
934
|
);
|
|
925
935
|
return { ok: true };
|
|
926
936
|
},
|
|
927
|
-
[]
|
|
937
|
+
[messages, t]
|
|
928
938
|
);
|
|
929
939
|
|
|
930
940
|
const toggleLayerMergeSelected = useCallback((layerId: string) => {
|
|
@@ -951,7 +961,9 @@ export function usePanelElements() {
|
|
|
951
961
|
const nextId = randomId("layer");
|
|
952
962
|
const nextLayer: PanelLayer = {
|
|
953
963
|
id: nextId,
|
|
954
|
-
name: name?.trim() ||
|
|
964
|
+
name: name?.trim() || t("panel.defaults.layerRandom", {
|
|
965
|
+
id: Math.random().toString(36).slice(2, 6),
|
|
966
|
+
}),
|
|
955
967
|
locked: false,
|
|
956
968
|
editable: true,
|
|
957
969
|
isPrimary: false,
|
|
@@ -978,7 +990,7 @@ export function usePanelElements() {
|
|
|
978
990
|
},
|
|
979
991
|
{ meta: { type: "layer.merge", name } }
|
|
980
992
|
);
|
|
981
|
-
}, []);
|
|
993
|
+
}, [t]);
|
|
982
994
|
|
|
983
995
|
const setPrimaryLayer = useCallback((layerId: string) => {
|
|
984
996
|
store.update(
|
|
@@ -1009,41 +1021,41 @@ export function usePanelElements() {
|
|
|
1009
1021
|
const entries = store.getHistoryEntries();
|
|
1010
1022
|
const cursor = store.getHistoryCursorIndex();
|
|
1011
1023
|
const labelByType: Record<string, string> = {
|
|
1012
|
-
initial: "
|
|
1013
|
-
"node.update": "
|
|
1014
|
-
"node.group-drag": "
|
|
1015
|
-
"node.group-resize": "
|
|
1016
|
-
"node.group-rotate": "
|
|
1017
|
-
"node.delete": "
|
|
1018
|
-
"node.batch-delete": "
|
|
1019
|
-
"node.z.front": "
|
|
1020
|
-
"node.z.back": "
|
|
1021
|
-
"node.z.up": "
|
|
1022
|
-
"node.z.down": "
|
|
1023
|
-
"node.duplicate": "
|
|
1024
|
-
"node.ref-copy-mode": "
|
|
1025
|
-
"node.add": "
|
|
1026
|
-
"layer.activate": "
|
|
1027
|
-
"layer.add": "
|
|
1028
|
-
"layer.rename": "
|
|
1029
|
-
"layer.toggle-lock": "
|
|
1030
|
-
"layer.open-selected-mapping": "
|
|
1031
|
-
"layer.delete": "
|
|
1032
|
-
"layer.toggle-merge": "
|
|
1033
|
-
"layer.merge": "
|
|
1034
|
-
"layer.set-primary": "
|
|
1035
|
-
"panel.import": "
|
|
1024
|
+
initial: t("panel.history.initial"),
|
|
1025
|
+
"node.update": t("panel.history.nodeUpdate"),
|
|
1026
|
+
"node.group-drag": t("panel.history.nodeGroupDrag"),
|
|
1027
|
+
"node.group-resize": t("panel.history.nodeGroupResize"),
|
|
1028
|
+
"node.group-rotate": t("panel.history.nodeGroupRotate"),
|
|
1029
|
+
"node.delete": t("panel.history.nodeDelete"),
|
|
1030
|
+
"node.batch-delete": t("panel.history.nodeBatchDelete"),
|
|
1031
|
+
"node.z.front": t("panel.history.nodeZFront"),
|
|
1032
|
+
"node.z.back": t("panel.history.nodeZBack"),
|
|
1033
|
+
"node.z.up": t("panel.history.nodeZUp"),
|
|
1034
|
+
"node.z.down": t("panel.history.nodeZDown"),
|
|
1035
|
+
"node.duplicate": t("panel.history.nodeDuplicate"),
|
|
1036
|
+
"node.ref-copy-mode": t("panel.history.nodeRefCopyMode"),
|
|
1037
|
+
"node.add": t("panel.history.nodeAdd"),
|
|
1038
|
+
"layer.activate": t("panel.history.layerActivate"),
|
|
1039
|
+
"layer.add": t("panel.history.layerAdd"),
|
|
1040
|
+
"layer.rename": t("panel.history.layerRename"),
|
|
1041
|
+
"layer.toggle-lock": t("panel.history.layerToggleLock"),
|
|
1042
|
+
"layer.open-selected-mapping": t("panel.history.layerOpenSelectedMapping"),
|
|
1043
|
+
"layer.delete": t("panel.history.layerDelete"),
|
|
1044
|
+
"layer.toggle-merge": t("panel.history.layerToggleMerge"),
|
|
1045
|
+
"layer.merge": t("panel.history.layerMerge"),
|
|
1046
|
+
"layer.set-primary": t("panel.history.layerSetPrimary"),
|
|
1047
|
+
"panel.import": t("panel.history.panelImport"),
|
|
1036
1048
|
};
|
|
1037
1049
|
return entries.map((entry, index) => {
|
|
1038
1050
|
const type = entry.meta?.type as string | undefined;
|
|
1039
1051
|
return {
|
|
1040
1052
|
index,
|
|
1041
1053
|
timestamp: entry.timestamp,
|
|
1042
|
-
label: (type && labelByType[type]) || "
|
|
1054
|
+
label: (type && labelByType[type]) || t("panel.history.fallback"),
|
|
1043
1055
|
active: index === cursor,
|
|
1044
1056
|
};
|
|
1045
1057
|
});
|
|
1046
|
-
}, [state]);
|
|
1058
|
+
}, [state, t]);
|
|
1047
1059
|
|
|
1048
1060
|
const exportPanelData = useCallback(() => {
|
|
1049
1061
|
const current = store.getState();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
2
|
+
import { useI18nOptional } from "@arronqzy/i18n/react";
|
|
2
3
|
import { BlueprintGraph } from "@arronqzy/react-blueprint";
|
|
3
4
|
import type { BlueprintDocument, BlueprintMetaDraft } from "@arronqzy/react-blueprint";
|
|
4
5
|
import type { State } from "@arronqzy/rx-store";
|
|
@@ -63,14 +64,15 @@ export function useWorkspaceProjects({
|
|
|
63
64
|
panelRevision,
|
|
64
65
|
onProjectApplied,
|
|
65
66
|
}: UseWorkspaceProjectsOptions) {
|
|
67
|
+
const { t } = useI18nOptional();
|
|
66
68
|
const [projects, setProjects] = useState<WorkspaceProjectListItem[]>([]);
|
|
67
69
|
const [activeProjectId, setActiveProjectId] = useState<string | null>(null);
|
|
68
70
|
const [activeProjectName, setActiveProjectName] = useState<string | null>(null);
|
|
69
71
|
const syncedSnapshotRef = useRef<WorkspaceSnapshot | null>(null);
|
|
70
72
|
|
|
71
73
|
const resolveProjectName = useCallback(() => {
|
|
72
|
-
return productName.trim() || "
|
|
73
|
-
}, [productName]);
|
|
74
|
+
return productName.trim() || t("panel.defaults.unnamedProduct");
|
|
75
|
+
}, [productName, t]);
|
|
74
76
|
|
|
75
77
|
const buildCurrentSnapshot = useCallback((): WorkspaceSnapshot => {
|
|
76
78
|
return {
|
|
@@ -115,7 +117,7 @@ export function useWorkspaceProjects({
|
|
|
115
117
|
const blueprintDocument =
|
|
116
118
|
record.blueprintDocument ?? BlueprintGraph.empty().document;
|
|
117
119
|
const blueprintMeta: BlueprintMetaDraft = {
|
|
118
|
-
name: record.blueprintMeta?.name ?? "
|
|
120
|
+
name: record.blueprintMeta?.name ?? t("panel.defaults.unnamedBlueprint"),
|
|
119
121
|
remark: record.blueprintMeta?.remark ?? "",
|
|
120
122
|
};
|
|
121
123
|
|
|
@@ -146,6 +148,7 @@ export function useWorkspaceProjects({
|
|
|
146
148
|
setBlueprintMeta,
|
|
147
149
|
setProductName,
|
|
148
150
|
setTitleIconDataUrl,
|
|
151
|
+
t,
|
|
149
152
|
]
|
|
150
153
|
);
|
|
151
154
|
|
|
@@ -206,16 +209,16 @@ export function useWorkspaceProjects({
|
|
|
206
209
|
const record = await getWorkspaceProject(id);
|
|
207
210
|
if (!record) {
|
|
208
211
|
await refreshProjects();
|
|
209
|
-
throw new Error("
|
|
212
|
+
throw new Error(t("panel.messages.workspaceNotFound"));
|
|
210
213
|
}
|
|
211
214
|
applyProjectRecord(record);
|
|
212
215
|
},
|
|
213
|
-
[applyProjectRecord, refreshProjects]
|
|
216
|
+
[applyProjectRecord, refreshProjects, t]
|
|
214
217
|
);
|
|
215
218
|
|
|
216
219
|
const handleSyncProject = useCallback(async () => {
|
|
217
220
|
if (!activeProjectId) {
|
|
218
|
-
throw new Error("
|
|
221
|
+
throw new Error(t("panel.messages.saveWorkspaceFirst"));
|
|
219
222
|
}
|
|
220
223
|
const existing = await getWorkspaceProject(activeProjectId);
|
|
221
224
|
if (!existing) {
|
|
@@ -223,7 +226,7 @@ export function useWorkspaceProjects({
|
|
|
223
226
|
setActiveProjectName(null);
|
|
224
227
|
syncedSnapshotRef.current = null;
|
|
225
228
|
await refreshProjects();
|
|
226
|
-
throw new Error("
|
|
229
|
+
throw new Error(t("panel.messages.workspaceNotFound"));
|
|
227
230
|
}
|
|
228
231
|
const name = resolveProjectName() || existing.name;
|
|
229
232
|
await persistProject({
|
|
@@ -232,7 +235,7 @@ export function useWorkspaceProjects({
|
|
|
232
235
|
createdAt: existing.createdAt,
|
|
233
236
|
});
|
|
234
237
|
return name;
|
|
235
|
-
}, [activeProjectId, persistProject, refreshProjects, resolveProjectName]);
|
|
238
|
+
}, [activeProjectId, persistProject, refreshProjects, resolveProjectName, t]);
|
|
236
239
|
|
|
237
240
|
const handleDeleteProject = useCallback(
|
|
238
241
|
async (id: string) => {
|
package/src/panel/types.ts
CHANGED
|
@@ -54,6 +54,9 @@ export type PanelElementStyle = {
|
|
|
54
54
|
|
|
55
55
|
export type ReferenceCopyMode = "shallow" | "deep";
|
|
56
56
|
|
|
57
|
+
export type { PanelTableConfig } from "@arronqzy/view-table";
|
|
58
|
+
import type { PanelTableConfig } from "@arronqzy/view-table";
|
|
59
|
+
|
|
57
60
|
export type PanelElement = {
|
|
58
61
|
id: string;
|
|
59
62
|
layerId: string;
|
|
@@ -65,6 +68,7 @@ export type PanelElement = {
|
|
|
65
68
|
refCopyMode?: ReferenceCopyMode;
|
|
66
69
|
refSnapshot?: PanelElement[];
|
|
67
70
|
chart?: PanelChartConfig;
|
|
71
|
+
table?: PanelTableConfig;
|
|
68
72
|
textHtml?: string;
|
|
69
73
|
textAllowInput?: boolean;
|
|
70
74
|
textFontFamily?: string;
|
|
@@ -1,41 +1,53 @@
|
|
|
1
|
+
import type { TranslateFn } from "@arronqzy/i18n";
|
|
2
|
+
import { tForLocale } from "@arronqzy/i18n";
|
|
1
3
|
import type { PanelChartConfig, PanelLayer } from "../types";
|
|
4
|
+
import { createDefaultTableConfig, type PanelTableConfig } from "@arronqzy/view-table";
|
|
2
5
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
6
|
+
const tFallback = tForLocale("zh-CN");
|
|
7
|
+
|
|
8
|
+
const DEFAULT_NODE_NAME_KEYS: Record<string, string> = {
|
|
9
|
+
bar: "panel.defaults.bar",
|
|
10
|
+
line: "panel.defaults.line",
|
|
11
|
+
pie: "panel.defaults.pie",
|
|
12
|
+
area: "panel.defaults.area",
|
|
13
|
+
scatter: "panel.defaults.scatter",
|
|
14
|
+
radar: "panel.defaults.radar",
|
|
15
|
+
gauge: "panel.defaults.gauge",
|
|
16
|
+
funnel: "panel.defaults.funnel",
|
|
17
|
+
text: "panel.defaults.text",
|
|
18
|
+
grid: "panel.defaults.grid",
|
|
19
|
+
image: "panel.defaults.image",
|
|
20
|
+
video: "panel.defaults.video",
|
|
21
|
+
audio: "panel.defaults.audio",
|
|
22
|
+
reference: "panel.defaults.reference",
|
|
23
|
+
geometry: "panel.defaults.geometry",
|
|
24
|
+
table: "panel.defaults.table",
|
|
19
25
|
};
|
|
20
26
|
|
|
21
27
|
export const DEFAULT_LAYER_ID = "layer-1";
|
|
22
28
|
|
|
23
|
-
export function getDefaultNodeName(materialType: string): string {
|
|
24
|
-
|
|
29
|
+
export function getDefaultNodeName(materialType: string, t: TranslateFn = tFallback): string {
|
|
30
|
+
const key = DEFAULT_NODE_NAME_KEYS[materialType];
|
|
31
|
+
return key ? t(key) : materialType;
|
|
25
32
|
}
|
|
26
33
|
|
|
27
|
-
export
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
export function getDefaultLayer(t: TranslateFn = tFallback): PanelLayer {
|
|
35
|
+
return {
|
|
36
|
+
id: DEFAULT_LAYER_ID,
|
|
37
|
+
name: t("panel.defaults.layer1"),
|
|
38
|
+
locked: false,
|
|
39
|
+
editable: false,
|
|
40
|
+
isPrimary: true,
|
|
41
|
+
isMapping: false,
|
|
42
|
+
mappingBaseLayerId: undefined,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** @deprecated Prefer getDefaultLayer(t); kept for non-React call sites */
|
|
47
|
+
export const DEFAULT_LAYER: PanelLayer = getDefaultLayer();
|
|
36
48
|
|
|
37
49
|
export function normalizePrimaryLayer(layers: PanelLayer[]): PanelLayer[] {
|
|
38
|
-
if (layers.length === 0) return [
|
|
50
|
+
if (layers.length === 0) return [getDefaultLayer()];
|
|
39
51
|
const explicitPrimary = layers.find((layer) => layer.isPrimary);
|
|
40
52
|
const primaryId = explicitPrimary?.id ?? layers[0].id;
|
|
41
53
|
return layers.map((layer) => {
|
|
@@ -68,15 +80,17 @@ export function getDefaultSizeByMaterial(materialType: string) {
|
|
|
68
80
|
return { width: 280, height: 180 };
|
|
69
81
|
case "geometry":
|
|
70
82
|
return { width: 220, height: 220 };
|
|
83
|
+
case "table":
|
|
84
|
+
return { width: 480, height: 280 };
|
|
71
85
|
default:
|
|
72
86
|
return { width: 220, height: 130 };
|
|
73
87
|
}
|
|
74
88
|
}
|
|
75
89
|
|
|
76
|
-
export function getDefaultTextContent(materialType: string) {
|
|
90
|
+
export function getDefaultTextContent(materialType: string, t: TranslateFn = tFallback) {
|
|
77
91
|
if (materialType !== "text") return {};
|
|
78
92
|
return {
|
|
79
|
-
textHtml: "
|
|
93
|
+
textHtml: `<p>${t("panel.defaults.doubleClickTextHtml")}</p>`,
|
|
80
94
|
textAllowInput: true,
|
|
81
95
|
textFontSize: 14,
|
|
82
96
|
textFontWeight: "400",
|
|
@@ -96,7 +110,10 @@ export function getDefaultGridConfig(materialType: string) {
|
|
|
96
110
|
} as const;
|
|
97
111
|
}
|
|
98
112
|
|
|
99
|
-
export function getDefaultChartConfig(
|
|
113
|
+
export function getDefaultChartConfig(
|
|
114
|
+
materialType: string,
|
|
115
|
+
t: TranslateFn = tFallback
|
|
116
|
+
): PanelChartConfig | undefined {
|
|
100
117
|
if (!["bar", "line", "pie", "area", "scatter", "radar", "gauge", "funnel"].includes(materialType))
|
|
101
118
|
return undefined;
|
|
102
119
|
const common = {
|
|
@@ -107,40 +124,40 @@ export function getDefaultChartConfig(materialType: string): PanelChartConfig |
|
|
|
107
124
|
};
|
|
108
125
|
if (materialType === "bar") {
|
|
109
126
|
return {
|
|
110
|
-
title: "
|
|
127
|
+
title: t("panel.defaults.bar"),
|
|
111
128
|
...common,
|
|
112
129
|
barWidth: 24,
|
|
113
130
|
};
|
|
114
131
|
}
|
|
115
132
|
if (materialType === "line") {
|
|
116
133
|
return {
|
|
117
|
-
title: "
|
|
134
|
+
title: t("panel.defaults.line"),
|
|
118
135
|
...common,
|
|
119
136
|
smooth: true,
|
|
120
137
|
};
|
|
121
138
|
}
|
|
122
139
|
if (materialType === "area") {
|
|
123
140
|
return {
|
|
124
|
-
title: "
|
|
141
|
+
title: t("panel.defaults.area"),
|
|
125
142
|
...common,
|
|
126
143
|
smooth: true,
|
|
127
144
|
};
|
|
128
145
|
}
|
|
129
146
|
if (materialType === "scatter") {
|
|
130
147
|
return {
|
|
131
|
-
title: "
|
|
148
|
+
title: t("panel.defaults.scatter"),
|
|
132
149
|
...common,
|
|
133
150
|
};
|
|
134
151
|
}
|
|
135
152
|
if (materialType === "radar") {
|
|
136
153
|
return {
|
|
137
|
-
title: "
|
|
154
|
+
title: t("panel.defaults.radar"),
|
|
138
155
|
...common,
|
|
139
156
|
};
|
|
140
157
|
}
|
|
141
158
|
if (materialType === "gauge") {
|
|
142
159
|
return {
|
|
143
|
-
title: "
|
|
160
|
+
title: t("panel.defaults.gauge"),
|
|
144
161
|
color: "#3b82f6",
|
|
145
162
|
renderMode: "canvas",
|
|
146
163
|
values: [68],
|
|
@@ -148,14 +165,27 @@ export function getDefaultChartConfig(materialType: string): PanelChartConfig |
|
|
|
148
165
|
}
|
|
149
166
|
if (materialType === "funnel") {
|
|
150
167
|
return {
|
|
151
|
-
title: "
|
|
168
|
+
title: t("panel.defaults.funnel"),
|
|
152
169
|
...common,
|
|
153
170
|
};
|
|
154
171
|
}
|
|
155
172
|
return {
|
|
156
|
-
title: "
|
|
173
|
+
title: t("panel.defaults.pie"),
|
|
157
174
|
...common,
|
|
158
175
|
pieInnerRadius: 30,
|
|
159
176
|
pieOuterRadius: 65,
|
|
160
177
|
};
|
|
161
178
|
}
|
|
179
|
+
|
|
180
|
+
export function getDefaultTableConfig(
|
|
181
|
+
materialType: string,
|
|
182
|
+
t: TranslateFn = tFallback
|
|
183
|
+
): PanelTableConfig | undefined {
|
|
184
|
+
if (materialType !== "table") return undefined;
|
|
185
|
+
const cfg = createDefaultTableConfig();
|
|
186
|
+
cfg.emptyText = t("panel.config.tableEmpty");
|
|
187
|
+
if (cfg.columns?.[0]) cfg.columns[0].title = t("panel.config.tableColName");
|
|
188
|
+
if (cfg.columns?.[1]) cfg.columns[1].title = t("panel.config.tableColStatus");
|
|
189
|
+
if (cfg.columns?.[2]) cfg.columns[2].title = t("panel.config.tableColScore");
|
|
190
|
+
return cfg;
|
|
191
|
+
}
|