@marimo-team/frontend 0.23.2-dev13 → 0.23.2-dev15

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 (28) hide show
  1. package/dist/assets/{JsonOutput-DSDJDUaa.js → JsonOutput-CAXIiTe3.js} +9 -9
  2. package/dist/assets/{add-connection-dialog-QrjKitAG.js → add-connection-dialog-BwYyQhY7.js} +1 -1
  3. package/dist/assets/{agent-panel-Dickktil.js → agent-panel-ZshQwFmu.js} +1 -1
  4. package/dist/assets/cell-editor-BhI8rHG0.js +22 -0
  5. package/dist/assets/{column-preview-CV6DJwQH.js → column-preview-BhAfBc9w.js} +1 -1
  6. package/dist/assets/{command-palette-BAWNAZMp.js → command-palette-hvx9iar3.js} +1 -1
  7. package/dist/assets/{edit-page-DL44Xhld.js → edit-page-hdE7fE4U.js} +3 -3
  8. package/dist/assets/{file-explorer-panel-Cm0rqLaG.js → file-explorer-panel-BA3zZrWa.js} +1 -1
  9. package/dist/assets/{form-D8rkP8Ig.js → form-0zEqjNB_.js} +1 -1
  10. package/dist/assets/{hooks-D2tqOhv8.js → hooks-DlocGflD.js} +1 -1
  11. package/dist/assets/{index-DR9Po2ic.js → index-BQ--F_mR.js} +16 -16
  12. package/dist/assets/{layout-UpIwnVzJ.js → layout-XI0hPL8R.js} +1 -1
  13. package/dist/assets/{panels-DVbiAjhB.js → panels-pUxQODxa.js} +1 -1
  14. package/dist/assets/{run-page-IeagkCfu.js → run-page-D2jwK6o6.js} +1 -1
  15. package/dist/assets/{scratchpad-panel-ByYUuUE7.js → scratchpad-panel-Da_3I_76.js} +1 -1
  16. package/dist/assets/{session-panel-C86D9rsy.js → session-panel-BRmjEs5F.js} +1 -1
  17. package/dist/assets/{state-BvTo39vs.js → state-Bf4SryDJ.js} +1 -1
  18. package/dist/assets/{useNotebookActions-BhIJMijf.js → useNotebookActions-D-wDki2H.js} +1 -1
  19. package/dist/index.html +5 -5
  20. package/package.json +1 -1
  21. package/src/components/data-table/__tests__/filters.test.ts +304 -0
  22. package/src/components/data-table/filters.ts +87 -33
  23. package/src/components/editor/cell/code/cell-editor.tsx +1 -0
  24. package/src/plugins/impl/DataTablePlugin.tsx +7 -20
  25. package/src/plugins/impl/data-frames/DataFramePlugin.tsx +4 -4
  26. package/src/plugins/impl/data-frames/schema.ts +41 -9
  27. package/src/plugins/impl/data-frames/utils/operators.ts +2 -0
  28. package/dist/assets/cell-editor-B3eWG04j.js +0 -22
@@ -1,9 +1,12 @@
1
1
  /* Copyright 2026 Marimo. All rights reserved. */
2
2
  "use no memo";
3
3
 
4
- import type { RowData } from "@tanstack/react-table";
4
+ import type { ColumnFiltersState, RowData } from "@tanstack/react-table";
5
5
  import type { DataType } from "@/core/kernel/messages";
6
- import type { ConditionType } from "@/plugins/impl/data-frames/schema";
6
+ import type {
7
+ FilterConditionType,
8
+ FilterGroupType,
9
+ } from "@/plugins/impl/data-frames/schema";
7
10
  import type { ColumnId } from "@/plugins/impl/data-frames/types";
8
11
  import type { OperatorType } from "@/plugins/impl/data-frames/utils/operators";
9
12
  import { assertNever } from "@/utils/assertNever";
