@trops/dash-core 0.1.597 → 0.1.599

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.esm.js CHANGED
@@ -2,7 +2,7 @@ import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
2
2
  import _typeof from '@babel/runtime/helpers/typeof';
3
3
  import _defineProperty from '@babel/runtime/helpers/defineProperty';
4
4
  import * as DashReact from '@trops/dash-react';
5
- import { isObject, ThemeContext, Modal, FontAwesomeIcon, deepCopy, MainSection, getUUID, getStylesForItem, themeObjects, Heading, SearchInput, ButtonIcon, SubHeading3, InputText, Button, Tag, Button3, Button2, Paragraph, Sidebar, Panel, Stepper, Tag3, Card2, Card3, Heading3, MenuItem3, FormLabel, SelectMenu, Switch, SelectInput, CodeEditorVS, SettingsModal, SubHeading2, tailwindHeightFractions, Menu3, Panel3, ButtonIcon2, DropdownPanel, MenuItem2, DragComponent, ConfirmationModal, DropComponent, getStyleName, capitalizeFirstLetter, isHexColor as isHexColor$1, deriveShades, colorTypes, TAILWIND_PALETTE, Toggle, normalizeHex as normalizeHex$1, contrastRatio, Caption2, Caption, getColorFamilies, getCuratedColorGrid, DashPanel, hexToRgb as hexToRgb$1, themeVariants, SubHeading, Heading2, Paragraph2, Paragraph3, ButtonIcon3, Tag2, Alert, Alert2, Alert3, Toast, Toast2, Toast3, ProgressBar, ProgressBar2, ProgressBar3, MenuItem, Breadcrumbs, Breadcrumbs2, Breadcrumbs3, Caption3, Code, Code2, Code3, Divider, Divider2, Divider3, DashPanel2, DashPanel3, Tabs, Tabs2, Tabs3, Accordion, Accordion2, Accordion3, Toggle2, Toggle3, TextArea, Checkbox, Slider, RadioGroup, AlertBanner, StatusBadge, Skeleton, StatCard, DataList, EmptyState, Card, Panel2, ThemeFromUrlPane, CodeEditorInline, Icon2, AlgoliaSearchBox, CommandPalette, useSidebar, Navbar, withRouter, Menu as Menu$1 } from '@trops/dash-react';
5
+ import { isObject, ThemeContext, Modal, FontAwesomeIcon, deepCopy, MainSection, getUUID, getStylesForItem, themeObjects, Heading, SearchInput, ButtonIcon, SubHeading3, InputText, Button, Tag, Button3, Button2, Paragraph, Sidebar, Panel, Stepper, Tag3, Card2, Card3, Heading3, MenuItem3, FormLabel, SelectMenu, Switch, SelectInput, CodeEditorVS, SettingsModal, SubHeading2, tailwindHeightFractions, Menu3, Panel3, ButtonIcon2, DropdownPanel, MenuItem2, DragComponent, ConfirmationModal, DropComponent, getStyleName, capitalizeFirstLetter, isHexColor as isHexColor$1, deriveShades, colorTypes, TAILWIND_PALETTE, Toggle, normalizeHex as normalizeHex$1, contrastRatio, Caption2, Caption, getColorFamilies, getCuratedColorGrid, DashPanel, hexToRgb as hexToRgb$1, themeVariants, SubHeading, Heading2, Paragraph2, Paragraph3, ButtonIcon3, Tag2, Alert, Alert2, Alert3, Toast, Toast2, Toast3, ProgressBar, ProgressBar2, ProgressBar3, MenuItem, Breadcrumbs, Breadcrumbs2, Breadcrumbs3, Caption3, Code, Code2, Code3, Divider, Divider2, Divider3, DashPanel2, DashPanel3, Tabs, Tabs2, Tabs3, Accordion, Accordion2, Accordion3, Toggle2, Toggle3, TextArea, Checkbox, Slider, RadioGroup, AlertBanner, StatusBadge as StatusBadge$1, Skeleton, StatCard, DataList, EmptyState, Card, Panel2, ThemeFromUrlPane, CodeEditorInline, Icon2, AlgoliaSearchBox, CommandPalette, useSidebar, Navbar, withRouter, Menu as Menu$1 } from '@trops/dash-react';
6
6
  export * from '@trops/dash-react';
7
7
  export { FontAwesomeIcon, ThemeContext } from '@trops/dash-react';
8
8
  import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
@@ -10134,11 +10134,91 @@ function applyFilters(items, filters, mode) {
10134
10134
  });
10135
10135
  }
10136
10136
 
10137
+ var PREVIEW_TEMPLATE_SHAPE = {
10138
+ single: {
10139
+ rows: 1,
10140
+ cols: 1
10141
+ },
10142
+ "two-columns": {
10143
+ rows: 1,
10144
+ cols: 2
10145
+ },
10146
+ "two-rows": {
10147
+ rows: 2,
10148
+ cols: 1
10149
+ },
10150
+ "three-columns": {
10151
+ rows: 1,
10152
+ cols: 3
10153
+ },
10154
+ "two-by-two": {
10155
+ rows: 2,
10156
+ cols: 2
10157
+ },
10158
+ "two-by-three": {
10159
+ rows: 2,
10160
+ cols: 3
10161
+ },
10162
+ "three-by-three": {
10163
+ rows: 3,
10164
+ cols: 3
10165
+ }
10166
+ };
10167
+ function WizardThemePreview(_ref) {
10168
+ var theme = _ref.theme,
10169
+ templateKey = _ref.templateKey;
10170
+ if (!theme) return null;
10171
+ var shape = PREVIEW_TEMPLATE_SHAPE[templateKey] || {
10172
+ rows: 2,
10173
+ cols: 2
10174
+ };
10175
+ var familyOrder = [theme.primary, theme.secondary, theme.tertiary].filter(function (f) {
10176
+ return typeof f === "string" && f.length > 0;
10177
+ });
10178
+ if (familyOrder.length === 0) return null;
10179
+ var totalCells = shape.rows * shape.cols;
10180
+ return /*#__PURE__*/jsxs("div", {
10181
+ className: "rounded-lg border border-gray-700/50 bg-gray-900/30 p-3 flex flex-col gap-2",
10182
+ "data-testid": "wizard-theme-preview",
10183
+ children: [/*#__PURE__*/jsxs("div", {
10184
+ className: "flex items-center gap-2 text-xs text-gray-400",
10185
+ children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
10186
+ icon: "eye",
10187
+ fixedWidth: true,
10188
+ className: "text-gray-500"
10189
+ }), /*#__PURE__*/jsxs("span", {
10190
+ children: ["Preview \xB7 ", theme.name || ""]
10191
+ }), templateKey && /*#__PURE__*/jsxs("span", {
10192
+ className: "text-gray-600",
10193
+ children: ["(", shape.rows, "\xD7", shape.cols, ")"]
10194
+ })]
10195
+ }), /*#__PURE__*/jsx("div", {
10196
+ className: "grid gap-1.5",
10197
+ style: {
10198
+ gridTemplateRows: "repeat(".concat(shape.rows, ", minmax(0, 1fr))"),
10199
+ gridTemplateColumns: "repeat(".concat(shape.cols, ", minmax(0, 1fr))"),
10200
+ minHeight: "5rem"
10201
+ },
10202
+ "data-testid": "wizard-theme-preview-grid",
10203
+ children: Array.from({
10204
+ length: totalCells
10205
+ }).map(function (_, i) {
10206
+ var family = familyOrder[i % familyOrder.length];
10207
+ return /*#__PURE__*/jsx("div", {
10208
+ className: "rounded bg-".concat(family, "-500/70 border border-").concat(family, "-400/40"),
10209
+ "data-testid": "wizard-theme-preview-cell-".concat(i),
10210
+ "data-family": family
10211
+ }, i);
10212
+ })
10213
+ })]
10214
+ });
10215
+ }
10216
+
10137
10217
  function _createForOfIteratorHelper$G(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$G(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
10138
10218
  function _unsupportedIterableToArray$G(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$G(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$G(r, a) : void 0; } }
10139
10219
  function _arrayLikeToArray$G(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
10140
10220
  var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
10141
- var _state$selectedDashbo, _state$selectedDashbo2;
10221
+ var _state$selectedDashbo, _state$selectedDashbo2, _state$layout;
10142
10222
  var state = _ref.state,
10143
10223
  dispatch = _ref.dispatch,
10144
10224
  _ref$menuItems = _ref.menuItems,
@@ -10910,6 +10990,9 @@ var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
10910
10990
  })
10911
10991
  }, key);
10912
10992
  })
10993
+ }), state.customization.theme && /*#__PURE__*/jsx(WizardThemePreview, {
10994
+ theme: themes === null || themes === void 0 ? void 0 : themes[state.customization.theme],
10995
+ templateKey: (_state$layout = state.layout) === null || _state$layout === void 0 ? void 0 : _state$layout.templateKey
10913
10996
  })]
