@revisium/schema-toolkit-ui 0.6.1 → 0.6.3

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/dist/index.cjs CHANGED
@@ -6920,6 +6920,88 @@ const SYSTEM_FIELD_IDS = new Set([
6920
6920
  "schemaHash"
6921
6921
  ]);
6922
6922
 
6923
+ //#endregion
6924
+ //#region src/table-editor/TableEditor/model/SchemaContext.ts
6925
+ const DATA_FIELD = "data";
6926
+ function stripDataFieldPrefix(field) {
6927
+ const prefix = `${DATA_FIELD}.`;
6928
+ if (field.startsWith(prefix)) return field.slice(prefix.length);
6929
+ if (field === DATA_FIELD) return "";
6930
+ return field;
6931
+ }
6932
+ const SYSTEM_REF_SCHEMAS = {
6933
+ [_revisium_schema_toolkit.SystemSchemaIds.File]: _revisium_schema_toolkit.fileSchema,
6934
+ [_revisium_schema_toolkit.SystemSchemaIds.RowId]: _revisium_schema_toolkit.rowIdSchema,
6935
+ [_revisium_schema_toolkit.SystemSchemaIds.RowCreatedAt]: _revisium_schema_toolkit.rowCreatedAtSchema,
6936
+ [_revisium_schema_toolkit.SystemSchemaIds.RowCreatedId]: _revisium_schema_toolkit.rowCreatedIdSchema,
6937
+ [_revisium_schema_toolkit.SystemSchemaIds.RowVersionId]: _revisium_schema_toolkit.rowVersionIdSchema,
6938
+ [_revisium_schema_toolkit.SystemSchemaIds.RowPublishedAt]: _revisium_schema_toolkit.rowPublishedAtSchema,
6939
+ [_revisium_schema_toolkit.SystemSchemaIds.RowUpdatedAt]: _revisium_schema_toolkit.rowUpdatedAtSchema,
6940
+ [_revisium_schema_toolkit.SystemSchemaIds.RowHash]: _revisium_schema_toolkit.rowHashSchema,
6941
+ [_revisium_schema_toolkit.SystemSchemaIds.RowSchemaHash]: _revisium_schema_toolkit.rowSchemaHashSchema
6942
+ };
6943
+ function wrapDataSchema(dataSchema) {
6944
+ return {
6945
+ type: "object",
6946
+ properties: { [DATA_FIELD]: dataSchema },
6947
+ additionalProperties: false,
6948
+ required: [DATA_FIELD]
6949
+ };
6950
+ }
6951
+ function buildRowSchema(wrappedDataSchema) {
6952
+ const systemProperties = {};
6953
+ for (const sf of SYSTEM_FIELDS) systemProperties[sf.id] = { $ref: sf.ref };
6954
+ return {
6955
+ type: "object",
6956
+ properties: {
6957
+ ...systemProperties,
6958
+ ...wrappedDataSchema.properties
6959
+ },
6960
+ additionalProperties: false,
6961
+ required: [...Object.keys(systemProperties), ...wrappedDataSchema.required]
6962
+ };
6963
+ }
6964
+ var SchemaContext = class {
6965
+ _allColumns = [];
6966
+ _dataSchema = null;
6967
+ _wrappedDataSchema = null;
6968
+ _fullRefSchemas = {};
6969
+ _rootNode = null;
6970
+ get allColumns() {
6971
+ return this._allColumns;
6972
+ }
6973
+ get sortableFields() {
6974
+ return this._allColumns.filter((col) => !col.isDeprecated && col.fieldType !== FilterFieldType.File);
6975
+ }
6976
+ get filterableFields() {
6977
+ return this.sortableFields;
6978
+ }
6979
+ get dataSchema() {
6980
+ return this._dataSchema;
6981
+ }
6982
+ get wrappedDataSchema() {
6983
+ return this._wrappedDataSchema;
6984
+ }
6985
+ get fullRefSchemas() {
6986
+ return this._fullRefSchemas;
6987
+ }
6988
+ get rootNode() {
6989
+ return this._rootNode;
6990
+ }
6991
+ init(dataSchema, refSchemas) {
6992
+ this._dataSchema = dataSchema;
6993
+ this._fullRefSchemas = {
6994
+ ...SYSTEM_REF_SCHEMAS,
6995
+ ...refSchemas
6996
+ };
6997
+ const wrapped = wrapDataSchema(dataSchema);
6998
+ this._wrappedDataSchema = wrapped;
6999
+ const rowSchema = buildRowSchema(wrapped);
7000
+ this._rootNode = new _revisium_schema_toolkit.SchemaParser().parse(rowSchema, this._fullRefSchemas);
7001
+ this._allColumns = extractColumns(this._rootNode);
7002
+ }
7003
+ };
7004
+
6923
7005
  //#endregion
6924
7006
  //#region src/table-editor/Columns/model/extractColumns.ts