@@ -84,28 +87,34 @@ export type ColumnFilterForType<T extends FilterType> = T extends FilterType
84
87
  export function filterToFilterCondition(
85
88
  columnIdString: string,
86
89
  filter: ColumnFilterValue | undefined,
87
- ): ConditionType[] | ConditionType {
90
+ ): FilterConditionType[] {
88
91
  if (!filter) {
89
92
  return [];
90
93
  }
91
94
  const columnId = columnIdString as ColumnId;
92
95
 
93
96
  if (filter.operator === "is_null" || filter.operator === "is_not_null") {
94
- return {
95
- column_id: columnId,
96
- operator: filter.operator,
97
- value: undefined,
98
- };
97
+ return [
98
+ {
99
+ column_id: columnId,
100
+ operator: filter.operator,
101
+ value: undefined,
102
+ type: "condition",
103
+ negate: false,
104
+ },
105
+ ];
99
106
  }
100
107
 
101
108
  switch (filter.type) {
102
109
  case "number": {
103
- const conditions: ConditionType[] = [];
110
+ const conditions: FilterConditionType[] = [];
104
111
  if (filter.min !== undefined) {
105
112
  conditions.push({
106
113
  column_id: columnId,
107
114
  operator: ">=",
108
115
  value: filter.min,
116
+ type: "condition",
117
+ negate: false,
109
118
  });
110
119
  }
111
120
  if (filter.max !== undefined) {
@@ -113,23 +122,31 @@ export function filterToFilterCondition(
113
122
  column_id: columnId,
114
123
  operator: "<=",
115
124
  value: filter.max,
125
+ type: "condition",
126
+ negate: false,
116
127
  });
117
128
  }
118
129
  return conditions;
119
130
  }
120
131
  case "text":
121
- return {
122
- column_id: columnId,
123
- operator: filter.operator,
124
- value: filter.text,
125
- };
132
+ return [
133
+ {
134
+ column_id: columnId,
135
+ operator: filter.operator,
136
+ value: filter.text,
137
+ type: "condition",
138
+ negate: false,
139
+ },
140
+ ];
126
141
  case "datetime": {
127
- const conditions: ConditionType[] = [];
142
+ const conditions: FilterConditionType[] = [];
128
143
  if (filter.min !== undefined) {
129
144
  conditions.push({
130
145
  column_id: columnId,
131
146
  operator: ">=",
132
147
  value: filter.min.toISOString(),
148
+ type: "condition",
149
+ negate: false,
133
150
  });
134
151
  }
135
152
  if (filter.max !== undefined) {
@@ -137,17 +154,21 @@ export function filterToFilterCondition(
137
154
  column_id: columnId,
138
155
  operator: "<=",
139
156
  value: filter.max.toISOString(),
157
+ type: "condition",
158
+ negate: false,
140
159
  });
141
160
  }
142
161
  return conditions;
143
162
  }
144
163
  case "date": {
145
- const conditions: ConditionType[] = [];
164
+ const conditions: FilterConditionType[] = [];
146
165
  if (filter.min !== undefined) {
147
166
  conditions.push({
148
167
  column_id: columnId,
149
168
  operator: ">=",
150
169
  value: filter.min.toISOString(),
170
+ type: "condition",
171
+ negate: false,
151
172
  });
152
173
  }
153
174
  if (filter.max !== undefined) {
@@ -155,17 +176,21 @@ export function filterToFilterCondition(
155
176
  column_id: columnId,
156
177
  operator: "<=",
157
178
  value: filter.max.toISOString(),
179
+ type: "condition",
180
+ negate: false,
158
181
  });
159
182
  }
160
183
  return conditions;
161
184
  }
162
185
  case "time": {
163
- const conditions: ConditionType[] = [];
186
+ const conditions: FilterConditionType[] = [];
164
187
  if (filter.min !== undefined) {
165
188
  conditions.push({
166
189
  column_id: columnId,
167
190
  operator: ">=",
168
191
  value: filter.min.toISOString(),
192
+ type: "condition",
193
+ negate: false,
169
194
  });
170
195
  }
171
196
  if (filter.max !== undefined) {
@@ -173,24 +198,34 @@ export function filterToFilterCondition(
173
198
  column_id: columnId,
174
199
  operator: "<=",
175
200
  value: filter.max.toISOString(),
201
+ type: "condition",
202
+ negate: false,
176
203
  });
177
204
  }
178
205
  return conditions;
179
206
  }
180
207
  case "boolean":
181
208
  if (filter.value) {
182
- return {
183
- column_id: columnId,
184
- operator: "is_true",
185
- value: undefined,
186
- };
209
+ return [
210
+ {
211
+ column_id: columnId,
212
+ operator: "is_true",
213
+ value: undefined,
214
+ type: "condition",
215
+ negate: false,
216
+ },
217
+ ];
187
218
  }
188
219
  if (!filter.value) {
189
- return {
190
- column_id: columnId,
191
- operator: "is_false",
192
- value: undefined,
193
- };
220
+ return [
221
+ {
222
+ column_id: columnId,
223
+ operator: "is_false",
224
+ value: undefined,
225
+ type: "condition",
226
+ negate: false,
227
+ },
228
+ ];
194
229
  }
195
230
 
196
231
  return [];
@@ -200,16 +235,35 @@ export function filterToFilterCondition(
200
235
  Logger.warn("Invalid operator for select filter", {
201
236
  operator: filter.operator,
202
237
  });
203
- operator = "in"; // default to in operator
238
+ operator = "in";
204
239
  }
