@firecms/core 3.0.1 → 3.1.0-canary.24c8270

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 (186) hide show
  1. package/README.md +1 -1
  2. package/dist/components/AIIcon.d.ts +16 -0
  3. package/dist/components/EntityCollectionTable/EntityCollectionRowActions.d.ts +7 -1
  4. package/dist/components/EntityCollectionTable/EntityCollectionTable.d.ts +1 -1
  5. package/dist/components/EntityCollectionTable/EntityCollectionTableProps.d.ts +14 -0
  6. package/dist/components/EntityCollectionTable/PropertyTableCell.d.ts +6 -0
  7. package/dist/components/EntityCollectionTable/internal/CollectionTableToolbar.d.ts +5 -4
  8. package/dist/components/EntityCollectionTable/internal/EntityTableCell.d.ts +6 -0
  9. package/dist/components/EntityCollectionTable/internal/popup_field/useDraggable.d.ts +2 -2
  10. package/dist/components/EntityCollectionView/Board.d.ts +2 -0
  11. package/dist/components/EntityCollectionView/BoardColumn.d.ts +42 -0
  12. package/dist/components/EntityCollectionView/BoardColumnTitle.d.ts +9 -0
  13. package/dist/components/EntityCollectionView/BoardSortableList.d.ts +14 -0
  14. package/dist/components/EntityCollectionView/EntityBoardCard.d.ts +26 -0
  15. package/dist/components/EntityCollectionView/EntityCard.d.ts +19 -0
  16. package/dist/components/EntityCollectionView/EntityCollectionBoardView.d.ts +20 -0
  17. package/dist/components/EntityCollectionView/EntityCollectionCardView.d.ts +31 -0
  18. package/dist/components/EntityCollectionView/EntityCollectionViewActions.d.ts +2 -2
  19. package/dist/components/EntityCollectionView/EntityCollectionViewStartActions.d.ts +7 -3
  20. package/dist/components/EntityCollectionView/FiltersDialog.d.ts +14 -0
  21. package/dist/components/EntityCollectionView/ViewModeToggle.d.ts +44 -0
  22. package/dist/components/EntityCollectionView/board_types.d.ts +105 -0
  23. package/dist/components/EntityCollectionView/useBoardDataController.d.ts +60 -0
  24. package/dist/components/ErrorBoundary.d.ts +1 -1
  25. package/dist/components/SelectableTable/SelectableTable.d.ts +5 -1
  26. package/dist/components/SelectableTable/filters/DateTimeFilterField.d.ts +2 -1
  27. package/dist/components/VirtualTable/VirtualTableCell.d.ts +6 -0
  28. package/dist/components/VirtualTable/VirtualTableHeader.d.ts +3 -1
  29. package/dist/components/VirtualTable/VirtualTableHeaderRow.d.ts +1 -1
  30. package/dist/components/VirtualTable/VirtualTableProps.d.ts +11 -0
  31. package/dist/components/VirtualTable/fields/VirtualTableDateField.d.ts +1 -0
  32. package/dist/components/VirtualTable/types.d.ts +2 -0
  33. package/dist/components/index.d.ts +3 -0
  34. package/dist/contexts/index.d.ts +10 -0
  35. package/dist/core/DrawerNavigationGroup.d.ts +45 -0
  36. package/dist/core/index.d.ts +1 -0
  37. package/dist/form/components/ErrorFocus.d.ts +1 -1
  38. package/dist/form/validation.d.ts +3 -2
  39. package/dist/hooks/useBreadcrumbsController.d.ts +16 -0
  40. package/dist/hooks/useCollapsedGroups.d.ts +4 -1
  41. package/dist/index.es.js +5316 -1592
  42. package/dist/index.es.js.map +1 -1
  43. package/dist/index.umd.js +5309 -1586
  44. package/dist/index.umd.js.map +1 -1
  45. package/dist/internal/useRestoreScroll.d.ts +1 -1
  46. package/dist/preview/PropertyPreviewProps.d.ts +5 -0
  47. package/dist/preview/components/DatePreview.d.ts +13 -3
  48. package/dist/preview/components/ImagePreview.d.ts +5 -1
  49. package/dist/preview/components/StorageThumbnail.d.ts +2 -1
  50. package/dist/preview/components/UrlComponentPreview.d.ts +2 -1
  51. package/dist/preview/property_previews/ArrayOfStorageComponentsPreview.d.ts +1 -1
  52. package/dist/preview/property_previews/ArrayOfStringsPreview.d.ts +1 -1
  53. package/dist/preview/property_previews/SkeletonPropertyComponent.d.ts +1 -1
  54. package/dist/types/analytics.d.ts +1 -1
  55. package/dist/types/collections.d.ts +50 -2
  56. package/dist/types/datasource.d.ts +0 -1
  57. package/dist/types/plugins.d.ts +62 -1
  58. package/dist/types/properties.d.ts +259 -4
  59. package/dist/util/__tests__/conditions.test.d.ts +1 -0
  60. package/dist/util/__tests__/objects.test.d.ts +1 -0
  61. package/dist/util/conditions.d.ts +26 -0
  62. package/dist/util/entities.d.ts +2 -3
  63. package/dist/util/index.d.ts +2 -1
  64. package/dist/util/property_utils.d.ts +2 -1
  65. package/dist/util/resolutions.d.ts +3 -3
  66. package/package.json +14 -11
  67. package/src/app/Scaffold.tsx +14 -15
  68. package/src/components/AIIcon.tsx +39 -0
  69. package/src/components/ArrayContainer.tsx +1 -4
  70. package/src/components/ClearFilterSortButton.tsx +19 -16
  71. package/src/components/ConfirmationDialog.tsx +0 -2
  72. package/src/components/DeleteEntityDialog.tsx +2 -4
  73. package/src/components/EntityCollectionTable/EntityCollectionRowActions.tsx +74 -41
  74. package/src/components/EntityCollectionTable/EntityCollectionTable.tsx +130 -79
  75. package/src/components/EntityCollectionTable/EntityCollectionTableProps.tsx +121 -104
  76. package/src/components/EntityCollectionTable/PropertyTableCell.tsx +132 -103
  77. package/src/components/EntityCollectionTable/internal/CollectionTableToolbar.tsx +20 -42
  78. package/src/components/EntityCollectionTable/internal/EntityTableCell.tsx +90 -49
  79. package/src/components/EntityCollectionTable/internal/EntityTableCellActions.tsx +1 -1
  80. package/src/components/EntityCollectionTable/internal/popup_field/useDraggable.tsx +11 -11
  81. package/src/components/EntityCollectionView/Board.tsx +324 -0
  82. package/src/components/EntityCollectionView/BoardColumn.tsx +158 -0
  83. package/src/components/EntityCollectionView/BoardColumnTitle.tsx +45 -0
  84. package/src/components/EntityCollectionView/BoardSortableList.tsx +172 -0
  85. package/src/components/EntityCollectionView/EntityBoardCard.tsx +212 -0
  86. package/src/components/EntityCollectionView/EntityCard.tsx +235 -0
  87. package/src/components/EntityCollectionView/EntityCollectionBoardView.tsx +733 -0
  88. package/src/components/EntityCollectionView/EntityCollectionCardView.tsx +244 -0
  89. package/src/components/EntityCollectionView/EntityCollectionView.tsx +519 -203
  90. package/src/components/EntityCollectionView/EntityCollectionViewActions.tsx +31 -19
  91. package/src/components/EntityCollectionView/EntityCollectionViewStartActions.tsx +84 -15
  92. package/src/components/EntityCollectionView/FiltersDialog.tsx +249 -0
  93. package/src/components/EntityCollectionView/ViewModeToggle.tsx +199 -0
  94. package/src/components/EntityCollectionView/board_types.ts +113 -0
  95. package/src/components/EntityCollectionView/useBoardDataController.tsx +490 -0
  96. package/src/components/ErrorTooltip.tsx +2 -1
  97. package/src/components/HomePage/DefaultHomePage.tsx +47 -10
  98. package/src/components/HomePage/HomePageDnD.tsx +56 -41
  99. package/src/components/HomePage/NavigationCard.tsx +20 -18
  100. package/src/components/HomePage/NavigationGroup.tsx +17 -16
  101. package/src/components/HomePage/RenameGroupDialog.tsx +0 -2
  102. package/src/components/HomePage/SmallNavigationCard.tsx +10 -9
  103. package/src/components/ReferenceTable/ReferenceSelectionTable.tsx +3 -10
  104. package/src/components/ReferenceWidget.tsx +2 -4
  105. package/src/components/SelectableTable/SelectableTable.tsx +75 -67
  106. package/src/components/SelectableTable/filters/BooleanFilterField.tsx +7 -6
  107. package/src/components/SelectableTable/filters/DateTimeFilterField.tsx +39 -40
  108. package/src/components/SelectableTable/filters/ReferenceFilterField.tsx +38 -38
  109. package/src/components/SelectableTable/filters/StringNumberFilterField.tsx +49 -58
  110. package/src/components/UnsavedChangesDialog.tsx +0 -2
  111. package/src/components/UserDisplay.tsx +4 -4
  112. package/src/components/VirtualTable/VirtualTable.tsx +272 -118
  113. package/src/components/VirtualTable/VirtualTableCell.tsx +18 -2
  114. package/src/components/VirtualTable/VirtualTableHeader.tsx +59 -50
  115. package/src/components/VirtualTable/VirtualTableHeaderRow.tsx +158 -42
  116. package/src/components/VirtualTable/VirtualTableProps.tsx +14 -1
  117. package/src/components/VirtualTable/VirtualTableRow.tsx +1 -1
  118. package/src/components/VirtualTable/fields/VirtualTableDateField.tsx +3 -0
  119. package/src/components/VirtualTable/fields/VirtualTableSelect.tsx +19 -6
  120. package/src/components/VirtualTable/types.tsx +2 -0
  121. package/src/components/common/useColumnsIds.tsx +95 -3
  122. package/src/components/common/useDataSourceTableController.tsx +21 -4
  123. package/src/components/index.tsx +4 -0
  124. package/src/contexts/BreacrumbsContext.tsx +15 -8
  125. package/src/contexts/index.ts +10 -0
  126. package/src/core/DefaultAppBar.tsx +40 -27
  127. package/src/core/DefaultDrawer.tsx +42 -56
  128. package/src/core/DrawerNavigationGroup.tsx +118 -0
  129. package/src/core/DrawerNavigationItem.tsx +4 -3
  130. package/src/core/EntityEditView.tsx +41 -43
  131. package/src/core/EntitySidePanel.tsx +28 -26
  132. package/src/core/SideDialogs.tsx +4 -2
  133. package/src/core/field_configs.tsx +14 -9
  134. package/src/core/index.tsx +1 -0
  135. package/src/form/EntityForm.tsx +69 -60
  136. package/src/form/PropertyFieldBinding.tsx +61 -46
  137. package/src/form/components/ErrorFocus.tsx +3 -3
  138. package/src/form/components/StorageItemPreview.tsx +2 -1
  139. package/src/form/field_bindings/ArrayOfReferencesFieldBinding.tsx +0 -1
  140. package/src/form/field_bindings/DateTimeFieldBinding.tsx +17 -16
  141. package/src/form/field_bindings/KeyValueFieldBinding.tsx +0 -1
  142. package/src/form/field_bindings/MapFieldBinding.tsx +69 -67
  143. package/src/form/field_bindings/MarkdownEditorFieldBinding.tsx +22 -18
  144. package/src/form/field_bindings/StorageUploadFieldBinding.tsx +83 -83
  145. package/src/form/field_bindings/TextFieldBinding.tsx +71 -35
  146. package/src/form/validation.ts +245 -160
  147. package/src/hooks/useBreadcrumbsController.tsx +18 -0
  148. package/src/hooks/useBuildNavigationController.tsx +71 -28
  149. package/src/hooks/useCollapsedGroups.ts +12 -4
  150. package/src/hooks/useValidateAuthenticator.tsx +1 -1
  151. package/src/internal/useBuildDataSource.ts +68 -34
  152. package/src/internal/useBuildSideDialogsController.tsx +11 -8
  153. package/src/internal/useBuildSideEntityController.tsx +24 -24
  154. package/src/internal/useRestoreScroll.tsx +26 -14
  155. package/src/preview/PropertyPreview.tsx +41 -32
  156. package/src/preview/PropertyPreviewProps.tsx +6 -0
  157. package/src/preview/components/DatePreview.tsx +72 -4
  158. package/src/preview/components/EmptyValue.tsx +1 -1
  159. package/src/preview/components/ImagePreview.tsx +37 -21
  160. package/src/preview/components/StorageThumbnail.tsx +16 -12
  161. package/src/preview/components/UrlComponentPreview.tsx +28 -25
  162. package/src/preview/property_previews/ArrayOfStorageComponentsPreview.tsx +9 -7
  163. package/src/preview/property_previews/ArrayOfStringsPreview.tsx +11 -9
  164. package/src/preview/property_previews/ArrayPropertyPreview.tsx +26 -24
  165. package/src/preview/property_previews/SkeletonPropertyComponent.tsx +61 -56
  166. package/src/routes/CustomCMSRoute.tsx +1 -0
  167. package/src/routes/FireCMSRoute.tsx +26 -13
  168. package/src/types/analytics.ts +10 -0
  169. package/src/types/collections.ts +57 -3
  170. package/src/types/datasource.ts +54 -56
  171. package/src/types/plugins.tsx +69 -1
  172. package/src/types/properties.ts +347 -27
  173. package/src/util/__tests__/conditions.test.ts +506 -0
  174. package/src/util/__tests__/objects.test.ts +196 -0
  175. package/src/util/callbacks.ts +6 -3
  176. package/src/util/collections.ts +51 -6
  177. package/src/util/conditions.ts +339 -0
  178. package/src/util/entities.ts +29 -30
  179. package/src/util/entity_cache.ts +2 -1
  180. package/src/util/index.ts +2 -1
  181. package/src/util/join_collections.ts +10 -8
  182. package/src/util/objects.ts +31 -13
  183. package/src/util/{references.ts → previews.ts} +16 -2
  184. package/src/util/property_utils.tsx +37 -11
  185. package/src/util/resolutions.ts +62 -58
  186. /package/dist/util/{references.d.ts → previews.d.ts} +0 -0
