@stndrds/schema 0.1.0-alpha.61 → 0.1.0-alpha.63

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.
@@ -7083,6 +7083,15 @@ var BaseTableTabConfig = class {
7083
7083
  this.tabData.allowCreate = true;
7084
7084
  return this;
7085
7085
  }
7086
+ /**
7087
+ * Set creation behavior when clicking "+"
7088
+ * @param mode - "redirect" (navigate to detail), "inline" (empty row), or "modal" (stacked modal)
7089
+ * @example .createMode("inline") or .createMode("modal")
7090
+ */
7091
+ createMode(mode) {
7092
+ this.tabData.createMode = mode;
7093
+ return this;
7094
+ }
7086
7095
  /**
7087
7096
  * Allow inline editing
7088
7097
  */
@@ -7688,8 +7697,6 @@ var ListViewBuilder = class {
7688
7697
  this.data = {
7689
7698
  name,
7690
7699
  label,
7691
- layout: "table",
7692
- columns: [],
7693
7700
  tabs: []
7694
7701
  };
7695
7702
  }
@@ -7730,82 +7737,21 @@ var ListViewBuilder = class {
7730
7737
  return this;
7731
7738
  }
7732
7739
  /**
7733
- * Set the layout to table (default)
7734
- */
7735
- table() {
7736
- this.data.layout = "table";
7737
- return this;
7738
- }
7739
- /**
7740
- * Set the layout to kanban and specify the grouping attribute
7741
- * @param groupByAttribute - Attribute to group by (must be a select/status type)
7742
- */
7743
- kanban(groupByAttribute) {
7744
- this.data.layout = "kanban";
7745
- this.data.groupByAttribute = groupByAttribute;
7746
- return this;
7747
- }
7748
- /**
7749
- * Set columns to display
7750
- * @example .columns("name", "email", "status", "createdAt")
7751
- */
7752
- columns(...names) {
7753
- this.data.columns = names;
7754
- return this;
7755
- }
7756
- /**
7757
- * Set width for a specific column in pixels
7758
- * @example .columnWidth("email", 200)
7740
+ * Set base filters applied to ALL tabs (scoping, tenant, etc.)
7741
+ * @example .baseFilter({ combinator: "and", rules: [{ attribute: "tenant", operator: "is", value: "acme" }] })
7759
7742
  */