205
- return {
206
- column_id: columnId,
207
- operator,
208
- value: filter.options,
209
- };
240
+ return [
241
+ {
242
+ column_id: columnId,
243
+ operator,
244
+ value: filter.options,
245
+ type: "condition",
246
+ negate: false,
247
+ },
248
+ ];
210
249
  }
211
250
 
212
251
  default:
213
252
  assertNever(filter);
214
253
  }
215
254
  }
255
+
256
+ export function filtersToFilterGroup(
257
+ columnFilters: ColumnFiltersState,
258
+ ): FilterGroupType {
259
+ const conditions = columnFilters.flatMap((filter) =>
260
+ filterToFilterCondition(filter.id, filter.value as ColumnFilterValue),
261
+ );
262
+ // To maintain existing behavior "and" all the conditions
263
+ return {
264
+ type: "group",
265
+ operator: "and",
266
+ children: conditions,
267
+ negate: false,
268
+ };
269
+ }
@@ -270,6 +270,7 @@ const CellEditorInternal = ({
270
270
  userConfig.language_servers,
271
271
  userConfig.display,
272
272
  userConfig.diagnostics,
273
+ userConfig.ai?.inline_tooltip,
273
274
  aiEnabled,
274
275
  theme,
275
276
  showPlaceholder,
@@ -28,10 +28,7 @@ import { TablePanel } from "@/components/data-table/charts/charts";
28
28
  import { hasChart } from "@/components/data-table/charts/storage";
29
29
  import { ColumnChartSpecModel } from "@/components/data-table/column-summary/chart-spec-model";
30
30
  import { ColumnChartContext } from "@/components/data-table/column-summary/column-summary";
31
- import {
32
- type ColumnFilterValue,
33
- filterToFilterCondition,
34
- } from "@/components/data-table/filters";
31
+ import { filtersToFilterGroup } from "@/components/data-table/filters";
35
32
  import { usePanelOwnership } from "@/components/data-table/hooks/use-panel-ownership";
36
33
  import { LoadingTable } from "@/components/data-table/loading-table";
37
34
  import {
@@ -86,8 +83,8 @@ import { rpc } from "../core/rpc";
86
83
  import { Banner } from "./common/error-banner";
87
84
  import { Labeled } from "./common/labeled";
88
85
  import {
89
- ConditionSchema,
90
- type ConditionType,
86
+ FilterGroupSchema,
87
+ type FilterGroupType,
91
88
  columnToFieldTypesSchema,
92
89
  } from "./data-frames/schema";
93
90
 
@@ -213,7 +210,7 @@ type DataTableFunctions = {
213
210
  descending: boolean;
214
211
  }[];
215
212
  query?: string;
216
- filters?: ConditionType[];
213
+ filters?: FilterGroupType;
217
214
  page_number: number;
218
215
  page_size: number;
219
216
  max_columns?: number | null;
@@ -312,7 +309,7 @@ export const DataTablePlugin = createPlugin<S>("marimo-table")
312
309
  )
313
310
  .optional(),
314
311
  query: z.string().optional(),
315
- filters: z.array(ConditionSchema).optional(),
312
+ filters: FilterGroupSchema.optional(),
316
313
  page_number: z.number(),
317
314
  page_size: z.number(),
318
315
  max_columns: z.number().nullable().optional(),
@@ -578,12 +575,7 @@ export const LoadingDataTableComponent = memo(
578
575
  query: searchQuery,
579
576
  page_number: paginationState.pageIndex,
580
577
  page_size: paginationState.pageSize,
581
- filters: filters.flatMap((filter) => {
582
- return filterToFilterCondition(
583
- filter.id,
584
- filter.value as ColumnFilterValue,
585
- );
586
- }),
578
+ filters: filtersToFilterGroup(filters),
587
579
  });
588
580
 
589
581
  if (canShowInitialPage) {
@@ -641,12 +633,7 @@ export const LoadingDataTableComponent = memo(
641
633
  page_size: 1,
642
634
  sort: sortArgs,
643
635
  query: searchQuery,
644
- filters: filters.flatMap((filter) => {
645
- return filterToFilterCondition(
646
- filter.id,
647
- filter.value as ColumnFilterValue,
648
- );
649
- }),
636
+ filters: filtersToFilterGroup(filters),
650
637
  // Do not clamp number of columns since we are viewing a single row
651
638
  max_columns: null,
652
639
  });
@@ -29,8 +29,8 @@ import { LoadingDataTableComponent, TableProviders } from "../DataTablePlugin";
29
29
  import type { DataType } from "../vega/vega-loader";
30
30
  import { TransformPanel, type TransformPanelHandle } from "./panel";
31
31
  import {
32
- ConditionSchema,
33
- type ConditionType,
32
+ FilterGroupSchema,
33
+ type FilterGroupType,
34
34
  columnToFieldTypesSchema,
35
35
  type Transformations,
36
36
  } from "./schema";
@@ -75,7 +75,7 @@ type PluginFunctions = {
75
75
  descending: boolean;
76
76
  }[];
77
77
  query?: string;
78
- filters?: ConditionType[];
78
+ filters?: FilterGroupType;
79
79
  page_number: number;
80
80
  page_size: number;
81
81
  }) => Promise<{
@@ -138,7 +138,7 @@ export const DataFramePlugin = createPlugin<S>("marimo-dataframe")
138
138
  )