6925
7007
  const NODE_TYPE_TO_FIELD_TYPE = {
@@ -6963,15 +7045,20 @@ function resolveRefColumn(child, fieldPath) {
6963
7045
  const refValue = child.ref();
6964
7046
  if (!refValue) return null;
6965
7047
  const systemDef = SYSTEM_FIELD_BY_REF.get(refValue);
6966
- if (systemDef) return {
6967
- field: systemDef.id,
6968
- label: systemDef.label,
6969
- fieldType: systemDef.fieldType,
6970
- isSystem: true,
6971
- systemFieldId: systemDef.id,
6972
- isDeprecated: child.metadata().deprecated ?? false,
6973
- hasFormula: child.hasFormula()
6974
- };
7048
+ if (systemDef) {
7049
+ const isDeprecated = child.metadata().deprecated ?? false;
7050
+ const hasFormula = child.hasFormula();
7051
+ return {
7052
+ field: systemDef.id,
7053
+ label: systemDef.label,
7054
+ fieldType: systemDef.fieldType,
7055
+ isSystem: true,
7056
+ systemFieldId: systemDef.id,
7057
+ isDeprecated,
7058
+ hasFormula,
7059
+ isSortable: !isDeprecated && !hasFormula
7060
+ };
7061
+ }
6975
7062
  if (refValue === _revisium_schema_toolkit.SystemSchemaIds.File) return resolveFileRefColumns(child, fieldPath);
6976
7063
  return null;
6977
7064
  }
@@ -6980,18 +7067,30 @@ function resolveFileRefColumns(child, fieldPath) {
6980
7067
  if (child.isObject()) for (const subField of child.properties()) {
6981
7068
  const subFieldPath = buildFieldPath(fieldPath, subField.name());
6982
7069
  const fieldType = NODE_TYPE_TO_FIELD_TYPE[subField.nodeType()];
6983
- if (fieldType) result.push(createColumn(subFieldPath, subField, fieldType));
7070
+ if (fieldType) {
7071
+ const subCol = createColumn(subFieldPath, subField, fieldType);
7072
+ subCol.parentFileField = fieldPath;
7073
+ result.push(subCol);
7074
+ }
6984
7075
  }
6985
7076
  return result;
6986
7077
  }
7078
+ function stripDataPrefix(fieldPath) {
7079
+ if (fieldPath === DATA_FIELD) return DATA_FIELD;
7080
+ if (fieldPath.startsWith(`${DATA_FIELD}.`)) return fieldPath.slice(DATA_FIELD.length + 1);
7081
+ return fieldPath;
7082
+ }
6987
7083
  function createColumn(fieldPath, child, fieldType) {
7084
+ const isDeprecated = child.metadata().deprecated ?? false;
7085
+ const hasFormula = child.hasFormula();
6988
7086
  return {
6989
7087
  field: fieldPath,
6990
- label: fieldPath,
7088
+ label: stripDataPrefix(fieldPath),
6991
7089
  fieldType,
6992
7090
  isSystem: false,
6993
- isDeprecated: child.metadata().deprecated ?? false,
6994
- hasFormula: child.hasFormula()
7091
+ isDeprecated,
7092
+ hasFormula,
7093
+ isSortable: !isDeprecated && !hasFormula && fieldType !== FilterFieldType.File
6995
7094
  };
6996
7095
  }
6997
7096
 
@@ -7061,6 +7160,9 @@ var ColumnsModel = class {
7061
7160
  constructor() {
7062
7161
  (0, mobx.makeAutoObservable)(this, {}, { autoBind: true });
7063
7162
  }
7163
+ get allColumns() {
7164
+ return this._allColumns;
7165
+ }
7064
7166
  get visibleColumns() {
7065
7167
  const lookup = this._columnLookup;
7066
7168
  const result = [];
@@ -7078,6 +7180,10 @@ var ColumnsModel = class {
7078
7180
  const visible = this._visibleFieldSet;
7079
7181
  return this._allColumns.filter((col) => !visible.has(col.field) && !col.isSystem);
7080
7182
  }
7183
+ get availableFieldsToInsert() {
7184
+ const visible = this._visibleFieldSet;
7185
+ return this._allColumns.filter((col) => !visible.has(col.field));
7186
+ }
7081
7187
  get availableSystemFieldsToAdd() {
7082
7188
  const visible = this._visibleFieldSet;
7083
7189
  return this._allColumns.filter((col) => !visible.has(col.field) && col.isSystem);
@@ -7458,11 +7564,9 @@ var ColumnsModel = class {
7458
7564
  return this._pinnedColumns.get(neighbor) === pin;
7459
7565
  }
7460
7566
  _toViewField(field) {
7461
- if (this._columnLookup.get(field)?.isSystem) return field;
7462
- return `data.${field}`;
7567
+ return field;
7463
7568
  }
7464
7569
  _fromViewField(viewField) {
7465
- if (viewField.startsWith("data.")) return viewField.slice(5);
7466
7570
  return viewField;
7467
7571
  }
7468
7572
  _resolveWidthUntracked(field) {
@@ -7491,6 +7595,49 @@ var ColumnsModel = class {
7491
7595
  }
7492
7596
  };
7493
7597
 
7598
+ //#endregion
7599
+ //#region src/table-editor/Columns/model/groupFileFields.ts
7600
+ function isFileFieldGroup(item) {
7601
+ return "parent" in item && "children" in item;
7602
+ }
7603
+ function groupFileFields(columns, allColumns) {
7604
+ const allLookup = allColumns ? new Map(allColumns.map((c) => [c.field, c])) : null;
7605
+ const groups = /* @__PURE__ */ new Map();
7606
+ const result = [];
7607
+ for (const col of columns) if (col.fieldType === FilterFieldType.File) {
7608
+ const existing = groups.get(col.field);
7609
+ if (existing) {
7610
+ existing.parent = col;
7611
+ existing.parentVisible = false;
7612
+ } else {
7613
+ const group = {
7614
+ parent: col,
7615
+ children: [],
7616
+ parentVisible: false
7617
+ };
7618
+ groups.set(col.field, group);
7619
+ result.push(group);
7620
+ }
7621
+ } else if (col.parentFileField) {
7622
+ let group = groups.get(col.parentFileField);
7623
+ if (!group) {
7624
+ const parentCol = allLookup?.get(col.parentFileField);
7625
+ if (parentCol) {
7626
+ group = {
7627
+ parent: parentCol,
7628
+ children: [],
7629
+ parentVisible: true
7630
+ };
7631
+ groups.set(col.parentFileField, group);
7632
+ result.push(group);
7633
+ }
7634
+ }
7635
+ if (group) group.children.push(col);
7636
+ else result.push(col);
7637
+ } else result.push(col);
7638
+ return result;
7639
+ }
7640
+
7494
7641
  //#endregion
7495
7642
  //#region src/table-editor/Filters/model/utils/operators.ts
7496
7643
  let FilterOperator = /* @__PURE__ */ function(FilterOperator) {
@@ -7952,15 +8099,15 @@ function parseValue(value, fieldType) {
7952
8099
  }
7953
8100
  return value;
7954
8101
  }
7955
- function buildOperatorClause(operator, value, fieldType) {
8102
+ function buildOperatorClause(operator, value, fieldType, isSystemField) {
7956
8103
  const parsed = parseValue(value, fieldType);
7957
8104
  switch (operator) {
7958
8105
  case FilterOperator.Equals: return { equals: parsed };
7959
8106
  case FilterOperator.NotEquals: return { not: { equals: parsed } };
7960
- case FilterOperator.Contains: return { string_contains: value };
7961
- case FilterOperator.NotContains: return { not: { string_contains: value } };
7962
- case FilterOperator.StartsWith: return { string_starts_with: value };
7963
- case FilterOperator.EndsWith: return { string_ends_with: value };
8107
+ case FilterOperator.Contains: return isSystemField ? { contains: value } : { string_contains: value };
8108
+ case FilterOperator.NotContains: return isSystemField ? { not: { contains: value } } : { not: { string_contains: value } };
8109
+ case FilterOperator.StartsWith: return isSystemField ? { startsWith: value } : { string_starts_with: value };
8110
+ case FilterOperator.EndsWith: return isSystemField ? { endsWith: value } : { string_ends_with: value };
7964
8111
  case FilterOperator.Gt: return { gt: parsed };
7965
8112
  case FilterOperator.Gte: return { gte: parsed };
7966
8113
  case FilterOperator.Lt: return { lt: parsed };
@@ -7981,16 +8128,17 @@ function buildConditionClause(condition) {
7981
8128
  searchType: condition.searchType || "plain"
7982
8129
  } };
7983
8130
  return { data: {
7984
- path: condition.field,
8131
+ path: stripDataFieldPrefix(condition.field),
7985
8132
  search: condition.value,
7986
8133
  searchLanguage: condition.searchLanguage || "simple",
7987
8134
  searchType: condition.searchType || "plain"
7988
8135
  } };
7989
8136
  }
7990
- const opClause = buildOperatorClause(condition.operator, condition.value, condition.fieldType);
7991
- if (SYSTEM_FIELD_IDS.has(condition.field)) return { [condition.field]: opClause };
8137
+ const isSystemField = SYSTEM_FIELD_IDS.has(condition.field);
8138
+ const opClause = buildOperatorClause(condition.operator, condition.value, condition.fieldType, isSystemField);
8139
+ if (isSystemField) return { [condition.field]: opClause };
7992
8140
  return { data: {
7993
- path: condition.field,
8141
+ path: stripDataFieldPrefix(condition.field),
7994
8142
  ...opClause
7995
8143
  } };
7996
8144
  }
@@ -9157,7 +9305,10 @@ const SearchWidget = (0, mobx_react_lite.observer)(({ model }) => {
9157
9305
  right: "0",
9158
9306
  top: "50%",
9159
9307
  transform: "translateY(-50%)",
9160
- onClick: () => model.clear(),
9308
+ onClick: () => {
9309
+ model.clear();
9310
+ setExpanded(false);
9311
+ },
9161
9312
  color: "gray.400",
9162
9313
  _hover: { color: "black" },
9163
9314
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiXBold, {})
@@ -9316,22 +9467,18 @@ var SortModel = class {
9316
9467
  if (firstAvailable) this.addSort(firstAvailable.field);
9317
9468
  }
9318
9469
  serializeToViewSorts() {
9319
- const lookup = this._fieldLookup;
9320
- return this.sorts.map((sort) => {
9321
- return {
9322
- field: lookup.get(sort.field)?.isSystem ? sort.field : `data.${sort.field}`,
9323
- direction: sort.direction
9324
- };
9325
- });
9470
+ return this.sorts.map((sort) => ({
9471
+ field: sort.field,
9472
+ direction: sort.direction
9473
+ }));
9326
9474
  }
9327
9475
  applyViewSorts(viewSorts) {
9328
9476
  const lookup = this._fieldLookup;
9329
9477
  const sorts = [];
9330
9478
  for (const vs of viewSorts) {
9331
- const field = vs.field.startsWith("data.") ? vs.field.slice(5) : vs.field;
9332
9479
  const direction = vs.direction === "desc" ? "desc" : "asc";
9333
- if (lookup.has(field)) sorts.push({
9334
- field,
9480
+ if (lookup.has(vs.field)) sorts.push({
9481
+ field: vs.field,
9335
9482
  direction
9336
9483
  });
9337
9484
  }
@@ -12155,10 +12302,69 @@ const FieldMenuItem = (0, react.memo)(({ field, name, fieldType, valuePrefix, on
12155
12302
  });
12156
12303
  });
12157
12304
 
12305
+ //#endregion
12306
+ //#region src/table-editor/Table/ui/Header/FileFieldSubmenu.tsx
12307
+ const FileFieldSubmenu = ({ group, parentVisible, valuePrefix, onClick }) => {
12308
+ if (group.children.length === 0 && !parentVisible) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldMenuItem, {
12309
+ field: group.parent.field,
12310
+ name: group.parent.label,
12311
+ fieldType: group.parent.fieldType,
12312
+ valuePrefix,
12313
+ onClick
12314
+ });
12315
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Menu.Root, {
12316
+ positioning: {
12317
+ placement: "right-start",
12318
+ gutter: 2
12319
+ },
12320
+ lazyMount: true,
12321
+ unmountOnExit: true,
12322
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Menu.TriggerItem, {
12323
+ "data-testid": `file-group-${group.parent.field}`,
12324
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Box, {
12325
+ display: "flex",
12326
+ alignItems: "center",
12327
+ gap: 2,
12328
+ flex: 1,
12329
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Box, {
12330
+ as: "span",
12331
+ fontSize: "xs",
12332
+ fontWeight: "medium",
12333
+ color: "gray.400",
12334
+ fontFamily: "mono",
12335
+ minWidth: "20px",
12336
+ children: getFieldTypeIcon(group.parent.fieldType)
12337
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Text, {
12338
+ truncate: true,
12339
+ children: group.parent.label
12340
+ })]
12341
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_lu.LuChevronRight, {})]
12342
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Portal, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Menu.Positioner, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Menu.Content, {
12343
+ maxH: "300px",
12344
+ minW: "200px",
12345
+ overflowY: "auto",
12346
+ children: [!parentVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldMenuItem, {
12347
+ field: group.parent.field,
12348
+ name: group.parent.label,
12349
+ fieldType: group.parent.fieldType,
12350
+ valuePrefix,
12351
+ onClick
12352
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Menu.Separator, {})] }), group.children.map((col) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldMenuItem, {
12353
+ field: col.field,
12354
+ name: col.label,
12355
+ fieldType: col.fieldType,
12356
+ valuePrefix,
12357
+ onClick
12358
+ }, col.field))]
12359
+ }) }) })]
12360
+ });
12361
+ };
12362
+
12158
12363
  //#endregion