10914
10997
  }), selectedProviders.length > 0 && /*#__PURE__*/jsxs("div", {
10915
10998
  className: "flex flex-col gap-2",
@@ -36479,7 +36562,7 @@ var REGISTRY = {
36479
36562
  themeKey: "status-badge",
36480
36563
  category: "Feedback",
36481
36564
  render: function render() {
36482
- return /*#__PURE__*/jsx(StatusBadge, {
36565
+ return /*#__PURE__*/jsx(StatusBadge$1, {
36483
36566
  state: "success",
36484
36567
  label: "Active"
36485
36568
  });
@@ -49733,7 +49816,23 @@ var WidgetsSection = function WidgetsSection(_ref) {
49733
49816
  }
49734
49817
  var listContent = /*#__PURE__*/jsxs("div", {
49735
49818
  className: "flex flex-col h-full",
49736
- children: [isChecking && packagesWithUpdates.length === 0 && /*#__PURE__*/jsxs("div", {
49819
+ children: [/*#__PURE__*/jsx("div", {
49820
+ className: "flex-shrink-0 px-3 pt-2 pb-1",
49821
+ children: /*#__PURE__*/jsxs("button", {
49822
+ type: "button",
49823
+ onClick: function onClick() {
49824
+ return window.dispatchEvent(new Event("dash:open-widget-builder"));
49825
+ },
49826
+ className: "w-full flex items-center justify-center gap-2 px-3 py-2 text-sm font-medium rounded bg-indigo-600 hover:bg-indigo-500 text-white",
49827
+ "data-testid": "widgets-section-new-widget-button",
49828
+ children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
49829
+ icon: "plus",
49830
+ className: "text-xs"
49831
+ }), /*#__PURE__*/jsx("span", {
49832
+ children: "New Widget"
49833
+ })]
49834
+ })
49835
+ }), isChecking && packagesWithUpdates.length === 0 && /*#__PURE__*/jsxs("div", {
49737
49836
  className: "flex-shrink-0 px-3 py-2 border-b border-white/10 bg-gray-800/60 flex items-center gap-2 text-xs text-gray-400",
49738
49837
  "data-testid": "widgets-section-checking-updates",
49739
49838
  children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
@@ -54583,6 +54682,413 @@ var DashboardLoaderModal = function DashboardLoaderModal(_ref) {
54583
54682
  });
54584
54683
  };
54585
54684
 
54685
+ var KITCHEN_SINK_PACKAGE = "trops/kitchen-sink";
54686
+ var STATE = {
54687
+ WELCOME: "welcome",
54688
+ INSTALLING: "installing",
54689
+ DONE: "done",
54690
+ ERROR: "error"
54691
+ };
54692
+ var OnboardingModal = function OnboardingModal(_ref) {
54693
+ var open = _ref.open,
54694
+ appId = _ref.appId,
54695
+ onOpenDashboard = _ref.onOpenDashboard,
54696
+ onDismiss = _ref.onDismiss,
54697
+ onComplete = _ref.onComplete;
54698
+ var _ref2 = useContext(ThemeContext) || {},
54699
+ currentTheme = _ref2.currentTheme;
54700
+ var _useState = useState(STATE.WELCOME),
54701
+ _useState2 = _slicedToArray(_useState, 2),
54702
+ state = _useState2[0],
54703
+ setState = _useState2[1];
54704
+ var _useState3 = useState([]),
54705
+ _useState4 = _slicedToArray(_useState3, 2),
54706
+ progressItems = _useState4[0],
54707
+ setProgressItems = _useState4[1];
54708
+ var _useState5 = useState(null),
54709
+ _useState6 = _slicedToArray(_useState5, 2),
54710
+ installError = _useState6[0],
54711
+ setInstallError = _useState6[1];
54712
+ var installResultRef = useRef(null);
54713
+ var cleanupProgressRef = useRef(null);
54714
+ useEffect(function () {
54715
+ if (open) {
54716
+ setState(STATE.WELCOME);
54717
+ setProgressItems([]);
54718
+ setInstallError(null);
54719
+ installResultRef.current = null;
54720
+ }
54721
+ return function () {
54722
+ if (cleanupProgressRef.current) {
54723
+ cleanupProgressRef.current();
54724
+ cleanupProgressRef.current = null;
54725
+ }
54726
+ };
54727
+ }, [open]);
54728
+ var markCompletedAndClose = useCallback(/*#__PURE__*/function () {
54729
+ var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(source) {
54730
+ var _window$mainApi, _window$mainApi$markC;
54731
+ return _regeneratorRuntime.wrap(function (_context) {
54732
+ while (1) switch (_context.prev = _context.next) {
54733
+ case 0:
54734
+ _context.prev = 0;
54735
+ _context.next = 1;
54736
+ return (_window$mainApi = window.mainApi) === null || _window$mainApi === void 0 || (_window$mainApi = _window$mainApi.onboarding) === null || _window$mainApi === void 0 || (_window$mainApi$markC = _window$mainApi.markCompleted) === null || _window$mainApi$markC === void 0 ? void 0 : _window$mainApi$markC.call(_window$mainApi, {
54737
+ source: source
54738
+ });
54739
+ case 1:
54740
+ _context.next = 3;
54741
+ break;
54742
+ case 2:
54743
+ _context.prev = 2;
54744
+ _context["catch"](0);
54745
+ case 3:
54746
+ if (onComplete) onComplete({
54747
+ source: source
54748
+ });
54749
+ case 4:
54750
+ case "end":
54751
+ return _context.stop();
54752
+ }
54753
+ }, _callee, null, [[0, 2]]);
54754
+ }));
54755
+ return function (_x) {
54756
+ return _ref3.apply(this, arguments);
54757
+ };
54758
+ }(), [onComplete]);
54759
+ var handleSkip = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
54760
+ return _regeneratorRuntime.wrap(function (_context2) {
54761
+ while (1) switch (_context2.prev = _context2.next) {
54762
+ case 0:
54763
+ _context2.next = 1;
54764
+ return markCompletedAndClose("dismissed");
54765
+ case 1:
54766
+ if (onDismiss) onDismiss();
54767
+ case 2:
54768
+ case "end":
54769
+ return _context2.stop();
54770
+ }
54771
+ }, _callee2);
54772
+ })), [markCompletedAndClose, onDismiss]);
54773
+ var handleInstall = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
54774
+ var _window$mainApi2, _window$mainApi2$onIn;
54775
+ var _window$mainApi3, _window$mainApi3$inst, result, _t2;
54776
+ return _regeneratorRuntime.wrap(function (_context3) {
54777
+ while (1) switch (_context3.prev = _context3.next) {
54778
+ case 0:
54779
+ if (appId) {
54780
+ _context3.next = 1;
54781
+ break;
54782
+ }
54783
+ setInstallError("Cannot install — application not initialized. Try again in a moment.");
54784
+ setState(STATE.ERROR);
54785
+ return _context3.abrupt("return");
54786
+ case 1:
54787
+ setState(STATE.INSTALLING);
54788
+ setProgressItems([]);
54789
+ setInstallError(null);
54790
+ if (cleanupProgressRef.current) cleanupProgressRef.current();
54791
+ cleanupProgressRef.current = (_window$mainApi2 = window.mainApi) === null || _window$mainApi2 === void 0 || (_window$mainApi2 = _window$mainApi2.dashboardConfig) === null || _window$mainApi2 === void 0 || (_window$mainApi2$onIn = _window$mainApi2.onInstallProgress) === null || _window$mainApi2$onIn === void 0 ? void 0 : _window$mainApi2$onIn.call(_window$mainApi2, function (data) {
54792
+ setProgressItems(function (prev) {
54793
+ var next = prev.length > 0 ? _toConsumableArray(prev) : [];
54794
+ if (next.length === 0 && typeof data.total === "number") {
54795
+ for (var i = 0; i < data.total; i += 1) {
54796
+ next.push({
54797
+ packageName: i === data.index ? data.packageName : "",
54798
+ displayName: i === data.index ? data.displayName : "",
54799
+ status: "pending"
54800
+ });
54801
+ }
54802
+ }
54803
+ if (typeof data.index === "number" && data.index >= 0 && data.index < next.length) {
54804
+ next[data.index] = {
54805
+ packageName: data.packageName || next[data.index].packageName,
54806
+ displayName: data.displayName || next[data.index].displayName || data.packageName || "",
54807
+ status: data.status || next[data.index].status,
54808
+ error: data.error || null
54809
+ };
54810
+ }
54811
+ return next;
54812
+ });
54813
+ });
54814
+ _context3.prev = 2;
54815
+ _context3.next = 3;
54816
+ return (_window$mainApi3 = window.mainApi) === null || _window$mainApi3 === void 0 || (_window$mainApi3 = _window$mainApi3.dashboardConfig) === null || _window$mainApi3 === void 0 || (_window$mainApi3$inst = _window$mainApi3.installDashboardFromRegistry) === null || _window$mainApi3$inst === void 0 ? void 0 : _window$mainApi3$inst.call(_window$mainApi3, appId, KITCHEN_SINK_PACKAGE, {});
54817
+ case 3:
54818
+ result = _context3.sent;
54819
+ if (cleanupProgressRef.current) {
54820
+ cleanupProgressRef.current();
54821
+ cleanupProgressRef.current = null;
54822
+ }
54823
+ if (!(!result || !result.success)) {
54824
+ _context3.next = 4;
54825
+ break;
54826
+ }
54827
+ setInstallError((result === null || result === void 0 ? void 0 : result.error) || "Failed to install Kitchen Sink. Check your internet connection and try again.");
54828
+ setState(STATE.ERROR);
54829
+ return _context3.abrupt("return");
54830
+ case 4:
54831
+ installResultRef.current = result;
54832
+ setState(STATE.DONE);
54833
+ _context3.next = 6;
54834
+ break;
54835
+ case 5:
54836
+ _context3.prev = 5;
54837
+ _t2 = _context3["catch"](2);
54838
+ if (cleanupProgressRef.current) {
54839
+ cleanupProgressRef.current();
54840
+ cleanupProgressRef.current = null;
54841
+ }
54842
+ setInstallError((_t2 === null || _t2 === void 0 ? void 0 : _t2.message) || "Installation failed.");
54843
+ setState(STATE.ERROR);
54844
+ case 6:
54845
+ case "end":
54846
+ return _context3.stop();
54847
+ }
54848
+ }, _callee3, null, [[2, 5]]);
54849
+ })), [appId]);
54850
+ var handleOpen = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
54851
+ var _installResultRef$cur;
54852
+ var workspace;
54853
+ return _regeneratorRuntime.wrap(function (_context4) {
54854
+ while (1) switch (_context4.prev = _context4.next) {
54855
+ case 0:
54856
+ workspace = ((_installResultRef$cur = installResultRef.current) === null || _installResultRef$cur === void 0 ? void 0 : _installResultRef$cur.workspace) || null;
54857
+ _context4.next = 1;
54858
+ return markCompletedAndClose("kitchen-sink");
54859
+ case 1:
54860
+ if (workspace && onOpenDashboard) {
54861
+ onOpenDashboard(workspace);
54862
+ }
54863
+ case 2:
54864
+ case "end":
54865
+ return _context4.stop();
54866
+ }
54867
+ }, _callee4);
54868
+ })), [markCompletedAndClose, onOpenDashboard]);
54869
+ var handleRetry = useCallback(function () {
54870
+ setInstallError(null);
54871
+ handleInstall();
54872
+ }, [handleInstall]);
54873
+
54874
+ // The Modal dispatches setIsOpen(false) on Escape / backdrop click.
54875
+ // Route any close attempt through handleSkip so the completion flag
54876
+ // is always stamped (otherwise Escape would silently re-show the
54877
+ // modal on the next launch).
54878
+ var handleSetIsOpen = useCallback(function (next) {
54879
+ if (next === false) handleSkip();
54880
+ }, [handleSkip]);
54881
+ var bgPanel = (currentTheme === null || currentTheme === void 0 ? void 0 : currentTheme["bg-primary-medium"]) || "bg-gray-900";
54882
+ var textPrimary = (currentTheme === null || currentTheme === void 0 ? void 0 : currentTheme["text-primary-light"]) || "text-gray-100";
54883
+ var textMuted = (currentTheme === null || currentTheme === void 0 ? void 0 : currentTheme["text-primary-medium"]) || "text-gray-400";
54884
+ var borderPanel = (currentTheme === null || currentTheme === void 0 ? void 0 : currentTheme["border-primary-medium"]) || "border-gray-700";
54885
+ return /*#__PURE__*/jsx(Modal, {
54886
+ isOpen: open,
54887
+ setIsOpen: handleSetIsOpen,
54888
+ width: "w-full max-w-2xl",
54889
+ height: "h-auto",
54890
+ children: /*#__PURE__*/jsxs("div", {
54891
+ className: "flex flex-col ".concat(bgPanel, " ").concat(textPrimary, " rounded-lg overflow-hidden p-8"),
54892
+ "data-testid": "onboarding-modal",
54893
+ children: [state === STATE.WELCOME && /*#__PURE__*/jsx(WelcomeBody, {
54894
+ onInstall: handleInstall,
54895
+ onSkip: handleSkip,
54896
+ textMuted: textMuted
54897
+ }), state === STATE.INSTALLING && /*#__PURE__*/jsx(InstallingBody, {
54898
+ items: progressItems,
54899
+ borderPanel: borderPanel,
54900
+ textMuted: textMuted
54901
+ }), state === STATE.DONE && /*#__PURE__*/jsx(DoneBody, {
54902
+ onOpen: handleOpen,
54903
+ textMuted: textMuted
54904
+ }), state === STATE.ERROR && /*#__PURE__*/jsx(ErrorBody, {
54905
+ message: installError,
54906
+ onRetry: handleRetry,
54907
+ onSkip: handleSkip,
54908
+ textMuted: textMuted
54909
+ })]
54910
+ })
54911
+ });
54912
+ };
54913
+ function WelcomeBody(_ref7) {
54914
+ var onInstall = _ref7.onInstall,
54915
+ onSkip = _ref7.onSkip,
54916
+ textMuted = _ref7.textMuted;
54917
+ return /*#__PURE__*/jsxs(Fragment, {
54918
+ children: [/*#__PURE__*/jsxs("div", {
54919
+ className: "flex items-center gap-3 mb-2",
54920
+ children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
54921
+ icon: "sink",
54922
+ className: "text-2xl"
54923
+ }), /*#__PURE__*/jsx(Heading2, {
54924
+ title: "Welcome to Dash"
54925
+ })]
54926
+ }), /*#__PURE__*/jsxs(Paragraph, {
54927
+ className: "".concat(textMuted, " mb-6"),
54928
+ children: ["Get started with the ", /*#__PURE__*/jsx("strong", {
54929
+ children: "Kitchen Sink"
54930
+ }), " dashboard \u2014 a curated set of widgets that shows what Dash can do. You can swap anything out, or build your own from scratch later."]
54931
+ }), /*#__PURE__*/jsxs("div", {
54932
+ className: "flex items-center justify-end gap-3 mt-2",
54933
+ children: [/*#__PURE__*/jsx(Button, {
54934
+ onClick: onSkip,
54935
+ title: "Skip for now",
54936
+ textSize: "text-sm",
54937
+ padding: "py-2 px-4",
54938
+ backgroundColor: "bg-gray-700",
54939
+ textColor: "text-gray-300",
54940
+ hoverTextColor: "hover:text-white",
54941
+ hoverBackgroundColor: "hover:bg-gray-600",
54942
+ "data-testid": "onboarding-skip-button"
54943
+ }), /*#__PURE__*/jsx(Button, {
54944
+ onClick: onInstall,
54945
+ title: "Install Kitchen Sink",
54946
+ textSize: "text-sm",
54947
+ padding: "py-2 px-4",
54948
+ backgroundColor: "bg-blue-600",
54949
+ textColor: "text-white",
54950
+ hoverTextColor: "hover:text-white",
54951
+ hoverBackgroundColor: "hover:bg-blue-500",
54952
+ icon: "download",
54953
+ "data-testid": "onboarding-install-button"
54954
+ })]
54955
+ })]
54956
+ });
54957
+ }
54958
+ function InstallingBody(_ref8) {
54959
+ var items = _ref8.items,
54960
+ borderPanel = _ref8.borderPanel,
54961
+ textMuted = _ref8.textMuted;
54962
+ return /*#__PURE__*/jsxs(Fragment, {
54963
+ children: [/*#__PURE__*/jsx(SubHeading, {
54964
+ title: "Installing Kitchen Sink\u2026"
54965
+ }), /*#__PURE__*/jsx(Paragraph, {
54966
+ className: "".concat(textMuted, " mt-2 mb-4"),
54967
+ children: "Downloading widgets, theme, and dashboard configuration from the registry. This usually takes a few seconds."
54968
+ }), /*#__PURE__*/jsxs("div", {
54969
+ className: "border ".concat(borderPanel, " rounded-md max-h-64 overflow-y-auto"),
54970
+ "data-testid": "onboarding-progress-list",
54971
+ children: [items.length === 0 && /*#__PURE__*/jsx("div", {
54972
+ className: "p-3 ".concat(textMuted),
54973
+ children: "Starting install\u2026"
54974
+ }), items.map(function (item, idx) {
54975
+ return /*#__PURE__*/jsxs("div", {
54976
+ className: "flex items-center justify-between px-3 py-2",
54977
+ "data-status": item.status,
54978
+ children: [/*#__PURE__*/jsx("span", {
54979
+ className: "truncate",
54980
+ children: item.displayName || item.packageName || "Item ".concat(idx + 1)
54981
+ }), /*#__PURE__*/jsx(StatusBadge, {
54982
+ status: item.status
54983
+ })]
54984
+ }, "".concat(item.packageName || "slot", "-").concat(idx));
54985
+ })]
54986
+ })]
54987
+ });
54988
+ }
54989
+ function StatusBadge(_ref9) {
54990
+ var status = _ref9.status;
54991
+ switch (status) {
54992
+ case "installed":
54993
+ case "already-installed":
54994
+ return /*#__PURE__*/jsx(FontAwesomeIcon, {
54995
+ icon: "check",
54996
+ className: "text-green-500",
54997
+ "data-testid": "status-installed"
54998
+ });
54999
+ case "failed":
55000
+ return /*#__PURE__*/jsx(FontAwesomeIcon, {
55001
+ icon: "xmark",
55002
+ className: "text-red-500",
55003
+ "data-testid": "status-failed"
55004
+ });
55005
+ case "downloading":
55006
+ case "pending":
55007
+ default:
55008
+ return /*#__PURE__*/jsx(FontAwesomeIcon, {
55009
+ icon: "circle-notch",
55010
+ className: "animate-spin",
55011
+ "data-testid": "status-".concat(status || "pending")
55012
+ });
55013
+ }
55014
+ }
55015
+ function DoneBody(_ref0) {
55016
+ var onOpen = _ref0.onOpen,
55017
+ textMuted = _ref0.textMuted;
55018
+ return /*#__PURE__*/jsxs(Fragment, {
55019
+ children: [/*#__PURE__*/jsxs("div", {
55020
+ className: "flex items-center gap-3 mb-2",
55021
+ children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
55022
+ icon: "check",
55023
+ className: "text-2xl text-green-500"
55024
+ }), /*#__PURE__*/jsx(Heading2, {
55025
+ title: "Kitchen Sink Installed"
55026
+ })]
55027
+ }), /*#__PURE__*/jsx(Paragraph, {
55028
+ className: "".concat(textMuted, " mb-6"),
55029
+ children: "Your first dashboard is ready. Open it to explore \u2014 every widget and the theme are now installed locally."
55030
+ }), /*#__PURE__*/jsx("div", {
55031
+ className: "flex items-center justify-end",
55032
+ children: /*#__PURE__*/jsx(Button, {
55033
+ onClick: onOpen,
55034
+ title: "Open Kitchen Sink",
55035
+ textSize: "text-sm",
55036
+ padding: "py-2 px-4",
55037
+ backgroundColor: "bg-green-600",
55038
+ textColor: "text-white",
55039
+ hoverTextColor: "hover:text-white",
55040
+ hoverBackgroundColor: "hover:bg-green-500",
55041
+ icon: "arrow-right",
55042
+ "data-testid": "onboarding-open-button"
55043
+ })
55044
+ })]
55045
+ });
55046
+ }
55047
+ function ErrorBody(_ref1) {
55048
+ var message = _ref1.message,
55049
+ onRetry = _ref1.onRetry,
55050
+ onSkip = _ref1.onSkip,
55051
+ textMuted = _ref1.textMuted;
55052
+ return /*#__PURE__*/jsxs(Fragment, {
55053
+ children: [/*#__PURE__*/jsxs("div", {
55054
+ className: "flex items-center gap-3 mb-2",
55055
+ children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
55056
+ icon: "triangle-exclamation",
55057
+ className: "text-2xl text-red-500"
55058
+ }), /*#__PURE__*/jsx(Heading2, {
55059
+ title: "Install Failed"
55060
+ })]
55061
+ }), /*#__PURE__*/jsx(Paragraph, {
55062
+ className: "".concat(textMuted, " mb-6"),
55063
+ children: message || "Something went wrong installing Kitchen Sink."
55064
+ }), /*#__PURE__*/jsxs("div", {
55065
+ className: "flex items-center justify-end gap-3",
55066
+ children: [/*#__PURE__*/jsx(Button, {
55067
+ onClick: onSkip,
55068
+ title: "Skip for now",
55069
+ textSize: "text-sm",
55070
+ padding: "py-2 px-4",
55071
+ backgroundColor: "bg-gray-700",
55072
+ textColor: "text-gray-300",
55073
+ hoverTextColor: "hover:text-white",
55074
+ hoverBackgroundColor: "hover:bg-gray-600",
55075
+ "data-testid": "onboarding-skip-after-error-button"
55076
+ }), /*#__PURE__*/jsx(Button, {
55077
+ onClick: onRetry,
55078
+ title: "Try again",
55079
+ textSize: "text-sm",
55080
+ padding: "py-2 px-4",
55081
+ backgroundColor: "bg-blue-600",
55082
+ textColor: "text-white",
55083
+ hoverTextColor: "hover:text-white",
55084
+ hoverBackgroundColor: "hover:bg-blue-500",
55085
+ icon: "rotate-right",
55086
+ "data-testid": "onboarding-retry-button"
55087
+ })]
55088
+ })]
55089
+ });
55090
+ }
55091
+
54586
55092
  var DashCommandPalette = function DashCommandPalette(_ref) {
54587
55093
  var isOpen = _ref.isOpen,
54588
55094
  setIsOpen = _ref.setIsOpen,
@@ -58053,6 +58559,8 @@ var DashboardConfigModal = function DashboardConfigModal(_ref) {
58053
58559
  onSaveListeners = _ref.onSaveListeners,
58054
58560
  _ref$onSaveUserPrefs = _ref.onSaveUserPrefs,
58055
58561
  onSaveUserPrefs = _ref$onSaveUserPrefs === void 0 ? null : _ref$onSaveUserPrefs,
58562
+ _ref$onSkip = _ref.onSkip,
58563
+ onSkip = _ref$onSkip === void 0 ? null : _ref$onSkip,
58056
58564
  _ref$initialTab = _ref.initialTab,
58057
58565
  initialTab = _ref$initialTab === void 0 ? "providers" : _ref$initialTab;
58058
58566
  var _useContext = useContext(ThemeContext),
@@ -58566,6 +59074,23 @@ var DashboardConfigModal = function DashboardConfigModal(_ref) {
58566
59074
  setStagedPrefs({});
58567
59075
  setIsOpen(false);
58568
59076
  }
59077
+
59078
+ // "Skip for now" — closes the modal AND tells the parent to suppress
59079
+ // the unresolved-providers banner for the current session. Cancel
59080
+ // just closes; Skip means "I'm intentionally not dealing with this
59081
+ // right now." Without this affordance, new users who hit the
59082
+ // post-install state can feel cornered by the banner reappearing
59083
+ // every time they close the modal without resolving every provider.
59084
+ function handleSkip() {
59085
+ setStaged({});
59086
+ setStagedListeners({
59087
+ adds: [],
59088
+ removes: []
59089
+ });
59090
+ setStagedPrefs({});
59091
+ if (typeof onSkip === "function") onSkip();
59092
+ setIsOpen(false);
59093
+ }
58569
59094
  if (!isOpen) return null;
58570
59095
  return /*#__PURE__*/jsx(Modal, {
58571
59096
  isOpen: isOpen,
@@ -58677,7 +59202,10 @@ var DashboardConfigModal = function DashboardConfigModal(_ref) {
58677
59202
  })]
58678
59203
  }), /*#__PURE__*/jsx(Divider, {}), /*#__PURE__*/jsxs("div", {
58679
59204
  className: "flex-shrink-0 flex flex-row justify-end gap-2 p-4",
58680
- children: [/*#__PURE__*/jsx(Button3, {
59205
+ children: [typeof onSkip === "function" && /*#__PURE__*/jsx(Button3, {
59206
+ title: "Skip for now",
59207
+ onClick: handleSkip
59208
+ }), /*#__PURE__*/jsx(Button3, {
58681
59209
  title: "Cancel",
58682
59210
  onClick: handleCancel
58683
59211
  }), /*#__PURE__*/jsx(Button2, {
@@ -60391,64 +60919,75 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60391
60919
  isWizardOpen = _useState36[0],
60392
60920
  setIsWizardOpen = _useState36[1];
60393
60921
 
60922
+ // First-run onboarding (Phase 3A). Tri-state:
60923
+ // null — status not yet loaded from main; do not render anything
60924
+ // true — show the OnboardingModal
60925
+ // false — onboarding already completed (or app is not first-run)
60926
+ // The status read happens once per mount; subsequent dismiss/complete
60927
+ // flips this to false without re-fetching.
60928
+ var _useState37 = useState(null),
60929
+ _useState38 = _slicedToArray(_useState37, 2),
60930
+ isOnboardingOpen = _useState38[0],
60931
+ setIsOnboardingOpen = _useState38[1];
60932
+
60394
60933
  // Missing widgets detection
60395
60934
  var _useMissingWidgets = useMissingWidgets(workspaceSelected),
60396
60935
  missingComponents = _useMissingWidgets.missingComponents,
60397
60936
  hasMissing = _useMissingWidgets.hasMissing;
60398
- var _useState37 = useState(false),
60399
- _useState38 = _slicedToArray(_useState37, 2),
60400
- isMissingWidgetsModalOpen = _useState38[0],
60401
- setIsMissingWidgetsModalOpen = _useState38[1];
60402
- var _useState39 = useState(new Set()),
60937
+ var _useState39 = useState(false),
60403
60938
  _useState40 = _slicedToArray(_useState39, 2),
60404
- dismissedMissingForWorkspace = _useState40[0],
60405
- setDismissedMissingForWorkspace = _useState40[1];
60939
+ isMissingWidgetsModalOpen = _useState40[0],
60940
+ setIsMissingWidgetsModalOpen = _useState40[1];
60941
+ var _useState41 = useState(new Set()),
60942
+ _useState42 = _slicedToArray(_useState41, 2),
60943
+ dismissedMissingForWorkspace = _useState42[0],
60944
+ setDismissedMissingForWorkspace = _useState42[1];
60406
60945
 
60407
60946
  // Dashboard Config modal — bulk provider wiring for the current
60408
60947
  // workspace. Auto-opens on first load of a workspace with unresolved
60409
60948
  // providers (tracked per session via `configModalAutoOpenedFor` so
60410
60949
  // switching tabs doesn't re-fire the modal).
60411
- var _useState41 = useState(false),
60412
- _useState42 = _slicedToArray(_useState41, 2),
60413
- isConfigModalOpen = _useState42[0],
60414
- setIsConfigModalOpen = _useState42[1];
60415
- useRef(new Set());
60416
- var _useState43 = useState(new Set()),
60950
+ var _useState43 = useState(false),
60417
60951
  _useState44 = _slicedToArray(_useState43, 2),
60418
- dismissedUnresolvedForWorkspace = _useState44[0],
60419
- setDismissedUnresolvedForWorkspace = _useState44[1];
60952
+ isConfigModalOpen = _useState44[0],
60953
+ setIsConfigModalOpen = _useState44[1];
60954
+ useRef(new Set());
60955
+ var _useState45 = useState(new Set()),
60956
+ _useState46 = _slicedToArray(_useState45, 2),
60957
+ dismissedUnresolvedForWorkspace = _useState46[0],
60958
+ setDismissedUnresolvedForWorkspace = _useState46[1];
60420
60959
 
60421
60960
  // Unified App Settings Modal
60422
- var _useState45 = useState(false),
60423
- _useState46 = _slicedToArray(_useState45, 2),
60424
- isAppSettingsOpen = _useState46[0],
60425
- setIsAppSettingsOpen = _useState46[1];
60426
- var _useState47 = useState("dashboards"),
60961
+ var _useState47 = useState(false),
60427
60962
  _useState48 = _slicedToArray(_useState47, 2),
60428
- appSettingsInitialSection = _useState48[0],
60429
- setAppSettingsInitialSection = _useState48[1];
60430
- var _useState49 = useState(null),
60963
+ isAppSettingsOpen = _useState48[0],
60964
+ setIsAppSettingsOpen = _useState48[1];
60965
+ var _useState49 = useState("dashboards"),
60431
60966
  _useState50 = _slicedToArray(_useState49, 2),
60432
- appSettingsInitialProvider = _useState50[0],
60433
- setAppSettingsInitialProvider = _useState50[1];
60434
- var _useState51 = useState(false),
60967
+ appSettingsInitialSection = _useState50[0],
60968
+ setAppSettingsInitialSection = _useState50[1];
60969
+ var _useState51 = useState(null),
60435
60970
  _useState52 = _slicedToArray(_useState51, 2),
60436
- appSettingsCreateProvider = _useState52[0],
60437
- setAppSettingsCreateProvider = _useState52[1];
60971
+ appSettingsInitialProvider = _useState52[0],
60972
+ setAppSettingsInitialProvider = _useState52[1];
60973
+ var _useState53 = useState(false),
60974
+ _useState54 = _slicedToArray(_useState53, 2),
60975
+ appSettingsCreateProvider = _useState54[0],
60976
+ setAppSettingsCreateProvider = _useState54[1];
60438
60977
  // Optional pre-fills used by the cross-modal "Add new <type>"
60439
60978
  // flow dispatched from dash-electron's WidgetBuilderModal.
60440
60979
  // initialProviderType is the type id (e.g. "filesystem", "slack").
60441
60980
  // initialProviderClass routes the create flow: "mcp" opens the
60442
60981
  // catalog detail with that type pre-selected; otherwise opens
60443
60982
  // the credential create form with formType pre-filled.
60444
- var _useState53 = useState(null),
60445
- _useState54 = _slicedToArray(_useState53, 2),
60446
- appSettingsInitialProviderType = _useState54[0],
60447
- setAppSettingsInitialProviderType = _useState54[1];
60448
60983
  var _useState55 = useState(null),
60449
60984
  _useState56 = _slicedToArray(_useState55, 2),
60450
- appSettingsInitialProviderClass = _useState56[0],
60451
- setAppSettingsInitialProviderClass = _useState56[1];
60985
+ appSettingsInitialProviderType = _useState56[0],
60986
+ setAppSettingsInitialProviderType = _useState56[1];
60987
+ var _useState57 = useState(null),
60988
+ _useState58 = _slicedToArray(_useState57, 2),
60989
+ appSettingsInitialProviderClass = _useState58[0],
60990
+ setAppSettingsInitialProviderClass = _useState58[1];
60452
60991
  function openAppSettings() {
60453
60992
  var section = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "general";
60454
60993
  var providerName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
@@ -60466,27 +61005,27 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60466
61005
  return _handleProfileUpdated.apply(this, arguments);
60467
61006
  } // Ref to access LayoutBuilder's current workspace without re-render cascades
60468
61007
  function _handleProfileUpdated() {
60469
- _handleProfileUpdated = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
60470
- var _window$mainApi11, profile;
60471
- return _regeneratorRuntime.wrap(function (_context2) {
60472
- while (1) switch (_context2.prev = _context2.next) {
61008
+ _handleProfileUpdated = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
61009
+ var _window$mainApi12, profile;
61010
+ return _regeneratorRuntime.wrap(function (_context3) {
61011
+ while (1) switch (_context3.prev = _context3.next) {
60473
61012
  case 0:
60474
- _context2.prev = 0;
60475
- _context2.next = 1;
60476
- return (_window$mainApi11 = window.mainApi) === null || _window$mainApi11 === void 0 || (_window$mainApi11 = _window$mainApi11.registryAuth) === null || _window$mainApi11 === void 0 ? void 0 : _window$mainApi11.getProfile();
61013
+ _context3.prev = 0;
61014
+ _context3.next = 1;
61015
+ return (_window$mainApi12 = window.mainApi) === null || _window$mainApi12 === void 0 || (_window$mainApi12 = _window$mainApi12.registryAuth) === null || _window$mainApi12 === void 0 ? void 0 : _window$mainApi12.getProfile();
60477
61016
  case 1:
60478
- profile = _context2.sent;
61017
+ profile = _context3.sent;
60479
61018
  if (profile) setAuthProfile(profile);
60480
- _context2.next = 3;
61019
+ _context3.next = 3;
60481
61020
  break;
60482
61021
  case 2:
60483
- _context2.prev = 2;
60484
- _context2["catch"](0);
61022
+ _context3.prev = 2;
61023
+ _context3["catch"](0);
60485
61024
  case 3:
60486
61025
  case "end":
60487
- return _context2.stop();
61026
+ return _context3.stop();
60488
61027
  }
60489
- }, _callee2, null, [[0, 2]]);
61028
+ }, _callee3, null, [[0, 2]]);
60490
61029
  }));
60491
61030
  return _handleProfileUpdated.apply(this, arguments);
60492
61031
  }
@@ -60523,14 +61062,14 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60523
61062
  // editing. Shapes:
60524
61063
  // { kind: "open-workspace", workspace } — sidebar switch
60525
61064
  // { kind: "cancel-edit" } — Cancel button
60526
- var _useState57 = useState(false),
60527
- _useState58 = _slicedToArray(_useState57, 2),
60528
- isDirty = _useState58[0],
60529
- setIsDirty = _useState58[1];
60530
- var _useState59 = useState(null),
61065
+ var _useState59 = useState(false),
60531
61066
  _useState60 = _slicedToArray(_useState59, 2),
60532
- pendingNavigation = _useState60[0],
60533
- setPendingNavigation = _useState60[1];
61067
+ isDirty = _useState60[0],
61068
+ setIsDirty = _useState60[1];
61069
+ var _useState61 = useState(null),
61070
+ _useState62 = _slicedToArray(_useState61, 2),
61071
+ pendingNavigation = _useState62[0],
61072
+ setPendingNavigation = _useState62[1];
60534
61073
  useEffect(function () {
60535
61074
  if (typeof globalThis !== "undefined") {
60536
61075
  globalThis.__dashboardIsDirty = isDirty;
@@ -60541,6 +61080,63 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60541
61080
  }
60542
61081
  };
60543
61082
  }, [isDirty]);
61083
+
61084
+ // ─── First-run onboarding gate (Phase 3A) ────────────────────────
61085
+ // Decision fires exactly once per mount after the first workspaces
61086
+ // load completes. We need to wait for `isLoadingWorkspaces` to flip
61087
+ // true→false at least once; otherwise the gate reads workspaceConfig
61088
+ // at its initial empty value and would flash the modal on every
61089
+ // launch.
61090
+ //
61091
+ // Popout windows never show the modal — they're a slave to the
61092
+ // main window's onboarding decision and don't need their own gate.
61093
+ var onboardingCheckedRef = useRef(false);
61094
+ useEffect(function () {
61095
+ if (popout) {
61096
+ setIsOnboardingOpen(false);
61097
+ return;
61098
+ }
61099
+ if (onboardingCheckedRef.current) return;
61100
+ if (isLoadingWorkspaces) return;
61101
+ onboardingCheckedRef.current = true;
61102
+ var cancelled = false;
61103
+ _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
61104
+ var _window$mainApi, _window$mainApi$getSt, status;
61105
+ return _regeneratorRuntime.wrap(function (_context) {
61106
+ while (1) switch (_context.prev = _context.next) {
61107
+ case 0:
61108
+ _context.prev = 0;
61109
+ _context.next = 1;
61110
+ return (_window$mainApi = window.mainApi) === null || _window$mainApi === void 0 || (_window$mainApi = _window$mainApi.onboarding) === null || _window$mainApi === void 0 || (_window$mainApi$getSt = _window$mainApi.getStatus) === null || _window$mainApi$getSt === void 0 ? void 0 : _window$mainApi$getSt.call(_window$mainApi);
61111
+ case 1:
61112
+ status = _context.sent;
61113
+ if (!cancelled) {
61114
+ _context.next = 2;
61115
+ break;
61116
+ }
61117
+ return _context.abrupt("return");
61118
+ case 2:
61119
+ if (status && status.completed === false && workspaceConfig.length === 0) {
61120
+ setIsOnboardingOpen(true);
61121
+ } else {
61122
+ setIsOnboardingOpen(false);
61123
+ }
61124
+ _context.next = 4;
61125
+ break;
61126
+ case 3:
61127
+ _context.prev = 3;
61128
+ _context["catch"](0);
61129
+ if (!cancelled) setIsOnboardingOpen(false);
61130
+ case 4:
61131
+ case "end":
61132
+ return _context.stop();
61133
+ }
61134
+ }, _callee, null, [[0, 3]]);
61135
+ }))();
61136
+ return function () {
61137
+ cancelled = true;
61138
+ };
61139
+ }, [popout, isLoadingWorkspaces, workspaceConfig.length]);
60544
61140
  useEffect(function () {
60545
61141
  isLoadingWorkspaces === false && loadWorkspaces();
60546
61142
  isLoadingMenuItems === false && loadMenuItems();
@@ -60555,9 +61151,9 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60555
61151
  return ws.id === popoutWorkspaceId;
60556
61152
  });
60557
61153
  if (target) {
60558
- var _window$mainApi;
61154
+ var _window$mainApi2;
60559
61155
  handleOpenTab(target);
60560
- if ((_window$mainApi = window.mainApi) !== null && _window$mainApi !== void 0 && (_window$mainApi = _window$mainApi.popout) !== null && _window$mainApi !== void 0 && _window$mainApi.setTitle) {
61156
+ if ((_window$mainApi2 = window.mainApi) !== null && _window$mainApi2 !== void 0 && (_window$mainApi2 = _window$mainApi2.popout) !== null && _window$mainApi2 !== void 0 && _window$mainApi2.setTitle) {
60561
61157
  window.mainApi.popout.setTitle(popoutWorkspaceId, target.name || "Untitled");
60562
61158
  }
60563
61159
  }
@@ -60566,15 +61162,15 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60566
61162
 
60567
61163
  // ─── Listen for workspace:saved broadcasts (MCP tools, popouts) ──
60568
61164
  useEffect(function () {
60569
- var _window$mainApi2;
60570
- if (!((_window$mainApi2 = window.mainApi) !== null && _window$mainApi2 !== void 0 && _window$mainApi2.on)) return;
61165
+ var _window$mainApi3;
61166
+ if (!((_window$mainApi3 = window.mainApi) !== null && _window$mainApi3 !== void 0 && _window$mainApi3.on)) return;
60571
61167
  var handler = function handler() {
60572
61168
  loadWorkspaces();
60573
61169
  };
60574
61170
  window.mainApi.on("workspace:saved", handler);
60575
61171
  return function () {
60576
- var _window$mainApi3;
60577
- if ((_window$mainApi3 = window.mainApi) !== null && _window$mainApi3 !== void 0 && _window$mainApi3.removeListener) {
61172
+ var _window$mainApi4;
61173
+ if ((_window$mainApi4 = window.mainApi) !== null && _window$mainApi4 !== void 0 && _window$mainApi4.removeListener) {
60578
61174
  window.mainApi.removeListener("workspace:saved", handler);
60579
61175
  }
60580
61176
  };
@@ -60606,9 +61202,9 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60606
61202
  // closing the builder modal — this listener only opens Settings.
60607
61203
  useEffect(function () {
60608
61204
  var handler = function handler(e) {
60609
- var _ref4 = (e === null || e === void 0 ? void 0 : e.detail) || {},
60610
- type = _ref4.type,
60611
- providerClass = _ref4.providerClass;
61205
+ var _ref5 = (e === null || e === void 0 ? void 0 : e.detail) || {},
61206
+ type = _ref5.type,
61207
+ providerClass = _ref5.providerClass;
60612
61208
  if (!type) return;
60613
61209
  openAppSettings("providers", null, true, type, providerClass || null);
60614
61210
  };
@@ -60628,10 +61224,10 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60628
61224
  // We record the requested ID and open it once it appears in
60629
61225
  // workspaceConfig — handles the case where the workspace was just
60630
61226
  // created and the config reload is still in flight.
60631
- var _useState61 = useState(null),
60632
- _useState62 = _slicedToArray(_useState61, 2),
60633
- pendingOpenWorkspaceId = _useState62[0],
60634
- setPendingOpenWorkspaceId = _useState62[1];
61227
+ var _useState63 = useState(null),
61228
+ _useState64 = _slicedToArray(_useState63, 2),
61229
+ pendingOpenWorkspaceId = _useState64[0],
61230
+ setPendingOpenWorkspaceId = _useState64[1];
60635
61231
  useEffect(function () {
60636
61232
  var handler = function handler(e) {
60637
61233
  var _e$detail2;
@@ -60659,30 +61255,30 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60659
61255
 
60660
61256
  // ─── Load recents on mount ───────────────────────────────────────
60661
61257
  useEffect(function () {
60662
- var _window$mainApi4;
61258
+ var _window$mainApi5;
60663
61259
  if (popout) return;
60664
- (_window$mainApi4 = window.mainApi) === null || _window$mainApi4 === void 0 || (_window$mainApi4 = _window$mainApi4.session) === null || _window$mainApi4 === void 0 || _window$mainApi4.getRecents().then(function (recents) {
61260
+ (_window$mainApi5 = window.mainApi) === null || _window$mainApi5 === void 0 || (_window$mainApi5 = _window$mainApi5.session) === null || _window$mainApi5 === void 0 || _window$mainApi5.getRecents().then(function (recents) {
60665
61261
  if (recents) setRecentDashboards(recents);
60666
61262
  });
60667
61263
  }, [popout]);
60668
61264
 
60669
61265
  // ─── Session save (continuous) ──────────────────────────────────
60670
61266
  useEffect(function () {
60671
- var _window$mainApi5;
61267
+ var _window$mainApi6;
60672
61268
  if (popout) return;
60673
61269
  var tabIds = openTabs.map(function (t) {
60674
61270
  return t.id;
60675
61271
  });
60676
- (_window$mainApi5 = window.mainApi) === null || _window$mainApi5 === void 0 || (_window$mainApi5 = _window$mainApi5.session) === null || _window$mainApi5 === void 0 || _window$mainApi5.saveState(tabIds, activeTabId);
61272
+ (_window$mainApi6 = window.mainApi) === null || _window$mainApi6 === void 0 || (_window$mainApi6 = _window$mainApi6.session) === null || _window$mainApi6 === void 0 || _window$mainApi6.saveState(tabIds, activeTabId);
60677
61273
  }, [openTabs, activeTabId, popout]);
60678
61274
 
60679
61275
  // ─── Session restore on launch ─────────────────────────────────
60680
61276
  useEffect(function () {
60681
- var _window$mainApi6;
61277
+ var _window$mainApi7;
60682
61278
  if (popout || workspaceConfig.length === 0 || sessionRestored.current) return;
60683
61279
  sessionRestored.current = true;
60684
- (_window$mainApi6 = window.mainApi) === null || _window$mainApi6 === void 0 || (_window$mainApi6 = _window$mainApi6.session) === null || _window$mainApi6 === void 0 || _window$mainApi6.getState().then(function (state) {
60685
- var _state$openTabIds, _window$mainApi7;
61280
+ (_window$mainApi7 = window.mainApi) === null || _window$mainApi7 === void 0 || (_window$mainApi7 = _window$mainApi7.session) === null || _window$mainApi7 === void 0 || _window$mainApi7.getState().then(function (state) {
61281
+ var _state$openTabIds, _window$mainApi8;
60686
61282
  if (!(state !== null && state !== void 0 && (_state$openTabIds = state.openTabIds) !== null && _state$openTabIds !== void 0 && _state$openTabIds.length)) return;
60687
61283
  state.openTabIds.forEach(function (wsId) {
60688
61284
  var ws = workspaceConfig.find(function (w) {
@@ -60691,7 +61287,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60691
61287
  if (ws) handleOpenTab(ws);
60692
61288
  });
60693
61289
  if (state.activeTabId) setActiveTabId(state.activeTabId);
60694
- (_window$mainApi7 = window.mainApi) === null || _window$mainApi7 === void 0 || (_window$mainApi7 = _window$mainApi7.session) === null || _window$mainApi7 === void 0 || _window$mainApi7.clearState();
61290
+ (_window$mainApi8 = window.mainApi) === null || _window$mainApi8 === void 0 || (_window$mainApi8 = _window$mainApi8.session) === null || _window$mainApi8 === void 0 || _window$mainApi8.clearState();
60695
61291
  });
60696
61292
  // eslint-disable-next-line react-hooks/exhaustive-deps
60697
61293
  }, [workspaceConfig, popout]);
@@ -60704,35 +61300,35 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60704
61300
  return _checkAuth.apply(this, arguments);
60705
61301
  }
60706
61302
  function _checkAuth() {
60707
- _checkAuth = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
60708
- var _window$mainApi8, status, _window$mainApi9, profile;
60709
- return _regeneratorRuntime.wrap(function (_context) {
60710
- while (1) switch (_context.prev = _context.next) {
61303
+ _checkAuth = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
61304
+ var _window$mainApi9, status, _window$mainApi0, profile;
61305
+ return _regeneratorRuntime.wrap(function (_context2) {
61306
+ while (1) switch (_context2.prev = _context2.next) {
60711
61307
  case 0:
60712
- _context.prev = 0;
60713
- _context.next = 1;
60714
- return (_window$mainApi8 = window.mainApi) === null || _window$mainApi8 === void 0 || (_window$mainApi8 = _window$mainApi8.registryAuth) === null || _window$mainApi8 === void 0 ? void 0 : _window$mainApi8.getStatus();
61308
+ _context2.prev = 0;
61309
+ _context2.next = 1;
61310
+ return (_window$mainApi9 = window.mainApi) === null || _window$mainApi9 === void 0 || (_window$mainApi9 = _window$mainApi9.registryAuth) === null || _window$mainApi9 === void 0 ? void 0 : _window$mainApi9.getStatus();
60715
61311
  case 1:
60716
- status = _context.sent;
61312
+ status = _context2.sent;
60717
61313
  if (!cancelled) {
60718
- _context.next = 2;
61314
+ _context2.next = 2;
60719
61315
  break;
60720
61316
  }
60721
- return _context.abrupt("return");
61317
+ return _context2.abrupt("return");
60722
61318
  case 2:
60723
61319
  if (!(status !== null && status !== void 0 && status.authenticated)) {
60724
- _context.next = 5;
61320
+ _context2.next = 5;
60725
61321
  break;
60726
61322
  }
60727
- _context.next = 3;
60728
- return (_window$mainApi9 = window.mainApi) === null || _window$mainApi9 === void 0 || (_window$mainApi9 = _window$mainApi9.registryAuth) === null || _window$mainApi9 === void 0 ? void 0 : _window$mainApi9.getProfile();
61323
+ _context2.next = 3;
61324
+ return (_window$mainApi0 = window.mainApi) === null || _window$mainApi0 === void 0 || (_window$mainApi0 = _window$mainApi0.registryAuth) === null || _window$mainApi0 === void 0 ? void 0 : _window$mainApi0.getProfile();
60729
61325
  case 3:
60730
- profile = _context.sent;
61326
+ profile = _context2.sent;
60731
61327
  if (!cancelled) {
60732
- _context.next = 4;
61328
+ _context2.next = 4;
60733
61329
  break;
60734
61330
  }
60735
- return _context.abrupt("return");
61331
+ return _context2.abrupt("return");
60736
61332
  case 4:
60737
61333
  if (profile) {
60738
61334
  setAuthProfile(profile);
@@ -60740,22 +61336,22 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60740
61336
  } else {
60741
61337
  setAuthStatus("unauthenticated");
60742
61338
  }
60743
- _context.next = 6;
61339
+ _context2.next = 6;
60744
61340
  break;
60745
61341
  case 5:
60746
61342
  setAuthStatus("unauthenticated");
60747
61343
  case 6:
60748
- _context.next = 8;
61344
+ _context2.next = 8;
60749
61345
  break;
60750
61346
  case 7:
60751
- _context.prev = 7;
60752
- _context["catch"](0);
61347
+ _context2.prev = 7;
61348
+ _context2["catch"](0);
60753
61349
  if (!cancelled) setAuthStatus("unauthenticated");
60754
61350
  case 8:
60755
61351
  case "end":
60756
- return _context.stop();
61352
+ return _context2.stop();
60757
61353
  }
60758
- }, _callee, null, [[0, 7]]);
61354
+ }, _callee2, null, [[0, 7]]);
60759
61355
  }));
60760
61356
  return _checkAuth.apply(this, arguments);
60761
61357
  }
@@ -60882,8 +61478,8 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60882
61478
 
60883
61479
  // Track in recents
60884
61480
  if (!popout) {
60885
- var _window$mainApi0;
60886
- (_window$mainApi0 = window.mainApi) === null || _window$mainApi0 === void 0 || (_window$mainApi0 = _window$mainApi0.session) === null || _window$mainApi0 === void 0 || _window$mainApi0.addRecent(workspaceItem.id, workspaceItem.name || "Untitled").then(function (updated) {
61481
+ var _window$mainApi1;
61482
+ (_window$mainApi1 = window.mainApi) === null || _window$mainApi1 === void 0 || (_window$mainApi1 = _window$mainApi1.session) === null || _window$mainApi1 === void 0 || _window$mainApi1.addRecent(workspaceItem.id, workspaceItem.name || "Untitled").then(function (updated) {
60887
61483
  if (updated) setRecentDashboards(updated);
60888
61484
  });
60889
61485
  }
@@ -61258,10 +61854,10 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
61258
61854
  }
61259
61855
 
61260
61856
  // ─── Page State ──────────────────────────────────────────────────
61261
- var _useState63 = useState(null),
61262
- _useState64 = _slicedToArray(_useState63, 2),
61263
- activePageId = _useState64[0],
61264
- setActivePageId = _useState64[1];
61857
+ var _useState65 = useState(null),
61858
+ _useState66 = _slicedToArray(_useState65, 2),
61859
+ activePageId = _useState66[0],
61860
+ setActivePageId = _useState66[1];
61265
61861
 
61266
61862
  // Page history stack for goBack() — pushes the previous page id
61267
61863
  // whenever a navigation happens through navigateToPage().
@@ -61295,9 +61891,9 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
61295
61891
  // Listen for programmatic page switches via DashboardActionsApi
61296
61892
  useEffect(function () {
61297
61893
  function onSwitchPage(e) {
61298
- var _ref5 = e.detail || {},
61299
- pageId = _ref5.pageId,
61300
- pageName = _ref5.pageName;
61894
+ var _ref6 = e.detail || {},
61895
+ pageId = _ref6.pageId,
61896
+ pageName = _ref6.pageName;
61301
61897
  if (pageId) {
61302
61898
  navigateToPage(pageId);
61303
61899
  } else if (pageName) {
@@ -61887,70 +62483,70 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
61887
62483
  return _handleSidebarSignIn.apply(this, arguments);
61888
62484
  }
61889
62485
  function _handleSidebarSignIn() {
61890
- _handleSidebarSignIn = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
62486
+ _handleSidebarSignIn = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
61891
62487
  var flow, interval, poll;
61892
- return _regeneratorRuntime.wrap(function (_context4) {
61893
- while (1) switch (_context4.prev = _context4.next) {
62488
+ return _regeneratorRuntime.wrap(function (_context5) {
62489
+ while (1) switch (_context5.prev = _context5.next) {
61894
62490
  case 0:
61895
- _context4.prev = 0;
61896
- _context4.next = 1;
62491
+ _context5.prev = 0;
62492
+ _context5.next = 1;
61897
62493
  return window.mainApi.registryAuth.initiateLogin();
61898
62494
  case 1:
61899
- flow = _context4.sent;
62495
+ flow = _context5.sent;
61900
62496
  if (flow.verificationUrlComplete) {
61901
62497
  window.mainApi.shell.openExternal(flow.verificationUrlComplete);
61902
62498
  }
61903
62499
  interval = (flow.interval || 5) * 1000;
61904
- poll = setInterval(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
62500
+ poll = setInterval(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
61905
62501
  var result, profile;
61906
- return _regeneratorRuntime.wrap(function (_context3) {
61907
- while (1) switch (_context3.prev = _context3.next) {
62502
+ return _regeneratorRuntime.wrap(function (_context4) {
62503
+ while (1) switch (_context4.prev = _context4.next) {
61908
62504
  case 0:
61909
- _context3.prev = 0;
61910
- _context3.next = 1;
62505
+ _context4.prev = 0;
62506
+ _context4.next = 1;
61911
62507
  return window.mainApi.registryAuth.pollToken(flow.deviceCode);
61912
62508
  case 1:
61913
- result = _context3.sent;
62509
+ result = _context4.sent;
61914
62510
  if (!(result.status === "authorized")) {
61915
- _context3.next = 3;
62511
+ _context4.next = 3;
61916
62512
  break;
61917
62513
  }
61918
62514
  clearInterval(poll);
61919
- _context3.next = 2;
62515
+ _context4.next = 2;
61920
62516
  return window.mainApi.registryAuth.getProfile();
61921
62517
  case 2:
61922
- profile = _context3.sent;
62518
+ profile = _context4.sent;
61923
62519
  setAuthProfile(profile);
61924
62520
  setAuthStatus("authenticated");
61925
- _context3.next = 4;
62521
+ _context4.next = 4;
61926
62522
  break;
61927
62523
  case 3:
61928
62524
  if (result.status === "expired") {
61929
62525
  clearInterval(poll);
61930
62526
  }
61931
62527
  case 4:
61932
- _context3.next = 6;
62528
+ _context4.next = 6;
61933
62529
  break;
61934
62530
  case 5:
61935
- _context3.prev = 5;
61936
- _context3["catch"](0);
62531
+ _context4.prev = 5;
62532
+ _context4["catch"](0);
61937
62533
  clearInterval(poll);
61938
62534
  case 6:
61939
62535
  case "end":
61940
- return _context3.stop();
62536
+ return _context4.stop();
61941
62537
  }
61942
- }, _callee3, null, [[0, 5]]);
62538
+ }, _callee4, null, [[0, 5]]);
61943
62539
  })), interval);
61944
- _context4.next = 3;
62540
+ _context5.next = 3;
61945
62541
  break;
61946
62542
  case 2:
61947
- _context4.prev = 2;
61948
- _context4["catch"](0);
62543
+ _context5.prev = 2;
62544
+ _context5["catch"](0);
61949
62545
  case 3:
61950
62546
  case "end":
61951
- return _context4.stop();
62547
+ return _context5.stop();
61952
62548
  }
61953
- }, _callee4, null, [[0, 2]]);
62549
+ }, _callee5, null, [[0, 2]]);
61954
62550
  }));
61955
62551
  return _handleSidebarSignIn.apply(this, arguments);
61956
62552
  }
@@ -61958,38 +62554,38 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
61958
62554
  return _handleSidebarSignOut.apply(this, arguments);
61959
62555
  }
61960
62556
  function _handleSidebarSignOut() {
61961
- _handleSidebarSignOut = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
61962
- return _regeneratorRuntime.wrap(function (_context5) {
61963
- while (1) switch (_context5.prev = _context5.next) {
62557
+ _handleSidebarSignOut = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee6() {
62558
+ return _regeneratorRuntime.wrap(function (_context6) {
62559
+ while (1) switch (_context6.prev = _context6.next) {
61964
62560
  case 0:
61965
- _context5.prev = 0;
61966
- _context5.next = 1;
62561
+ _context6.prev = 0;
62562
+ _context6.next = 1;
61967
62563
  return window.mainApi.registryAuth.logout();
61968
62564
  case 1:
61969
62565
  setAuthStatus("unauthenticated");
61970
62566
  setAuthProfile(null);
61971
- _context5.next = 3;
62567
+ _context6.next = 3;
61972
62568
  break;
61973
62569
  case 2:
61974
- _context5.prev = 2;
61975
- _context5["catch"](0);
62570
+ _context6.prev = 2;
62571
+ _context6["catch"](0);
61976
62572
  case 3:
61977
62573
  case "end":
61978
- return _context5.stop();
62574
+ return _context6.stop();
61979
62575
  }
61980
- }, _callee5, null, [[0, 2]]);
62576
+ }, _callee6, null, [[0, 2]]);
61981
62577
  }));
61982
62578
  return _handleSidebarSignOut.apply(this, arguments);
61983
62579
  }
61984
62580
  function handlePopout() {
61985
- var _window$mainApi1;
61986
- if (workspaceSelected && (_window$mainApi1 = window.mainApi) !== null && _window$mainApi1 !== void 0 && (_window$mainApi1 = _window$mainApi1.popout) !== null && _window$mainApi1 !== void 0 && _window$mainApi1.open) {
62581
+ var _window$mainApi10;
62582
+ if (workspaceSelected && (_window$mainApi10 = window.mainApi) !== null && _window$mainApi10 !== void 0 && (_window$mainApi10 = _window$mainApi10.popout) !== null && _window$mainApi10 !== void 0 && _window$mainApi10.open) {
61987
62583
  window.mainApi.popout.open(workspaceSelected.id);
61988
62584
  }
61989
62585
  }
61990
62586
  function handleWidgetPopout(widgetId) {
61991
- var _window$mainApi10;
61992
- if (workspaceSelected && (_window$mainApi10 = window.mainApi) !== null && _window$mainApi10 !== void 0 && (_window$mainApi10 = _window$mainApi10.widgetPopout) !== null && _window$mainApi10 !== void 0 && _window$mainApi10.open) {
62587
+ var _window$mainApi11;
62588
+ if (workspaceSelected && (_window$mainApi11 = window.mainApi) !== null && _window$mainApi11 !== void 0 && (_window$mainApi11 = _window$mainApi11.widgetPopout) !== null && _window$mainApi11 !== void 0 && _window$mainApi11.open) {
61993
62589
  window.mainApi.widgetPopout.open(workspaceSelected.id, widgetId);
61994
62590
  }
61995
62591
  }
@@ -62308,7 +62904,36 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
62308
62904
  onSaveBindings: handleBulkProviderBindings,
62309
62905
  onSaveListeners: handleBulkListenerBindings,
62310
62906
  onSaveUserPrefs: handleBulkUserPrefs,
62907
+ onSkip: function onSkip() {
62908
+ // Suppress the unresolved-providers banner for this
62909
+ // workspace (session-scoped). Matches the banner's own
62910
+ // X-dismiss behavior so the user has parity between
62911
+ // "dismiss from the banner" and "dismiss from the
62912
+ // modal footer."
62913
+ if ((workspaceSelected === null || workspaceSelected === void 0 ? void 0 : workspaceSelected.id) != null) {
62914
+ setDismissedUnresolvedForWorkspace(function (prev) {
62915
+ return new Set([].concat(_toConsumableArray(prev), [workspaceSelected.id]));
62916
+ });
62917
+ }
62918
+ },
62311
62919
  initialTab: "providers"
62920
+ }), /*#__PURE__*/jsx(OnboardingModal, {
62921
+ open: isOnboardingOpen === true,
62922
+ appId: credentials === null || credentials === void 0 ? void 0 : credentials.appId,
62923
+ onDismiss: function onDismiss() {
62924
+ return setIsOnboardingOpen(false);
62925
+ },
62926
+ onComplete: function onComplete() {
62927
+ return setIsOnboardingOpen(false);
62928
+ },
62929
+ onOpenDashboard: function onOpenDashboard(ws) {
62930
+ setIsOnboardingOpen(false);
62931
+ // Refresh workspaces before opening so the just-
62932
+ // installed Kitchen Sink shows up in the sidebar list
62933
+ // alongside the open tab.
62934
+ loadWorkspaces();
62935
+ handleOpenTab(ws);
62936
+ }
62312
62937
  })]
62313
62938
  })]
62314
62939
  }), !popout && /*#__PURE__*/jsx(DashCommandPalette, {