@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.
Files changed (77) hide show
  1. package/LICENSE +661 -0
  2. package/dist/assets/index-DD9fzkbz.js +232 -0
  3. package/dist/index.html +70 -0
  4. package/index.html +0 -1
  5. package/npm-shrinkwrap.json +6329 -0
  6. package/package.json +95 -51
  7. package/CHANGELOG.md +0 -120
  8. package/eslint.config.js +0 -23
  9. package/public/vite.svg +0 -1
  10. package/src/app/AppShell.tsx +0 -1733
  11. package/src/assets/20px-Microsoft_Office_Excel_(2025/342/200/223present).svg.png +0 -0
  12. package/src/assets/react.svg +0 -1
  13. package/src/features/fetchxml/api/dataverseMetadata.ts +0 -192
  14. package/src/features/fetchxml/api/excelExport.ts +0 -318
  15. package/src/features/fetchxml/api/formattedValues.ts +0 -107
  16. package/src/features/fetchxml/api/pptbClient.ts +0 -2635
  17. package/src/features/fetchxml/model/displaySettings.ts +0 -18
  18. package/src/features/fetchxml/model/fetchxml.ts +0 -346
  19. package/src/features/fetchxml/model/fetchxmlIntellisense.ts +0 -583
  20. package/src/features/fetchxml/model/fetchxmlParser.ts +0 -708
  21. package/src/features/fetchxml/model/layoutxml.ts +0 -372
  22. package/src/features/fetchxml/model/nodes.ts +0 -255
  23. package/src/features/fetchxml/model/operators.ts +0 -624
  24. package/src/features/fetchxml/model/treeUtils.ts +0 -174
  25. package/src/features/fetchxml/state/builderStore.tsx +0 -1160
  26. package/src/features/fetchxml/state/cache.ts +0 -393
  27. package/src/features/fetchxml/ui/Dialogs/BulkDeleteDialog.tsx +0 -352
  28. package/src/features/fetchxml/ui/Dialogs/DeleteConfirmDialog.tsx +0 -396
  29. package/src/features/fetchxml/ui/Dialogs/SaveViewDialog.tsx +0 -612
  30. package/src/features/fetchxml/ui/Dialogs/SolutionPicker.tsx +0 -114
  31. package/src/features/fetchxml/ui/Dialogs/WorkflowPickerDialog.tsx +0 -437
  32. package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/AttributeEditor.tsx +0 -214
  33. package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/ConditionEditor.tsx +0 -533
  34. package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/FetchOptionsEditor.tsx +0 -296
  35. package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/FilterEditor.tsx +0 -106
  36. package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/LinkEntityEditor.tsx +0 -433
  37. package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/OrderEditor.tsx +0 -161
  38. package/src/features/fetchxml/ui/LeftPane/PropertiesPanel/editors/ValueOfPicker.tsx +0 -194
  39. package/src/features/fetchxml/ui/LeftPane/PropertiesPanel.tsx +0 -225
  40. package/src/features/fetchxml/ui/LeftPane/TreeView.tsx +0 -604
  41. package/src/features/fetchxml/ui/RightPane/AddColumnsPanel.tsx +0 -800
  42. package/src/features/fetchxml/ui/RightPane/ColumnConfigDialog.tsx +0 -170
  43. package/src/features/fetchxml/ui/RightPane/DataGridCellRenderers.tsx +0 -356
  44. package/src/features/fetchxml/ui/RightPane/EditColumnsPanel.tsx +0 -372
  45. package/src/features/fetchxml/ui/RightPane/FetchXmlEditor.tsx +0 -399
  46. package/src/features/fetchxml/ui/RightPane/FormattedValueUtils.ts +0 -189
  47. package/src/features/fetchxml/ui/RightPane/LayoutXmlViewer.tsx +0 -171
  48. package/src/features/fetchxml/ui/RightPane/PreviewTabs.tsx +0 -471
  49. package/src/features/fetchxml/ui/RightPane/ResultsCommandBar.tsx +0 -430
  50. package/src/features/fetchxml/ui/RightPane/ResultsGrid.tsx +0 -983
  51. package/src/features/fetchxml/ui/RightPane/XmlTextArea.tsx +0 -65
  52. package/src/features/fetchxml/ui/Settings/SettingsDrawer.tsx +0 -175
  53. package/src/features/fetchxml/ui/Toolbar/EntitySelector.tsx +0 -788
  54. package/src/features/fetchxml/ui/Toolbar/LoadViewPicker.tsx +0 -274
  55. package/src/features/fetchxml/ui/Toolbar/SaveViewButton.tsx +0 -174
  56. package/src/main.tsx +0 -11
  57. package/src/shared/components/AttributePicker.tsx +0 -138
  58. package/src/shared/components/BetweenInputPicker.tsx +0 -120
  59. package/src/shared/components/BooleanValuePicker.tsx +0 -165
  60. package/src/shared/components/DateTimeInputPicker.tsx +0 -170
  61. package/src/shared/components/DynamicValueList.tsx +0 -128
  62. package/src/shared/components/ExcelIcon.tsx +0 -30
  63. package/src/shared/components/MultiValuePicker.tsx +0 -178
  64. package/src/shared/components/NumericInputPicker.tsx +0 -156
  65. package/src/shared/components/OptionSetValuePicker.tsx +0 -150
  66. package/src/shared/components/RelationshipPicker.tsx +0 -268
  67. package/src/shared/contexts/ThemeContext.tsx +0 -19
  68. package/src/shared/hooks/useAccessMode.ts +0 -77
  69. package/src/shared/hooks/useLazyMetadata.ts +0 -132
  70. package/src/shared/hooks/usePptbContext.ts +0 -170
  71. package/src/shared/hooks/usePublisherFilter.ts +0 -214
  72. package/src/shared/hooks/useSolutionFilter.ts +0 -162
  73. package/src/shared/utils/debug.ts +0 -87
  74. package/tsconfig.app.json +0 -28
  75. package/tsconfig.json +0 -7
  76. package/tsconfig.node.json +0 -26
  77. package/vite.config.ts +0 -7
