@mohsinonxrm/pptb-fetchxml-studio 1.0.0 → 1.0.1
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/LICENSE +661 -0
- package/dist/assets/index-DD9fzkbz.js +232 -0
- package/dist/index.html +70 -0
- package/index.html +0 -1
- package/npm-shrinkwrap.json +6329 -0
- package/package.json +95 -51
- package/CHANGELOG.md +0 -120
- package/eslint.config.js +0 -23
- package/public/vite.svg +0 -1
- package/src/app/AppShell.tsx +0 -1733
- package/src/assets/20px-Microsoft_Office_Excel_(2025/342/200/223present).svg.png +0 -0
- package/src/assets/react.svg +0 -1
- package/src/features/fetchxml/api/dataverseMetadata.ts +0 -192
- package/src/features/fetchxml/api/excelExport.ts +0 -318
- package/src/features/fetchxml/api/formattedValues.ts +0 -107
- package/src/features/fetchxml/api/pptbClient.ts +0 -2635
- package/src/features/fetchxml/model/displaySettings.ts +0 -18
- package/src/features/fetchxml/model/fetchxml.ts +0 -346
- package/src/features/fetchxml/model/fetchxmlIntellisense.ts +0 -583
- package/src/features/fetchxml/model/fetchxmlParser.ts +0 -708
- package/src/features/fetchxml/model/layoutxml.ts +0 -372
- package/src/features/fetchxml/model/nodes.ts +0 -255
- package/src/features/fetchxml/model/operators.ts +0 -624
- package/src/features/fetchxml/model/treeUtils.ts +0 -174
- package/src/features/fetchxml/state/builderStore.tsx +0 -1160
- package/src/features/fetchxml/state/cache.ts +0 -393
- package/src/features/fetchxml/ui/Dialogs/BulkDeleteDialog.tsx +0 -352
- package/src/features/fetchxml/ui/Dialogs/DeleteConfirmDialog.tsx +0 -396
- package/src/features/fetchxml/ui/Dialogs/SaveViewDialog.tsx +0 -612
- package/src/features/fetchxml/ui/Dialogs/SolutionPicker.tsx +0 -114
- package/src/features/fetchxml/ui/Dialogs/WorkflowPickerDialog.tsx +0 -437
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/AttributeEditor.tsx +0 -214
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/ConditionEditor.tsx +0 -533
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/FetchOptionsEditor.tsx +0 -296
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/FilterEditor.tsx +0 -106
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/LinkEntityEditor.tsx +0 -433
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/OrderEditor.tsx +0 -161
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/ValueOfPicker.tsx +0 -194
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel.tsx +0 -225
- package/src/features/fetchxml/ui/LeftPane/TreeView.tsx +0 -604
- package/src/features/fetchxml/ui/RightPane/AddColumnsPanel.tsx +0 -800
- package/src/features/fetchxml/ui/RightPane/ColumnConfigDialog.tsx +0 -170
- package/src/features/fetchxml/ui/RightPane/DataGridCellRenderers.tsx +0 -356
- package/src/features/fetchxml/ui/RightPane/EditColumnsPanel.tsx +0 -372
- package/src/features/fetchxml/ui/RightPane/FetchXmlEditor.tsx +0 -399
- package/src/features/fetchxml/ui/RightPane/FormattedValueUtils.ts +0 -189
- package/src/features/fetchxml/ui/RightPane/LayoutXmlViewer.tsx +0 -171
- package/src/features/fetchxml/ui/RightPane/PreviewTabs.tsx +0 -471
- package/src/features/fetchxml/ui/RightPane/ResultsCommandBar.tsx +0 -430
- package/src/features/fetchxml/ui/RightPane/ResultsGrid.tsx +0 -983
- package/src/features/fetchxml/ui/RightPane/XmlTextArea.tsx +0 -65
- package/src/features/fetchxml/ui/Settings/SettingsDrawer.tsx +0 -175
- package/src/features/fetchxml/ui/Toolbar/EntitySelector.tsx +0 -788
- package/src/features/fetchxml/ui/Toolbar/LoadViewPicker.tsx +0 -274
- package/src/features/fetchxml/ui/Toolbar/SaveViewButton.tsx +0 -174
- package/src/main.tsx +0 -11
- package/src/shared/components/AttributePicker.tsx +0 -138
- package/src/shared/components/BetweenInputPicker.tsx +0 -120
- package/src/shared/components/BooleanValuePicker.tsx +0 -165
- package/src/shared/components/DateTimeInputPicker.tsx +0 -170
- package/src/shared/components/DynamicValueList.tsx +0 -128
- package/src/shared/components/ExcelIcon.tsx +0 -30
- package/src/shared/components/MultiValuePicker.tsx +0 -178
- package/src/shared/components/NumericInputPicker.tsx +0 -156
- package/src/shared/components/OptionSetValuePicker.tsx +0 -150
- package/src/shared/components/RelationshipPicker.tsx +0 -268
- package/src/shared/contexts/ThemeContext.tsx +0 -19
- package/src/shared/hooks/useAccessMode.ts +0 -77
- package/src/shared/hooks/useLazyMetadata.ts +0 -132
- package/src/shared/hooks/usePptbContext.ts +0 -170
- package/src/shared/hooks/usePublisherFilter.ts +0 -214
- package/src/shared/hooks/useSolutionFilter.ts +0 -162
- package/src/shared/utils/debug.ts +0 -87
- package/tsconfig.app.json +0 -28
- package/tsconfig.json +0 -7
- package/tsconfig.node.json +0 -26
- package/vite.config.ts +0 -7
|
@@ -1,194 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* ValueOf Picker Component
|
|
3
|
-
* Allows selecting a column for valueof comparison, including cross-entity columns
|
|
4
|
-
* Implements Option B: select entity/alias first, then attribute
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { useState, useEffect, useMemo } from "react";
|
|
8
|
-
import { Field, Dropdown, Option, Tooltip, makeStyles, tokens } from "@fluentui/react-components";
|
|
9
|
-
import { Info16Regular } from "@fluentui/react-icons";
|
|
10
|
-
import type { FetchNode } from "../../../../model/nodes";
|
|
11
|
-
import { collectLinkEntityReferences } from "../../../../model/treeUtils";
|
|
12
|
-
import { AttributePicker } from "../../../../../../shared/components/AttributePicker";
|
|
13
|
-
|
|
14
|
-
const useStyles = makeStyles({
|
|
15
|
-
container: {
|
|
16
|
-
display: "flex",
|
|
17
|
-
flexDirection: "column",
|
|
18
|
-
gap: tokens.spacingVerticalS,
|
|
19
|
-
},
|
|
20
|
-
fieldWithTooltip: {
|
|
21
|
-
display: "flex",
|
|
22
|
-
alignItems: "center",
|
|
23
|
-
gap: tokens.spacingHorizontalXS,
|
|
24
|
-
},
|
|
25
|
-
tooltipIcon: {
|
|
26
|
-
color: tokens.colorNeutralForeground3,
|
|
27
|
-
cursor: "help",
|
|
28
|
-
},
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
interface ValueOfPickerProps {
|
|
32
|
-
fetchQuery: FetchNode | null;
|
|
33
|
-
rootEntityName: string;
|
|
34
|
-
effectiveEntityName: string;
|
|
35
|
-
valueof: string;
|
|
36
|
-
compatibleTypes: string[];
|
|
37
|
-
onChange: (valueof: string | undefined) => void;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Parse a valueof string into entity alias and attribute parts
|
|
42
|
-
* - "createdon" -> { alias: undefined, attribute: "createdon" }
|
|
43
|
-
* - "contact_alias.modifiedon" -> { alias: "contact_alias", attribute: "modifiedon" }
|
|
44
|
-
*/
|
|
45
|
-
function parseValueOf(valueof: string): { alias: string | undefined; attribute: string } {
|
|
46
|
-
if (!valueof) {
|
|
47
|
-
return { alias: undefined, attribute: "" };
|
|
48
|
-
}
|
|
49
|
-
const dotIndex = valueof.indexOf(".");
|
|
50
|
-
if (dotIndex === -1) {
|
|
51
|
-
return { alias: undefined, attribute: valueof };
|
|
52
|
-
}
|
|
53
|
-
return {
|
|
54
|
-
alias: valueof.substring(0, dotIndex),
|
|
55
|
-
attribute: valueof.substring(dotIndex + 1),
|
|
56
|
-
};
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Build a valueof string from entity alias and attribute
|
|
61
|
-
*/
|
|
62
|
-
function buildValueOf(alias: string | undefined, attribute: string): string {
|
|
63
|
-
if (!attribute) return "";
|
|
64
|
-
if (!alias) return attribute;
|
|
65
|
-
return `${alias}.${attribute}`;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export function ValueOfPicker({
|
|
69
|
-
fetchQuery,
|
|
70
|
-
rootEntityName,
|
|
71
|
-
effectiveEntityName,
|
|
72
|
-
valueof,
|
|
73
|
-
compatibleTypes,
|
|
74
|
-
onChange,
|
|
75
|
-
}: ValueOfPickerProps) {
|
|
76
|
-
const styles = useStyles();
|
|
77
|
-
|
|
78
|
-
// Collect all available entities (root + link-entities)
|
|
79
|
-
const linkEntityReferences = useMemo(() => collectLinkEntityReferences(fetchQuery), [fetchQuery]);
|
|
80
|
-
|
|
81
|
-
// Build entity options: root entity + all link-entities
|
|
82
|
-
const entityOptions = useMemo(() => {
|
|
83
|
-
const options: Array<{ value: string; label: string; entityName: string }> = [];
|
|
84
|
-
|
|
85
|
-
// Add root entity (empty alias means root)
|
|
86
|
-
if (rootEntityName) {
|
|
87
|
-
options.push({
|
|
88
|
-
value: "", // empty means root entity
|
|
89
|
-
label: `${rootEntityName} (root)`,
|
|
90
|
-
entityName: rootEntityName,
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// Add link-entities
|
|
95
|
-
for (const ref of linkEntityReferences) {
|
|
96
|
-
options.push({
|
|
97
|
-
value: ref.identifier,
|
|
98
|
-
label: ref.displayLabel,
|
|
99
|
-
entityName: ref.entityName,
|
|
100
|
-
});
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return options;
|
|
104
|
-
}, [rootEntityName, linkEntityReferences]);
|
|
105
|
-
|
|
106
|
-
// Parse current valueof to get alias and attribute
|
|
107
|
-
const parsed = useMemo(() => parseValueOf(valueof), [valueof]);
|
|
108
|
-
|
|
109
|
-
// Track selected entity alias (empty string = root entity)
|
|
110
|
-
const [selectedAlias, setSelectedAlias] = useState<string>(parsed.alias || "");
|
|
111
|
-
|
|
112
|
-
// Get the entity name for the selected alias
|
|
113
|
-
const selectedEntityName = useMemo(() => {
|
|
114
|
-
if (selectedAlias === "") {
|
|
115
|
-
return effectiveEntityName || rootEntityName;
|
|
116
|
-
}
|
|
117
|
-
const ref = linkEntityReferences.find((r) => r.identifier === selectedAlias);
|
|
118
|
-
return ref?.entityName || "";
|
|
119
|
-
}, [selectedAlias, effectiveEntityName, rootEntityName, linkEntityReferences]);
|
|
120
|
-
|
|
121
|
-
// Sync selectedAlias when valueof changes externally (e.g., parsing FetchXML)
|
|
122
|
-
useEffect(() => {
|
|
123
|
-
setSelectedAlias(parsed.alias || "");
|
|
124
|
-
}, [parsed.alias]);
|
|
125
|
-
|
|
126
|
-
const handleEntityChange = (_ev: unknown, data: { optionValue?: string }) => {
|
|
127
|
-
const newAlias = data.optionValue ?? "";
|
|
128
|
-
setSelectedAlias(newAlias);
|
|
129
|
-
// Clear the attribute when entity changes, but keep valueof defined (empty string)
|
|
130
|
-
// to prevent the switch from reverting to literal mode
|
|
131
|
-
onChange("");
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
const handleAttributeChange = (logicalName: string) => {
|
|
135
|
-
const newValueof = buildValueOf(selectedAlias || undefined, logicalName);
|
|
136
|
-
onChange(newValueof || undefined);
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
return (
|
|
140
|
-
<div className={styles.container}>
|
|
141
|
-
{/* Entity/Alias selector */}
|
|
142
|
-
<Field label="Compare From Entity">
|
|
143
|
-
<div className={styles.fieldWithTooltip}>
|
|
144
|
-
<Dropdown
|
|
145
|
-
value={
|
|
146
|
-
entityOptions.find((o) => o.value === selectedAlias)?.label || "Select entity..."
|
|
147
|
-
}
|
|
148
|
-
selectedOptions={[selectedAlias]}
|
|
149
|
-
onOptionSelect={handleEntityChange}
|
|
150
|
-
placeholder="Select entity..."
|
|
151
|
-
>
|
|
152
|
-
{entityOptions.map((opt) => (
|
|
153
|
-
<Option key={opt.value} value={opt.value}>
|
|
154
|
-
{opt.label}
|
|
155
|
-
</Option>
|
|
156
|
-
))}
|
|
157
|
-
</Dropdown>
|
|
158
|
-
<Tooltip
|
|
159
|
-
content="Select which entity to pick the comparison column from. Use root entity for same-row comparison, or a linked entity for cross-table comparison."
|
|
160
|
-
relationship="description"
|
|
161
|
-
>
|
|
162
|
-
<Info16Regular className={styles.tooltipIcon} />
|
|
163
|
-
</Tooltip>
|
|
164
|
-
</div>
|
|
165
|
-
</Field>
|
|
166
|
-
|
|
167
|
-
{/* Attribute picker for selected entity */}
|
|
168
|
-
<Field label="Compare To Column">
|
|
169
|
-
<div className={styles.fieldWithTooltip}>
|
|
170
|
-
<AttributePicker
|
|
171
|
-
entityLogicalName={selectedEntityName}
|
|
172
|
-
value={parsed.attribute}
|
|
173
|
-
onChange={handleAttributeChange}
|
|
174
|
-
placeholder={selectedEntityName ? "Select column to compare" : "Select an entity first"}
|
|
175
|
-
disabled={!selectedEntityName}
|
|
176
|
-
filterByTypes={compatibleTypes.length > 0 ? compatibleTypes : undefined}
|
|
177
|
-
/>
|
|
178
|
-
<Tooltip
|
|
179
|
-
content={
|
|
180
|
-
compatibleTypes.length > 0
|
|
181
|
-
? `Select a column of compatible type (${compatibleTypes.join(
|
|
182
|
-
", "
|
|
183
|
-
)}) to compare against.`
|
|
184
|
-
: "Select another column to compare against."
|
|
185
|
-
}
|
|
186
|
-
relationship="description"
|
|
187
|
-
>
|
|
188
|
-
<Info16Regular className={styles.tooltipIcon} />
|
|
189
|
-
</Tooltip>
|
|
190
|
-
</div>
|
|
191
|
-
</Field>
|
|
192
|
-
</div>
|
|
193
|
-
);
|
|
194
|
-
}
|
|
@@ -1,225 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Properties panel that displays editors for the selected tree node
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { makeStyles, tokens } from "@fluentui/react-components";
|
|
6
|
-
import { debugLog } from "../../../../shared/utils/debug";
|
|
7
|
-
import type {
|
|
8
|
-
FetchNode,
|
|
9
|
-
EntityNode,
|
|
10
|
-
AttributeNode,
|
|
11
|
-
AllAttributesNode,
|
|
12
|
-
OrderNode,
|
|
13
|
-
FilterNode,
|
|
14
|
-
ConditionNode,
|
|
15
|
-
LinkEntityNode,
|
|
16
|
-
NodeId,
|
|
17
|
-
} from "../../model/nodes";
|
|
18
|
-
import { FetchOptionsEditor } from "./PropertiesPanel/editors/FetchOptionsEditor";
|
|
19
|
-
import { AttributeEditor } from "./PropertiesPanel/editors/AttributeEditor";
|
|
20
|
-
import { OrderEditor } from "./PropertiesPanel/editors/OrderEditor";
|
|
21
|
-
import { FilterEditor } from "./PropertiesPanel/editors/FilterEditor";
|
|
22
|
-
import { ConditionEditor } from "./PropertiesPanel/editors/ConditionEditor";
|
|
23
|
-
import { LinkEntityEditor } from "./PropertiesPanel/editors/LinkEntityEditor";
|
|
24
|
-
|
|
25
|
-
const useStyles = makeStyles({
|
|
26
|
-
container: {
|
|
27
|
-
overflow: "auto",
|
|
28
|
-
height: "100%",
|
|
29
|
-
minHeight: 0, // Important for flex child with overflow
|
|
30
|
-
scrollbarGutter: "stable",
|
|
31
|
-
},
|
|
32
|
-
emptyState: {
|
|
33
|
-
padding: "16px",
|
|
34
|
-
color: tokens.colorNeutralForeground3,
|
|
35
|
-
fontSize: "13px",
|
|
36
|
-
fontStyle: "italic",
|
|
37
|
-
},
|
|
38
|
-
section: {
|
|
39
|
-
padding: "16px",
|
|
40
|
-
},
|
|
41
|
-
label: {
|
|
42
|
-
display: "block",
|
|
43
|
-
fontSize: "13px",
|
|
44
|
-
fontWeight: 600,
|
|
45
|
-
marginBottom: "8px",
|
|
46
|
-
color: tokens.colorNeutralForeground2,
|
|
47
|
-
},
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
type SelectedNode =
|
|
51
|
-
| FetchNode
|
|
52
|
-
| EntityNode
|
|
53
|
-
| AttributeNode
|
|
54
|
-
| AllAttributesNode
|
|
55
|
-
| OrderNode
|
|
56
|
-
| FilterNode
|
|
57
|
-
| ConditionNode
|
|
58
|
-
| LinkEntityNode
|
|
59
|
-
| null;
|
|
60
|
-
|
|
61
|
-
interface PropertiesPanelProps {
|
|
62
|
-
selectedNode: SelectedNode;
|
|
63
|
-
fetchQuery: FetchNode | null;
|
|
64
|
-
onNodeUpdate: (nodeId: NodeId, updates: Record<string, unknown>) => void;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export function PropertiesPanel({ selectedNode, fetchQuery, onNodeUpdate }: PropertiesPanelProps) {
|
|
68
|
-
const styles = useStyles();
|
|
69
|
-
|
|
70
|
-
// Helper to find the parent entity/link-entity for a node
|
|
71
|
-
const findParentEntity = (nodeId: NodeId): string | null => {
|
|
72
|
-
if (!fetchQuery) return null;
|
|
73
|
-
|
|
74
|
-
const findInNode = (
|
|
75
|
-
node: unknown,
|
|
76
|
-
targetId: NodeId,
|
|
77
|
-
parentEntityName: string | null
|
|
78
|
-
): string | null => {
|
|
79
|
-
if (!node || typeof node !== "object") return null;
|
|
80
|
-
|
|
81
|
-
const n = node as Record<string, unknown>;
|
|
82
|
-
|
|
83
|
-
// If this is the target node, return the current parent entity name
|
|
84
|
-
if (n.id === targetId) {
|
|
85
|
-
debugLog("propertiesPanel", "Found target node:", {
|
|
86
|
-
targetId,
|
|
87
|
-
nodeType: n.type,
|
|
88
|
-
nodeName: n.name,
|
|
89
|
-
resolvedParentEntityName: parentEntityName,
|
|
90
|
-
});
|
|
91
|
-
return parentEntityName;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
// If this is an entity or link-entity, update parent name
|
|
95
|
-
// BUT only if it has a valid entity name (not a placeholder like "new_entity")
|
|
96
|
-
let currentEntityName = parentEntityName;
|
|
97
|
-
if (n.type === "entity" || n.type === "link-entity") {
|
|
98
|
-
const entityName = n.name as string;
|
|
99
|
-
// Only use the entity name if it's not a placeholder
|
|
100
|
-
if (entityName && entityName !== "new_entity") {
|
|
101
|
-
currentEntityName = entityName;
|
|
102
|
-
debugLog("propertiesPanel", "Traversing entity/link-entity:", {
|
|
103
|
-
nodeId: n.id,
|
|
104
|
-
nodeType: n.type,
|
|
105
|
-
entityName,
|
|
106
|
-
updatedCurrentEntityName: currentEntityName,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// Search in arrays
|
|
112
|
-
const arrayProps = ["attributes", "orders", "filters", "conditions", "subfilters", "links"];
|
|
113
|
-
for (const prop of arrayProps) {
|
|
114
|
-
if (Array.isArray(n[prop])) {
|
|
115
|
-
for (const item of n[prop]) {
|
|
116
|
-
const found = findInNode(item, targetId, currentEntityName);
|
|
117
|
-
if (found) return found;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Search in nested objects
|
|
123
|
-
if (n.entity) {
|
|
124
|
-
const found = findInNode(n.entity, targetId, currentEntityName);
|
|
125
|
-
if (found) return found;
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
return null;
|
|
129
|
-
};
|
|
130
|
-
|
|
131
|
-
return findInNode(fetchQuery, nodeId, fetchQuery.entity.name);
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
if (!selectedNode) {
|
|
135
|
-
return (
|
|
136
|
-
<div className={styles.container}>
|
|
137
|
-
<div className={styles.emptyState}>Select a node in the tree to view its properties</div>
|
|
138
|
-
</div>
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
const renderProperties = () => {
|
|
143
|
-
switch (selectedNode.type) {
|
|
144
|
-
case "fetch":
|
|
145
|
-
return (
|
|
146
|
-
<FetchOptionsEditor
|
|
147
|
-
node={selectedNode}
|
|
148
|
-
onUpdate={(updates) => onNodeUpdate(selectedNode.id, updates)}
|
|
149
|
-
/>
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
case "entity":
|
|
153
|
-
return (
|
|
154
|
-
<div className={styles.section}>
|
|
155
|
-
<div className={styles.label}>Entity: {selectedNode.name}</div>
|
|
156
|
-
<div className={styles.emptyState}>
|
|
157
|
-
Entity properties editor (Phase 5)
|
|
158
|
-
<br />- enableprefiltering, prefilterparametername
|
|
159
|
-
</div>
|
|
160
|
-
</div>
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
case "all-attributes":
|
|
164
|
-
return (
|
|
165
|
-
<div className={styles.section}>
|
|
166
|
-
<div className={styles.label}>All Attributes</div>
|
|
167
|
-
<div className={styles.emptyState}>All-attributes toggle (Phase 5)</div>
|
|
168
|
-
</div>
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
case "attribute":
|
|
172
|
-
return (
|
|
173
|
-
<AttributeEditor
|
|
174
|
-
node={selectedNode}
|
|
175
|
-
entityName={findParentEntity(selectedNode.id) ?? ""}
|
|
176
|
-
onUpdate={(updates) => onNodeUpdate(selectedNode.id, updates)}
|
|
177
|
-
isAggregateQuery={fetchQuery?.options.aggregate ?? false}
|
|
178
|
-
/>
|
|
179
|
-
);
|
|
180
|
-
|
|
181
|
-
case "order":
|
|
182
|
-
return (
|
|
183
|
-
<OrderEditor
|
|
184
|
-
node={selectedNode}
|
|
185
|
-
entityName={findParentEntity(selectedNode.id) ?? ""}
|
|
186
|
-
fetchQuery={fetchQuery ?? null}
|
|
187
|
-
onUpdate={(updates) => onNodeUpdate(selectedNode.id, updates)}
|
|
188
|
-
/>
|
|
189
|
-
);
|
|
190
|
-
|
|
191
|
-
case "filter":
|
|
192
|
-
return (
|
|
193
|
-
<FilterEditor
|
|
194
|
-
node={selectedNode}
|
|
195
|
-
onUpdate={(updates) => onNodeUpdate(selectedNode.id, updates)}
|
|
196
|
-
/>
|
|
197
|
-
);
|
|
198
|
-
|
|
199
|
-
case "condition":
|
|
200
|
-
return (
|
|
201
|
-
<ConditionEditor
|
|
202
|
-
node={selectedNode}
|
|
203
|
-
entityName={findParentEntity(selectedNode.id) ?? ""}
|
|
204
|
-
onUpdate={(updates) => onNodeUpdate(selectedNode.id, updates)}
|
|
205
|
-
isAggregateQuery={fetchQuery?.options.aggregate ?? false}
|
|
206
|
-
fetchQuery={fetchQuery}
|
|
207
|
-
/>
|
|
208
|
-
);
|
|
209
|
-
|
|
210
|
-
case "link-entity":
|
|
211
|
-
return (
|
|
212
|
-
<LinkEntityEditor
|
|
213
|
-
node={selectedNode}
|
|
214
|
-
parentEntityName={findParentEntity(selectedNode.id) ?? ""}
|
|
215
|
-
onUpdate={(updates) => onNodeUpdate(selectedNode.id, updates)}
|
|
216
|
-
/>
|
|
217
|
-
);
|
|
218
|
-
|
|
219
|
-
default:
|
|
220
|
-
return <div className={styles.emptyState}>Unknown node type</div>;
|
|
221
|
-
}
|
|
222
|
-
};
|
|
223
|
-
|
|
224
|
-
return <div className={styles.container}>{renderProperties()}</div>;
|
|
225
|
-
}
|