12159
12364
  //#region src/table-editor/Table/ui/Header/InsertColumnSubmenu.tsx
12160
- const InsertColumnSubmenu = ({ label, valuePrefix, availableFields, onSelect }) => {
12365
+ const InsertColumnSubmenu = ({ label, valuePrefix, availableFields, allColumns, onSelect }) => {
12161
12366
  if (availableFields.length === 0) return null;
12367
+ const groupedFields = groupFileFields(availableFields, allColumns);
12162
12368
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Menu.Root, {
12163
12369
  positioning: {
12164
12370
  placement: "right-start",
@@ -12173,13 +12379,18 @@ const InsertColumnSubmenu = ({ label, valuePrefix, availableFields, onSelect })
12173
12379
  maxH: "300px",
12174
12380
  minW: "200px",
12175
12381
  overflowY: "auto",
12176
- children: availableFields.map((col) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldMenuItem, {
12177
- field: col.field,
12178
- name: col.label,
12179
- fieldType: col.fieldType,
12382
+ children: groupedFields.map((item) => isFileFieldGroup(item) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FileFieldSubmenu, {
12383
+ group: item,
12384
+ parentVisible: item.parentVisible,
12385
+ valuePrefix,
12386
+ onClick: onSelect
12387
+ }, item.parent.field) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldMenuItem, {
12388
+ field: item.field,
12389
+ name: item.label,
12390
+ fieldType: item.fieldType,
12180
12391
  valuePrefix,
12181
12392
  onClick: onSelect
12182
- }, col.field))
12393
+ }, item.field))
12183
12394
  }) }) })]
