@trops/dash-core 0.1.429 → 0.1.432

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.js CHANGED
@@ -27686,6 +27686,16 @@ var LayoutModel = function LayoutModel(layoutItem, workspaceLayout, dashboardId)
27686
27686
  if (Array.isArray(widgetConfig.eventHandlers)) {
27687
27687
  layout.eventHandlers = widgetConfig.eventHandlers;
27688
27688
  }
27689
+ // Migrate legacy bare `component` references to the canonical
27690
+ // scoped form (`scope.package.Component`). ComponentManager.config
27691
+ // returns the resolved scoped key on `widgetConfig.component`, so
27692
+ // we just lift it. Idempotent: items already scoped pass through
27693
+ // unchanged because resolveComponentKey returns the input verbatim
27694
+ // when it's already in the map. Persisted on next save — no
27695
+ // separate migration step needed.
27696
+ if (typeof widgetConfig.component === "string" && widgetConfig.component && widgetConfig.component !== layout.component) {
27697
+ layout.component = widgetConfig.component;
27698
+ }
27689
27699
  }
27690
27700
 
27691
27701
  // Merge user-entered config values (from EnhancedWidgetDropdown) into userPrefs
@@ -28752,8 +28762,16 @@ var WorkspaceModel = function WorkspaceModel(workspaceItem) {
28752
28762
  // Skip items already produced by LayoutModel (idempotent: LayoutModel
28753
28763
  // is safe to call on its own output).
28754
28764
  var wsId = "id" in obj ? obj["id"] : workspace.id;
28765
+ // LayoutModel returns null when an item can't be normalized (e.g.
28766
+ // throw inside its catch). A null in the layout array crashes
28767
+ // downstream forEach/map consumers with `Cannot read properties of
28768
+ // null (reading 'type')`. Filter nulls so the renderer never sees
28769
+ // them — the original raw item is already lost at that point, so
28770
+ // dropping it is the only safe action.
28755
28771
  workspace.layout = rawLayout.map(function (item) {
28756
28772
  return LayoutModel(item, rawLayout, wsId);
28773
+ }).filter(function (item) {
28774
+ return item != null;
28757
28775
  });
28758
28776
  workspace.pages = "pages" in obj ? obj["pages"] : [];
28759
28777
  workspace.activePageId = "activePageId" in obj ? obj["activePageId"] : null;
@@ -31363,7 +31381,117 @@ var ContextModel = /*#__PURE__*/function () {
31363
31381
  }]);
31364
31382
  }();
31365
31383
 
