@trops/dash-core 0.1.383 → 0.1.385

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
@@ -51625,6 +51625,8 @@ var FooterPopover = function FooterPopover(_ref3) {
51625
51625
  _useState2 = _slicedToArray(_useState, 2),
51626
51626
  doNotDisturb = _useState2[0],
51627
51627
  setDoNotDisturb = _useState2[1];
51628
+ var _ref4 = React.useContext(DashReact.ThemeContext) || {},
51629
+ currentTheme = _ref4.currentTheme;
51628
51630
  var displayName = authStatus === "authenticated" && authProfile ? authProfile.displayName || authProfile.username : "Account";
51629
51631
 
51630
51632
  // Load initial DND state
@@ -51663,10 +51665,10 @@ var FooterPopover = function FooterPopover(_ref3) {
51663
51665
  }
51664
51666
  return /*#__PURE__*/jsxRuntime.jsx(react.Popover, {
51665
51667
  className: "relative",
51666
- children: function children(_ref4) {
51668
+ children: function children(_ref5) {
51667
51669
  var _rect$left;
51668
- var open = _ref4.open,
51669
- close = _ref4.close;
51670
+ var open = _ref5.open,
51671
+ close = _ref5.close;
51670
51672
  var rect = open && buttonRef.current ? buttonRef.current.getBoundingClientRect() : null;
51671
51673
  return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
51672
51674
  children: [/*#__PURE__*/jsxRuntime.jsxs(react.Popover.Button, {
@@ -51696,7 +51698,7 @@ var FooterPopover = function FooterPopover(_ref3) {
51696
51698
  onClick: close
51697
51699
  }), /*#__PURE__*/jsxRuntime.jsx(react.Popover.Panel, {
51698
51700
  "static": true,
51699
- className: "fixed w-52 rounded-lg border border-white/10 bg-neutral-900 shadow-xl",
51701
+ className: "fixed w-52 rounded-lg border border-white/10 ".concat((currentTheme === null || currentTheme === void 0 ? void 0 : currentTheme["bg-primary-dark"]) || "bg-neutral-900", " shadow-xl"),
51700
51702
  style: {
51701
51703
  zIndex: 9999,
51702
51704
  left: (_rect$left = rect === null || rect === void 0 ? void 0 : rect.left) !== null && _rect$left !== void 0 ? _rect$left : 0,
@@ -51747,12 +51749,12 @@ var FooterPopover = function FooterPopover(_ref3) {
51747
51749
  }
51748
51750
  });
51749
51751
  };
51750
- var PopoverItem = function PopoverItem(_ref5) {
51751
- var icon = _ref5.icon,
51752
- label = _ref5.label,
51753
- onClick = _ref5.onClick,
51754
- _ref5$active = _ref5.active,
51755
- active = _ref5$active === void 0 ? false : _ref5$active;
51752
+ var PopoverItem = function PopoverItem(_ref6) {
51753
+ var icon = _ref6.icon,
51754
+ label = _ref6.label,
51755
+ onClick = _ref6.onClick,
51756
+ _ref6$active = _ref6.active,
51757
+ active = _ref6$active === void 0 ? false : _ref6$active;
51756
51758
  return /*#__PURE__*/jsxRuntime.jsxs("button", {
51757
51759
  type: "button",
51758
51760
  onClick: onClick,
@@ -53423,6 +53425,61 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
53423
53425
  // eslint-disable-next-line react-hooks/exhaustive-deps
53424
53426
  }, []);
53425
53427
 
53428
+ // ─── Listen for external "apply theme" requests ─────────────────
53429
+ // MCP-driven apply_theme updates settings in the main process; this
53430
+ // listener pulls the new theme into ThemeContext without a remount.
53431
+ React.useEffect(function () {
53432
+ var handler = function handler(e) {
53433
+ var _e$detail;
53434
+ var themeKey = e === null || e === void 0 || (_e$detail = e.detail) === null || _e$detail === void 0 ? void 0 : _e$detail.themeKey;
53435
+ if (themeKey && typeof changeCurrentTheme === "function") {
53436
+ changeCurrentTheme(themeKey);
53437
+ }
53438
+ };
53439
+ window.addEventListener("dash:apply-theme", handler);
53440
+ return function () {
53441
+ return window.removeEventListener("dash:apply-theme", handler);
53442
+ };
53443
+ }, [changeCurrentTheme]);
53444
+
53445
+ // ─── Listen for external "open workspace" requests ──────────────
53446
+ // Fired by: Dash.js notification click, MCP state-changed for
53447
+ // create_dashboard, etc. Any code that wants to switch the active
53448
+ // dashboard from outside this component dispatches
53449
+ // window.dispatchEvent(new CustomEvent("dash:navigate-workspace",
53450
+ // { detail: { workspaceId: <number> } }))
53451
+ // We record the requested ID and open it once it appears in
53452
+ // workspaceConfig — handles the case where the workspace was just
53453
+ // created and the config reload is still in flight.
53454
+ var _useState49 = React.useState(null),
53455
+ _useState50 = _slicedToArray(_useState49, 2),
53456
+ pendingOpenWorkspaceId = _useState50[0],
53457
+ setPendingOpenWorkspaceId = _useState50[1];
53458
+ React.useEffect(function () {
53459
+ var handler = function handler(e) {
53460
+ var _e$detail2;
53461
+ var id = e === null || e === void 0 || (_e$detail2 = e.detail) === null || _e$detail2 === void 0 ? void 0 : _e$detail2.workspaceId;
53462
+ if (id != null) setPendingOpenWorkspaceId(Number(id));
53463
+ };
53464
+ window.addEventListener("dash:navigate-workspace", handler);
53465
+ return function () {
53466
+ return window.removeEventListener("dash:navigate-workspace", handler);
53467
+ };
53468
+ }, []);
53469
+ React.useEffect(function () {
53470
+ if (pendingOpenWorkspaceId == null) return;
53471
+ var ws = workspaceConfig.find(function (w) {
53472
+ return Number(w.id) === Number(pendingOpenWorkspaceId);
53473
+ });
53474
+ if (ws) {
53475
+ handleOpenTab(ws);
53476
+ setPendingOpenWorkspaceId(null);
53477
+ }
53478
+ // If not found yet, keep the pending ID and wait for the next
53479
+ // workspaceConfig update (workspace:saved triggers a reload).
53480
+ // eslint-disable-next-line react-hooks/exhaustive-deps
53481
+ }, [pendingOpenWorkspaceId, workspaceConfig]);
53482
+
53426
53483
  // ─── Load recents on mount ───────────────────────────────────────
53427
53484
  React.useEffect(function () {
53428
53485
  var _window$mainApi4;
@@ -53674,6 +53731,22 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
53674
53731
  setWorkspaceConfig(function () {
53675
53732
  return workspacesTemp;
53676
53733
  });
53734
+ // Also sync fresh workspace data into any open tabs. Without this,
53735
+ // MCP-driven mutations (update_layout, add_widget, etc.) update the
53736
+ // config but the active tab keeps its stale snapshot — users only
53737
+ // see the change after closing and reopening the tab.
53738
+ setOpenTabs(function (prevTabs) {
53739
+ return prevTabs.map(function (tab) {
53740
+ var fresh = workspacesTemp.find(function (w) {
53741
+ return Number(w.id) === Number(tab.id);
53742
+ });
53743
+ if (!fresh) return tab; // workspace was deleted; leave tab for handleCloseTab to reap
53744
+ return _objectSpread$6(_objectSpread$6({}, tab), {}, {
53745
+ name: fresh.name || tab.name,
53746
+ workspace: fresh
53747
+ });
53748
+ });
53749
+ });
53677
53750
  setIsLoadingWorkspaces(false);
53678
53751
  } catch (e) {
53679
53752
  }
@@ -53747,10 +53820,10 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
53747
53820
  }
53748
53821
 
53749
53822
  // ─── Page State ──────────────────────────────────────────────────
53750
- var _useState49 = React.useState(null),
53751
- _useState50 = _slicedToArray(_useState49, 2),
53752
- activePageId = _useState50[0],
53753
- setActivePageId = _useState50[1];
53823
+ var _useState51 = React.useState(null),
53824
+ _useState52 = _slicedToArray(_useState51, 2),
53825
+ activePageId = _useState52[0],
53826
+ setActivePageId = _useState52[1];
53754
53827
 
53755
53828
  // Page history stack for goBack() — pushes the previous page id
53756
53829
  // whenever a navigation happens through navigateToPage().
@@ -53810,8 +53883,8 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
53810
53883
  if (prev) setActivePageId(prev); // bypass history recording
53811
53884
  }
53812
53885
  function onSetNavSidebar(e) {
53813
- var _e$detail;
53814
- setSidebarCollapsed(!!((_e$detail = e.detail) !== null && _e$detail !== void 0 && _e$detail.collapsed));
53886
+ var _e$detail3;
53887
+ setSidebarCollapsed(!!((_e$detail3 = e.detail) !== null && _e$detail3 !== void 0 && _e$detail3.collapsed));
53815
53888
  }
53816
53889
  function onToggleNavSidebar() {
53817
53890
  setSidebarCollapsed(function (c) {
@@ -53847,16 +53920,18 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
53847
53920
  }, []);
53848
53921
  var workspacePages = (workspaceSelected === null || workspaceSelected === void 0 ? void 0 : workspaceSelected.pages) || [];
53849
53922
 
53850
- // Memoize sorted pages so page object references stay stable across re-renders
53923
+ // Memoize sorted pages so page object references stay stable across re-renders.
53924
+ // Depend on `workspaceSelected` so the memo invalidates whenever the workspace
53925
+ // is refreshed (e.g. after an MCP-driven layout/widget change). Without this,
53926
+ // PageLayoutBuilder's React.memo would see the same page reference and skip
53927
+ // re-rendering even though the page's layout array changed underneath.
53851
53928
  var sortedPagesForRender = React.useMemo(function () {
53852
53929
  return _toConsumableArray(workspacePages).sort(function (a, b) {
53853
53930
  return (a.order || 0) - (b.order || 0);
53854
53931
  });
53855
53932
  },
53856
53933
  // eslint-disable-next-line react-hooks/exhaustive-deps
53857
- [workspacePages.length,
53858
- // Re-sort when page names/order change but not on every parent render
53859
- workspacePages.map(function (p) {
53934
+ [workspaceSelected, workspacePages.length, workspacePages.map(function (p) {
53860
53935
  return "".concat(p.id, ":").concat(p.order, ":").concat(p.name);
53861
53936
  }).join(",")]);
53862
53937
  var currentActivePageId = activePageId || (workspaceSelected === null || workspaceSelected === void 0 ? void 0 : workspaceSelected.activePageId) || ((_workspacePages$0$id = (_workspacePages$ = workspacePages[0]) === null || _workspacePages$ === void 0 ? void 0 : _workspacePages$.id) !== null && _workspacePages$0$id !== void 0 ? _workspacePages$0$id : null);
@@ -53877,8 +53952,8 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
53877
53952
  // Listen for open/close dashboard actions via DashboardActionsApi
53878
53953
  React.useEffect(function () {
53879
53954
  function onOpen(e) {
53880
- var _e$detail2;
53881
- var name = (_e$detail2 = e.detail) === null || _e$detail2 === void 0 ? void 0 : _e$detail2.name;
53955
+ var _e$detail4;
53956
+ var name = (_e$detail4 = e.detail) === null || _e$detail4 === void 0 ? void 0 : _e$detail4.name;
53882
53957
  if (!name) return;
53883
53958
  var ws = (workspaceConfigRef.current || []).find(function (w) {
53884
53959
  return (w.name || "").toLowerCase() === name.toLowerCase();
@@ -53886,8 +53961,8 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
53886
53961
  if (ws && handleOpenTabRef.current) handleOpenTabRef.current(ws);
53887
53962
  }
53888
53963
  function onClose(e) {
53889
- var _e$detail3;
53890
- var name = (_e$detail3 = e.detail) === null || _e$detail3 === void 0 ? void 0 : _e$detail3.name;
53964
+ var _e$detail5;
53965
+ var name = (_e$detail5 = e.detail) === null || _e$detail5 === void 0 ? void 0 : _e$detail5.name;
53891
53966
  if (name) {
53892
53967
  var tab = (openTabsRef.current || []).find(function (t) {
53893
53968
  return (t.name || "").toLowerCase() === name.toLowerCase();
@@ -56560,6 +56635,13 @@ var MessageBubble = function MessageBubble(_ref2) {
56560
56635
  content = message.content,
56561
56636
  toolCalls = message.toolCalls,
56562
56637
  hidden = message.hidden;
56638
+ var _ref3 = React.useContext(DashReact.ThemeContext) || {},
56639
+ currentTheme = _ref3.currentTheme;
56640
+ // Prefer theme-provided panel colors so assistant chrome follows the
56641
+ // active app theme. Fall back to the original muted neutral if no
56642
+ // theme is in scope.
56643
+ var bubbleBg = (currentTheme === null || currentTheme === void 0 ? void 0 : currentTheme["bg-secondary-dark"]) || (currentTheme === null || currentTheme === void 0 ? void 0 : currentTheme["bg-primary-dark"]) || "bg-gray-800/40";
56644
+ var userBubbleBg = (currentTheme === null || currentTheme === void 0 ? void 0 : currentTheme["bg-primary-bright"]) || (currentTheme === null || currentTheme === void 0 ? void 0 : currentTheme["bg-primary"]) || "bg-indigo-700/40";
56563
56645
 
56564
56646
  // App-injected priming messages (e.g. widget-builder "Hello…" seed)
56565
56647
  // are kept in state for conversation continuity but suppressed from
@@ -56579,7 +56661,7 @@ var MessageBubble = function MessageBubble(_ref2) {
56579
56661
  className: "text-[10px] font-semibold uppercase tracking-wider text-indigo-400 mb-1 text-right",
56580
56662
  children: "You"
56581
56663
  }), /*#__PURE__*/jsxRuntime.jsx("div", {
56582
- className: "px-3 py-2 rounded-lg bg-indigo-700/40 text-sm text-gray-100 whitespace-pre-wrap break-words leading-relaxed",
56664
+ className: "px-3 py-2 rounded-lg text-sm text-gray-100 whitespace-pre-wrap break-words leading-relaxed ".concat(userBubbleBg),
56583
56665
  children: text
56584
56666
  })]
56585
56667
  })
@@ -56659,7 +56741,7 @@ var MessageBubble = function MessageBubble(_ref2) {
56659
56741
  className: "text-[10px] font-semibold uppercase tracking-wider text-gray-500 mb-1",
56660
56742
  children: "Assistant"
56661
56743
  }), /*#__PURE__*/jsxRuntime.jsx("div", {
56662
- className: "text-sm leading-relaxed px-3 py-2 rounded-lg bg-gray-800/40 text-gray-500 italic",
56744
+ className: "text-sm leading-relaxed px-3 py-2 rounded-lg text-gray-500 italic ".concat(bubbleBg),
56663
56745
  children: "Thinking..."
56664
56746
  })]
56665
56747
  });
@@ -56672,7 +56754,7 @@ var MessageBubble = function MessageBubble(_ref2) {
56672
56754
  className: "text-[10px] font-semibold uppercase tracking-wider text-gray-500 mb-1",
56673
56755
  children: "Assistant"
56674
56756
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
56675
- className: "text-sm leading-relaxed px-3 py-2 rounded-lg bg-gray-800/40",
56757
+ className: "text-sm leading-relaxed px-3 py-2 rounded-lg ".concat(bubbleBg),
56676
56758
  children: [isStreaming && /*#__PURE__*/jsxRuntime.jsx("div", {
56677
56759
  className: "text-gray-200",
56678
56760
  children: /*#__PURE__*/jsxRuntime.jsx(StreamingText, {
@@ -57344,6 +57426,10 @@ function ChatCore(_ref) {
57344
57426
  setStreamingText("");
57345
57427
  setSessionActive(false);
57346
57428
  saveConversation([]);
57429
+ // Allow the initial-message auto-send to re-fire on the fresh
57430
+ // empty conversation. Without this reset, the greeting only ever
57431
+ // appears once per mount, and New Chat leaves the panel blank.
57432
+ initialMessageFiredRef.current = false;
57347
57433
  if (isCliBackend && mainApi !== null && mainApi !== void 0 && (_mainApi$llm3 = mainApi.llm) !== null && _mainApi$llm3 !== void 0 && _mainApi$llm3.clearCliSession) {
57348
57434
  mainApi.llm.clearCliSession(uuid || persistKey || sessionKey);
57349
57435
  }