12184
12395
  });
12185
12396
  };
@@ -12188,8 +12399,8 @@ const InsertColumnSubmenu = ({ label, valuePrefix, availableFields, onSelect })
12188
12399
  //#region src/table-editor/Table/ui/Header/ColumnHeaderMenu.tsx
12189
12400
  const ColumnHeaderMenu = (0, mobx_react_lite.observer)(({ column, columnsModel, sortModel, filterModel, onCopyPath, onClose }) => {
12190
12401
  const canRemove = columnsModel.canRemoveColumn;
12191
- const availableFields = columnsModel.availableFieldsToAdd;
12192
- const hasAvailableFields = availableFields.length > 0;
12402
+ const insertableFields = columnsModel.availableFieldsToInsert;
12403
+ const hasInsertableFields = insertableFields.length > 0;
12193
12404
  const canMove = columnsModel.canMoveLeft(column.field) || columnsModel.canMoveRight(column.field);
12194
12405
  const isPinned = columnsModel.isPinned(column.field);
12195
12406
  const canPinLeft = columnsModel.canPinLeft(column.field);
@@ -12227,11 +12438,11 @@ const ColumnHeaderMenu = (0, mobx_react_lite.observer)(({ column, columnsModel,
12227
12438
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Menu.Content, {
12228
12439
  minW: "180px",
12229
12440
  children: [
12230
- sortModel && !column.hasFormula && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SortSubmenu, {
12441
+ sortModel && column.isSortable && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(SortSubmenu, {
12231
12442
  field: column.field,
12232
12443
  sortModel
12233
12444
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Menu.Separator, {})] }),
12234
- filterModel && !column.hasFormula && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Menu.Item, {
12445
+ filterModel && column.isSortable && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Menu.Item, {
12235
12446
  value: "add-filter",
12236
12447
  onClick: handleAddFilter,
12237
12448
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_lu.LuFilter, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Text, { children: "Add filter" })]
@@ -12257,17 +12468,19 @@ const ColumnHeaderMenu = (0, mobx_react_lite.observer)(({ column, columnsModel,
12257
12468
  }),
12258
12469
  (canPinLeft || canPinRight) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Menu.Separator, {})
12259
12470
  ] }),
12260
- hasAvailableFields && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
12471
+ hasInsertableFields && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
12261
12472
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InsertColumnSubmenu, {
12262
12473
  label: "Insert before",
12263
12474
  valuePrefix: "before",
12264
- availableFields,
12475
+ availableFields: insertableFields,
12476
+ allColumns: columnsModel.allColumns,
12265
12477
  onSelect: handleInsertBefore
12266
12478
  }),
12267
12479
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InsertColumnSubmenu, {
12268
12480
  label: "Insert after",
12269
12481
  valuePrefix: "after",
12270
- availableFields,
12482
+ availableFields: insertableFields,
12483
+ allColumns: columnsModel.allColumns,
12271
12484
  onSelect: handleInsertAfter
12272
12485
  }),
12273
12486
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Menu.Separator, {})
@@ -12385,11 +12598,11 @@ const ColumnHeader = (0, mobx_react_lite.observer)(({ column, columnsModel, sort
12385
12598
  field: column.field,
12386
12599
  columnsModel
12387
12600
  }),
12388
- filterModel && !column.hasFormula && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FilterIndicator, {
12601
+ filterModel && column.isSortable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FilterIndicator, {
12389
12602
  field: column.field,
12390
12603
  filterModel
12391
12604
  }),
12392
- sortModel && !column.hasFormula && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SortIndicator, {
12605
+ sortModel && column.isSortable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SortIndicator, {
12393
12606
  field: column.field,
12394
12607
  sortModel
12395
12608
  })
@@ -12416,6 +12629,7 @@ const AddColumnButton = (0, mobx_react_lite.observer)(({ columnsModel }) => {
12416
12629
  const availableFields = columnsModel.availableFieldsToAdd;
12417
12630
  const availableSystemFields = columnsModel.availableSystemFieldsToAdd;
12418
12631
  if (!columnsModel.hasHiddenColumns) return null;
12632
+ const groupedFields = groupFileFields(availableFields, columnsModel.allColumns);
12419
12633
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Flex, {
12420
12634
  alignItems: "center",
12421
12635
  px: "4px",
@@ -12449,17 +12663,21 @@ const AddColumnButton = (0, mobx_react_lite.observer)(({ columnsModel }) => {
12449
12663
  onClick: columnsModel.addAll,
12450
12664
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiListBullets, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Text, { children: "Add all columns" })]
12451
12665
  }),
12452
- availableFields.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Menu.Separator, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Menu.ItemGroup, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Menu.ItemGroupLabel, {
12666
+ groupedFields.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Menu.Separator, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Menu.ItemGroup, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Menu.ItemGroupLabel, {
12453
12667
  fontWeight: "medium",
12454
12668
  color: "gray.500",
12455
12669
  fontSize: "xs",
12456
12670
  children: "Data fields"
12457
- }), availableFields.map((col) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldMenuItem, {
12458
- field: col.field,
12459
- name: col.label,
12460
- fieldType: col.fieldType,
12671
+ }), groupedFields.map((item) => isFileFieldGroup(item) ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FileFieldSubmenu, {
12672
+ group: item,
12673
+ parentVisible: item.parentVisible,
12674
+ onClick: columnsModel.showColumn
12675
+ }, item.parent.field) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FieldMenuItem, {
12676
+ field: item.field,
12677
+ name: item.label,
12678
+ fieldType: item.fieldType,
12461
12679
  onClick: columnsModel.showColumn
12462
- }, col.field))] })] }),
12680
+ }, item.field))] })] }),
12463
12681
  availableSystemFields.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Menu.Separator, {}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Menu.ItemGroup, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Menu.ItemGroupLabel, {
12464
12682
  fontWeight: "medium",
12465
12683
  color: "gray.500",
@@ -12834,45 +13052,48 @@ const SelectionToolbar = (0, mobx_react_lite.observer)(({ selection, allRowIds,
12834
13052
  const isAllSelected = selection.isAllSelected(allRowIds);
12835
13053
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.ActionBar.Root, {
12836
13054
  open: selection.isSelectionMode,
12837
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Portal, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.ActionBar.Positioner, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.ActionBar.Content, {
12838
- "data-testid": "selection-toolbar",
12839
- children: [
12840
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.ActionBar.SelectionTrigger, { children: [selection.selectedCount, " selected"] }),
12841
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.ActionBar.Separator, {}),
12842
- !isAllSelected && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Button, {
12843
- variant: "outline",
12844
- size: "sm",
12845
- onClick: () => selection.selectAll(allRowIds),
12846
- "data-testid": "select-all",
12847
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiCheckSquare, {}), "Select all"]
12848
- }),
12849
- onDuplicate && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Button, {
12850
- variant: "outline",
12851
- size: "sm",
12852
- onClick: () => onDuplicate(selection.selectedIds),
12853
- "data-testid": "duplicate-selected",
12854
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_lu.LuCopy, {}), "Duplicate"]
12855
- }),
12856
- onDelete && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Button, {
12857
- variant: "outline",
12858
- size: "sm",
12859
- onClick: () => onDelete(selection.selectedIds),
12860
- "data-testid": "delete-selected",
12861
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_lu.LuTrash2, {}), "Delete"]
12862
- }),
12863
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.ActionBar.CloseTrigger, {
12864
- asChild: true,
12865
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Button, {
12866
- variant: "ghost",
13055
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Portal, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.ActionBar.Positioner, {
13056
+ zIndex: 5,
13057
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.ActionBar.Content, {
13058
+ "data-testid": "selection-toolbar",
13059
+ children: [
13060
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.ActionBar.SelectionTrigger, { children: [selection.selectedCount, " selected"] }),
13061
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.ActionBar.Separator, {}),
13062
+ !isAllSelected && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Button, {
13063
+ variant: "outline",
13064
+ size: "sm",
13065
+ onClick: () => selection.selectAll(allRowIds),
13066
+ "data-testid": "select-all",
13067
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiCheckSquare, {}), "Select all"]
13068
+ }),
13069
+ onDuplicate && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Button, {
13070
+ variant: "outline",
12867
13071
  size: "sm",
12868
- "aria-label": "Exit selection",
12869
- onClick: () => selection.exitSelectionMode(),
12870
- "data-testid": "exit-selection",
12871
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiX, {})
13072
+ onClick: () => onDuplicate(selection.selectedIds),
13073
+ "data-testid": "duplicate-selected",
13074
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_lu.LuCopy, {}), "Duplicate"]
13075
+ }),
13076
+ onDelete && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_chakra_ui_react.Button, {
13077
+ variant: "outline",
13078
+ size: "sm",
13079
+ onClick: () => onDelete(selection.selectedIds),
13080
+ "data-testid": "delete-selected",
13081
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_lu.LuTrash2, {}), "Delete"]
13082
+ }),
13083
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.ActionBar.CloseTrigger, {
13084
+ asChild: true,
13085
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_chakra_ui_react.Button, {
13086
+ variant: "ghost",
13087
+ size: "sm",
13088
+ "aria-label": "Exit selection",
13089
+ onClick: () => selection.exitSelectionMode(),
13090
+ "data-testid": "exit-selection",
13091
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_icons_pi.PiX, {})
13092
+ })
12872
13093
  })