139
139
  .optional(),
140
140
  query: z.string().optional(),
141
- filters: z.array(ConditionSchema).optional(),
141
+ filters: FilterGroupSchema.optional(),
142
142
  page_number: z.number(),
143
143
  page_size: z.number(),
144
144
  }),
@@ -73,16 +73,36 @@ const SortColumnTransformSchema = z.object({
73
73
  .default("last"),
74
74
  });
75
75
 
76
- export const ConditionSchema = z
76
+ export const FilterConditionSchema = z
77
77
  .object({
78
78
  column_id: column_id,
79
79
  operator: z
80
80
  .enum(Object.keys(ALL_OPERATORS) as [OperatorType, ...OperatorType[]])
81
81
  .describe(FieldOptions.of({ label: " " })),
82
+ type: z.literal("condition").default("condition"),
82
83
  value: z.any().describe(FieldOptions.of({ label: "Value" })),
84
+ negate: z.boolean().default(false),
83
85
  })
84
86
  .describe(FieldOptions.of({ direction: "row", special: "column_filter" }));
85
- export type ConditionType = z.infer<typeof ConditionSchema>;
87
+ export type FilterConditionType = z.infer<typeof FilterConditionSchema>;
88
+
89
+ export interface FilterGroupType {
90
+ type: "group";
91
+ operator: "and" | "or";
92
+ children: (FilterConditionType | FilterGroupType)[];
93
+ negate: boolean;
94
+ }
95
+
96
+ export const FilterGroupSchema: z.ZodType<FilterGroupType> = z.lazy(() =>
97
+ z.object({
98
+ type: z.literal("group").default("group"),
99
+ operator: z.enum(["and", "or"]).default("and"),
100
+ children: z
101
+ .array(z.union([FilterConditionSchema, FilterGroupSchema]))
102
+ .default([]),
103
+ negate: z.boolean().default(false),
104
+ }),
105
+ );
86
106
 
87
107
  const FilterRowsTransformSchema = z.object({
88
108
  type: z.literal("filter_rows"),
@@ -91,17 +111,29 @@ const FilterRowsTransformSchema = z.object({
91
111
  .default("keep_rows")
92
112
  .describe(FieldOptions.of({ special: "radio_group" })),
93
113
  where: z
94
- .array(ConditionSchema)
114
+ .array(FilterConditionSchema)
95
115
  .min(1)
96
116
  .describe(FieldOptions.of({ label: "Value", minLength: 1 }))
97
- .transform((value) => {
98
- return value.filter((condition) => {
117
+ .default(() => [
118
+ {
119
+ column_id: "" as ColumnId,
120
+ operator: "==" as const,
121
+ value: "",
122
+ type: "condition" as const,
123
+ negate: false,
124
+ },
125
+ ])
126
+ .transform((value): FilterGroupType => {
127
+ const validConditions = value.filter((condition) => {
99
128
  return isConditionValueValid(condition.operator, condition.value);
100
129
  });
101
- })
102
- .default(() => [
103
- { column_id: "" as ColumnId, operator: "==" as const, value: "" },
104
- ]),
130
+ return {
131
+ type: "group",
132
+ operator: "and",
133
+ children: validConditions,
134
+ negate: false,
135
+ };
136
+ }),
105
137
  });
106
138
 
107
139
  const GroupByTransformSchema = z
@@ -41,6 +41,7 @@ const createComparisonOperators = (schema: z.ZodType) => ({
41
41
  ">=": [schema],
42
42
  "<": [schema],
43
43
  "<=": [schema],
44
+ between: [z.object({ min: schema, max: schema })],
44
45
  is_null: [],
45
46
  is_not_null: [],
46
47
  });
@@ -59,6 +60,7 @@ export const STRING_OPERATORS = {
59
60
  ends_with: [Schema.string],
60
61
  in: [Schema.stringMultiColumnValues],
61
62
  not_in: [Schema.stringMultiColumnValues],
63
+ is_empty: [],
62
64
  is_null: [],
63
65
  is_not_null: [],
64
66
  };