@mohsinonxrm/pptb-fetchxml-studio 1.0.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/CHANGELOG.md +120 -0
- package/README.md +250 -0
- package/eslint.config.js +23 -0
- package/index.html +71 -0
- package/package.json +53 -0
- package/public/vite.svg +1 -0
- package/src/app/AppShell.tsx +1733 -0
- package/src/assets/20px-Microsoft_Office_Excel_(2025/342/200/223present).svg.png +0 -0
- package/src/assets/react.svg +1 -0
- package/src/features/fetchxml/api/dataverseMetadata.ts +192 -0
- package/src/features/fetchxml/api/excelExport.ts +318 -0
- package/src/features/fetchxml/api/formattedValues.ts +107 -0
- package/src/features/fetchxml/api/pptbClient.ts +2635 -0
- package/src/features/fetchxml/model/displaySettings.ts +18 -0
- package/src/features/fetchxml/model/fetchxml.ts +346 -0
- package/src/features/fetchxml/model/fetchxmlIntellisense.ts +583 -0
- package/src/features/fetchxml/model/fetchxmlParser.ts +708 -0
- package/src/features/fetchxml/model/layoutxml.ts +372 -0
- package/src/features/fetchxml/model/nodes.ts +255 -0
- package/src/features/fetchxml/model/operators.ts +624 -0
- package/src/features/fetchxml/model/treeUtils.ts +174 -0
- package/src/features/fetchxml/state/builderStore.tsx +1160 -0
- package/src/features/fetchxml/state/cache.ts +393 -0
- package/src/features/fetchxml/ui/Dialogs/BulkDeleteDialog.tsx +352 -0
- package/src/features/fetchxml/ui/Dialogs/DeleteConfirmDialog.tsx +396 -0
- package/src/features/fetchxml/ui/Dialogs/SaveViewDialog.tsx +612 -0
- package/src/features/fetchxml/ui/Dialogs/SolutionPicker.tsx +114 -0
- package/src/features/fetchxml/ui/Dialogs/WorkflowPickerDialog.tsx +437 -0
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/AttributeEditor.tsx +214 -0
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/ConditionEditor.tsx +533 -0
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/FetchOptionsEditor.tsx +296 -0
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/FilterEditor.tsx +106 -0
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/LinkEntityEditor.tsx +433 -0
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/OrderEditor.tsx +161 -0
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/ValueOfPicker.tsx +194 -0
- package/src/features/fetchxml/ui/LeftPane/PropertiesPanel.tsx +225 -0
- package/src/features/fetchxml/ui/LeftPane/TreeView.tsx +604 -0
- package/src/features/fetchxml/ui/RightPane/AddColumnsPanel.tsx +800 -0
- package/src/features/fetchxml/ui/RightPane/ColumnConfigDialog.tsx +170 -0
- package/src/features/fetchxml/ui/RightPane/DataGridCellRenderers.tsx +356 -0
- package/src/features/fetchxml/ui/RightPane/EditColumnsPanel.tsx +372 -0
- package/src/features/fetchxml/ui/RightPane/FetchXmlEditor.tsx +399 -0
- package/src/features/fetchxml/ui/RightPane/FormattedValueUtils.ts +189 -0
- package/src/features/fetchxml/ui/RightPane/LayoutXmlViewer.tsx +171 -0
- package/src/features/fetchxml/ui/RightPane/PreviewTabs.tsx +471 -0
- package/src/features/fetchxml/ui/RightPane/ResultsCommandBar.tsx +430 -0
- package/src/features/fetchxml/ui/RightPane/ResultsGrid.tsx +983 -0
- package/src/features/fetchxml/ui/RightPane/XmlTextArea.tsx +65 -0
- package/src/features/fetchxml/ui/Settings/SettingsDrawer.tsx +175 -0
- package/src/features/fetchxml/ui/Toolbar/EntitySelector.tsx +788 -0
- package/src/features/fetchxml/ui/Toolbar/LoadViewPicker.tsx +274 -0
- package/src/features/fetchxml/ui/Toolbar/SaveViewButton.tsx +174 -0
- package/src/main.tsx +11 -0
- package/src/shared/components/AttributePicker.tsx +138 -0
- package/src/shared/components/BetweenInputPicker.tsx +120 -0
- package/src/shared/components/BooleanValuePicker.tsx +165 -0
- package/src/shared/components/DateTimeInputPicker.tsx +170 -0
- package/src/shared/components/DynamicValueList.tsx +128 -0
- package/src/shared/components/ExcelIcon.tsx +30 -0
- package/src/shared/components/MultiValuePicker.tsx +178 -0
- package/src/shared/components/NumericInputPicker.tsx +156 -0
- package/src/shared/components/OptionSetValuePicker.tsx +150 -0
- package/src/shared/components/RelationshipPicker.tsx +268 -0
- package/src/shared/contexts/ThemeContext.tsx +19 -0
- package/src/shared/hooks/useAccessMode.ts +77 -0
- package/src/shared/hooks/useLazyMetadata.ts +132 -0
- package/src/shared/hooks/usePptbContext.ts +170 -0
- package/src/shared/hooks/usePublisherFilter.ts +214 -0
- package/src/shared/hooks/useSolutionFilter.ts +162 -0
- package/src/shared/utils/debug.ts +87 -0
- package/tsconfig.app.json +28 -0
- package/tsconfig.json +7 -0
- package/tsconfig.node.json +26 -0
- package/vite.config.ts +7 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Property editor for Attribute nodes
|
|
3
|
+
* Controls column selection, aliases, aggregation, and grouping
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
Field,
|
|
8
|
+
Input,
|
|
9
|
+
Dropdown,
|
|
10
|
+
Option,
|
|
11
|
+
Checkbox,
|
|
12
|
+
Label,
|
|
13
|
+
Tooltip,
|
|
14
|
+
makeStyles,
|
|
15
|
+
tokens,
|
|
16
|
+
} from "@fluentui/react-components";
|
|
17
|
+
import { Info16Regular } from "@fluentui/react-icons";
|
|
18
|
+
import type { AttributeNode } from "../../../../model/nodes";
|
|
19
|
+
import { AttributePicker } from "../../../../../../shared/components/AttributePicker";
|
|
20
|
+
|
|
21
|
+
const useStyles = makeStyles({
|
|
22
|
+
container: {
|
|
23
|
+
display: "flex",
|
|
24
|
+
flexDirection: "column",
|
|
25
|
+
gap: tokens.spacingVerticalM,
|
|
26
|
+
padding: tokens.spacingVerticalM,
|
|
27
|
+
},
|
|
28
|
+
section: {
|
|
29
|
+
display: "flex",
|
|
30
|
+
flexDirection: "column",
|
|
31
|
+
gap: tokens.spacingVerticalS,
|
|
32
|
+
},
|
|
33
|
+
fieldWithTooltip: {
|
|
34
|
+
display: "flex",
|
|
35
|
+
alignItems: "center",
|
|
36
|
+
gap: tokens.spacingHorizontalXS,
|
|
37
|
+
},
|
|
38
|
+
tooltipIcon: {
|
|
39
|
+
color: tokens.colorNeutralForeground3,
|
|
40
|
+
cursor: "help",
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
interface AttributeEditorProps {
|
|
45
|
+
node: AttributeNode;
|
|
46
|
+
entityName: string;
|
|
47
|
+
onUpdate: (updates: Record<string, unknown>) => void;
|
|
48
|
+
isAggregateQuery?: boolean; // Whether parent fetch has aggregate=true
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function AttributeEditor({
|
|
52
|
+
node,
|
|
53
|
+
entityName,
|
|
54
|
+
onUpdate,
|
|
55
|
+
isAggregateQuery = false,
|
|
56
|
+
}: AttributeEditorProps) {
|
|
57
|
+
const styles = useStyles();
|
|
58
|
+
|
|
59
|
+
const handleTextChange = (field: string) => (_: unknown, data: { value: string }) => {
|
|
60
|
+
let value = data.value;
|
|
61
|
+
// For alias field, remove spaces (aliases cannot contain spaces)
|
|
62
|
+
if (field === "alias") {
|
|
63
|
+
value = value.replace(/\s/g, "");
|
|
64
|
+
}
|
|
65
|
+
onUpdate({ [field]: value || undefined });
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const handleCheckboxChange =
|
|
69
|
+
(field: string) => (_: unknown, data: { checked: boolean | "mixed" }) => {
|
|
70
|
+
onUpdate({ [field]: data.checked === true ? true : undefined });
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const handleDropdownChange = (field: string) => (_: unknown, data: { optionValue?: string }) => {
|
|
74
|
+
onUpdate({ [field]: data.optionValue || undefined });
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
return (
|
|
78
|
+
<div className={styles.container}>
|
|
79
|
+
{/* Basic Properties */}
|
|
80
|
+
<div className={styles.section}>
|
|
81
|
+
<Label weight="semibold">Attribute Properties</Label>
|
|
82
|
+
|
|
83
|
+
<Field label="Attribute Name" required>
|
|
84
|
+
<div className={styles.fieldWithTooltip}>
|
|
85
|
+
<AttributePicker
|
|
86
|
+
entityLogicalName={entityName}
|
|
87
|
+
value={node.name}
|
|
88
|
+
onChange={(logicalName) => onUpdate({ name: logicalName })}
|
|
89
|
+
placeholder="Select or type attribute name"
|
|
90
|
+
/>
|
|
91
|
+
<Tooltip
|
|
92
|
+
content="Logical name of the attribute/column to retrieve from the entity."
|
|
93
|
+
relationship="description"
|
|
94
|
+
>
|
|
95
|
+
<Info16Regular className={styles.tooltipIcon} />
|
|
96
|
+
</Tooltip>
|
|
97
|
+
</div>
|
|
98
|
+
</Field>
|
|
99
|
+
|
|
100
|
+
<Field label="Alias (optional)">
|
|
101
|
+
<div className={styles.fieldWithTooltip}>
|
|
102
|
+
<Input
|
|
103
|
+
value={node.alias ?? ""}
|
|
104
|
+
onChange={handleTextChange("alias")}
|
|
105
|
+
placeholder="e.g., account_name, total_value"
|
|
106
|
+
/>
|
|
107
|
+
<Tooltip
|
|
108
|
+
content="Optional alias for the column in results. Useful for aggregate queries or when joining multiple entities."
|
|
109
|
+
relationship="description"
|
|
110
|
+
>
|
|
111
|
+
<Info16Regular className={styles.tooltipIcon} />
|
|
112
|
+
</Tooltip>
|
|
113
|
+
</div>
|
|
114
|
+
</Field>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
{/* Aggregation Section (only show if parent fetch has aggregate=true) */}
|
|
118
|
+
{isAggregateQuery && (
|
|
119
|
+
<div className={styles.section}>
|
|
120
|
+
<Label weight="semibold">Aggregation</Label>
|
|
121
|
+
|
|
122
|
+
<Field label="Aggregate Function">
|
|
123
|
+
<div className={styles.fieldWithTooltip}>
|
|
124
|
+
<Dropdown
|
|
125
|
+
value={node.aggregate ?? "none"}
|
|
126
|
+
selectedOptions={[node.aggregate ?? "none"]}
|
|
127
|
+
onOptionSelect={handleDropdownChange("aggregate")}
|
|
128
|
+
placeholder="None"
|
|
129
|
+
>
|
|
130
|
+
<Option value="none">None</Option>
|
|
131
|
+
<Option value="count">Count</Option>
|
|
132
|
+
<Option value="countcolumn">Count Column (non-null)</Option>
|
|
133
|
+
<Option value="sum">Sum</Option>
|
|
134
|
+
<Option value="avg">Average</Option>
|
|
135
|
+
<Option value="min">Minimum</Option>
|
|
136
|
+
<Option value="max">Maximum</Option>
|
|
137
|
+
<Option value="rowaggregate">Row Aggregate</Option>
|
|
138
|
+
</Dropdown>
|
|
139
|
+
<Tooltip
|
|
140
|
+
content="Aggregate function to apply. SUM/AVG only work with numeric types. COUNT works with all types."
|
|
141
|
+
relationship="description"
|
|
142
|
+
>
|
|
143
|
+
<Info16Regular className={styles.tooltipIcon} />
|
|
144
|
+
</Tooltip>
|
|
145
|
+
</div>
|
|
146
|
+
</Field>
|
|
147
|
+
|
|
148
|
+
<Field>
|
|
149
|
+
<div className={styles.fieldWithTooltip}>
|
|
150
|
+
<Checkbox
|
|
151
|
+
checked={node.groupby ?? false}
|
|
152
|
+
onChange={handleCheckboxChange("groupby")}
|
|
153
|
+
label="Group By"
|
|
154
|
+
/>
|
|
155
|
+
<Tooltip
|
|
156
|
+
content="Include this attribute in GROUP BY clause. Required for non-aggregated columns in aggregate queries."
|
|
157
|
+
relationship="description"
|
|
158
|
+
>
|
|
159
|
+
<Info16Regular className={styles.tooltipIcon} />
|
|
160
|
+
</Tooltip>
|
|
161
|
+
</div>
|
|
162
|
+
</Field>
|
|
163
|
+
</div>
|
|
164
|
+
)}
|
|
165
|
+
|
|
166
|
+
{/* DateTime Grouping Section */}
|
|
167
|
+
<div className={styles.section}>
|
|
168
|
+
<Label weight="semibold">DateTime Options</Label>
|
|
169
|
+
|
|
170
|
+
<Field label="Date Grouping (for datetime attributes)">
|
|
171
|
+
<div className={styles.fieldWithTooltip}>
|
|
172
|
+
<Dropdown
|
|
173
|
+
value={node.dategrouping ?? "none"}
|
|
174
|
+
selectedOptions={[node.dategrouping ?? "none"]}
|
|
175
|
+
onOptionSelect={handleDropdownChange("dategrouping")}
|
|
176
|
+
placeholder="None"
|
|
177
|
+
>
|
|
178
|
+
<Option value="none">None</Option>
|
|
179
|
+
<Option value="day">Day</Option>
|
|
180
|
+
<Option value="week">Week</Option>
|
|
181
|
+
<Option value="month">Month</Option>
|
|
182
|
+
<Option value="quarter">Quarter</Option>
|
|
183
|
+
<Option value="year">Year</Option>
|
|
184
|
+
<Option value="fiscal-period">Fiscal Period</Option>
|
|
185
|
+
<Option value="fiscal-year">Fiscal Year</Option>
|
|
186
|
+
</Dropdown>
|
|
187
|
+
<Tooltip
|
|
188
|
+
content="Group datetime values by time period. Only applicable to datetime attributes."
|
|
189
|
+
relationship="description"
|
|
190
|
+
>
|
|
191
|
+
<Info16Regular className={styles.tooltipIcon} />
|
|
192
|
+
</Tooltip>
|
|
193
|
+
</div>
|
|
194
|
+
</Field>
|
|
195
|
+
|
|
196
|
+
<Field>
|
|
197
|
+
<div className={styles.fieldWithTooltip}>
|
|
198
|
+
<Checkbox
|
|
199
|
+
checked={node.usertimezone ?? false}
|
|
200
|
+
onChange={handleCheckboxChange("usertimezone")}
|
|
201
|
+
label="Convert to User's Timezone"
|
|
202
|
+
/>
|
|
203
|
+
<Tooltip
|
|
204
|
+
content="Convert datetime values from UTC to the user's timezone. Only for datetime attributes."
|
|
205
|
+
relationship="description"
|
|
206
|
+
>
|
|
207
|
+
<Info16Regular className={styles.tooltipIcon} />
|
|
208
|
+
</Tooltip>
|
|
209
|
+
</div>
|
|
210
|
+
</Field>
|
|
211
|
+
</div>
|
|
212
|
+
</div>
|
|
213
|
+
);
|
|
214
|
+
}
|