12873
- })
12874
- ]
12875
- }) }) })
13094
+ ]
13095
+ })
13096
+ }) })
12876
13097
  });
12877
13098
  });
12878
13099
 
@@ -13505,67 +13726,6 @@ var ViewSettingsBadgeModel = class {
13505
13726
  }
13506
13727
  };
13507
13728
 
13508
- //#endregion
13509
- //#region src/table-editor/TableEditor/model/SchemaContext.ts
13510
- const SYSTEM_REF_SCHEMAS = {
13511
- [_revisium_schema_toolkit.SystemSchemaIds.File]: _revisium_schema_toolkit.fileSchema,
13512
- [_revisium_schema_toolkit.SystemSchemaIds.RowId]: _revisium_schema_toolkit.rowIdSchema,
13513
- [_revisium_schema_toolkit.SystemSchemaIds.RowCreatedAt]: _revisium_schema_toolkit.rowCreatedAtSchema,
13514
- [_revisium_schema_toolkit.SystemSchemaIds.RowCreatedId]: _revisium_schema_toolkit.rowCreatedIdSchema,
13515
- [_revisium_schema_toolkit.SystemSchemaIds.RowVersionId]: _revisium_schema_toolkit.rowVersionIdSchema,
13516
- [_revisium_schema_toolkit.SystemSchemaIds.RowPublishedAt]: _revisium_schema_toolkit.rowPublishedAtSchema,
13517
- [_revisium_schema_toolkit.SystemSchemaIds.RowUpdatedAt]: _revisium_schema_toolkit.rowUpdatedAtSchema,
13518
- [_revisium_schema_toolkit.SystemSchemaIds.RowHash]: _revisium_schema_toolkit.rowHashSchema,
13519
- [_revisium_schema_toolkit.SystemSchemaIds.RowSchemaHash]: _revisium_schema_toolkit.rowSchemaHashSchema
13520
- };
13521
- function buildRowSchema(dataSchema) {
13522
- const systemProperties = {};
13523
- for (const sf of SYSTEM_FIELDS) systemProperties[sf.id] = { $ref: sf.ref };
13524
- return {
13525
- type: "object",
13526
- properties: {
13527
- ...systemProperties,
13528
- ...dataSchema.properties
13529
- },
13530
- additionalProperties: false,
13531
- required: [...Object.keys(systemProperties), ...dataSchema.required ?? []]
13532
- };
13533
- }
13534
- var SchemaContext = class {
13535
- _allColumns = [];
13536
- _dataSchema = null;
13537
- _fullRefSchemas = {};
13538
- _rootNode = null;
13539
- get allColumns() {
13540
- return this._allColumns;
13541
- }
13542
- get sortableFields() {
13543
- return this._allColumns.filter((col) => !col.isDeprecated && col.fieldType !== FilterFieldType.File);
13544
- }
13545
- get filterableFields() {
13546
- return this.sortableFields;
13547
- }
13548
- get dataSchema() {
13549
- return this._dataSchema;
13550
- }
13551
- get fullRefSchemas() {
13552
- return this._fullRefSchemas;
13553
- }
13554
- get rootNode() {
13555
- return this._rootNode;
13556
- }
13557
- init(dataSchema, refSchemas) {
13558
- this._dataSchema = dataSchema;
13559
- this._fullRefSchemas = {
13560
- ...SYSTEM_REF_SCHEMAS,
13561
- ...refSchemas
13562
- };
13563
- const rowSchema = buildRowSchema(dataSchema);
13564
- this._rootNode = new _revisium_schema_toolkit.SchemaParser().parse(rowSchema, this._fullRefSchemas);
13565
- this._allColumns = extractColumns(this._rootNode);
13566
- }
13567
- };
13568
-
13569
13729
  //#endregion