@@ -1,170 +0,0 @@
1
- /**
2
- * Column Configuration Dialog
3
- * Allows users to reorder columns by moving them up/down
4
- */
5
-
6
- import { useState, useCallback, useEffect } from "react";
7
- import {
8
- Dialog,
9
- DialogSurface,
10
- DialogTitle,
11
- DialogBody,
12
- DialogContent,
13
- DialogActions,
14
- Button,
15
- makeStyles,
16
- tokens,
17
- } from "@fluentui/react-components";
18
- import { ArrowUp24Regular, ArrowDown24Regular } from "@fluentui/react-icons";
19
- import type { LayoutColumn } from "../../model/layoutxml";
20
-
21
- const useStyles = makeStyles({
22
- columnList: {
23
- display: "flex",
24
- flexDirection: "column",
25
- gap: tokens.spacingVerticalXS,
26
- maxHeight: "400px",
27
- overflowY: "auto",
28
- padding: tokens.spacingVerticalS,
29
- border: `1px solid ${tokens.colorNeutralStroke1}`,
30
- borderRadius: tokens.borderRadiusMedium,
31
- },
32
- columnItem: {
33
- display: "flex",
34
- alignItems: "center",
35
- justifyContent: "space-between",
36
- padding: `${tokens.spacingVerticalS} ${tokens.spacingHorizontalM}`,
37
- backgroundColor: tokens.colorNeutralBackground1,
38
- border: `1px solid ${tokens.colorNeutralStroke2}`,
39
- borderRadius: tokens.borderRadiusSmall,
40
- "&:hover": {
41
- backgroundColor: tokens.colorNeutralBackground1Hover,
42
- },
43
- },
44
- columnName: {
45
- flex: 1,
46
- overflow: "hidden",
47
- textOverflow: "ellipsis",
48
- whiteSpace: "nowrap",
49
- },
50
- buttonGroup: {
51
- display: "flex",
52
- gap: tokens.spacingHorizontalXS,
53
- },
54
- indexBadge: {
55
- minWidth: "24px",
56
- textAlign: "center",
57
- color: tokens.colorNeutralForeground3,
58
- fontSize: tokens.fontSizeBase200,
59
- marginRight: tokens.spacingHorizontalS,
60
- },
61
- });
62
-
63
- interface ColumnConfigDialogProps {
64
- /** Whether the dialog is open */
65
- open: boolean;
66
- /** Columns to display for reordering */
67
- columns: LayoutColumn[];
68
- /** Called when dialog is closed without applying */
69
- onClose: () => void;
70
- /** Called when Apply is clicked with the new column order */
71
- onReorder: (columns: LayoutColumn[]) => void;
72
- }
73
-
74
- export function ColumnConfigDialog({ open, columns, onClose, onReorder }: ColumnConfigDialogProps) {
75
- const styles = useStyles();
76
- const [localColumns, setLocalColumns] = useState<LayoutColumn[]>([]);
77
-
78
- // Initialize local state when dialog opens or columns change
79
- useEffect(() => {
80
- if (open && columns.length > 0) {
81
- setLocalColumns([...columns]);
82
- }
83
- }, [open, columns]);
84
-
85
- const moveColumn = useCallback((index: number, direction: "up" | "down") => {
86
- setLocalColumns((prev) => {
87
- const newColumns = [...prev];
88
- const targetIndex = direction === "up" ? index - 1 : index + 1;
89
-
90
- if (targetIndex < 0 || targetIndex >= newColumns.length) {
91
- return prev;
92
- }
93
-
94
- // Swap columns
95
- [newColumns[index], newColumns[targetIndex]] = [newColumns[targetIndex], newColumns[index]];
96
- return newColumns;
97
- });
98
- }, []);
99
-
100
- const handleApply = useCallback(() => {
101
- onReorder(localColumns);
102
- }, [localColumns, onReorder]);
103
-
104
- if (columns.length === 0) {
105
- return null;
106
- }
107
-
108
- return (
109
- <Dialog open={open} onOpenChange={(_e, data) => !data.open && onClose()}>
110
- <DialogSurface>
111
- <DialogBody>
112
- <DialogTitle>Configure Columns</DialogTitle>
113
- <DialogContent>
114
- <p
115
- style={{
116
- marginBottom: tokens.spacingVerticalM,
117
- color: tokens.colorNeutralForeground2,
118
- }}
119
- >
120
- Use the arrow buttons to reorder columns. Changes apply when you click Apply.
121
- </p>
122
- <div className={styles.columnList}>
123
- {localColumns.map((column, index) => (
124
- <div key={column.name} className={styles.columnItem}>
125
- <span className={styles.indexBadge}>{index + 1}</span>
126
- <span className={styles.columnName}>{column.displayName || column.name}</span>
127
- <span
128
- style={{
129
- color: tokens.colorNeutralForeground3,
130
- fontSize: tokens.fontSizeBase200,
131
- marginRight: tokens.spacingHorizontalS,
132
- }}
133
- >
134
- {column.width}px
135
- </span>
136
- <div className={styles.buttonGroup}>
137
- <Button
138
- appearance="subtle"
139
- size="small"
140
- icon={<ArrowUp24Regular />}
141
- disabled={index === 0}
142
- onClick={() => moveColumn(index, "up")}
143
- title="Move up"
144
- />
145
- <Button
146
- appearance="subtle"
147
- size="small"
148
- icon={<ArrowDown24Regular />}
149
- disabled={index === localColumns.length - 1}
150
- onClick={() => moveColumn(index, "down")}
151
- title="Move down"
152
- />
153
- </div>
154
- </div>
155
- ))}
156
- </div>
157
- </DialogContent>
158
- <DialogActions>
159
- <Button appearance="secondary" onClick={onClose}>
160
- Cancel
161
- </Button>
162
- <Button appearance="primary" onClick={handleApply}>
163
- Apply
164
- </Button>
165
- </DialogActions>
166
- </DialogBody>
167
- </DialogSurface>
168
- </Dialog>
169
- );
170
- }
@@ -1,356 +0,0 @@
1
- /**
2
- * Rich cell renderers for different attribute types in DataGrid
3
- * Renders values using appropriate Fluent UI v9 components
4
- * Prefers formatted values from OData annotations when available
5
- */
6
-
7
- import { Switch, Badge, Label, SkeletonItem, makeStyles, tokens } from "@fluentui/react-components";
8
- import type { AttributeMetadata } from "../../api/pptbClient";
9
-
10
- const useStyles = makeStyles({
11
- booleanCell: {
12
- display: "flex",
13
- alignItems: "center",
14
- gap: tokens.spacingHorizontalXS,
15
- },
16
- lookupCell: {
17
- display: "flex",
18
- flexDirection: "column",
19
- gap: "2px",
20
- },
21
- lookupName: {
22
- fontSize: tokens.fontSizeBase200,
23
- fontWeight: tokens.fontWeightSemibold,
24
- },
25
- lookupType: {
26
- fontSize: tokens.fontSizeBase100,
27
- color: tokens.colorNeutralForeground3,
28
- },
29
- numberCell: {
30
- textAlign: "right",
31
- fontVariantNumeric: "tabular-nums",
32
- },
33
- dateCell: {
34
- fontVariantNumeric: "tabular-nums",
35
- },
36
- picklistCell: {
37
- display: "flex",
38
- alignItems: "center",
39
- },
40
- });
41
-
42
- /**
43
- * Render a boolean/two-option value as a read-only Switch
44
- * Uses formatted value from OData annotations if available
45
- */
46
- export function BooleanCellRenderer({
47
- value,
48
- formattedValue,
49
- attribute,
50
- }: {
51
- value: unknown;
52
- formattedValue?: unknown;
53
- attribute?: AttributeMetadata;
54
- }) {
55
- const styles = useStyles();
56
- const boolValue = Boolean(value);
57
-
58
- // Prefer formatted value, otherwise use metadata labels
59
- const displayValue =
60
- formattedValue ||
61
- (boolValue
62
- ? attribute?.OptionSet?.TrueOption?.Label?.UserLocalizedLabel?.Label || "Yes"
63
- : attribute?.OptionSet?.FalseOption?.Label?.UserLocalizedLabel?.Label || "No");
64
-
65
- return (
66
- <div className={styles.booleanCell}>
67
- <Switch checked={boolValue} disabled />
68
- <Label size="small">{String(displayValue)}</Label>
69
- </div>
70
- );
71
- }
72
-
73
- /**
74
- * Render a picklist/state/status value as a Badge
75
- * Uses formatted value from OData annotations if available
76
- */
77
- export function PicklistCellRenderer({
78
- value,
79
- formattedValue,
80
- attribute,
81
- }: {
82
- value: unknown;
83
- formattedValue?: unknown;
84
- attribute?: AttributeMetadata;
85
- }) {
86
- const styles = useStyles();
87
-
88
- // Prefer formatted value
89
- if (formattedValue) {
90
- const appearance =
91
- attribute?.AttributeType === "State" || attribute?.AttributeType === "Status"
92
- ? "filled"
93
- : "tint";
94
- return (
95
- <div className={styles.picklistCell}>
96
- <Badge appearance={appearance}>{String(formattedValue)}</Badge>
97
- </div>
98
- );
99
- }
100
-
101
- // Fallback to raw value with metadata lookup
102
- const numValue = typeof value === "number" ? value : parseInt(String(value), 10);
103
-
104
- if (isNaN(numValue)) {
105
- return <span>—</span>;
106
- }
107
-
108
- // Find the option label from metadata
109
- const option = attribute?.OptionSet?.Options?.find((opt) => opt.Value === numValue);
110
- const label = option?.Label?.UserLocalizedLabel?.Label || String(numValue);
111
-
112
- // Use different badge colors for different states
113
- const appearance =
114
- attribute?.AttributeType === "State" || attribute?.AttributeType === "Status"
115
- ? "filled"
116
- : "tint";
117
-
118
- return (
119
- <div className={styles.picklistCell}>
120
- <Badge appearance={appearance}>{label}</Badge>
121
- </div>
122
- );
123
- }
124
-
125
- /**
126
- * Render a lookup/customer/owner value
127
- * Uses formatted value from OData annotations (preferred)
128
- */
129
- export function LookupCellRenderer({
130
- value,
131
- formattedValue,
132
- }: {
133
- value: unknown;
134
- formattedValue?: unknown;
135
- }) {
136
- const styles = useStyles();
137
-
138
- // Prefer formatted value (just the name string)
139
- if (formattedValue) {
140
- return <span className={styles.lookupName}>{String(formattedValue)}</span>;
141
- }
142
-
143
- // Fallback to raw value (structured object)
144
- if (!value || typeof value !== "object") {
145
- return <span>—</span>;
146
- }
147
-
148
- const lookupValue = value as { Id?: string; Name?: string; LogicalName?: string };
149
-
150
- return (
151
- <div className={styles.lookupCell}>
152
- <span className={styles.lookupName}>{lookupValue.Name || "—"}</span>
153
- {lookupValue.LogicalName && (
154
- <span className={styles.lookupType}>{lookupValue.LogicalName}</span>
155
- )}
156
- </div>
157
- );
158
- }
159
-
160
- /**
161
- * Render a numeric value (integer, decimal, money)
162
- * Uses formatted value from OData annotations if available
163
- */
164
- export function NumberCellRenderer({
165
- value,
166
- formattedValue,
167
- attribute,
168
- }: {
169
- value: unknown;
170
- formattedValue?: unknown;
171
- attribute?: AttributeMetadata;
172
- }) {
173
- const styles = useStyles();
174
-
175
- // Prefer formatted value (already includes currency symbol, etc.)
176
- if (formattedValue) {
177
- return <span className={styles.numberCell}>{String(formattedValue)}</span>;
178
- }
179
-
180
- // Fallback to manual formatting
181
- if (value === null || value === undefined || value === "") {
182
- return <span>—</span>;
183
- }
184
-
185
- const numValue = typeof value === "number" ? value : parseFloat(String(value));
186
-
187
- if (isNaN(numValue)) {
188
- return <span>—</span>;
189
- }
190
-
191
- // Format based on attribute type
192
- if (attribute?.AttributeType === "Money") {
193
- // Format as currency (would need locale info for proper currency symbol)
194
- return (
195
- <span className={styles.numberCell}>
196
- $
197
- {numValue.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 })}
198
- </span>
199
- );
200
- }
201
-
202
- if (attribute?.AttributeType === "Integer" || attribute?.AttributeType === "BigInt") {
203
- return <span className={styles.numberCell}>{numValue.toLocaleString()}</span>;
204
- }
205
-
206
- // Decimal/Double - use precision from metadata if available
207
- const precision = attribute?.Precision ?? 2;
208
- return (
209
- <span className={styles.numberCell}>
210
- {numValue.toLocaleString(undefined, {
211
- minimumFractionDigits: 0,
212
- maximumFractionDigits: precision,
213
- })}
214
- </span>
215
- );
216
- }
217
-
218
- /**
219
- * Render a date/time value
220
- * Uses formatted value from OData annotations if available
221
- */
222
- export function DateTimeCellRenderer({
223
- value,
224
- formattedValue,
225
- attribute,
226
- }: {
227
- value: unknown;
228
- formattedValue?: unknown;
229
- attribute?: AttributeMetadata;
230
- }) {
231
- const styles = useStyles();
232
-
233
- // Prefer formatted value
234
- if (formattedValue) {
235
- return <span className={styles.dateCell}>{String(formattedValue)}</span>;
236
- }
237
-
238
- // Fallback to manual formatting
239
- if (!value) {
240
- return <span>—</span>;
241
- }
242
-
243
- const dateValue = new Date(String(value));
244
-
245
- if (isNaN(dateValue.getTime())) {
246
- return <span>—</span>;
247
- }
248
-
249
- // Check if DateOnly format
250
- const isDateOnly =
251
- attribute?.Format === "DateOnly" || attribute?.DateTimeBehavior?.Value === "DateOnly";
252
-
253
- if (isDateOnly) {
254
- return (
255
- <span className={styles.dateCell}>
256
- {dateValue.toLocaleDateString(undefined, {
257
- year: "numeric",
258
- month: "short",
259
- day: "numeric",
260
- })}
261
- </span>
262
- );
263
- }
264
-
265
- // Full date-time
266
- return (
267
- <span className={styles.dateCell}>
268
- {dateValue.toLocaleString(undefined, {
269
- year: "numeric",
270
- month: "short",
271
- day: "numeric",
272
- hour: "2-digit",
273
- minute: "2-digit",
274
- })}
275
- </span>
276
- );
277
- }
278
-
279
- /**
280
- * Default text renderer for strings and other types
281
- * Uses formatted value from OData annotations if available
282
- */
283
- export function TextCellRenderer({
284
- value,
285
- formattedValue,
286
- }: {
287
- value: unknown;
288
- formattedValue?: unknown;
289
- }) {
290
- // Prefer formatted value
291
- const displayValue = formattedValue ?? value;
292
-
293
- if (displayValue === null || displayValue === undefined || displayValue === "") {
294
- return <span>—</span>;
295
- }
296
-
297
- return <span>{String(displayValue)}</span>;
298
- }
299
-
300
- /**
301
- * Loading skeleton for virtualized cells
302
- */
303
- export function LoadingCellRenderer() {
304
- return <SkeletonItem />;
305
- }
306
-
307
- /**
308
- * Get the appropriate cell renderer for an attribute type
309
- * Now accepts formatted value from OData annotations
310
- */
311
- export function getCellRenderer(
312
- attributeType: string | undefined,
313
- value: unknown,
314
- formattedValue: unknown | undefined,
315
- attribute?: AttributeMetadata
316
- ) {
317
- if (value === null || value === undefined) {
318
- return <span>—</span>;
319
- }
320
-
321
- switch (attributeType) {
322
- case "Boolean":
323
- return (
324
- <BooleanCellRenderer value={value} formattedValue={formattedValue} attribute={attribute} />
325
- );
326
-
327
- case "Picklist":
328
- case "State":
329
- case "Status":
330
- return (
331
- <PicklistCellRenderer value={value} formattedValue={formattedValue} attribute={attribute} />
332
- );
333
-
334
- case "Lookup":
335
- case "Customer":
336
- case "Owner":
337
- return <LookupCellRenderer value={value} formattedValue={formattedValue} />;
338
-
339
- case "Integer":
340
- case "BigInt":
341
- case "Decimal":
342
- case "Double":
343
- case "Money":
344
- return (
345
- <NumberCellRenderer value={value} formattedValue={formattedValue} attribute={attribute} />
346
- );
347
-
348
- case "DateTime":
349
- return (
350
- <DateTimeCellRenderer value={value} formattedValue={formattedValue} attribute={attribute} />
351
- );
352
-
353
- default:
354
- return <TextCellRenderer value={value} formattedValue={formattedValue} />;
355
- }
356
- }