7760
- columnWidth(columnName, width) {
7761
- if (!this.data.columnSizing) {
7762
- this.data.columnSizing = {};
7763
- }
7764
- this.data.columnSizing[columnName] = width;
7765
- return this;
7766
- }
7767
- /**
7768
- * Set widths for multiple columns
7769
- * @example .columnWidths({ email: 200, name: 300, status: 100 })
7770
- */
7771
- columnWidths(widths) {
7772
- this.data.columnSizing = { ...this.data.columnSizing, ...widths };
7773
- return this;
7774
- }
7775
- /**
7776
- * Set default filters
7777
- * @example .filter({ combinator: "and", rules: [{ attribute: "status", operator: "is", value: "active" }] })
7778
- */
7779
- filter(filters) {
7743
+ baseFilter(filters) {
7780
7744
  this.data.defaultFilters = filters;
7781
7745
  return this;
7782
7746
  }
7783
7747
  /**
7784
- * Add a single sort rule
7785
- * @example .sort("lastName", "asc")
7786
- */
7787
- sort(attribute, direction = "asc") {
7788
- if (!this.data.defaultSorts) {
7789
- this.data.defaultSorts = [];
7790
- }
7791
- this.data.defaultSorts.push({ attribute, direction });
7792
- return this;
7793
- }
7794
- /**
7795
- * Set multiple sort rules
7796
- * @example .sorts([{ attribute: "lastName", direction: "asc" }, { attribute: "firstName", direction: "asc" }])
7797
- */
7798
- sorts(rules) {
7799
- this.data.defaultSorts = rules;
7800
- return this;
7801
- }
7802
- /**
7803
- * Add an internal tab (filter preset)
7804
- * Returns a TabConfigBuilder for chaining tab configuration
7748
+ * Add a tab with its own full configuration (layout, columns, filters, sorts, groupBy)
7749
+ * Returns a ListViewTabConfigBuilder for chaining tab configuration
7805
7750
  * @example
7806
7751
  * ```typescript
7807
- * .tab("all", "All Contacts").icon("users").default()
7808
- * .tab("active", "Active").icon("check").filter({ ... })
7752
+ * .tab("all", "All Contacts").columns("name", "email").default()
7753
+ * .tab("active", "Active").columns("name", "email").filter({ ... })
7754
+ * .tab("pipeline", "Pipeline").kanban("stage").columns("name", "amount")
7809
7755
  * ```
7810
7756
  */
7811
7757
  tab(id, label) {
@@ -7825,13 +7771,8 @@ var ListViewBuilder = class {
7825
7771
  if (!this.data.object) {
7826
7772
  throw new Error("[ListViewBuilder] for() is required - specify the target object");
7827
7773
  }
7828
- if (this.data.columns.length === 0) {
7829
- throw new Error("[ListViewBuilder] columns() is required - specify at least one column");
7830
- }
7831
- if (this.data.layout === "kanban" && !this.data.groupByAttribute) {
7832
- throw new Error(
7833
- "[ListViewBuilder] kanban() requires a groupByAttribute - specify the attribute to group by"
7834
- );
7774
+ if (this.data.tabs.length === 0) {
7775
+ throw new Error("[ListViewBuilder] At least one tab is required");
7835
7776
  }
7836
7777
  const tabIds = /* @__PURE__ */ new Set();
7837
7778
  for (const tab of this.data.tabs) {
@@ -7844,28 +7785,39 @@ var ListViewBuilder = class {
7844
7785
  if (defaultTabs.length > 1) {
7845
7786
  throw new Error("[ListViewBuilder] Only one tab can be marked as default");
7846
7787
  }
7788
+ for (const tab of this.data.tabs) {
7789
+ if (tab.columns.length === 0) {
7790
+ throw new Error(`[ListViewBuilder] Tab "${tab.id}" must have at least one column`);
7791
+ }
7792
+ if (tab.layout === "kanban" && !tab.groupByAttribute) {
7793
+ throw new Error(`[ListViewBuilder] Kanban tab "${tab.id}" requires a groupByAttribute`);
7794
+ }
7795
+ }
7847
7796
  const config = {
7848
- layout: this.data.layout,
7849
- columns: this.data.columns,
7850
- columnSizing: this.data.columnSizing,
7851
7797
  defaultFilters: this.data.defaultFilters ? {
7852
7798
  id: _chunkNEVERCM3js.generateId.call(void 0, ),
7853
7799
  combinator: this.data.defaultFilters.combinator,
7854
7800
  rules: this.data.defaultFilters.rules
7855
7801
  } : void 0,
7856
- defaultSorts: this.data.defaultSorts,
7857
- groupByAttribute: this.data.groupByAttribute,
7858
- tabs: this.data.tabs.length > 0 ? this.data.tabs.map((tab) => ({
7802
+ tabs: this.data.tabs.map((tab) => ({
7859
7803
  id: tab.id,
7860
7804
  label: tab.label,
7861
7805
  icon: tab.icon,
7806
+ default: tab.default,
7807
+ layout: tab.layout,
7808
+ columns: tab.columns,
7809
+ columnSizing: tab.columnSizing,
7862
7810
  filters: tab.filters ? {
7863
7811
  id: _chunkNEVERCM3js.generateId.call(void 0, ),
7864
7812
  combinator: tab.filters.combinator,
7865
7813
  rules: tab.filters.rules
7866
7814
  } : void 0,
7867
- default: tab.default
7868
- })) : void 0
7815
+ sorts: tab.sorts,
7816
+ groupByAttribute: tab.groupByAttribute,
7817
+ cardUserAttribute: tab.cardUserAttribute,
7818
+ cardDateAttribute: tab.cardDateAttribute,
7819
+ createMode: tab.createMode
7820
+ }))
7869
7821
  };
7870
7822
  return {
7871
7823
  name: this.data.name,
@@ -7900,7 +7852,12 @@ var ListViewTabConfigBuilder = class _ListViewTabConfigBuilder {
7900
7852
  /** @internal */
7901
7853
  constructor(view2, id, label) {
7902
7854
  this.view = view2;
7903
- this.tabData = { id, label };
7855
+ this.tabData = {
7856
+ id,
7857
+ label,
7858
+ layout: "table",
7859
+ columns: []
7860
+ };
7904
7861
  }
7905
7862
  /**
7906
7863
  * Set tab icon
@@ -7910,7 +7867,74 @@ var ListViewTabConfigBuilder = class _ListViewTabConfigBuilder {
7910
7867
  return this;
7911
7868
  }
7912
7869
  /**
7913
- * Set filters for this tab (filter preset)
7870
+ * Mark this tab as the default tab
7871
+ */
7872
+ default() {
7873
+ this.tabData.default = true;
7874
+ return this;
7875
+ }
7876
+ /**
7877
+ * Set the layout to table (default)
7878
+ */
7879
+ table() {
7880
+ this.tabData.layout = "table";
7881
+ return this;
7882
+ }
7883
+ /**
7884
+ * Set the layout to kanban and specify the grouping attribute
7885
+ * @param groupByAttribute - Attribute to group by (must be a select/status type)
7886
+ */
7887
+ kanban(groupByAttribute) {
7888
+ this.tabData.layout = "kanban";
7889
+ this.tabData.groupByAttribute = groupByAttribute;
7890
+ return this;
7891
+ }
7892
+ /**
7893
+ * Set the user attribute to display on kanban cards (bottom-left)
7894
+ * @param attributeName - Name of a user-type attribute
7895
+ */
7896
+ cardUserAttribute(attributeName) {
7897
+ this.tabData.cardUserAttribute = attributeName;
7898
+ return this;
7899
+ }
7900
+ /**
7901
+ * Set the date attribute to display on kanban cards (bottom-right)
7902
+ * @param attributeName - Name of a date-type attribute
7903
+ */
7904
+ cardDateAttribute(attributeName) {
7905
+ this.tabData.cardDateAttribute = attributeName;
7906
+ return this;
7907
+ }
7908
+ /**
7909
+ * Set creation behavior when clicking "+"
7910
+ * @param mode - "redirect" (navigate to detail), "inline" (empty row), or "modal" (stacked modal)
7911
+ * @example .createMode("inline") or .createMode("modal")
7912
+ */
7913
+ createMode(mode) {
7914
+ this.tabData.createMode = mode;
7915
+ return this;
7916
+ }
7917
+ /**
7918
+ * Set columns to display
7919
+ * @example .columns("name", "email", "status", "createdAt")
7920
+ */
7921
+ columns(...names) {
7922
+ this.tabData.columns = names;
7923
+ return this;
7924
+ }
7925
+ /**
7926
+ * Set width for a specific column in pixels
7927
+ * @example .columnWidth("email", 200)
7928
+ */
7929
+ columnWidth(columnName, width) {
7930
+ if (!this.tabData.columnSizing) {
7931
+ this.tabData.columnSizing = {};
7932
+ }
7933
+ this.tabData.columnSizing[columnName] = width;
7934
+ return this;
7935
+ }
7936
+ /**
7937
+ * Set filters for this tab
7914
7938
  * @example .filter({ combinator: "and", rules: [{ attribute: "status", operator: "is", value: "active" }] })
7915
7939
  */
7916
7940
  filter(filters) {
@@ -7918,10 +7942,22 @@ var ListViewTabConfigBuilder = class _ListViewTabConfigBuilder {
7918
7942
  return this;
7919
7943
  }
7920
7944
  /**
7921
- * Mark this tab as the default tab
7945
+ * Add a single sort rule
7946
+ * @example .sort("lastName", "asc")
7922
7947
  */
7923
- default() {
7924
- this.tabData.default = true;
7948
+ sort(attribute, direction = "asc") {
7949
+ if (!this.tabData.sorts) {
7950
+ this.tabData.sorts = [];
7951
+ }
7952
+ this.tabData.sorts.push({ attribute, direction });
7953
+ return this;
7954
+ }
7955
+ /**
7956
+ * Set multiple sort rules
7957
+ * @example .sorts([{ attribute: "lastName", direction: "asc" }, { attribute: "firstName", direction: "asc" }])
7958
+ */
7959
+ sorts(rules) {
7960
+ this.tabData.sorts = rules;
7925
7961
  return this;
7926
7962
  }
7927
7963
  /**
@@ -11969,6 +12005,28 @@ var RecordService = class extends BaseService {
11969
12005
  });
11970
12006
  }
11971
12007
  }
12008
+ /**
12009
+ * Delete multiple records (soft delete).
12010
+ * Each record goes through the full deleteRecord pipeline (permissions, policies, hooks, audit).
12011
+ *
12012
+ * @returns Summary with successfully deleted IDs and any errors encountered
12013
+ */
12014
+ async bulkDeleteRecords(recordIds, options) {
12015
+ const deleted = [];
12016
+ const errors = [];
12017
+ for (const id of recordIds) {
12018
+ try {
12019
+ await this.deleteRecord(id, options);
12020
+ deleted.push(id);
12021
+ } catch (err) {
12022
+ errors.push({
12023
+ id,
12024
+ error: err instanceof Error ? err.message : String(err)
12025
+ });
12026
+ }
12027
+ }
12028
+ return { deleted, errors };
12029
+ }
11972
12030
  /**
11973
12031
  * Permanently delete a record (hard delete)
11974
12032
  */
@@ -17241,8 +17299,15 @@ var ViewService = class extends BaseService {
17241
17299
  );
17242
17300
  const columns = visibleAttrs.sort((a, b) => (_nullishCoalesce(a.order, () => ( 999))) - (_nullishCoalesce(b.order, () => ( 999)))).slice(0, 5).map((attr) => attr.name);
17243
17301
  const config = {
17244
- layout: "table",
17245
- columns
17302
+ tabs: [
17303
+ {
17304
+ id: "all",
17305
+ label: "All",
17306
+ default: true,
17307
+ layout: "table",
17308
+ columns
17309
+ }
17310
+ ]
17246
17311
  };
17247
17312
  return {
17248
17313
  name: "default",
@@ -7083,6 +7083,15 @@ var BaseTableTabConfig = class {
7083
7083
  this.tabData.allowCreate = true;
7084
7084
  return this;
7085
7085
  }
7086
+ /**
7087
+ * Set creation behavior when clicking "+"
7088
+ * @param mode - "redirect" (navigate to detail), "inline" (empty row), or "modal" (stacked modal)
7089
+ * @example .createMode("inline") or .createMode("modal")
7090
+ */
7091
+ createMode(mode) {
7092
+ this.tabData.createMode = mode;
7093
+ return this;
7094
+ }
7086
7095
  /**
7087
7096
  * Allow inline editing
7088
7097
  */
@@ -7688,8 +7697,6 @@ var ListViewBuilder = class {
7688
7697
  this.data = {
7689
7698
  name,
7690
7699
  label,
7691
- layout: "table",
7692
- columns: [],
7693
7700
  tabs: []
7694
7701
  };
7695
7702
  }
@@ -7730,82 +7737,21 @@ var ListViewBuilder = class {
7730
7737
  return this;
7731
7738
  }
7732
7739
  /**
7733
- * Set the layout to table (default)
7734
- */
7735
- table() {
7736
- this.data.layout = "table";
7737
- return this;
7738
- }
7739
- /**
7740
- * Set the layout to kanban and specify the grouping attribute
7741
- * @param groupByAttribute - Attribute to group by (must be a select/status type)
7742
- */
7743
- kanban(groupByAttribute) {
7744
- this.data.layout = "kanban";
7745
- this.data.groupByAttribute = groupByAttribute;
7746
- return this;
7747
- }
7748
- /**
7749
- * Set columns to display
7750
- * @example .columns("name", "email", "status", "createdAt")
7751
- */
7752
- columns(...names) {
7753
- this.data.columns = names;
7754
- return this;
7755
- }
7756
- /**
7757
- * Set width for a specific column in pixels
7758
- * @example .columnWidth("email", 200)
7740
+ * Set base filters applied to ALL tabs (scoping, tenant, etc.)
7741
+ * @example .baseFilter({ combinator: "and", rules: [{ attribute: "tenant", operator: "is", value: "acme" }] })
7759
7742
  */
7760
- columnWidth(columnName, width) {
7761
- if (!this.data.columnSizing) {
7762
- this.data.columnSizing = {};
7763
- }
7764
- this.data.columnSizing[columnName] = width;
7765
- return this;
7766
- }
7767
- /**
7768
- * Set widths for multiple columns
7769
- * @example .columnWidths({ email: 200, name: 300, status: 100 })
7770
- */
7771
- columnWidths(widths) {
7772
- this.data.columnSizing = { ...this.data.columnSizing, ...widths };
7773
- return this;
7774
- }
7775
- /**
7776
- * Set default filters
7777
- * @example .filter({ combinator: "and", rules: [{ attribute: "status", operator: "is", value: "active" }] })
7778
- */
7779
- filter(filters) {
7743
+ baseFilter(filters) {
7780
7744
  this.data.defaultFilters = filters;
7781
7745
  return this;
7782
7746
  }
7783
7747
  /**
7784
- * Add a single sort rule
7785
- * @example .sort("lastName", "asc")
7786
- */
7787
- sort(attribute, direction = "asc") {
7788
- if (!this.data.defaultSorts) {
7789
- this.data.defaultSorts = [];
7790
- }
7791
- this.data.defaultSorts.push({ attribute, direction });
7792
- return this;
7793
- }
7794
- /**
7795
- * Set multiple sort rules
7796
- * @example .sorts([{ attribute: "lastName", direction: "asc" }, { attribute: "firstName", direction: "asc" }])
7797
- */
7798
- sorts(rules) {
7799
- this.data.defaultSorts = rules;
7800
- return this;
7801
- }
7802
- /**
7803
- * Add an internal tab (filter preset)
7804
- * Returns a TabConfigBuilder for chaining tab configuration
7748
+ * Add a tab with its own full configuration (layout, columns, filters, sorts, groupBy)
7749
+ * Returns a ListViewTabConfigBuilder for chaining tab configuration
7805
7750
  * @example
7806
7751
  * ```typescript
7807
- * .tab("all", "All Contacts").icon("users").default()
7808
- * .tab("active", "Active").icon("check").filter({ ... })
7752
+ * .tab("all", "All Contacts").columns("name", "email").default()
7753
+ * .tab("active", "Active").columns("name", "email").filter({ ... })
7754
+ * .tab("pipeline", "Pipeline").kanban("stage").columns("name", "amount")
7809
7755
  * ```
7810
7756
  */
7811
7757
  tab(id, label) {
@@ -7825,13 +7771,8 @@ var ListViewBuilder = class {
7825
7771
  if (!this.data.object) {
7826
7772
  throw new Error("[ListViewBuilder] for() is required - specify the target object");
7827
7773
  }
7828
- if (this.data.columns.length === 0) {
7829
- throw new Error("[ListViewBuilder] columns() is required - specify at least one column");
7830
- }
7831
- if (this.data.layout === "kanban" && !this.data.groupByAttribute) {
7832
- throw new Error(
7833
- "[ListViewBuilder] kanban() requires a groupByAttribute - specify the attribute to group by"
7834
- );
7774
+ if (this.data.tabs.length === 0) {
7775
+ throw new Error("[ListViewBuilder] At least one tab is required");
7835
7776
  }
7836
7777
  const tabIds = /* @__PURE__ */ new Set();
7837
7778
  for (const tab of this.data.tabs) {
@@ -7844,28 +7785,39 @@ var ListViewBuilder = class {
7844
7785
  if (defaultTabs.length > 1) {
7845
7786
  throw new Error("[ListViewBuilder] Only one tab can be marked as default");
7846
7787
  }
7788
+ for (const tab of this.data.tabs) {
7789
+ if (tab.columns.length === 0) {
7790
+ throw new Error(`[ListViewBuilder] Tab "${tab.id}" must have at least one column`);
7791
+ }
7792
+ if (tab.layout === "kanban" && !tab.groupByAttribute) {
7793
+ throw new Error(`[ListViewBuilder] Kanban tab "${tab.id}" requires a groupByAttribute`);
7794
+ }
7795
+ }
7847
7796
  const config = {
7848
- layout: this.data.layout,
7849
- columns: this.data.columns,
7850
- columnSizing: this.data.columnSizing,
7851
7797
  defaultFilters: this.data.defaultFilters ? {
7852
7798
  id: generateId(),
7853
7799
  combinator: this.data.defaultFilters.combinator,
7854
7800
  rules: this.data.defaultFilters.rules
7855
7801
  } : void 0,
7856
- defaultSorts: this.data.defaultSorts,
7857
- groupByAttribute: this.data.groupByAttribute,
7858
- tabs: this.data.tabs.length > 0 ? this.data.tabs.map((tab) => ({
7802
+ tabs: this.data.tabs.map((tab) => ({
7859
7803
  id: tab.id,
7860
7804
  label: tab.label,
7861
7805
  icon: tab.icon,
7806
+ default: tab.default,
7807
+ layout: tab.layout,
7808
+ columns: tab.columns,
7809
+ columnSizing: tab.columnSizing,
7862
7810
  filters: tab.filters ? {
7863
7811
  id: generateId(),
7864
7812
  combinator: tab.filters.combinator,
7865
7813
  rules: tab.filters.rules
7866
7814
  } : void 0,
7867
- default: tab.default
7868
- })) : void 0
7815
+ sorts: tab.sorts,
7816
+ groupByAttribute: tab.groupByAttribute,
7817
+ cardUserAttribute: tab.cardUserAttribute,
7818
+ cardDateAttribute: tab.cardDateAttribute,
7819
+ createMode: tab.createMode
7820
+ }))
7869
7821
  };
7870
7822
  return {
7871
7823
  name: this.data.name,
@@ -7900,7 +7852,12 @@ var ListViewTabConfigBuilder = class _ListViewTabConfigBuilder {
7900
7852
  /** @internal */
7901
7853
  constructor(view2, id, label) {
7902
7854
  this.view = view2;
7903
- this.tabData = { id, label };
7855
+ this.tabData = {
7856
+ id,
7857
+ label,
7858
+ layout: "table",
7859
+ columns: []
7860
+ };
7904
7861
  }
7905
7862
  /**
7906
7863
  * Set tab icon
@@ -7910,7 +7867,74 @@ var ListViewTabConfigBuilder = class _ListViewTabConfigBuilder {
7910
7867
  return this;
7911
7868
  }
7912
7869
  /**
7913
- * Set filters for this tab (filter preset)
7870
+ * Mark this tab as the default tab
7871
+ */
7872
+ default() {
7873
+ this.tabData.default = true;
7874
+ return this;
7875
+ }
7876
+ /**
7877
+ * Set the layout to table (default)
7878
+ */
7879
+ table() {
7880
+ this.tabData.layout = "table";
7881
+ return this;
7882
+ }
7883
+ /**
7884
+ * Set the layout to kanban and specify the grouping attribute
7885
+ * @param groupByAttribute - Attribute to group by (must be a select/status type)
7886
+ */
7887
+ kanban(groupByAttribute) {
7888
+ this.tabData.layout = "kanban";
7889
+ this.tabData.groupByAttribute = groupByAttribute;
7890
+ return this;
7891
+ }
7892
+ /**
7893
+ * Set the user attribute to display on kanban cards (bottom-left)
7894
+ * @param attributeName - Name of a user-type attribute
7895
+ */
7896
+ cardUserAttribute(attributeName) {
7897
+ this.tabData.cardUserAttribute = attributeName;
7898
+ return this;
7899
+ }
7900
+ /**
7901
+ * Set the date attribute to display on kanban cards (bottom-right)
7902
+ * @param attributeName - Name of a date-type attribute
7903
+ */
7904
+ cardDateAttribute(attributeName) {
7905
+ this.tabData.cardDateAttribute = attributeName;
7906
+ return this;
7907
+ }
7908
+ /**
7909
+ * Set creation behavior when clicking "+"
7910
+ * @param mode - "redirect" (navigate to detail), "inline" (empty row), or "modal" (stacked modal)
7911
+ * @example .createMode("inline") or .createMode("modal")
7912
+ */
7913
+ createMode(mode) {
7914
+ this.tabData.createMode = mode;
7915
+ return this;
7916
+ }
7917
+ /**
7918
+ * Set columns to display
7919
+ * @example .columns("name", "email", "status", "createdAt")
7920
+ */
7921
+ columns(...names) {
7922
+ this.tabData.columns = names;
7923
+ return this;
7924
+ }
7925
+ /**
7926
+ * Set width for a specific column in pixels
7927
+ * @example .columnWidth("email", 200)
7928
+ */
7929
+ columnWidth(columnName, width) {
7930
+ if (!this.tabData.columnSizing) {
7931
+ this.tabData.columnSizing = {};
7932
+ }
7933
+ this.tabData.columnSizing[columnName] = width;
7934
+ return this;
7935
+ }
7936
+ /**
7937
+ * Set filters for this tab
7914
7938
  * @example .filter({ combinator: "and", rules: [{ attribute: "status", operator: "is", value: "active" }] })
7915
7939
  */
7916
7940
  filter(filters) {
@@ -7918,10 +7942,22 @@ var ListViewTabConfigBuilder = class _ListViewTabConfigBuilder {
7918
7942
  return this;
7919
7943
  }
7920
7944
  /**
7921
- * Mark this tab as the default tab
7945
+ * Add a single sort rule
7946
+ * @example .sort("lastName", "asc")
7922
7947
  */
7923
- default() {
7924
- this.tabData.default = true;
7948
+ sort(attribute, direction = "asc") {
7949
+ if (!this.tabData.sorts) {
7950
+ this.tabData.sorts = [];
7951
+ }
7952
+ this.tabData.sorts.push({ attribute, direction });
7953
+ return this;
7954
+ }
7955
+ /**
7956
+ * Set multiple sort rules
7957
+ * @example .sorts([{ attribute: "lastName", direction: "asc" }, { attribute: "firstName", direction: "asc" }])
7958
+ */
7959
+ sorts(rules) {
7960
+ this.tabData.sorts = rules;
7925
7961
  return this;
7926
7962
  }
7927
7963
  /**
@@ -11969,6 +12005,28 @@ var RecordService = class extends BaseService {
11969
12005
  });
11970
12006
  }
11971
12007
  }
12008
+ /**
12009
+ * Delete multiple records (soft delete).
12010
+ * Each record goes through the full deleteRecord pipeline (permissions, policies, hooks, audit).
12011
+ *
12012
+ * @returns Summary with successfully deleted IDs and any errors encountered
12013
+ */
12014
+ async bulkDeleteRecords(recordIds, options) {
12015
+ const deleted = [];
12016
+ const errors = [];
12017
+ for (const id of recordIds) {
12018
+ try {
12019
+ await this.deleteRecord(id, options);
12020
+ deleted.push(id);
12021
+ } catch (err) {
12022
+ errors.push({
12023
+ id,
12024
+ error: err instanceof Error ? err.message : String(err)
12025
+ });
12026
+ }
12027
+ }
12028
+ return { deleted, errors };
12029
+ }
11972
12030
  /**
11973
12031
  * Permanently delete a record (hard delete)
11974
12032
  */
@@ -17241,8 +17299,15 @@ var ViewService = class extends BaseService {
17241
17299
  );
17242
17300
  const columns = visibleAttrs.sort((a, b) => (a.order ?? 999) - (b.order ?? 999)).slice(0, 5).map((attr) => attr.name);
17243
17301
  const config = {
17244
- layout: "table",
17245
- columns
17302
+ tabs: [
17303
+ {
17304
+ id: "all",
17305
+ label: "All",
17306
+ default: true,
17307
+ layout: "table",
17308
+ columns
17309
+ }
17310
+ ]
17246
17311
  };
17247
17312
  return {
17248
17313
  name: "default",