@trops/dash-core 0.1.428 → 0.1.431

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
@@ -28752,8 +28752,16 @@ var WorkspaceModel = function WorkspaceModel(workspaceItem) {
28752
28752
  // Skip items already produced by LayoutModel (idempotent: LayoutModel
28753
28753
  // is safe to call on its own output).
28754
28754
  var wsId = "id" in obj ? obj["id"] : workspace.id;
28755
+ // LayoutModel returns null when an item can't be normalized (e.g.
28756
+ // throw inside its catch). A null in the layout array crashes
28757
+ // downstream forEach/map consumers with `Cannot read properties of
28758
+ // null (reading 'type')`. Filter nulls so the renderer never sees
28759
+ // them — the original raw item is already lost at that point, so
28760
+ // dropping it is the only safe action.
28755
28761
  workspace.layout = rawLayout.map(function (item) {
28756
28762
  return LayoutModel(item, rawLayout, wsId);
28763
+ }).filter(function (item) {
28764
+ return item != null;
28757
28765
  });
28758
28766
  workspace.pages = "pages" in obj ? obj["pages"] : [];
28759
28767
  workspace.activePageId = "activePageId" in obj ? obj["activePageId"] : null;
@@ -40439,36 +40447,57 @@ var PublishDashboardModal = function PublishDashboardModal(_ref) {
40439
40447
  depSelections = _useState28[0],
40440
40448
  setDepSelections = _useState28[1];
40441
40449
 
40442
- // Step 5: Publish
40443
- var _useState29 = React.useState(false),
40450
+ // Step 5: Defaults verification — surfaced values from each owned
40451
+ // widget package's `.dash.js` userConfig[field].defaultValue. Lets
40452
+ // the publisher review (and optionally blank/edit) values set
40453
+ // during development before the ZIP ships.
40454
+ // defaultsByPackage: { [packageId]: Array<{widgetName, field, currentDefault, displayName, type, instructions}> }
40455
+ // defaultsOverrides: { [packageId]: { [widgetName]: { [field]: newValue } } }
40456
+ // — only fields the user actually edited appear here. Undefined
40457
+ // = "no change"; explicit empty-string = "blank it out".
40458
+ var _useState29 = React.useState({}),
40444
40459
  _useState30 = _slicedToArray(_useState29, 2),
40445
- isPublishing = _useState30[0],
40446
- setIsPublishing = _useState30[1];
40447
- var _useState31 = React.useState(null),
40460
+ defaultsByPackage = _useState30[0],
40461
+ setDefaultsByPackage = _useState30[1];
40462
+ var _useState31 = React.useState(false),
40448
40463
  _useState32 = _slicedToArray(_useState31, 2),
40449
- result = _useState32[0],
40450
- setResult = _useState32[1];
40451
- // Per-step progress during batch publish
40452
- var _useState33 = React.useState([]),
40464
+ defaultsLoading = _useState32[0],
40465
+ setDefaultsLoading = _useState32[1];
40466
+ var _useState33 = React.useState({}),
40453
40467
  _useState34 = _slicedToArray(_useState33, 2),
40454
- publishSteps = _useState34[0],
40455
- setPublishSteps = _useState34[1];
40468
+ defaultsOverrides = _useState34[0],
40469
+ setDefaultsOverrides = _useState34[1];
40456
40470
 
40457
- // Visibility chosen on the Details step. Defaults to public.
40458
- var _useState35 = React.useState("public"),
40471
+ // Step 6: Publish
40472
+ var _useState35 = React.useState(false),
40459
40473
  _useState36 = _slicedToArray(_useState35, 2),
40460
- visibility = _useState36[0],
40461
- setVisibility = _useState36[1];
40474
+ isPublishing = _useState36[0],
40475
+ setIsPublishing = _useState36[1];
40476
+ var _useState37 = React.useState(null),
40477
+ _useState38 = _slicedToArray(_useState37, 2),
40478
+ result = _useState38[0],
40479
+ setResult = _useState38[1];
40480
+ // Per-step progress during batch publish
40481
+ var _useState39 = React.useState([]),
40482
+ _useState40 = _slicedToArray(_useState39, 2),
40483
+ publishSteps = _useState40[0],
40484
+ setPublishSteps = _useState40[1];
40485
+
40486
+ // Visibility — chosen on the Details step. Defaults to public.
40487
+ var _useState41 = React.useState("public"),
40488
+ _useState42 = _slicedToArray(_useState41, 2),
40489
+ visibility = _useState42[0],
40490
+ setVisibility = _useState42[1];
40462
40491
 
40463
40492
  // Dashboard version bump — chosen on the Details step. Defaults to
40464
40493
  // "patch" so repeat-publishes auto-increment the registry's
40465
40494
  // latestVersion. Without this, every republish used the same
40466
40495
  // version string, the registry never saw a new version, and update
40467
40496
  // notifications never fired on installers.
40468
- var _useState37 = React.useState("patch"),
40469
- _useState38 = _slicedToArray(_useState37, 2),
40470
- dashboardBump = _useState38[0],
40471
- setDashboardBump = _useState38[1];
40497
+ var _useState43 = React.useState("patch"),
40498
+ _useState44 = _slicedToArray(_useState43, 2),
40499
+ dashboardBump = _useState44[0],
40500
+ setDashboardBump = _useState44[1];
40472
40501
 
40473
40502
  // Fetch publish preview (widget names) on open
40474
40503
  React.useEffect(function () {
@@ -40604,6 +40633,97 @@ var PublishDashboardModal = function PublishDashboardModal(_ref) {
40604
40633
  });
40605
40634
  // eslint-disable-next-line react-hooks/exhaustive-deps
40606
40635
  }, [step, isOpen]);
40636
+
40637
+ // Load per-package default-value scans when the user arrives at the
40638
+ // Defaults step. We only scan packages that are actually going to be
40639
+ // republished (include + owned) to keep the step focused — a
40640
+ // third-party package the user isn't republishing can't have its
40641
+ // defaults changed anyway.
40642
+ React.useEffect(function () {
40643
+ if (!isOpen || step !== 5 || !plan || defaultsLoading) return;
40644
+ var packagesToScan = [];
40645
+ var _iterator2 = _createForOfIteratorHelper$c(plan.widgets || []),
40646
+ _step2;
40647
+ try {
40648
+ for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
40649
+ var w = _step2.value;
40650
+ if (!w.scope || !w.packageName) continue;
40651
+ var key = "".concat(w.scope, "/").concat(w.packageName);
40652
+ var sel = depSelections[key];
40653
+ if (!(sel !== null && sel !== void 0 && sel.include) || !(sel !== null && sel !== void 0 && sel.owned)) continue;
40654
+ // Resolve the local package id the scanner expects — same shape
40655
+ // the inspect IPC already takes.
40656
+ var localPkgId = w.packageId || "@".concat(w.scope, "/").concat(w.packageName);
40657
+ if (!defaultsByPackage[localPkgId]) packagesToScan.push(localPkgId);
40658
+ }
40659
+ } catch (err) {
40660
+ _iterator2.e(err);
40661
+ } finally {
40662
+ _iterator2.f();
40663
+ }
40664
+ if (packagesToScan.length === 0) return;
40665
+ setDefaultsLoading(true);
40666
+ Promise.all(packagesToScan.map(function (pkgId) {
40667
+ return window.mainApi.registry.scanWidgetDefaults(pkgId).then(function (res) {
40668
+ return {
40669
+ pkgId: pkgId,
40670
+ res: res
40671
+ };
40672
+ })["catch"](function (err) {
40673
+ return {
40674
+ pkgId: pkgId,
40675
+ res: {
40676
+ success: false,
40677
+ error: (err === null || err === void 0 ? void 0 : err.message) || String(err)
40678
+ }
40679
+ };
40680
+ });
40681
+ })).then(function (results) {
40682
+ setDefaultsByPackage(function (prev) {
40683
+ var next = _objectSpread$r({}, prev);
40684
+ var _iterator3 = _createForOfIteratorHelper$c(results),
40685
+ _step3;
40686
+ try {
40687
+ for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
40688
+ var _step3$value = _step3.value,
40689
+ pkgId = _step3$value.pkgId,
40690
+ res = _step3$value.res;
40691
+ next[pkgId] = res !== null && res !== void 0 && res.success ? res.defaults || [] : [];
40692
+ }
40693
+ } catch (err) {
40694
+ _iterator3.e(err);
40695
+ } finally {
40696
+ _iterator3.f();
40697
+ }
40698
+ return next;
40699
+ });
40700
+ setDefaultsLoading(false);
40701
+ });
40702
+ // eslint-disable-next-line react-hooks/exhaustive-deps
40703
+ }, [step, isOpen, plan, depSelections]);
40704
+ function setDefaultOverride(packageId, widgetName, field, newValue) {
40705
+ setDefaultsOverrides(function (prev) {
40706
+ var next = _objectSpread$r({}, prev);
40707
+ var forPkg = _objectSpread$r({}, next[packageId] || {});
40708
+ var forWidget = _objectSpread$r({}, forPkg[widgetName] || {});
40709
+ if (newValue === undefined) {
40710
+ delete forWidget[field];
40711
+ } else {
40712
+ forWidget[field] = newValue;
40713
+ }
40714
+ if (Object.keys(forWidget).length === 0) {
40715
+ delete forPkg[widgetName];
40716
+ } else {
40717
+ forPkg[widgetName] = forWidget;
40718
+ }
40719
+ if (Object.keys(forPkg).length === 0) {
40720
+ delete next[packageId];
40721
+ } else {
40722
+ next[packageId] = forPkg;
40723
+ }
40724
+ return next;
40725
+ });
40726
+ }
40607
40727
  function updateDepSelection(key, patch) {
40608
40728
  setDepSelections(function (prev) {
40609
40729
  return _objectSpread$r(_objectSpread$r({}, prev), {}, _defineProperty({}, key, _objectSpread$r(_objectSpread$r({}, prev[key]), patch)));
@@ -40621,7 +40741,7 @@ var PublishDashboardModal = function PublishDashboardModal(_ref) {
40621
40741
  }
40622
40742
  function _handlePublish() {
40623
40743
  _handlePublish = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
40624
- var steps, seenPackages, _iterator2, _step2, w, _key2, _sel, key, sel, updateStep, i, _step3, _res$manifest, bump, options, res, _res, _options, _res2, _t2, _t3;
40744
+ var steps, seenPackages, _iterator4, _step4, w, _key2, _sel, key, sel, updateStep, i, _step5, _res$manifest, bump, options, res, _res, _options, _res2, _t2, _t3;
40625
40745
  return _regeneratorRuntime.wrap(function (_context2) {
40626
40746
  while (1) switch (_context2.prev = _context2.next) {
40627
40747
  case 0:
@@ -40643,15 +40763,15 @@ var PublishDashboardModal = function PublishDashboardModal(_ref) {
40643
40763
  break;
40644
40764
  }
40645
40765
  seenPackages = new Set();
40646
- _iterator2 = _createForOfIteratorHelper$c(plan.widgets || []);
40766
+ _iterator4 = _createForOfIteratorHelper$c(plan.widgets || []);
40647
40767
  _context2.prev = 2;
40648
- _iterator2.s();
40768
+ _iterator4.s();
40649
40769
  case 3:
40650
- if ((_step2 = _iterator2.n()).done) {
40770
+ if ((_step4 = _iterator4.n()).done) {
40651
40771
  _context2.next = 8;
40652
40772
  break;
40653
40773
  }
40654
- w = _step2.value;
40774
+ w = _step4.value;
40655
40775
  if (!(!w.scope || !w.packageName)) {
40656
40776
  _context2.next = 4;
40657
40777
  break;
@@ -40689,10 +40809,10 @@ var PublishDashboardModal = function PublishDashboardModal(_ref) {
40689
40809
  case 9:
40690
40810
  _context2.prev = 9;
40691
40811
  _t2 = _context2["catch"](2);
40692
- _iterator2.e(_t2);
40812
+ _iterator4.e(_t2);
40693
40813
  case 10:
40694
40814
  _context2.prev = 10;
40695
- _iterator2.f();
40815
+ _iterator4.f();
40696
40816
  return _context2.finish(10);
40697
40817
  case 11:
40698
40818
  if (plan.theme && plan.theme.scope && plan.theme.name) {
@@ -40736,28 +40856,30 @@ var PublishDashboardModal = function PublishDashboardModal(_ref) {
40736
40856
  _context2.next = 24;
40737
40857
  break;
40738
40858
  }
40739
- _step3 = steps[i];
40859
+ _step5 = steps[i];
40740
40860
  updateStep(i, {
40741
40861
  status: "running"
40742
40862
  });
40743
- if (!(_step3.kind === "widget")) {
40863
+ if (!(_step5.kind === "widget")) {
40744
40864
  _context2.next = 17;
40745
40865
  break;
40746
40866
  }
40747
- bump = _step3.selection.bump;
40867
+ bump = _step5.selection.bump;
40748
40868
  options = _objectSpread$r(_objectSpread$r({}, bump && bump !== "none" ? {
40749
40869
  bump: bump
40750
40870
  } : {}), {}, {
40751
- visibility: _step3.selection.visibility,
40871
+ visibility: _step5.selection.visibility,
40752
40872
  // Plumb the publisher's display name through to the widget
40753
40873
  // publish call so the manifest — and the rewritten dash.json
40754
40874
  // inside the zipped package — records the actual human who
40755
40875
  // published, not the AI Widget Builder's "AI Assistant"
40756
40876
  // placeholder.
40757
40877
  authorName: authorName.trim() || undefined
40758
- });
40878
+ }, defaultsOverrides[_step5.packageId] ? {
40879
+ defaultsOverride: defaultsOverrides[_step5.packageId]
40880
+ } : {});
40759
40881
  _context2.next = 15;
40760
- return window.mainApi.registry.publishWidget(appId, _step3.packageId, options);
40882
+ return window.mainApi.registry.publishWidget(appId, _step5.packageId, options);
40761
40883
  case 15:
40762
40884
  res = _context2.sent;
40763
40885
  if (res !== null && res !== void 0 && res.success) {
@@ -40770,7 +40892,7 @@ var PublishDashboardModal = function PublishDashboardModal(_ref) {
40770
40892
  });
40771
40893
  setResult({
40772
40894
  success: false,
40773
- error: "Failed to publish widget ".concat(_step3.key, ": ").concat((res === null || res === void 0 ? void 0 : res.error) || "unknown error")
40895
+ error: "Failed to publish widget ".concat(_step5.key, ": ").concat((res === null || res === void 0 ? void 0 : res.error) || "unknown error")
40774
40896
  });
40775
40897
  setIsPublishing(false);
40776
40898
  return _context2.abrupt("return");
@@ -40782,13 +40904,13 @@ var PublishDashboardModal = function PublishDashboardModal(_ref) {
40782
40904
  _context2.next = 23;
40783
40905
  break;
40784
40906
  case 17:
40785
- if (!(_step3.kind === "theme")) {
40907
+ if (!(_step5.kind === "theme")) {
40786
40908
  _context2.next = 20;
40787
40909
  break;
40788
40910
  }
40789
40911
  _context2.next = 18;
40790
- return window.mainApi.themes.publishTheme(appId, _step3.themeKey, {
40791
- visibility: _step3.selection.visibility
40912
+ return window.mainApi.themes.publishTheme(appId, _step5.themeKey, {
40913
+ visibility: _step5.selection.visibility
40792
40914
  });
40793
40915
  case 18:
40794
40916
  _res = _context2.sent;
@@ -40802,7 +40924,7 @@ var PublishDashboardModal = function PublishDashboardModal(_ref) {
40802
40924
  });
40803
40925
  setResult({
40804
40926
  success: false,
40805
- error: "Failed to publish theme ".concat(_step3.themeKey, ": ").concat((_res === null || _res === void 0 ? void 0 : _res.error) || "unknown error")
40927
+ error: "Failed to publish theme ".concat(_step5.themeKey, ": ").concat((_res === null || _res === void 0 ? void 0 : _res.error) || "unknown error")
40806
40928
  });
40807
40929
  setIsPublishing(false);
40808
40930
  return _context2.abrupt("return");
@@ -40814,7 +40936,7 @@ var PublishDashboardModal = function PublishDashboardModal(_ref) {
40814
40936
  _context2.next = 23;
40815
40937
  break;
40816
40938
  case 20:
40817
- if (!(_step3.kind === "dashboard")) {
40939
+ if (!(_step5.kind === "dashboard")) {
40818
40940
  _context2.next = 23;
40819
40941
  break;
40820
40942
  }
@@ -40968,7 +41090,7 @@ var PublishDashboardModal = function PublishDashboardModal(_ref) {
40968
41090
  }
40969
41091
  function handleSignOut() {
40970
41092
  return _handleSignOut.apply(this, arguments);
40971
- } // Steps: 0=Account, 1=Details, 2=Tags, 3=Icon, 4=Dependencies, 5=Publish
41093
+ } // Steps: 0=Account, 1=Details, 2=Tags, 3=Icon, 4=Dependencies, 5=Defaults, 6=Publish
40972
41094
  function _handleSignOut() {
40973
41095
  _handleSignOut = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
40974
41096
  return _regeneratorRuntime.wrap(function (_context5) {
@@ -40993,8 +41115,8 @@ var PublishDashboardModal = function PublishDashboardModal(_ref) {
40993
41115
  }));
40994
41116
  return _handleSignOut.apply(this, arguments);
40995
41117
  }
40996
- var isLastStep = step === 5;
40997
- var canAdvance = step === 0 ? authStatus === "authenticated" : step === 1 ? !!authorName.trim() : step === 2 ? selectedTags.length > 0 : step === 4 ? !planLoading : true;
41118
+ var isLastStep = step === 6;
41119
+ var canAdvance = step === 0 ? authStatus === "authenticated" : step === 1 ? !!authorName.trim() : step === 2 ? selectedTags.length > 0 : step === 4 ? !planLoading : step === 5 ? !defaultsLoading : true;
40998
41120
  return /*#__PURE__*/jsxRuntime.jsx(DashReact.Modal, {
40999
41121
  isOpen: isOpen,
41000
41122
  setIsOpen: handleClose,
@@ -41255,6 +41377,26 @@ var PublishDashboardModal = function PublishDashboardModal(_ref) {
41255
41377
  onChange: updateDepSelection
41256
41378
  })]
41257
41379
  })
41380
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Stepper.Step, {
41381
+ label: "Defaults",
41382
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
41383
+ className: "flex-1 min-h-0 overflow-y-auto pb-4 space-y-4",
41384
+ children: [/*#__PURE__*/jsxRuntime.jsxs("p", {
41385
+ className: "text-sm opacity-70",
41386
+ children: ["Review ", /*#__PURE__*/jsxRuntime.jsx("code", {
41387
+ children: "userConfig"
41388
+ }), " default values the widget's dev-time dash.js ships. Anything you leave as-is gets published as the current default. Values you blank or edit here get rewritten in a staged copy before the ZIP is built \u2014 your local source files are untouched."]
41389
+ }), defaultsLoading && /*#__PURE__*/jsxRuntime.jsx("div", {
41390
+ className: "text-sm opacity-60 py-6 text-center",
41391
+ children: "Scanning widget configs for default values\u2026"
41392
+ }), !defaultsLoading && /*#__PURE__*/jsxRuntime.jsx(DefaultsReviewList, {
41393
+ plan: plan,
41394
+ depSelections: depSelections,
41395
+ defaultsByPackage: defaultsByPackage,
41396
+ overrides: defaultsOverrides,
41397
+ onChange: setDefaultOverride
41398
+ })]
41399
+ })
41258
41400
  }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Stepper.Step, {
41259
41401
  label: "Publish",
41260
41402
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
@@ -41444,7 +41586,7 @@ var PublishDashboardModal = function PublishDashboardModal(_ref) {
41444
41586
  className: "flex-1 text-center",
41445
41587
  children: /*#__PURE__*/jsxRuntime.jsxs("span", {
41446
41588
  className: "text-xs opacity-40",
41447
- children: ["Step ", step + 1, " of 6"]
41589
+ children: ["Step ", step + 1, " of 7"]
41448
41590
  })
41449
41591
  }), /*#__PURE__*/jsxRuntime.jsx("div", {
41450
41592
  className: "flex flex-row gap-2",
@@ -41533,11 +41675,11 @@ function DependencyTable(_ref4) {
41533
41675
  // row. Each row shows the list of component widgets that live inside it
41534
41676
  // so the user knows what's getting published.
41535
41677
  var byKey = new Map();
41536
- var _iterator3 = _createForOfIteratorHelper$c(plan.widgets || []),
41537
- _step4;
41678
+ var _iterator5 = _createForOfIteratorHelper$c(plan.widgets || []),
41679
+ _step6;
41538
41680
  try {
41539
- for (_iterator3.s(); !(_step4 = _iterator3.n()).done;) {
41540
- var w = _step4.value;
41681
+ for (_iterator5.s(); !(_step6 = _iterator5.n()).done;) {
41682
+ var w = _step6.value;
41541
41683
  if (!w.scope || !w.packageName) continue;
41542
41684
  var _key3 = "".concat(w.scope, "/").concat(w.packageName);
41543
41685
  var entry = byKey.get(_key3) || {
@@ -41550,9 +41692,9 @@ function DependencyTable(_ref4) {
41550
41692
  byKey.set(_key3, entry);
41551
41693
  }
41552
41694
  } catch (err) {
41553
- _iterator3.e(err);
41695
+ _iterator5.e(err);
41554
41696
  } finally {
41555
- _iterator3.f();
41697
+ _iterator5.f();
41556
41698
  }
41557
41699
  var rows = Array.from(byKey.values()).map(function (e) {
41558
41700
  return _objectSpread$r(_objectSpread$r({}, e), {}, {
@@ -41686,6 +41828,134 @@ function DependencyTable(_ref4) {
41686
41828
  });
41687
41829
  }
41688
41830
 
41831
+ /**
41832
+ * Per-package editable list of every non-empty userConfig default.
41833
+ * Renders once per owned package selected for republish. Edits are
41834
+ * two-way: typing into a field stages an override; hitting "Reset"
41835
+ * clears the override so the original defaultValue ships. The
41836
+ * outside world treats `overrides[packageId][widgetName][field]` as
41837
+ * the source of truth for the publish call.
41838
+ */
41839
+ function DefaultsReviewList(_ref6) {
41840
+ var plan = _ref6.plan,
41841
+ depSelections = _ref6.depSelections,
41842
+ defaultsByPackage = _ref6.defaultsByPackage,
41843
+ overrides = _ref6.overrides,
41844
+ _onChange2 = _ref6.onChange;
41845
+ // Collect the packages we're actually about to republish so the UI
41846
+ // stays aligned with Dependencies — no surprises about WHICH
41847
+ // package's defaults you're editing.
41848
+ var rows = [];
41849
+ var _iterator6 = _createForOfIteratorHelper$c((plan === null || plan === void 0 ? void 0 : plan.widgets) || []),
41850
+ _step7;
41851
+ try {
41852
+ for (_iterator6.s(); !(_step7 = _iterator6.n()).done;) {
41853
+ var w = _step7.value;
41854
+ if (!w.scope || !w.packageName) continue;
41855
+ var key = "".concat(w.scope, "/").concat(w.packageName);
41856
+ var sel = depSelections[key];
41857
+ if (!(sel !== null && sel !== void 0 && sel.include) || !(sel !== null && sel !== void 0 && sel.owned)) continue;
41858
+ var localPkgId = w.packageId || "@".concat(w.scope, "/").concat(w.packageName);
41859
+ var defaults = defaultsByPackage[localPkgId];
41860
+ if (!Array.isArray(defaults)) continue;
41861
+ rows.push({
41862
+ key: key,
41863
+ localPkgId: localPkgId,
41864
+ label: "@".concat(w.scope, "/").concat(w.packageName),
41865
+ defaults: defaults
41866
+ });
41867
+ }
41868
+ } catch (err) {
41869
+ _iterator6.e(err);
41870
+ } finally {
41871
+ _iterator6.f();
41872
+ }
41873
+ if (rows.length === 0) {
41874
+ return /*#__PURE__*/jsxRuntime.jsx("div", {
41875
+ className: "text-sm opacity-60 py-6 text-center",
41876
+ children: "No non-empty defaults found in any owned widget. Nothing to review."
41877
+ });
41878
+ }
41879
+ return /*#__PURE__*/jsxRuntime.jsx("div", {
41880
+ className: "flex flex-col gap-4",
41881
+ children: rows.map(function (_ref7) {
41882
+ var key = _ref7.key,
41883
+ localPkgId = _ref7.localPkgId,
41884
+ label = _ref7.label,
41885
+ defaults = _ref7.defaults;
41886
+ if (defaults.length === 0) {
41887
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
41888
+ className: "border border-white/10 rounded-lg px-4 py-3 bg-white/5",
41889
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
41890
+ className: "text-sm font-semibold font-mono",
41891
+ children: label
41892
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
41893
+ className: "text-xs opacity-60 mt-1",
41894
+ children: ["No non-empty ", /*#__PURE__*/jsxRuntime.jsx("code", {
41895
+ children: "defaultValue"
41896
+ }), " entries detected."]
41897
+ })]
41898
+ }, key);
41899
+ }
41900
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
41901
+ className: "border border-white/10 rounded-lg px-4 py-3 bg-white/5",
41902
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
41903
+ className: "text-sm font-semibold font-mono mb-2",
41904
+ children: label
41905
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
41906
+ className: "flex flex-col gap-3",
41907
+ children: defaults.map(function (d) {
41908
+ var _overrides$localPkgId, _d$currentDefault;
41909
+ var overriddenValue = overrides === null || overrides === void 0 || (_overrides$localPkgId = overrides[localPkgId]) === null || _overrides$localPkgId === void 0 || (_overrides$localPkgId = _overrides$localPkgId[d.widgetName]) === null || _overrides$localPkgId === void 0 ? void 0 : _overrides$localPkgId[d.field];
41910
+ var isOverridden = overriddenValue !== undefined;
41911
+ var displayValue = isOverridden ? String(overriddenValue !== null && overriddenValue !== void 0 ? overriddenValue : "") : String((_d$currentDefault = d.currentDefault) !== null && _d$currentDefault !== void 0 ? _d$currentDefault : "");
41912
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
41913
+ className: "flex flex-col gap-1",
41914
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
41915
+ className: "flex items-center gap-2 flex-wrap",
41916
+ children: [/*#__PURE__*/jsxRuntime.jsxs("code", {
41917
+ className: "text-xs opacity-70",
41918
+ children: [d.widgetName, ".", d.field]
41919
+ }), /*#__PURE__*/jsxRuntime.jsxs("span", {
41920
+ className: "text-[10px] opacity-50",
41921
+ children: ["(", d.type, ")"]
41922
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
41923
+ className: "text-[10px] opacity-50",
41924
+ children: d.displayName
41925
+ }), isOverridden && /*#__PURE__*/jsxRuntime.jsx("span", {
41926
+ className: "text-[10px] uppercase tracking-wide px-1.5 py-0.5 rounded bg-amber-900/40 text-amber-200",
41927
+ children: "edited"
41928
+ })]
41929
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
41930
+ className: "flex items-center gap-2",
41931
+ children: [/*#__PURE__*/jsxRuntime.jsx("input", {
41932
+ type: "text",
41933
+ value: displayValue,
41934
+ onChange: function onChange(e) {
41935
+ return _onChange2(localPkgId, d.widgetName, d.field, e.target.value);
41936
+ },
41937
+ className: "flex-1 bg-gray-900 border border-white/10 rounded px-2 py-1 text-xs font-mono"
41938
+ }), isOverridden && /*#__PURE__*/jsxRuntime.jsx("button", {
41939
+ type: "button",
41940
+ onClick: function onClick() {
41941
+ return _onChange2(localPkgId, d.widgetName, d.field, undefined);
41942
+ },
41943
+ className: "text-xs opacity-60 hover:opacity-100 underline underline-offset-2",
41944
+ title: "Discard edit \u2014 ship the original defaultValue",
41945
+ children: "Reset"
41946
+ })]
41947
+ }), d.instructions && /*#__PURE__*/jsxRuntime.jsx("div", {
41948
+ className: "text-[10px] opacity-50",
41949
+ children: d.instructions
41950
+ })]
41951
+ }, "".concat(d.widgetName, "|").concat(d.field));
41952
+ })
41953
+ })]
41954
+ }, key);
41955
+ })
41956
+ });
41957
+ }
41958
+
41689
41959
  function ownKeys$q(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
41690
41960
  function _objectSpread$q(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$q(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$q(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
41691
41961
  var LayoutPreview = function LayoutPreview(_ref) {
@@ -57162,26 +57432,36 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
57162
57432
  try {
57163
57433
  var _message$workspaces;
57164
57434
  var workspaces = DashReact.deepCopy(message["workspaces"]);
57435
+ // LayoutModel returns null when normalization throws (e.g. a
57436
+ // widget config that references a component the registry can't
57437
+ // resolve yet — common right after a fresh dashboard install
57438
+ // where some widgets are still downloading). Filter nulls so
57439
+ // every renderer that walks the layout sees only well-formed
57440
+ // items and never crashes on `Cannot read properties of null
57441
+ // (reading 'type')` or similar.
57165
57442
  var workspacesTemp = workspaces.map(function (ws) {
57166
- var tempLayout = ws["layout"].map(function (layoutOG) {
57443
+ ws["layout"] = (ws["layout"] || []).map(function (layoutOG) {
57167
57444
  return LayoutModel(layoutOG, workspaces, ws["id"]);
57445
+ }).filter(function (item) {
57446
+ return item != null;
57168
57447
  });
57169
- ws["layout"] = tempLayout;
57170
- // Normalize page layouts too
57171
57448
  if (ws.pages && Array.isArray(ws.pages)) {
57172
57449
  ws.pages = ws.pages.map(function (page) {
57173
57450
  if (page.layout && Array.isArray(page.layout)) {
57174
57451
  page.layout = page.layout.map(function (layoutOG) {
57175
57452
  return LayoutModel(layoutOG, workspaces, ws["id"]);
57453
+ }).filter(function (item) {
57454
+ return item != null;
57176
57455
  });
57177
57456
  }
57178
57457
  return page;
57179
57458
  });
57180
57459
  }
57181
- // Normalize sidebar layout
57182
57460
  if (ws.sidebarLayout && Array.isArray(ws.sidebarLayout)) {
57183
57461
  ws.sidebarLayout = ws.sidebarLayout.map(function (layoutOG) {
57184
57462
  return LayoutModel(layoutOG, workspaces, ws["id"]);
57463
+ }).filter(function (item) {
57464
+ return item != null;
57185
57465
  });
57186
57466
  }
57187
57467
  return WorkspaceModel(ws);
@@ -57965,13 +58245,16 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
57965
58245
  }
57966
58246
  function handleSaveWorkspaceComplete(e, message) {
57967
58247
 
57968
- // Reconstruct workspaces through LayoutModel (same as load path)
58248
+ // Reconstruct workspaces through LayoutModel (same as load path).
58249
+ // Filter nulls so a partially-failed normalize doesn't poison the
58250
+ // layout array — see handleLoadWorkspacesComplete for the rationale.
57969
58251
  var workspaces = DashReact.deepCopy(message["workspaces"]);
57970
58252
  var workspacesTemp = workspaces.map(function (ws) {
57971
- var tempLayout = ws["layout"].map(function (layoutOG) {
58253
+ ws["layout"] = (ws["layout"] || []).map(function (layoutOG) {
57972
58254
  return LayoutModel(layoutOG, workspaces, ws["id"]);
58255
+ }).filter(function (item) {
58256
+ return item != null;
57973
58257
  });
57974
- ws["layout"] = tempLayout;
57975
58258
  return WorkspaceModel(ws);
57976
58259
  });
57977
58260
  pub.pub("dashboard.workspaceChange", {