13570
13730
  //#region src/table-editor/TableEditor/model/TableEditorCore.ts
13571
13731
  const DEFAULT_PAGE_SIZE = 50;
@@ -13712,7 +13872,10 @@ var TableEditorCore = class {
13712
13872
  _buildQuery(after = null) {
13713
13873
  return {
13714
13874
  where: this.filters.hasActiveFilters ? this.filters.buildCurrentWhereClause() : null,
13715
- orderBy: this.sorts.serializeToViewSorts(),
13875
+ orderBy: this.sorts.serializeToViewSorts().map((s) => ({
13876
+ field: stripDataFieldPrefix(s.field),
13877
+ direction: s.direction
13878
+ })),
13716
13879
  search: this.search.debouncedQuery,
13717
13880
  first: this._pageSize,
13718
13881
  after
@@ -13747,14 +13910,14 @@ var TableEditorCore = class {
13747
13910
  this._updateNavigationContext();
13748
13911
  }
13749
13912
  _createRowVMs(rawRows) {
13750
- const dataSchema = this._schemaContext.dataSchema;
13751
- if (!dataSchema) return [];
13913
+ const wrappedSchema = this._schemaContext.wrappedDataSchema;
13914
+ if (!wrappedSchema) return [];
13752
13915
  const tableModel = (0, _revisium_schema_toolkit.createTableModel)({
13753
13916
  tableId: this._tableId,
13754
- schema: dataSchema,
13917
+ schema: wrappedSchema,
13755
13918
  rows: rawRows.map((r) => ({
13756
13919
  rowId: r.rowId,
13757
- data: r.data
13920
+ data: { data: r.data }
13758
13921
  })),
13759
13922
  refSchemas: this._schemaContext.fullRefSchemas
13760
13923
  });
@@ -13768,10 +13931,14 @@ var TableEditorCore = class {
13768
13931
  id: rawRow.rowId
13769
13932
  };
13770
13933
  }
13934
+ _toPatchField(field) {
13935
+ return stripDataFieldPrefix(field);
13936
+ }
13771
13937
  async _commitCell(rowId, field, value, previousValue) {
13938
+ const patchField = this._toPatchField(field);
13772
13939
  const result = (await this._dataSource.patchCells([{
13773
13940
  rowId,
13774
- field,
13941
+ field: patchField,
13775
13942
  value
13776
13943
  }]))[0];
13777
13944
  if (result && !result.ok) (0, mobx.runInAction)(() => {
@@ -13851,7 +14018,7 @@ var MockDataSource = class {
13851
14018
  static createRow(rowId, data, systemFields) {
13852
14019
  const row = {
13853
14020
  rowId,
13854
- data: { ...data }
14021
+ data: data && typeof data === "object" && !Array.isArray(data) ? { ...data } : data
13855
14022
  };
13856
14023
  if (systemFields) row.systemFields = systemFields;
13857
14024
  return row;
@@ -13870,16 +14037,23 @@ var MockDataSource = class {
13870
14037
  let rows = [...this._allRows];
13871
14038
  if (query.search) {
13872
14039
  const lower = query.search.toLowerCase();
13873
- rows = rows.filter((row) => Object.values(row.data).some((val) => typeof val === "string" && val.toLowerCase().includes(lower)));
14040
+ rows = rows.filter((row) => {
14041
+ const data = row.data;
14042
+ if (data && typeof data === "object") return Object.values(data).some((val) => typeof val === "string" && val.toLowerCase().includes(lower));
14043
+ if (typeof data === "string") return data.toLowerCase().includes(lower);
14044
+ return false;
14045
+ });
13874
14046
  }
13875
14047
  if (query.orderBy.length > 0) {
13876
14048
  const firstOrder = query.orderBy[0];
13877
14049
  if (firstOrder) {
13878
- const field = firstOrder.field.startsWith("data.") ? firstOrder.field.slice(5) : firstOrder.field;
14050
+ const field = firstOrder.field;
13879
14051
  const dir = firstOrder.direction === "desc" ? -1 : 1;
13880
14052
  rows.sort((a, b) => {
13881
- const aVal = a.data[field];
13882
- const bVal = b.data[field];
14053
+ const aData = a.data;
14054
+ const bData = b.data;
14055
+ const aVal = aData?.[field];
14056
+ const bVal = bData?.[field];
13883
14057
  if (aVal === bVal) return 0;
13884
14058
  if (aVal == null) return 1;
13885
14059
  if (bVal == null) return -1;
@@ -13915,7 +14089,7 @@ var MockDataSource = class {
13915
14089
  error: "Mock failure"
13916
14090
  };
13917
14091
  const row = this._allRows.find((r) => r.rowId === patch.rowId);
13918
- if (row) row.data[patch.field] = patch.value;
14092
+ if (row?.data && typeof row.data === "object" && !Array.isArray(row.data)) row.data[patch.field] = patch.value;
13919
14093
  return {
13920
14094
  rowId: patch.rowId,
13921
14095
  field: patch.field,
@@ -14218,6 +14392,8 @@ exports.getDefaultOperator = getDefaultOperator;
14218
14392
  exports.getLabelByRef = getLabelByRef;
14219
14393
  exports.getOperatorLabel = getOperatorLabel;
14220
14394
  exports.getOperatorsForType = getOperatorsForType;
14395
+ exports.groupFileFields = groupFileFields;
14396
+ exports.isFileFieldGroup = isFileFieldGroup;
14221
14397
  exports.operatorRequiresValue = operatorRequiresValue;
14222
14398
  exports.selectDefaultColumns = selectDefaultColumns;
14223
14399
  exports.typeMenuGroups = typeMenuGroups;