@@ -10,11 +10,11 @@ interface BooleanFieldProps {
10
10
  }
11
11
 
12
12
  export function BooleanFilterField({
13
- name,
14
- title,
15
- value,
16
- setValue
17
- }: BooleanFieldProps) {
13
+ name,
14
+ title,
15
+ value,
16
+ setValue
17
+ }: BooleanFieldProps) {
18
18
 
19
19
  function updateFilter(val?: boolean) {
20
20
  if (val !== undefined) {
@@ -32,8 +32,9 @@ export function BooleanFilterField({
32
32
  const valueSet = !!value;
33
33
 
34
34
  return (
35
- <div className="w-[300px]">
35
+ <div className="w-full">
36
36
  <BooleanSwitchWithLabel
37
+ size={"medium"}
37
38
  value={valueSetToTrue}
38
39
  allowIndeterminate={true}
39
40
  onValueChange={(v: boolean | null) => updateFilter(v === null ? undefined : v)}
@@ -1,6 +1,6 @@
1
1
  import React, { useState } from "react";
2
2
  import { VirtualTableWhereFilterOp } from "../../VirtualTable";
3
- import { Checkbox, DateTimeField, Label, Select, SelectItem } from "@firecms/ui";
3
+ import { DateTimeField, Select, SelectItem } from "@firecms/ui";
4
4
  import { useCustomizationController } from "../../../hooks";
5
5
 
6
6
  interface DateTimeFilterFieldProps {
@@ -10,9 +10,10 @@ interface DateTimeFilterFieldProps {
10
10
  setValue: (value?: [op: VirtualTableWhereFilterOp, newValue: any]) => void;
11
11
  isArray?: boolean;
12
12
  title?: string;
13
+ timezone?: string;
13
14
  }
14
15
 
15
- const operationLabels: Record<VirtualTableWhereFilterOp, string> = {
16
+ const operationLabels: Record<VirtualTableWhereFilterOp | "is-null", string> = {
16
17
  "==": "==",
17
18
  "!=": "!=",
18
19
  ">": ">",
@@ -22,30 +23,42 @@ const operationLabels: Record<VirtualTableWhereFilterOp, string> = {
22
23
  "not-in": "not in",
23
24
  in: "in",
24
25
  "array-contains": "Contains",
25
- "array-contains-any": "Any"
26
+ "array-contains-any": "Any",
27
+ "is-null": "Is null"
26
28
  };
27
29
 
28
30
  const multipleSelectOperations = ["array-contains-any", "in"];
29
31
 
30
32
  export function DateTimeFilterField({
31
- name,
32
- isArray,
33
- mode,
34
- value,
35
- setValue,
36
- title
37
- }: DateTimeFilterFieldProps) {
33
+ name,
34
+ isArray,
35
+ mode,
36
+ value,
37
+ setValue,
38
+ title,
39
+ timezone
40
+ }: DateTimeFilterFieldProps) {
38
41
 
39
42
  const { locale } = useCustomizationController();
40
- const possibleOperations: (keyof typeof operationLabels) [] = isArray
43
+ const possibleOperations: (keyof typeof operationLabels)[] = isArray
41
44
  ? ["array-contains"]
42
- : ["==", "!=", ">", "<", ">=", "<="];
45
+ : ["==", "!=", ">", "<", ">=", "<=", "is-null"];
43
46
 
44
47
  const [fieldOperation, fieldValue] = value || [possibleOperations[0], undefined];
45
- const [operation, setOperation] = useState<VirtualTableWhereFilterOp>(fieldOperation);
48
+ const [operation, setOperation] = useState<VirtualTableWhereFilterOp | "is-null">(fieldOperation === "==" && fieldValue === null ? "is-null" : fieldOperation);
46
49
  const [internalValue, setInternalValue] = useState<Date | null | undefined>(fieldValue);
47
50
 
48
- function updateFilter(op: VirtualTableWhereFilterOp, val: Date | undefined | null) {
51
+ const isNullOperation = operation === "is-null";
52
+
53
+ function updateFilter(op: VirtualTableWhereFilterOp | "is-null", val: Date | undefined | null) {
54
+ // Handle "is null" operation
55
+ if (op === "is-null") {
56
+ setOperation(op);
57
+ setInternalValue(null);
58
+ setValue(["==", null]);
59
+ return;
60
+ }
61
+
49
62
  let newValue: Date | null | undefined = val;
50
63
  const prevOpIsArray = multipleSelectOperations.includes(operation);
51
64
  const newOpIsArray = multipleSelectOperations.includes(op);
@@ -73,15 +86,15 @@ export function DateTimeFilterField({
73
86
 
74
87
  return (
75
88
 
76
- <div className="flex w-[440px]">
77
- <div className="w-[80px]">
89
+ <div className="flex w-full">
90
+ <div className="w-[100px]">
78
91
  <Select value={operation}
79
- size={"large"}
80
- fullWidth={true}
81
- onValueChange={(value) => {
82
- updateFilter(value as VirtualTableWhereFilterOp, internalValue);
83
- }}
84
- renderValue={(op) => operationLabels[op as VirtualTableWhereFilterOp]}>
92
+ size={"medium"}
93
+ fullWidth={true}
94
+ onValueChange={(value) => {
95
+ updateFilter(value as VirtualTableWhereFilterOp | "is-null", internalValue);
96
+ }}
97
+ renderValue={(op) => operationLabels[op as keyof typeof operationLabels]}>
85
98
  {possibleOperations.map((op) => (
86
99
  <SelectItem key={op} value={op}>
87
100
  {operationLabels[op]}
@@ -94,31 +107,17 @@ export function DateTimeFilterField({
94
107
 
95
108
  <DateTimeField
96
109
  mode={mode}
97
- size={"large"}
110
+ size={"medium"}
98
111
  locale={locale}
99
- disabled={internalValue === null}
100
- value={internalValue ?? undefined}
112
+ timezone={timezone}
113
+ disabled={isNullOperation}
114
+ value={isNullOperation ? undefined : (internalValue ?? undefined)}
101
115
  onChange={(dateValue: Date | null) => {
102
116
  updateFilter(operation, dateValue === null ? undefined : dateValue);
103
117
  }}
104
118
  clearable={true}
105
119
  />
106
120
 
107
- <Label
108
- className="border cursor-pointer rounded-md p-2 flex items-center gap-2 [&:has(:checked)]:bg-surface-100 dark:[&:has(:checked)]:bg-surface-800"
109
- htmlFor="null-filter"
110
- >
111
- <Checkbox id="null-filter"
112
- checked={internalValue === null}
113
- size={"small"}
114
- onCheckedChange={(checked) => {
115
- if (internalValue !== null)
116
- updateFilter(operation, null);
117
- else updateFilter(operation, undefined);
118
- }}/>
119
- Filter for null values
120
- </Label>
121
-
122
121
  </div>
123
122
 
124
123
  </div>
@@ -35,16 +35,16 @@ const operationLabels = {
35
35
  const multipleSelectOperations = ["array-contains-any", "in", "not-in"];
36
36
 
37
37
  export function ReferenceFilterField({
38
- value,
39
- setValue,
40
- isArray,
41
- path,
42
- includeId = true,
43
- previewProperties,
44
- setHidden
45
- }: ReferenceFilterFieldProps) {
46
-
47
- const possibleOperations: (keyof typeof operationLabels) [] = isArray
38
+ value,
39
+ setValue,
40
+ isArray,
41
+ path,
42
+ includeId = true,
43
+ previewProperties,
44
+ setHidden
45
+ }: ReferenceFilterFieldProps) {
46
+
47
+ const possibleOperations: (keyof typeof operationLabels)[] = isArray
48
48
  ? ["array-contains"]
49
49
  : ["==", "!=", ">", "<", ">=", "<="];
50
50
 
@@ -110,16 +110,16 @@ export function ReferenceFilterField({
110
110
  const multiple = multipleSelectOperations.includes(operation);
111
111
 
112
112
  const referenceDialogController = useReferenceDialog({
113
- multiselect: multiple,
114
- path,
115
- collection,
116
- onSingleEntitySelected,
117
- onMultipleEntitiesSelected,
118
- selectedEntityIds,
119
- onClose: () => {
120
- setHidden(false);
121
- }
113
+ multiselect: multiple,
114
+ path,
115
+ collection,
116
+ onSingleEntitySelected,
117
+ onMultipleEntitiesSelected,
118
+ selectedEntityIds,
119
+ onClose: () => {
120
+ setHidden(false);
122
121
  }
122
+ }
123
123
  );
124
124
 
125
125
  const doOpenDialog = () => {
@@ -144,15 +144,15 @@ export function ReferenceFilterField({
144
144
 
145
145
  return (
146
146
 
147
- <div className="flex w-[480px] flex-row">
148
- <div className="w-[140px]">
147
+ <div className="flex w-full flex-row">
148
+ <div className="w-[100px]">
149
149
  <Select value={operation}
150
- size={"large"}
151
- fullWidth={true}
152
- onValueChange={(value) => {
153
- updateFilter(value as VirtualTableWhereFilterOp, internalValue);
154
- }}
155
- renderValue={(op) => operationLabels[op as VirtualTableWhereFilterOp]}>
150
+ size={"medium"}
151
+ fullWidth={true}
152
+ onValueChange={(value) => {
153
+ updateFilter(value as VirtualTableWhereFilterOp, internalValue);
154
+ }}
155
+ renderValue={(op) => operationLabels[op as VirtualTableWhereFilterOp]}>
156
156
  {possibleOperations.map((op) => (
157
157
  <SelectItem key={op} value={op}>
158
158
  {operationLabels[op]}
@@ -161,7 +161,7 @@ export function ReferenceFilterField({
161
161
  </Select>
162
162
  </div>
163
163
 
164
- <div className="flex-grow ml-2 h-full gap-2 flex flex-col w-[340px]">
164
+ <div className="flex-grow ml-2 h-full gap-2 flex flex-col">
165
165
 
166
166
  {internalValue && Array.isArray(internalValue) && <div>
167
167
  {internalValue.map((ref, index) => buildEntry(ref))}
@@ -173,9 +173,9 @@ export function ReferenceFilterField({
173
173
 
174
174
  {(!internalValue || (Array.isArray(internalValue) && internalValue.length === 0)) &&
175
175
  <Button onClick={doOpenDialog}
176
- variant={"outlined"}
177
- size={"large"}
178
- className="h-full w-full">
176
+
177
+ size={"medium"}
178
+ className="h-full w-full">
179
179
  {multiple ? "Select references" : "Select reference"}
180
180
  </Button>
181
181
  }
@@ -185,13 +185,13 @@ export function ReferenceFilterField({
185
185
  htmlFor="null-filter"
186
186
  >
187
187
  <Checkbox id="null-filter"
188
- checked={internalValue === null}
189
- size={"small"}
190
- onCheckedChange={(checked) => {
191
- if (internalValue !== null)
192
- updateFilter(operation, null);
193
- else updateFilter(operation, undefined);
194
- }}/>
188
+ checked={internalValue === null}
189
+ size={"small"}
190
+ onCheckedChange={(checked) => {
191
+ if (internalValue !== null)
192
+ updateFilter(operation, null);
193
+ else updateFilter(operation, undefined);
194
+ }} />
195
195
  Filter for null values
196
196
  </Label>}
197
197
 
@@ -2,10 +2,8 @@ import React, { useState } from "react";
2
2
  import { EnumValuesChip } from "../../../preview";
3
3
  import { VirtualTableWhereFilterOp } from "../../VirtualTable";
4
4
  import {
5
- Checkbox,
6
5
  CloseIcon,
7
6
  IconButton,
8
- Label,
9
7
  MultiSelect,
10
8
  MultiSelectItem,
11
9
  Select,
@@ -34,24 +32,25 @@ const operationLabels = {
34
32
  in: "In",
35
33
  "not-in": "Not in",
36
34
  "array-contains": "Contains",
37
- "array-contains-any": "Any"
35
+ "array-contains-any": "Any",
36
+ "is-null": "Is null"
38
37
  };
39
38
 
40
39
  const multipleSelectOperations = ["array-contains-any", "in", "not-in"];
41
40
 
42
41
  export function StringNumberFilterField({
43
- name,
44
- value,
45
- setValue,
46
- dataType,
47
- isArray,
48
- enumValues,
49
- title
50
- }: StringNumberFilterFieldProps) {
51
-
52
- const possibleOperations: (keyof typeof operationLabels) [] = isArray
42
+ name,
43
+ value,
44
+ setValue,
45
+ dataType,
46
+ isArray,
47
+ enumValues,
48
+ title
49
+ }: StringNumberFilterFieldProps) {
50
+
51
+ const possibleOperations: (keyof typeof operationLabels)[] = isArray
53
52
  ? ["array-contains"]
54
- : ["==", "!=", ">", "<", ">=", "<="];
53
+ : ["==", "!=", ">", "<", ">=", "<=", "is-null"];
55
54
 
56
55
  if (enumValues)
57
56
  isArray
@@ -59,10 +58,20 @@ export function StringNumberFilterField({
59
58
  : possibleOperations.push("in", "not-in");
60
59
 
61
60
  const [fieldOperation, fieldValue] = value || [possibleOperations[0], undefined];
62
- const [operation, setOperation] = useState<VirtualTableWhereFilterOp>(fieldOperation);
61
+ const [operation, setOperation] = useState<VirtualTableWhereFilterOp | "is-null">(fieldOperation === "==" && fieldValue === null ? "is-null" : fieldOperation);
63
62
  const [internalValue, setInternalValue] = useState<string | number | string[] | number[] | null | undefined>(fieldValue);
64
63
 
65
- function updateFilter(op: VirtualTableWhereFilterOp, val: string | number | string[] | number[] | null | undefined) {
64
+ const isNullOperation = operation === "is-null";
65
+
66
+ function updateFilter(op: VirtualTableWhereFilterOp | "is-null", val: string | number | string[] | number[] | null | undefined) {
67
+ // Handle "is null" operation
68
+ if (op === "is-null") {
69
+ setOperation(op);
70
+ setInternalValue(null);
71
+ setValue(["==", null]);
72
+ return;
73
+ }
74
+
66
75
  let newValue = val;
67
76
  const prevOpIsArray = multipleSelectOperations.includes(operation);
68
77
  const newOpIsArray = multipleSelectOperations.includes(op);
@@ -95,15 +104,16 @@ export function StringNumberFilterField({
95
104
 
96
105
  return (
97
106
 
98
- <div className="flex w-[440px]">
99
- <div className={"w-[80px]"}>
107
+ <div className="flex w-full">
108
+ <div className={"w-[100px]"}>
100
109
  <Select value={operation}
101
- fullWidth={true}
102
- position={"item-aligned"}
103
- onValueChange={(value) => {
104
- updateFilter(value as VirtualTableWhereFilterOp, internalValue);
105
- }}
106
- renderValue={(op) => operationLabels[op as VirtualTableWhereFilterOp]}>
110
+ size={"medium"}
111
+ fullWidth={true}
112
+ position={"item-aligned"}
113
+ onValueChange={(value) => {
114
+ updateFilter(value as VirtualTableWhereFilterOp | "is-null", internalValue);
115
+ }}
116
+ renderValue={(op) => operationLabels[op as keyof typeof operationLabels]}>
107
117
  {possibleOperations.map((op) => (
108
118
  <SelectItem key={op} value={op}>
109
119
  {operationLabels[op]}
@@ -115,8 +125,11 @@ export function StringNumberFilterField({
115
125
  <div className="flex-grow ml-2 flex flex-col gap-2">
116
126
 
117
127
  {!enumValues && <TextField
128
+ size={"medium"}
118
129
  type={dataType === "number" ? "number" : undefined}
119
130
  value={internalValue !== undefined && internalValue != null ? String(internalValue) : ""}
131
+ disabled={isNullOperation}
132
+ placeholder={isNullOperation ? "null" : undefined}
120
133
  onChange={(evt) => {
121
134
  const val = dataType === "number"
122
135
  ? parseFloat(evt.target.value)
@@ -125,14 +138,16 @@ export function StringNumberFilterField({
125
138
  }}
126
139
  endAdornment={internalValue !== undefined && internalValue != null && <IconButton
127
140
  onClick={(e) => updateFilter(operation, undefined)}>
128
- <CloseIcon/>
141
+ <CloseIcon />
129
142
  </IconButton>}
130
143
  />}
131
144
 
132
145
  {enumValues && !multiple &&
133
146
  <Select
147
+ size={"medium"}
134
148
  position={"item-aligned"}
135
149
  fullWidth={true}
150
+ disabled={isNullOperation}
136
151
  value={typeof internalValue === "string" ? internalValue : ""}
137
152
  onValueChange={(value) => {
138
153
  if (value !== "")
@@ -140,7 +155,7 @@ export function StringNumberFilterField({
140
155
  }}
141
156
  endAdornment={internalValue && <IconButton
142
157
  onClick={(e) => updateFilter(operation, undefined)}>
143
- <CloseIcon/>
158
+ <CloseIcon />
144
159
  </IconButton>}
145
160
  renderValue={(enumKey) => {
146
161
  if (enumKey === null)
@@ -152,15 +167,15 @@ export function StringNumberFilterField({
152
167
  key={`select_value_${name}_${enumKey}`}
153
168
  enumKey={enumKey}
154
169
  enumValues={enumValues}
155
- size={"small"}/>;
170
+ size={"small"} />;
156
171
  }}>
157
172
  {enumValues.map((enumConfig) => (
158
173
  <SelectItem key={`select_item_${name}_${enumConfig.id}`}
159
- value={String(enumConfig.id)}>
174
+ value={String(enumConfig.id)}>
160
175
  <EnumValuesChip
161
176
  enumKey={String(enumConfig.id)}
162
177
  enumValues={enumValues}
163
- size={"small"}/>
178
+ size={"small"} />
164
179
  </SelectItem>
165
180
  ))}
166
181
  </Select>
@@ -168,8 +183,10 @@ export function StringNumberFilterField({
168
183
 
169
184
  {enumValues && multiple &&
170
185
  <MultiSelect
186
+ size={"medium"}
171
187
  position={"item-aligned"}
172
188
  value={Array.isArray(internalValue) ? internalValue.map(e => String(e)) : []}
189
+ disabled={isNullOperation}
173
190
  onValueChange={(value) => {
174
191
  updateFilter(operation, dataType === "number" ? value.map(v => parseInt(v)) : value)
175
192
  }}
@@ -177,47 +194,21 @@ export function StringNumberFilterField({
177
194
  endAdornment={internalValue && <IconButton
178
195
  className="absolute right-2 top-3"
179
196
  onClick={(e) => updateFilter(operation, undefined)}>
180
- <CloseIcon/>
197
+ <CloseIcon />
181
198
  </IconButton>}
182
- // renderValues={(enumKeys) => {
183
- // console.log("renderValues", enumKeys);
184
- // if (enumKeys === null)
185
- // return "Filter for null values";
186
- //
187
- // return enumKeys.map(key => <EnumValuesChip
188
- // key={`select_value_${name}_${enumKeys}`}
189
- // enumKey={key}
190
- // enumValues={enumValues}
191
- // size={"small"}/>);
192
- // }}
193
199
  >
194
200
  {enumValues.map((enumConfig) => (
195
201
  <MultiSelectItem key={`select_value_${name}_${enumConfig.id}`}
196
- value={String(enumConfig.id)}>
202
+ value={String(enumConfig.id)}>
197
203
  <EnumValuesChip
198
204
  enumKey={String(enumConfig.id)}
199
205
  enumValues={enumValues}
200
- size={"small"}/>
206
+ size={"small"} />
201
207
  </MultiSelectItem>
202
208
  ))}
203
209
  </MultiSelect>
204
210
  }
205
211
 
206
- {!isArray && <Label
207
- className="border cursor-pointer rounded-md p-2 flex items-center gap-2 [&:has(:checked)]:bg-surface-100 dark:[&:has(:checked)]:bg-surface-800"
208
- htmlFor="null-filter"
209
- >
210
- <Checkbox id="null-filter"
211
- checked={internalValue === null}
212
- size={"small"}
213
- onCheckedChange={(checked) => {
214
- if (internalValue !== null)
215
- updateFilter(operation, null);
216
- else updateFilter(operation, undefined);
217
- }}/>
218
- Filter for null values
219
- </Label>}
220
-
221
212
  </div>
222
213
 
223
214
  </div>
@@ -35,10 +35,8 @@ export function UnsavedChangesDialog({
35
35
  </DialogContent>
36
36
  <DialogActions>
37
37
  <Button variant="text"
38
- color={"primary"}
39
38
  onClick={handleCancel} autoFocus> Cancel </Button>
40
39
  <Button
41
- color={"primary"}
42
40
  onClick={handleOk}> Ok </Button>
43
41
  </DialogActions>
44
42
  </Dialog>
@@ -6,17 +6,17 @@ import { EmptyValue } from "../preview";
6
6
  * Component to render a single user with name and email
7
7
  */
8
8
  export function UserDisplay({
9
- user,
10
- }: { user: User | null }) {
9
+ user,
10
+ }: { user: User | null }) {
11
11
  if (!user) {
12
- return <EmptyValue/>;
12
+ return <EmptyValue />;
13
13
  }
14
14
 
15
15
  const avatarSizeClass = "w-6 h-6";
16
16
 
17
17
  return (
18
18
  <div className={cls(
19
- "inline-flex items-center gap-4 px-2 py-1 rounded-xl",
19
+ "inline-flex items-center gap-4 px-2 py-1 rounded-xl text-left",
20
20
  "bg-surface-accent-100 dark:bg-surface-accent-800",
21
21
  "border",
22
22
  defaultBorderMixin