@juicemantics/veloiq-ui 0.6.0 → 0.8.0

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.mjs CHANGED
@@ -992,7 +992,7 @@ var CommandCenterPortal = ({
992
992
  }, [query, parsedCommand, search, clear]);
993
993
  const allModelChildren = useMemo(
994
994
  () => menuItems.flatMap(
995
- (m) => (m.children || []).map((c) => ({ ...c, moduleLabel: String(m.label || m.name || "") }))
995
+ (m) => (m.children || []).filter((c) => !c.meta?.hide).map((c) => ({ ...c, moduleLabel: String(m.label || m.name || "") }))
996
996
  ),
997
997
  [menuItems]
998
998
  );
@@ -1010,8 +1010,8 @@ var CommandCenterPortal = ({
1010
1010
  }, [allModelChildren]);
1011
1011
  const modules = useMemo(() => {
1012
1012
  const q2 = parsedCommand ? parsedCommand.modelQuery : query.toLowerCase().trim();
1013
- const moduleItems = menuItems.filter((item) => item.children && item.children.length > 0);
1014
- const sorted = navConfig.length > 0 ? sortItemsByNavConfig(moduleItems, navConfig) : moduleItems;
1013
+ const visibleModules = menuItems.filter((item) => item.children && item.children.length > 0).map((item) => ({ ...item, children: (item.children || []).filter((c) => !c.meta?.hide) })).filter((item) => item.children && item.children.length > 0);
1014
+ const sorted = navConfig.length > 0 ? sortItemsByNavConfig(visibleModules, navConfig) : visibleModules;
1015
1015
  if (!q2) return sorted;
1016
1016
  return sorted.map((module) => {
1017
1017
  const moduleMatch = (module.label || "").toLowerCase().includes(q2);
@@ -3992,6 +3992,12 @@ var getRecordId = (record, fields) => {
3992
3992
  }
3993
3993
  return record.eid ?? record.id;
3994
3994
  };
3995
+ var isPkField = (field, model) => {
3996
+ if (field.isPk === true) return true;
3997
+ if (model?.pkField != null && field.key === model.pkField) return true;
3998
+ return false;
3999
+ };
4000
+ var isReferenceField = (field) => !!field.reference;
3995
4001
  var getListViewFields = (model, filterField) => {
3996
4002
  const baseFields = filterField ? model.fields.filter((field) => field.key !== filterField) : model.fields;
3997
4003
  return baseFields.slice(0, 6);
@@ -4462,9 +4468,14 @@ var resolveRelationFromConfig = (relations, item) => {
4462
4468
  (rel) => (rel.relationName || "").toLowerCase() === target || (rel.resource || "").toLowerCase() === target || (rel.label || "").toLowerCase() === target
4463
4469
  );
4464
4470
  if (exact) return exact;
4465
- return relations.find(
4471
+ const byVariant = relations.find(
4466
4472
  (rel) => targetVariants.has((rel.relationName || "").toLowerCase()) || targetVariants.has((rel.resource || "").toLowerCase()) || targetVariants.has((rel.label || "").toLowerCase())
4467
4473
  );
4474
+ if (byVariant) return byVariant;
4475
+ const relPathBase = (rel) => String(rel.resourcePath || "").toLowerCase().replace(/_relation$/, "");
4476
+ return relations.find(
4477
+ (rel) => relPathBase(rel) === target || targetVariants.has(relPathBase(rel))
4478
+ );
4468
4479
  };
4469
4480
  var buildConfiguredRelationKeys = (rows) => {
4470
4481
  const keys = /* @__PURE__ */ new Set();
@@ -8433,7 +8444,7 @@ function buildColumnFilterOptions({
8433
8444
  }) {
8434
8445
  const filtersMap = /* @__PURE__ */ new Map();
8435
8446
  for (const field of fields) {
8436
- if (field.key === "eid") {
8447
+ if (isPkField(field)) {
8437
8448
  const labelValues = [];
8438
8449
  for (const record of data) {
8439
8450
  const lbl = record?._label;
@@ -8540,7 +8551,7 @@ function buildColumnFilterOptions({
8540
8551
  for (const record of data) {
8541
8552
  let value = record?.[field.key];
8542
8553
  let label = value;
8543
- if (field.key === "eid" && record?._label) {
8554
+ if (isPkField(field) && record?._label) {
8544
8555
  value = record.eid;
8545
8556
  label = record._label;
8546
8557
  }
@@ -8581,7 +8592,7 @@ function matchesColumnFilterValue(field, record, value) {
8581
8592
  const recordVal = String(record?.[field.key] ?? "");
8582
8593
  return recordVal.localeCompare(lo) >= 0 && recordVal.localeCompare(hi) <= 0;
8583
8594
  }
8584
- if (field.key === "eid" && strValue.startsWith("__catrange__:")) {
8595
+ if (isPkField(field) && strValue.startsWith("__catrange__:")) {
8585
8596
  const sub = strValue.substring("__catrange__:".length);
8586
8597
  const sepIdx = sub.indexOf(":");
8587
8598
  const lo = decodeURIComponent(sub.substring(0, sepIdx));
@@ -8589,7 +8600,7 @@ function matchesColumnFilterValue(field, record, value) {
8589
8600
  const recordLabel = String(record?._label ?? "");
8590
8601
  return recordLabel.localeCompare(lo) >= 0 && recordLabel.localeCompare(hi) <= 0;
8591
8602
  }
8592
- if (field.key === "eid" && record?._label) {
8603
+ if (isPkField(field) && record?._label) {
8593
8604
  return String(record._label) === strValue || String(record.eid) === strValue;
8594
8605
  }
8595
8606
  return String(record?.[field.key]) === strValue;
@@ -12707,11 +12718,11 @@ var RelatedObjectsTable = ({ rel, record, relatedModel, parentModel, showActions
12707
12718
  }
12708
12719
  }, [apiUrl, categoryField1, categoryField2, chartType, selectedSeriesKeys, summaryFn, rankingMode, rankingFieldKey, rankingN, crosstabFilterFields, relatedModel.name, relatedModel.resource, allModels]);
12709
12720
  const categoricalFields = useMemo(() => {
12710
- return relatedModel.fields.filter((field) => field.key === "eid" || (field.type !== "number" || field.reference));
12711
- }, [relatedModel.fields]);
12721
+ return relatedModel.fields.filter((field) => isPkField(field, relatedModel) || (field.type !== "number" || field.reference));
12722
+ }, [relatedModel]);
12712
12723
  const numericFields = useMemo(() => {
12713
- return relatedModel.fields.filter((field) => field.key !== "eid" && field.type === "number" && !field.reference);
12714
- }, [relatedModel.fields]);
12724
+ return relatedModel.fields.filter((field) => !isPkField(field, relatedModel) && field.type === "number" && !field.reference);
12725
+ }, [relatedModel]);
12715
12726
  const resetLayoutDefaults = useCallback(() => {
12716
12727
  setListVisible(true);
12717
12728
  setAnalyzeOpen(false);
@@ -13280,7 +13291,7 @@ var RelatedObjectsTable = ({ rel, record, relatedModel, parentModel, showActions
13280
13291
  if (!rowValues) return;
13281
13292
  const payload = {};
13282
13293
  relatedModel.fields.forEach((field) => {
13283
- if (field.key === "eid") return;
13294
+ if (isPkField(field, relatedModel)) return;
13284
13295
  if (!Object.prototype.hasOwnProperty.call(rowValues, field.key)) return;
13285
13296
  const newVal = normalizeFieldValue(field, rowValues[field.key]);
13286
13297
  const oldVal = normalizeFieldValue(field, row?.[field.key]);
@@ -13381,7 +13392,7 @@ var RelatedObjectsTable = ({ rel, record, relatedModel, parentModel, showActions
13381
13392
  const getSortValue = useCallback((field, recordRow) => {
13382
13393
  const raw = recordRow?.[field.key];
13383
13394
  if (raw === void 0 || raw === null) return null;
13384
- if (field.key === "eid" && recordRow?._label) return recordRow._label;
13395
+ if (isPkField(field, relatedModel) && recordRow?._label) return recordRow._label;
13385
13396
  if (field.reference) {
13386
13397
  const cacheKey = `${field.reference}:${raw}`;
13387
13398
  return labelCache[cacheKey] ?? raw;
@@ -13657,7 +13668,7 @@ var RelatedObjectsTable = ({ rel, record, relatedModel, parentModel, showActions
13657
13668
  if (!field) return _34("All");
13658
13669
  const raw = recordRow?.[field.key];
13659
13670
  if (raw === void 0 || raw === null) return "-";
13660
- if (field.key === "eid" && recordRow?._label) return recordRow._label;
13671
+ if (isPkField(field, relatedModel) && recordRow?._label) return recordRow._label;
13661
13672
  if (field.reference) {
13662
13673
  const cacheKey = `${field.reference}:${raw}`;
13663
13674
  return labelCache[cacheKey] || String(raw);
@@ -13938,7 +13949,7 @@ var RelatedObjectsTable = ({ rel, record, relatedModel, parentModel, showActions
13938
13949
  setSelectedSeriesKeys(value);
13939
13950
  },
13940
13951
  style: { width: "100%" },
13941
- options: relatedModel.fields.filter((field) => !field.isPk && field.key !== "eid").map((field) => ({ label: field.label, value: field.key })),
13952
+ options: relatedModel.fields.filter((field) => !isPkField(field, relatedModel)).map((field) => ({ label: field.label, value: field.key })),
13942
13953
  placeholder: _34("All numeric fields"),
13943
13954
  maxTagCount: "responsive"
13944
13955
  }
@@ -14205,9 +14216,9 @@ var RelatedObjectsTable = ({ rel, record, relatedModel, parentModel, showActions
14205
14216
  }, [columnFilteredRows, displayFields, labelCache]);
14206
14217
  const isTotalsDetailsVariant = viewVariant === "totals-details";
14207
14218
  const getDefaultTotalsSummaryFn = useCallback((field) => {
14208
- if (field.key === "eid") return "count";
14219
+ if (isPkField(field, relatedModel)) return "count";
14209
14220
  return "sum";
14210
- }, []);
14221
+ }, [relatedModel]);
14211
14222
  const resolveTotalsSummaryFn = useCallback((field) => {
14212
14223
  return totalsSummaryFunctions[field.key] || getDefaultTotalsSummaryFn(field);
14213
14224
  }, [getDefaultTotalsSummaryFn, totalsSummaryFunctions]);
@@ -15041,10 +15052,15 @@ var RelatedObjectsTable = ({ rel, record, relatedModel, parentModel, showActions
15041
15052
  allowInlineEdit && /* @__PURE__ */ jsx(
15042
15053
  Table.Column,
15043
15054
  {
15044
- title: rel.otherKey || "Related",
15055
+ title: relatedModel.label || relatedModel.name,
15056
+ sorter: { compare: (a, b) => getRecordDisplayLabel(a).localeCompare(getRecordDisplayLabel(b)) },
15057
+ filters: Array.from(new Set((filteredRows || []).map((r) => getRecordDisplayLabel(r)))).map((label) => ({ text: label, value: label })),
15058
+ filterSearch: true,
15059
+ onFilter: (value, row) => getRecordDisplayLabel(row) === String(value),
15045
15060
  render: (_unused, row) => {
15046
15061
  const id = row?.eid ?? row?.id;
15047
- if (!id) return "-";
15062
+ const label = getRecordDisplayLabel(row);
15063
+ if (!id) return label;
15048
15064
  return /* @__PURE__ */ jsx(
15049
15065
  "a",
15050
15066
  {
@@ -15059,7 +15075,7 @@ var RelatedObjectsTable = ({ rel, record, relatedModel, parentModel, showActions
15059
15075
  }
15060
15076
  },
15061
15077
  style: { cursor: "pointer", color: "inherit", textDecoration: "none" },
15062
- children: String(id)
15078
+ children: label
15063
15079
  }
15064
15080
  );
15065
15081
  }
@@ -15084,15 +15100,15 @@ var RelatedObjectsTable = ({ rel, record, relatedModel, parentModel, showActions
15084
15100
  }
15085
15101
  }),
15086
15102
  onFilter: (value, recordRow) => {
15087
- if (field.key === "eid" && recordRow?._label) {
15103
+ if (isPkField(field, relatedModel) && recordRow?._label) {
15088
15104
  return String(recordRow._label) === String(value) || String(recordRow.eid) === String(value);
15089
15105
  }
15090
15106
  const recordValue = recordRow?.[field.key];
15091
15107
  return String(recordValue) === String(value);
15092
15108
  },
15093
- align: field.type === "number" && !field.reference && !["eid", "eid_from", "eid_to"].includes(field.key) ? "right" : void 0,
15109
+ align: field.type === "number" && !isReferenceField(field) && !isPkField(field, relatedModel) ? "right" : void 0,
15094
15110
  render: (value, row) => {
15095
- if (allowInlineEdit && field.key !== "eid") {
15111
+ if (allowInlineEdit && !isPkField(field, relatedModel)) {
15096
15112
  const rowId = row?.eid ?? row?.id ?? row?.__relationKey;
15097
15113
  return /* @__PURE__ */ jsx(
15098
15114
  Form.Item,
@@ -15114,7 +15130,7 @@ var RelatedObjectsTable = ({ rel, record, relatedModel, parentModel, showActions
15114
15130
  const cacheKey = `${field.reference}:${value}`;
15115
15131
  return labelCache[cacheKey] || value;
15116
15132
  }
15117
- if (field.key === "eid" && row._label) return row._label;
15133
+ if (isPkField(field, relatedModel) && row._label) return row._label;
15118
15134
  if (field.type === "boolean") return /* @__PURE__ */ jsx(Checkbox, { checked: value, disabled: true });
15119
15135
  if (field.type === "number" && !field.reference) {
15120
15136
  const formatted = formatNumberValue(value);
@@ -16649,7 +16665,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
16649
16665
  const getSortValue = useCallback((field, record) => {
16650
16666
  const raw = record?.[field.key];
16651
16667
  if (raw === void 0 || raw === null) return null;
16652
- if (field.key === "eid" && record?._label) return record._label;
16668
+ if (isPkField(field, model) && record?._label) return record._label;
16653
16669
  if (field.reference) {
16654
16670
  const cacheKey = `${field.reference}:${raw}`;
16655
16671
  return labelCache[cacheKey] ?? raw;
@@ -16934,10 +16950,10 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
16934
16950
  };
16935
16951
  }, [handleTablePageChange, isClientFiltering, pageSize, tableProps.pagination]);
16936
16952
  const categoricalFields = useMemo(() => {
16937
- return model.fields.filter((field) => field.key === "eid" || (field.type !== "number" || field.reference));
16953
+ return model.fields.filter((field) => isPkField(field, model) || (field.type !== "number" || field.reference));
16938
16954
  }, [model.fields]);
16939
16955
  const numericFields = useMemo(() => {
16940
- return model.fields.filter((field) => field.key !== "eid" && field.type === "number" && !field.reference);
16956
+ return model.fields.filter((field) => !isPkField(field, model) && field.type === "number" && !field.reference);
16941
16957
  }, [model.fields]);
16942
16958
  const hasActiveRangeColumnFilter = useMemo(() => {
16943
16959
  return Object.values(columnFiltersSelected).some(
@@ -17536,7 +17552,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
17536
17552
  if (!field) return _36("All");
17537
17553
  const raw = record?.[field.key];
17538
17554
  if (raw === void 0 || raw === null) return "-";
17539
- if (field.key === "eid" && record?._label) return record._label;
17555
+ if (isPkField(field, model) && record?._label) return record._label;
17540
17556
  if (field.reference) {
17541
17557
  const cacheKey = `${field.reference}:${raw}`;
17542
17558
  return labelCache[cacheKey] || String(raw);
@@ -17806,7 +17822,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
17806
17822
  setSelectedSeriesKeys(value);
17807
17823
  },
17808
17824
  style: { width: "100%" },
17809
- options: model.fields.filter((field) => !field.isPk && field.key !== "eid").map((field) => ({ label: field.label, value: field.key })),
17825
+ options: model.fields.filter((field) => !isPkField(field, model)).map((field) => ({ label: field.label, value: field.key })),
17810
17826
  placeholder: _36("All numeric fields"),
17811
17827
  maxTagCount: "responsive"
17812
17828
  }
@@ -17957,7 +17973,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
17957
17973
  });
17958
17974
  }, [isTotalsDetailsView, allRows, displayFields, labelCache]);
17959
17975
  const getDefaultTotalsSummaryFn = useCallback((field) => {
17960
- if (["eid", "eid_from", "eid_to"].includes(field.key)) return "count";
17976
+ if (isPkField(field, model) || isReferenceField(field)) return "count";
17961
17977
  return "sum";
17962
17978
  }, []);
17963
17979
  const resolveTotalsSummaryFn = useCallback((field) => {
@@ -18254,8 +18270,8 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
18254
18270
  }
18255
18271
  const resourceName = model.isNamedQuery && model.primaryResource ? model.primaryResource : model.resource || model.name;
18256
18272
  const explicitPk = model.pkField ? record[model.pkField] : void 0;
18257
- const isPkField = model.fields?.find((f) => f.isPk)?.key;
18258
- const pkValue = explicitPk ?? (isPkField ? record[isPkField] : void 0) ?? record.eid ?? record.id ?? null;
18273
+ const isPkField2 = model.fields?.find((f) => f.isPk)?.key;
18274
+ const pkValue = explicitPk ?? (isPkField2 ? record[isPkField2] : void 0) ?? record.eid ?? record.id ?? null;
18259
18275
  if (pkValue != null) {
18260
18276
  return { resource: resourceName, id: pkValue, isLinkRow: false };
18261
18277
  }
@@ -19652,7 +19668,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
19652
19668
  dataIndex: field.key,
19653
19669
  title: field.label,
19654
19670
  sorter: { compare: (a, b) => compareSortValues(field, a, b), multiple: getSortPriority(columnSort, field.key) },
19655
- align: field.type === "number" && !field.reference && !["eid", "eid_from", "eid_to"].includes(field.key) ? "right" : void 0,
19671
+ align: field.type === "number" && !isReferenceField(field) && !isPkField(field, model) ? "right" : void 0,
19656
19672
  filters: columnFilters.get(field.key),
19657
19673
  filteredValue: columnFiltersSelected[field.key] || null,
19658
19674
  sortOrder: columnSort.find((item) => item.fieldKey === field.key)?.order ?? null,
@@ -19687,7 +19703,7 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
19687
19703
  }
19688
19704
  );
19689
19705
  }
19690
- if (field.key === "eid" && record._label) return record._label;
19706
+ if (isPkField(field, model) && record._label) return record._label;
19691
19707
  if (field.type === "boolean") return /* @__PURE__ */ jsx(Checkbox, { checked: value, disabled: true });
19692
19708
  if (field.type === "number" && !field.reference) {
19693
19709
  const formatted = formatNumberValue(value);
@@ -20130,18 +20146,38 @@ var DynamicList = ({ model: modelProp, allModels, filter, relationConfig, isEmbe
20130
20146
 
20131
20147
  // src/components/MultiPane/paneUtils.ts
20132
20148
  function parsePanes(searchParams) {
20133
- return searchParams.getAll("pane").map((param) => {
20134
- const colonIdx = param.indexOf(":");
20135
- if (colonIdx < 1) return null;
20136
- const resource = param.slice(0, colonIdx);
20137
- const id = param.slice(colonIdx + 1);
20138
- if (!resource || !id) return null;
20139
- return { resource, id };
20140
- }).filter((p) => p !== null);
20149
+ const standard = searchParams.getAll("pane");
20150
+ if (standard.length > 0) {
20151
+ return standard.map((param) => {
20152
+ const colonIdx = param.indexOf(":");
20153
+ if (colonIdx < 1) return null;
20154
+ const resource = param.slice(0, colonIdx);
20155
+ const id = param.slice(colonIdx + 1);
20156
+ if (!resource || !id) return null;
20157
+ return { resource, id };
20158
+ }).filter((p) => p !== null);
20159
+ }
20160
+ const legacy = [];
20161
+ for (const [key, value] of searchParams.entries()) {
20162
+ if (/^pane(?:\[\d*\])?$/.test(key)) {
20163
+ const colonIdx = value.indexOf(":");
20164
+ if (colonIdx < 1) continue;
20165
+ const resource = value.slice(0, colonIdx);
20166
+ const id = value.slice(colonIdx + 1);
20167
+ if (resource && id) {
20168
+ legacy.push({ resource, id });
20169
+ }
20170
+ }
20171
+ }
20172
+ return legacy;
20141
20173
  }
20142
20174
  function applyPanesToSearchParams(existing, panes) {
20143
20175
  const next = new URLSearchParams(existing);
20144
- next.delete("pane");
20176
+ for (const [key] of existing.entries()) {
20177
+ if (key === "pane" || /^pane\[\d+\]$/.test(key)) {
20178
+ next.delete(key);
20179
+ }
20180
+ }
20145
20181
  panes.forEach((p) => next.append("pane", `${p.resource}:${p.id}`));
20146
20182
  return next;
20147
20183
  }
@@ -20294,11 +20330,15 @@ var MultiPaneLayout = ({ children }) => {
20294
20330
  useEffect(() => {
20295
20331
  const newCount = panes.length;
20296
20332
  const prevCount = prevPaneCountRef.current;
20297
- prevPaneCountRef.current = newCount;
20298
- if (newCount <= prevCount || !pendingLayoutRef.current || !groupRef.current) {
20333
+ if (!pendingLayoutRef.current || !groupRef.current) {
20299
20334
  pendingLayoutRef.current = null;
20300
20335
  return;
20301
20336
  }
20337
+ if (newCount <= prevCount) {
20338
+ pendingLayoutRef.current = null;
20339
+ return;
20340
+ }
20341
+ prevPaneCountRef.current = newCount;
20302
20342
  const prevLayout = pendingLayoutRef.current;
20303
20343
  pendingLayoutRef.current = null;
20304
20344
  const donorId = prevCount === 0 ? LIST_PANEL_ID : detailPanelId(prevCount - 1);
@@ -21753,7 +21793,7 @@ function generateResources(models, moduleName, options = {}) {
21753
21793
  };
21754
21794
  const children = (models || []).map((model) => {
21755
21795
  const resource = model.resource || model.name;
21756
- const isRelation = hideRelations && (resource.toLowerCase().endsWith("_relation") || resource.toLowerCase().endsWith("_rela") || Array.isArray(model.fields) && model.fields.some((f) => f?.key === "eid_from") && model.fields.some((f) => f?.key === "eid_to"));
21796
+ const isRelation = hideRelations && (resource.toLowerCase().endsWith("_relation") || resource.toLowerCase().endsWith("_rela") || (Array.isArray(model.fields) && model.fields.some((f) => f?.key === "eid_from") && model.fields.some((f) => f?.key === "eid_to") || model.fields.length > 0 && model.fields.every((f) => !!f?.reference)));
21757
21797
  return {
21758
21798
  name: resource,
21759
21799
  list: `/${resource}`,