31384
+ /**
31385
+ * scopedComponentId.js
31386
+ *
31387
+ * Single source of truth for the canonical scoped component id used by
31388
+ * ComponentManager registration, layout items, and publish-time scope
31389
+ * remap. Format: `scope.packageName.ComponentName`.
31390
+ *
31391
+ * Why a 3-part dotted form (and not `@scope/pkg.Component`)?
31392
+ * - Matches existing `config.id` shape that `.dash.js` files already
31393
+ * set when authored explicitly (see ComponentManager.registerWidget:
31394
+ * `const registrationKey = config.id || widgetKey;`).
31395
+ * - Trivial to parse (`split(".")` — three parts, ordered).
31396
+ * - Avoids slashes inside object keys, which some downstream serializers
31397
+ * (older dash-registry indexers) historically choked on.
31398
+ *
31399
+ * The upstream package id may arrive in either of two shapes:
31400
+ * - "@scope/pkg" (npm-style)
31401
+ * - "scope/pkg" (bare scope)
31402
+ * Both produce the same scoped id.
31403
+ */
31404
+
31405
+ /**
31406
+ * Build the canonical scoped component id from a package name and a
31407
+ * bare component name.
31408
+ *
31409
+ * @param {string} packageName e.g. "@ai-built/pipeline" or "ai-built/pipeline"
31410
+ * @param {string} componentName e.g. "ProspectListColumn"
31411
+ * @returns {string} e.g. "ai-built.pipeline.ProspectListColumn"
31412
+ */
31413
+ function makeScopedComponentId(packageName, componentName) {
31414
+ if (!componentName) return "";
31415
+ if (!packageName) return componentName;
31416
+ var cleaned = String(packageName).replace(/^@/, "").replace(/\//g, ".");
31417
+ return "".concat(cleaned, ".").concat(componentName);
31418
+ }
31419
+
31420
+ /**
31421
+ * Parse a scoped component id into its three parts. Returns null when
31422
+ * the input isn't a 3-part dotted id (e.g. legacy bare names).
31423
+ *
31424
+ * @param {string} scopedId
31425
+ * @returns {{scope: string, packageName: string, componentName: string} | null}
31426
+ */
31427
+ function parseScopedComponentId(scopedId) {
31428
+ if (typeof scopedId !== "string") return null;
31429
+ var parts = scopedId.split(".");
31430
+ if (parts.length !== 3) return null;
31431
+ return {
31432
+ scope: parts[0],
31433
+ packageName: parts[1],
31434
+ componentName: parts[2]
31435
+ };
31436
+ }
31437
+
31438
+ /**
31439
+ * Pull the bare component name from a scoped or unscoped id.
31440
+ *
31441
+ * @param {string} idOrName
31442
+ * @returns {string}
31443
+ */
31444
+ function bareComponentName(idOrName) {
31445
+ if (typeof idOrName !== "string") return "";
31446
+ var parts = idOrName.split(".");
31447
+ return parts[parts.length - 1] || "";
31448
+ }
31449
+
31366
31450
  var _componentMap = {};
31451
+
31452
+ /**
31453
+ * Resolve the registry key for a component lookup. Returns null if no
31454
+ * match exists.
31455
+ *
31456
+ * Lookup order (the LAYOUT ITEM is the source of truth):
31457
+ * 1. EXACT match on `component` — covers the new scoped form
31458
+ * (`scope.package.X`) and any legacy `.dash.js` that already set
31459
+ * `config.id` to a scoped value.
31460
+ * 2. If `component` is bare (no dots) AND we have a packageId hint
31461
+ * on the layout item, build the scoped id and try that.
31462
+ * 3. Bare-name fallback: scan the map for any key ending in
31463
+ * `.${component}`. If exactly one matches, use it. If multiple
31464
+ * match (the collision case), prefer the one matching the layout
31465
+ * item's `packageId` / `_sourcePackage`; otherwise fall through
31466
+ * to the first match (deterministic, but also logs a warning so
31467
+ * callers can spot the ambiguity).
31468
+ *
31469
+ * Step (3) is the back-compat path for layouts authored before scoped
31470
+ * registration landed. New layouts ALWAYS resolve via step (1) — the
31471
+ * `component` field is already scoped.
31472
+ */
31473
+ function resolveComponentKey(componentMap, component, data) {
31474
+ if (!component) return null;
31475
+ if (component in componentMap) return component;
31476
+ if (typeof component !== "string") return null;
31477
+ if (component.includes(".")) return null;
31478
+ var packageId = (data === null || data === void 0 ? void 0 : data.packageId) || (data === null || data === void 0 ? void 0 : data._sourcePackage) || (data === null || data === void 0 ? void 0 : data.packageName) || null;
31479
+ if (packageId) {
31480
+ var scoped = makeScopedComponentId(packageId, component);
31481
+ if (scoped in componentMap) return scoped;
31482
+ }
31483
+ var suffix = ".".concat(component);
31484
+ var matches = Object.keys(componentMap).filter(function (k) {
31485
+ return k.endsWith(suffix);
31486
+ });
31487
+ if (matches.length === 0) return null;
31488
+ if (matches.length === 1) return matches[0];
31489
+ if (packageId) {
31490
+ var target = makeScopedComponentId(packageId, component);
31491
+ if (matches.includes(target)) return target;
31492
+ }
31493
+ return matches[0];
31494
+ }
31367
31495
  var _containerComponent = null;
31368
31496
  var _gridContainerComponent = null;
31369
31497
  var ComponentManager = {
@@ -31467,15 +31595,18 @@ var ComponentManager = {
31467
31595
  * @returns {Widget} the Widget in the component map
31468
31596
  */
31469
31597
  getComponent: function getComponent(component) {
31598
+ var data = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
31470
31599
  try {
31471
31600
  // console.log("get component");
31472
31601
  if (component && this.componentMap()) {
31473
31602
  if (ComponentManager.isLayoutContainer(component) === false) {
31474
31603
  var m = this.componentMap();
31475
- // Try exact match first (works for both scoped ids and legacy names)
31476
- var cmp = component in m ? m[component] : null;
31477
- if (cmp !== null) {
31478
- cmp["componentName"] = component;
31604
+ // Resolve through the scoped/bare lookup pipeline so layouts
31605
+ // authored under either format land at the same registry key.
31606
+ var resolvedKey = resolveComponentKey(m, component, data);
31607
+ var cmp = resolvedKey ? m[resolvedKey] : null;
31608
+ if (cmp !== null && cmp !== undefined) {
31609
+ cmp["componentName"] = resolvedKey;
31479
31610
  return cmp;
31480
31611
  }
31481
31612
  } else {
@@ -31653,17 +31784,20 @@ var ComponentManager = {
31653
31784
 
31654
31785
  // get the component configuration from the map
31655
31786
  var components = this.map();
31656
- if (component in components) {
31787
+ var resolvedKey = resolveComponentKey(components, component, data);
31788
+ if (resolvedKey && resolvedKey in components) {
31657
31789
  // let c = deepCopy(components['component']);
31658
31790
 
31659
31791
  // we have to make sure that we remove the component if this is a context
31660
31792
 
31661
- var tempComponent = components[component];
31793
+ var tempComponent = components[resolvedKey];
31662
31794
  delete tempComponent["component"];
31663
31795
  var c = JSON.parse(JSON.stringify(tempComponent));
31664
31796
 
31665
- // tack on the component name
31666
- c["component"] = component;
31797
+ // Carry the canonical scoped id forward so callers (LayoutModel,
31798
+ // ComponentManager.getComponent) can rewrite layout items'
31799
+ // `component` to the scoped form on first load.
31800
+ c["component"] = resolvedKey;
31667
31801
 
31668
31802
  // if no userConfig key. let's add it for the next step
31669
31803
  if ("userConfig" in c === false) {
@@ -57424,26 +57558,36 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
57424
57558
  try {
57425
57559
  var _message$workspaces;
57426
57560
  var workspaces = DashReact.deepCopy(message["workspaces"]);
57561
+ // LayoutModel returns null when normalization throws (e.g. a
57562
+ // widget config that references a component the registry can't
57563
+ // resolve yet — common right after a fresh dashboard install
57564
+ // where some widgets are still downloading). Filter nulls so
57565
+ // every renderer that walks the layout sees only well-formed
57566
+ // items and never crashes on `Cannot read properties of null
57567
+ // (reading 'type')` or similar.
57427
57568
  var workspacesTemp = workspaces.map(function (ws) {
57428
- var tempLayout = ws["layout"].map(function (layoutOG) {
57569
+ ws["layout"] = (ws["layout"] || []).map(function (layoutOG) {
57429
57570
  return LayoutModel(layoutOG, workspaces, ws["id"]);
57571
+ }).filter(function (item) {
57572
+ return item != null;
57430
57573
  });
57431
- ws["layout"] = tempLayout;
57432
- // Normalize page layouts too
57433
57574
  if (ws.pages && Array.isArray(ws.pages)) {
57434
57575
  ws.pages = ws.pages.map(function (page) {
57435
57576
  if (page.layout && Array.isArray(page.layout)) {
57436
57577
  page.layout = page.layout.map(function (layoutOG) {
57437
57578
  return LayoutModel(layoutOG, workspaces, ws["id"]);
57579
+ }).filter(function (item) {
57580
+ return item != null;
57438
57581
  });
57439
57582
  }
57440
57583
  return page;
57441
57584
  });
57442
57585
  }
57443
- // Normalize sidebar layout
57444
57586
  if (ws.sidebarLayout && Array.isArray(ws.sidebarLayout)) {
57445
57587
  ws.sidebarLayout = ws.sidebarLayout.map(function (layoutOG) {
57446
57588
  return LayoutModel(layoutOG, workspaces, ws["id"]);
57589
+ }).filter(function (item) {
57590
+ return item != null;
57447
57591
  });
57448
57592
  }
57449
57593
  return WorkspaceModel(ws);
@@ -58227,13 +58371,16 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
58227
58371
  }
58228
58372
  function handleSaveWorkspaceComplete(e, message) {
58229
58373
 
58230
- // Reconstruct workspaces through LayoutModel (same as load path)
58374
+ // Reconstruct workspaces through LayoutModel (same as load path).
58375
+ // Filter nulls so a partially-failed normalize doesn't poison the
58376
+ // layout array — see handleLoadWorkspacesComplete for the rationale.
58231
58377
  var workspaces = DashReact.deepCopy(message["workspaces"]);
58232
58378
  var workspacesTemp = workspaces.map(function (ws) {
58233
- var tempLayout = ws["layout"].map(function (layoutOG) {
58379
+ ws["layout"] = (ws["layout"] || []).map(function (layoutOG) {
58234
58380
  return LayoutModel(layoutOG, workspaces, ws["id"]);
58381
+ }).filter(function (item) {
58382
+ return item != null;
58235
58383
  });
58236
- ws["layout"] = tempLayout;
58237
58384
  return WorkspaceModel(ws);
58238
58385
  });
58239
58386
  pub.pub("dashboard.workspaceChange", {
@@ -62301,6 +62448,7 @@ exports.WorkspaceModel = WorkspaceModel;
62301
62448
  exports.WorkspaceScopeContext = WorkspaceScopeContext;
62302
62449
  exports.addChildToLayoutItem = addChildToLayoutItem;
62303
62450
  exports.addItemToItemLayout = addItemToItemLayout;
62451
+ exports.bareComponentName = bareComponentName;
62304
62452
  exports.buildMcpConfigFromOverrides = buildMcpConfigFromOverrides;
62305
62453
  exports.canHaveChildren = canHaveChildren;
62306
62454
  exports.changeDirectionForLayoutItem = changeDirectionForLayoutItem;
@@ -62346,10 +62494,12 @@ exports.isWidgetResolvable = isWidgetResolvable;
62346
62494
  exports.isWorkspace = isWorkspace;
62347
62495
  exports.layoutItemHasWorkspaceAsChild = layoutItemHasWorkspaceAsChild;
62348
62496
  exports.loadWidgetBundle = loadWidgetBundle;
62497
+ exports.makeScopedComponentId = makeScopedComponentId;
62349
62498
  exports.mcpJsonToFormState = mcpJsonToFormState;
62350
62499
  exports.moveWidgetAcrossContainers = moveWidgetAcrossContainers;
62351
62500
  exports.numChildrenForLayout = numChildrenForLayout;
62352
62501
  exports.parse = parse;
62502
+ exports.parseScopedComponentId = parseScopedComponentId;
62353
62503
  exports.removeItemFromLayout = removeItemFromLayout;
62354
62504
  exports.renderComponent = renderComponent;
62355
62505
  exports.renderGridLayout = renderGridLayout;