@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.js CHANGED
@@ -10152,11 +10152,91 @@ function applyFilters(items, filters, mode) {
10152
10152
  });
10153
10153
  }
10154
10154
 
10155
+ var PREVIEW_TEMPLATE_SHAPE = {
10156
+ single: {
10157
+ rows: 1,
10158
+ cols: 1
10159
+ },
10160
+ "two-columns": {
10161
+ rows: 1,
10162
+ cols: 2
10163
+ },
10164
+ "two-rows": {
10165
+ rows: 2,
10166
+ cols: 1
10167
+ },
10168
+ "three-columns": {
10169
+ rows: 1,
10170
+ cols: 3
10171
+ },
10172
+ "two-by-two": {
10173
+ rows: 2,
10174
+ cols: 2
10175
+ },
10176
+ "two-by-three": {
10177
+ rows: 2,
10178
+ cols: 3
10179
+ },
10180
+ "three-by-three": {
10181
+ rows: 3,
10182
+ cols: 3
10183
+ }
10184
+ };
10185
+ function WizardThemePreview(_ref) {
10186
+ var theme = _ref.theme,
10187
+ templateKey = _ref.templateKey;
10188
+ if (!theme) return null;
10189
+ var shape = PREVIEW_TEMPLATE_SHAPE[templateKey] || {
10190
+ rows: 2,
10191
+ cols: 2
10192
+ };
10193
+ var familyOrder = [theme.primary, theme.secondary, theme.tertiary].filter(function (f) {
10194
+ return typeof f === "string" && f.length > 0;
10195
+ });
10196
+ if (familyOrder.length === 0) return null;
10197
+ var totalCells = shape.rows * shape.cols;
10198
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
10199
+ className: "rounded-lg border border-gray-700/50 bg-gray-900/30 p-3 flex flex-col gap-2",
10200
+ "data-testid": "wizard-theme-preview",
10201
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
10202
+ className: "flex items-center gap-2 text-xs text-gray-400",
10203
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
10204
+ icon: "eye",
10205
+ fixedWidth: true,
10206
+ className: "text-gray-500"
10207
+ }), /*#__PURE__*/jsxRuntime.jsxs("span", {
10208
+ children: ["Preview \xB7 ", theme.name || ""]
10209
+ }), templateKey && /*#__PURE__*/jsxRuntime.jsxs("span", {
10210
+ className: "text-gray-600",
10211
+ children: ["(", shape.rows, "\xD7", shape.cols, ")"]
10212
+ })]
10213
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
10214
+ className: "grid gap-1.5",
10215
+ style: {
10216
+ gridTemplateRows: "repeat(".concat(shape.rows, ", minmax(0, 1fr))"),
10217
+ gridTemplateColumns: "repeat(".concat(shape.cols, ", minmax(0, 1fr))"),
10218
+ minHeight: "5rem"
10219
+ },
10220
+ "data-testid": "wizard-theme-preview-grid",
10221
+ children: Array.from({
10222
+ length: totalCells
10223
+ }).map(function (_, i) {
10224
+ var family = familyOrder[i % familyOrder.length];
10225
+ return /*#__PURE__*/jsxRuntime.jsx("div", {
10226
+ className: "rounded bg-".concat(family, "-500/70 border border-").concat(family, "-400/40"),
10227
+ "data-testid": "wizard-theme-preview-cell-".concat(i),
10228
+ "data-family": family
10229
+ }, i);
10230
+ })
10231
+ })]
10232
+ });
10233
+ }
10234
+
10155
10235
  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; } } }; }
10156
10236
  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; } }
10157
10237
  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; }
10158
10238
  var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
10159
- var _state$selectedDashbo, _state$selectedDashbo2;
10239
+ var _state$selectedDashbo, _state$selectedDashbo2, _state$layout;
10160
10240
  var state = _ref.state,
10161
10241
  dispatch = _ref.dispatch,
10162
10242
  _ref$menuItems = _ref.menuItems,
@@ -10928,6 +11008,9 @@ var WizardCustomizeStep = function WizardCustomizeStep(_ref) {
10928
11008
  })
10929
11009
  }, key);
10930
11010
  })
11011
+ }), state.customization.theme && /*#__PURE__*/jsxRuntime.jsx(WizardThemePreview, {
11012
+ theme: themes === null || themes === void 0 ? void 0 : themes[state.customization.theme],
11013
+ templateKey: (_state$layout = state.layout) === null || _state$layout === void 0 ? void 0 : _state$layout.templateKey
10931
11014
  })]
10932
11015
  }), selectedProviders.length > 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
10933
11016
  className: "flex flex-col gap-2",
@@ -49751,7 +49834,23 @@ var WidgetsSection = function WidgetsSection(_ref) {
49751
49834
  }
49752
49835
  var listContent = /*#__PURE__*/jsxRuntime.jsxs("div", {
49753
49836
  className: "flex flex-col h-full",
49754
- children: [isChecking && packagesWithUpdates.length === 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
49837
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
49838
+ className: "flex-shrink-0 px-3 pt-2 pb-1",
49839
+ children: /*#__PURE__*/jsxRuntime.jsxs("button", {
49840
+ type: "button",
49841
+ onClick: function onClick() {
49842
+ return window.dispatchEvent(new Event("dash:open-widget-builder"));
49843
+ },
49844
+ 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",
49845
+ "data-testid": "widgets-section-new-widget-button",
49846
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
49847
+ icon: "plus",
49848
+ className: "text-xs"
49849
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
49850
+ children: "New Widget"
49851
+ })]
49852
+ })
49853
+ }), isChecking && packagesWithUpdates.length === 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
49755
49854
  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",
49756
49855
  "data-testid": "widgets-section-checking-updates",
49757
49856
  children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
@@ -54601,6 +54700,413 @@ var DashboardLoaderModal = function DashboardLoaderModal(_ref) {
54601
54700
  });
54602
54701
  };
54603
54702
 
54703
+ var KITCHEN_SINK_PACKAGE = "trops/kitchen-sink";
54704
+ var STATE = {
54705
+ WELCOME: "welcome",
54706
+ INSTALLING: "installing",
54707
+ DONE: "done",
54708
+ ERROR: "error"
54709
+ };
54710
+ var OnboardingModal = function OnboardingModal(_ref) {
54711
+ var open = _ref.open,
54712
+ appId = _ref.appId,
54713
+ onOpenDashboard = _ref.onOpenDashboard,
54714
+ onDismiss = _ref.onDismiss,
54715
+ onComplete = _ref.onComplete;
54716
+ var _ref2 = React.useContext(DashReact.ThemeContext) || {},
54717
+ currentTheme = _ref2.currentTheme;
54718
+ var _useState = React.useState(STATE.WELCOME),
54719
+ _useState2 = _slicedToArray(_useState, 2),
54720
+ state = _useState2[0],
54721
+ setState = _useState2[1];
54722
+ var _useState3 = React.useState([]),
54723
+ _useState4 = _slicedToArray(_useState3, 2),
54724
+ progressItems = _useState4[0],
54725
+ setProgressItems = _useState4[1];
54726
+ var _useState5 = React.useState(null),
54727
+ _useState6 = _slicedToArray(_useState5, 2),
54728
+ installError = _useState6[0],
54729
+ setInstallError = _useState6[1];
54730
+ var installResultRef = React.useRef(null);
54731
+ var cleanupProgressRef = React.useRef(null);
54732
+ React.useEffect(function () {
54733
+ if (open) {
54734
+ setState(STATE.WELCOME);
54735
+ setProgressItems([]);
54736
+ setInstallError(null);
54737
+ installResultRef.current = null;
54738
+ }
54739
+ return function () {
54740
+ if (cleanupProgressRef.current) {
54741
+ cleanupProgressRef.current();
54742
+ cleanupProgressRef.current = null;
54743
+ }
54744
+ };
54745
+ }, [open]);
54746
+ var markCompletedAndClose = React.useCallback(/*#__PURE__*/function () {
54747
+ var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(source) {
54748
+ var _window$mainApi, _window$mainApi$markC;
54749
+ return _regeneratorRuntime.wrap(function (_context) {
54750
+ while (1) switch (_context.prev = _context.next) {
54751
+ case 0:
54752
+ _context.prev = 0;
54753
+ _context.next = 1;
54754
+ 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, {
54755
+ source: source
54756
+ });
54757
+ case 1:
54758
+ _context.next = 3;
54759
+ break;
54760
+ case 2:
54761
+ _context.prev = 2;
54762
+ _context["catch"](0);
54763
+ case 3:
54764
+ if (onComplete) onComplete({
54765
+ source: source
54766
+ });
54767
+ case 4:
54768
+ case "end":
54769
+ return _context.stop();
54770
+ }
54771
+ }, _callee, null, [[0, 2]]);
54772
+ }));
54773
+ return function (_x) {
54774
+ return _ref3.apply(this, arguments);
54775
+ };
54776
+ }(), [onComplete]);
54777
+ var handleSkip = React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
54778
+ return _regeneratorRuntime.wrap(function (_context2) {
54779
+ while (1) switch (_context2.prev = _context2.next) {
54780
+ case 0:
54781
+ _context2.next = 1;
54782
+ return markCompletedAndClose("dismissed");
54783
+ case 1:
54784
+ if (onDismiss) onDismiss();
54785
+ case 2:
54786
+ case "end":
54787
+ return _context2.stop();
54788
+ }
54789
+ }, _callee2);
54790
+ })), [markCompletedAndClose, onDismiss]);
54791
+ var handleInstall = React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
54792
+ var _window$mainApi2, _window$mainApi2$onIn;
54793
+ var _window$mainApi3, _window$mainApi3$inst, result, _t2;
54794
+ return _regeneratorRuntime.wrap(function (_context3) {
54795
+ while (1) switch (_context3.prev = _context3.next) {
54796
+ case 0:
54797
+ if (appId) {
54798
+ _context3.next = 1;
54799
+ break;
54800
+ }
54801
+ setInstallError("Cannot install — application not initialized. Try again in a moment.");
54802
+ setState(STATE.ERROR);
54803
+ return _context3.abrupt("return");
54804
+ case 1:
54805
+ setState(STATE.INSTALLING);
54806
+ setProgressItems([]);
54807
+ setInstallError(null);
54808
+ if (cleanupProgressRef.current) cleanupProgressRef.current();
54809
+ 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) {
54810
+ setProgressItems(function (prev) {
54811
+ var next = prev.length > 0 ? _toConsumableArray(prev) : [];
54812
+ if (next.length === 0 && typeof data.total === "number") {
54813
+ for (var i = 0; i < data.total; i += 1) {
54814
+ next.push({
54815
+ packageName: i === data.index ? data.packageName : "",
54816
+ displayName: i === data.index ? data.displayName : "",
54817
+ status: "pending"
54818
+ });
54819
+ }
54820
+ }
54821
+ if (typeof data.index === "number" && data.index >= 0 && data.index < next.length) {
54822
+ next[data.index] = {
54823
+ packageName: data.packageName || next[data.index].packageName,
54824
+ displayName: data.displayName || next[data.index].displayName || data.packageName || "",
54825
+ status: data.status || next[data.index].status,
54826
+ error: data.error || null
54827
+ };
54828
+ }
54829
+ return next;
54830
+ });
54831
+ });
54832
+ _context3.prev = 2;
54833
+ _context3.next = 3;
54834
+ 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, {});
54835
+ case 3:
54836
+ result = _context3.sent;
54837
+ if (cleanupProgressRef.current) {
54838
+ cleanupProgressRef.current();
54839
+ cleanupProgressRef.current = null;
54840
+ }
54841
+ if (!(!result || !result.success)) {
54842
+ _context3.next = 4;
54843
+ break;
54844
+ }
54845
+ setInstallError((result === null || result === void 0 ? void 0 : result.error) || "Failed to install Kitchen Sink. Check your internet connection and try again.");
54846
+ setState(STATE.ERROR);
54847
+ return _context3.abrupt("return");
54848
+ case 4:
54849
+ installResultRef.current = result;
54850
+ setState(STATE.DONE);
54851
+ _context3.next = 6;
54852
+ break;
54853
+ case 5:
54854
+ _context3.prev = 5;
54855
+ _t2 = _context3["catch"](2);
54856
+ if (cleanupProgressRef.current) {
54857
+ cleanupProgressRef.current();
54858
+ cleanupProgressRef.current = null;
54859
+ }
54860
+ setInstallError((_t2 === null || _t2 === void 0 ? void 0 : _t2.message) || "Installation failed.");
54861
+ setState(STATE.ERROR);
54862
+ case 6:
54863
+ case "end":
54864
+ return _context3.stop();
54865
+ }
54866
+ }, _callee3, null, [[2, 5]]);
54867
+ })), [appId]);
54868
+ var handleOpen = React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
54869
+ var _installResultRef$cur;
54870
+ var workspace;
54871
+ return _regeneratorRuntime.wrap(function (_context4) {
54872
+ while (1) switch (_context4.prev = _context4.next) {
54873
+ case 0:
54874
+ workspace = ((_installResultRef$cur = installResultRef.current) === null || _installResultRef$cur === void 0 ? void 0 : _installResultRef$cur.workspace) || null;
54875
+ _context4.next = 1;
54876
+ return markCompletedAndClose("kitchen-sink");
54877
+ case 1:
54878
+ if (workspace && onOpenDashboard) {
54879
+ onOpenDashboard(workspace);
54880
+ }
54881
+ case 2:
54882
+ case "end":
54883
+ return _context4.stop();
54884
+ }
54885
+ }, _callee4);
54886
+ })), [markCompletedAndClose, onOpenDashboard]);
54887
+ var handleRetry = React.useCallback(function () {
54888
+ setInstallError(null);
54889
+ handleInstall();
54890
+ }, [handleInstall]);
54891
+
54892
+ // The Modal dispatches setIsOpen(false) on Escape / backdrop click.
54893
+ // Route any close attempt through handleSkip so the completion flag
54894
+ // is always stamped (otherwise Escape would silently re-show the
54895
+ // modal on the next launch).
54896
+ var handleSetIsOpen = React.useCallback(function (next) {
54897
+ if (next === false) handleSkip();
54898
+ }, [handleSkip]);
54899
+ var bgPanel = (currentTheme === null || currentTheme === void 0 ? void 0 : currentTheme["bg-primary-medium"]) || "bg-gray-900";
54900
+ var textPrimary = (currentTheme === null || currentTheme === void 0 ? void 0 : currentTheme["text-primary-light"]) || "text-gray-100";
54901
+ var textMuted = (currentTheme === null || currentTheme === void 0 ? void 0 : currentTheme["text-primary-medium"]) || "text-gray-400";
54902
+ var borderPanel = (currentTheme === null || currentTheme === void 0 ? void 0 : currentTheme["border-primary-medium"]) || "border-gray-700";
54903
+ return /*#__PURE__*/jsxRuntime.jsx(DashReact.Modal, {
54904
+ isOpen: open,
54905
+ setIsOpen: handleSetIsOpen,
54906
+ width: "w-full max-w-2xl",
54907
+ height: "h-auto",
54908
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
54909
+ className: "flex flex-col ".concat(bgPanel, " ").concat(textPrimary, " rounded-lg overflow-hidden p-8"),
54910
+ "data-testid": "onboarding-modal",
54911
+ children: [state === STATE.WELCOME && /*#__PURE__*/jsxRuntime.jsx(WelcomeBody, {
54912
+ onInstall: handleInstall,
54913
+ onSkip: handleSkip,
54914
+ textMuted: textMuted
54915
+ }), state === STATE.INSTALLING && /*#__PURE__*/jsxRuntime.jsx(InstallingBody, {
54916
+ items: progressItems,
54917
+ borderPanel: borderPanel,
54918
+ textMuted: textMuted
54919
+ }), state === STATE.DONE && /*#__PURE__*/jsxRuntime.jsx(DoneBody, {
54920
+ onOpen: handleOpen,
54921
+ textMuted: textMuted
54922
+ }), state === STATE.ERROR && /*#__PURE__*/jsxRuntime.jsx(ErrorBody, {
54923
+ message: installError,
54924
+ onRetry: handleRetry,
54925
+ onSkip: handleSkip,
54926
+ textMuted: textMuted
54927
+ })]
54928
+ })
54929
+ });
54930
+ };
54931
+ function WelcomeBody(_ref7) {
54932
+ var onInstall = _ref7.onInstall,
54933
+ onSkip = _ref7.onSkip,
54934
+ textMuted = _ref7.textMuted;
54935
+ return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
54936
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
54937
+ className: "flex items-center gap-3 mb-2",
54938
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
54939
+ icon: "sink",
54940
+ className: "text-2xl"
54941
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Heading2, {
54942
+ title: "Welcome to Dash"
54943
+ })]
54944
+ }), /*#__PURE__*/jsxRuntime.jsxs(DashReact.Paragraph, {
54945
+ className: "".concat(textMuted, " mb-6"),
54946
+ children: ["Get started with the ", /*#__PURE__*/jsxRuntime.jsx("strong", {
54947
+ children: "Kitchen Sink"
54948
+ }), " 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."]
54949
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
54950
+ className: "flex items-center justify-end gap-3 mt-2",
54951
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
54952
+ onClick: onSkip,
54953
+ title: "Skip for now",
54954
+ textSize: "text-sm",
54955
+ padding: "py-2 px-4",
54956
+ backgroundColor: "bg-gray-700",
54957
+ textColor: "text-gray-300",
54958
+ hoverTextColor: "hover:text-white",
54959
+ hoverBackgroundColor: "hover:bg-gray-600",
54960
+ "data-testid": "onboarding-skip-button"
54961
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
54962
+ onClick: onInstall,
54963
+ title: "Install Kitchen Sink",
54964
+ textSize: "text-sm",
54965
+ padding: "py-2 px-4",
54966
+ backgroundColor: "bg-blue-600",
54967
+ textColor: "text-white",
54968
+ hoverTextColor: "hover:text-white",
54969
+ hoverBackgroundColor: "hover:bg-blue-500",
54970
+ icon: "download",
54971
+ "data-testid": "onboarding-install-button"
54972
+ })]
54973
+ })]
54974
+ });
54975
+ }
54976
+ function InstallingBody(_ref8) {
54977
+ var items = _ref8.items,
54978
+ borderPanel = _ref8.borderPanel,
54979
+ textMuted = _ref8.textMuted;
54980
+ return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
54981
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.SubHeading, {
54982
+ title: "Installing Kitchen Sink\u2026"
54983
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Paragraph, {
54984
+ className: "".concat(textMuted, " mt-2 mb-4"),
54985
+ children: "Downloading widgets, theme, and dashboard configuration from the registry. This usually takes a few seconds."
54986
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
54987
+ className: "border ".concat(borderPanel, " rounded-md max-h-64 overflow-y-auto"),
54988
+ "data-testid": "onboarding-progress-list",
54989
+ children: [items.length === 0 && /*#__PURE__*/jsxRuntime.jsx("div", {
54990
+ className: "p-3 ".concat(textMuted),
54991
+ children: "Starting install\u2026"
54992
+ }), items.map(function (item, idx) {
54993
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
54994
+ className: "flex items-center justify-between px-3 py-2",
54995
+ "data-status": item.status,
54996
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
54997
+ className: "truncate",
54998
+ children: item.displayName || item.packageName || "Item ".concat(idx + 1)
54999
+ }), /*#__PURE__*/jsxRuntime.jsx(StatusBadge, {
55000
+ status: item.status
55001
+ })]
55002
+ }, "".concat(item.packageName || "slot", "-").concat(idx));
55003
+ })]
55004
+ })]
55005
+ });
55006
+ }
55007
+ function StatusBadge(_ref9) {
55008
+ var status = _ref9.status;
55009
+ switch (status) {
55010
+ case "installed":
55011
+ case "already-installed":
55012
+ return /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
55013
+ icon: "check",
55014
+ className: "text-green-500",
55015
+ "data-testid": "status-installed"
55016
+ });
55017
+ case "failed":
55018
+ return /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
55019
+ icon: "xmark",
55020
+ className: "text-red-500",
55021
+ "data-testid": "status-failed"
55022
+ });
55023
+ case "downloading":
55024
+ case "pending":
55025
+ default:
55026
+ return /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
55027
+ icon: "circle-notch",
55028
+ className: "animate-spin",
55029
+ "data-testid": "status-".concat(status || "pending")
55030
+ });
55031
+ }
55032
+ }
55033
+ function DoneBody(_ref0) {
55034
+ var onOpen = _ref0.onOpen,
55035
+ textMuted = _ref0.textMuted;
55036
+ return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
55037
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
55038
+ className: "flex items-center gap-3 mb-2",
55039
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
55040
+ icon: "check",
55041
+ className: "text-2xl text-green-500"
55042
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Heading2, {
55043
+ title: "Kitchen Sink Installed"
55044
+ })]
55045
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Paragraph, {
55046
+ className: "".concat(textMuted, " mb-6"),
55047
+ children: "Your first dashboard is ready. Open it to explore \u2014 every widget and the theme are now installed locally."
55048
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
55049
+ className: "flex items-center justify-end",
55050
+ children: /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
55051
+ onClick: onOpen,
55052
+ title: "Open Kitchen Sink",
55053
+ textSize: "text-sm",
55054
+ padding: "py-2 px-4",
55055
+ backgroundColor: "bg-green-600",
55056
+ textColor: "text-white",
55057
+ hoverTextColor: "hover:text-white",
55058
+ hoverBackgroundColor: "hover:bg-green-500",
55059
+ icon: "arrow-right",
55060
+ "data-testid": "onboarding-open-button"
55061
+ })
55062
+ })]
55063
+ });
55064
+ }
55065
+ function ErrorBody(_ref1) {
55066
+ var message = _ref1.message,
55067
+ onRetry = _ref1.onRetry,
55068
+ onSkip = _ref1.onSkip,
55069
+ textMuted = _ref1.textMuted;
55070
+ return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
55071
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
55072
+ className: "flex items-center gap-3 mb-2",
55073
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
55074
+ icon: "triangle-exclamation",
55075
+ className: "text-2xl text-red-500"
55076
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Heading2, {
55077
+ title: "Install Failed"
55078
+ })]
55079
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Paragraph, {
55080
+ className: "".concat(textMuted, " mb-6"),
55081
+ children: message || "Something went wrong installing Kitchen Sink."
55082
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
55083
+ className: "flex items-center justify-end gap-3",
55084
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
55085
+ onClick: onSkip,
55086
+ title: "Skip for now",
55087
+ textSize: "text-sm",
55088
+ padding: "py-2 px-4",
55089
+ backgroundColor: "bg-gray-700",
55090
+ textColor: "text-gray-300",
55091
+ hoverTextColor: "hover:text-white",
55092
+ hoverBackgroundColor: "hover:bg-gray-600",
55093
+ "data-testid": "onboarding-skip-after-error-button"
55094
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
55095
+ onClick: onRetry,
55096
+ title: "Try again",
55097
+ textSize: "text-sm",
55098
+ padding: "py-2 px-4",
55099
+ backgroundColor: "bg-blue-600",
55100
+ textColor: "text-white",
55101
+ hoverTextColor: "hover:text-white",
55102
+ hoverBackgroundColor: "hover:bg-blue-500",
55103
+ icon: "rotate-right",
55104
+ "data-testid": "onboarding-retry-button"
55105
+ })]
55106
+ })]
55107
+ });
55108
+ }
55109
+
54604
55110
  var DashCommandPalette = function DashCommandPalette(_ref) {
54605
55111
  var isOpen = _ref.isOpen,
54606
55112
  setIsOpen = _ref.setIsOpen,
@@ -58071,6 +58577,8 @@ var DashboardConfigModal = function DashboardConfigModal(_ref) {
58071
58577
  onSaveListeners = _ref.onSaveListeners,
58072
58578
  _ref$onSaveUserPrefs = _ref.onSaveUserPrefs,
58073
58579
  onSaveUserPrefs = _ref$onSaveUserPrefs === void 0 ? null : _ref$onSaveUserPrefs,
58580
+ _ref$onSkip = _ref.onSkip,
58581
+ onSkip = _ref$onSkip === void 0 ? null : _ref$onSkip,
58074
58582
  _ref$initialTab = _ref.initialTab,
58075
58583
  initialTab = _ref$initialTab === void 0 ? "providers" : _ref$initialTab;
58076
58584
  var _useContext = React.useContext(DashReact.ThemeContext),
@@ -58584,6 +59092,23 @@ var DashboardConfigModal = function DashboardConfigModal(_ref) {
58584
59092
  setStagedPrefs({});
58585
59093
  setIsOpen(false);
58586
59094
  }
59095
+
59096
+ // "Skip for now" — closes the modal AND tells the parent to suppress
59097
+ // the unresolved-providers banner for the current session. Cancel
59098
+ // just closes; Skip means "I'm intentionally not dealing with this
59099
+ // right now." Without this affordance, new users who hit the
59100
+ // post-install state can feel cornered by the banner reappearing
59101
+ // every time they close the modal without resolving every provider.
59102
+ function handleSkip() {
59103
+ setStaged({});
59104
+ setStagedListeners({
59105
+ adds: [],
59106
+ removes: []
59107
+ });
59108
+ setStagedPrefs({});
59109
+ if (typeof onSkip === "function") onSkip();
59110
+ setIsOpen(false);
59111
+ }
58587
59112
  if (!isOpen) return null;
58588
59113
  return /*#__PURE__*/jsxRuntime.jsx(DashReact.Modal, {
58589
59114
  isOpen: isOpen,
@@ -58695,7 +59220,10 @@ var DashboardConfigModal = function DashboardConfigModal(_ref) {
58695
59220
  })]
58696
59221
  }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Divider, {}), /*#__PURE__*/jsxRuntime.jsxs("div", {
58697
59222
  className: "flex-shrink-0 flex flex-row justify-end gap-2 p-4",
58698
- children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.Button3, {
59223
+ children: [typeof onSkip === "function" && /*#__PURE__*/jsxRuntime.jsx(DashReact.Button3, {
59224
+ title: "Skip for now",
59225
+ onClick: handleSkip
59226
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Button3, {
58699
59227
  title: "Cancel",
58700
59228
  onClick: handleCancel
58701
59229
  }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Button2, {
@@ -60409,64 +60937,75 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60409
60937
  isWizardOpen = _useState36[0],
60410
60938
  setIsWizardOpen = _useState36[1];
60411
60939
 
60940
+ // First-run onboarding (Phase 3A). Tri-state:
60941
+ // null — status not yet loaded from main; do not render anything
60942
+ // true — show the OnboardingModal
60943
+ // false — onboarding already completed (or app is not first-run)
60944
+ // The status read happens once per mount; subsequent dismiss/complete
60945
+ // flips this to false without re-fetching.
60946
+ var _useState37 = React.useState(null),
60947
+ _useState38 = _slicedToArray(_useState37, 2),
60948
+ isOnboardingOpen = _useState38[0],
60949
+ setIsOnboardingOpen = _useState38[1];
60950
+
60412
60951
  // Missing widgets detection
60413
60952
  var _useMissingWidgets = useMissingWidgets(workspaceSelected),
60414
60953
  missingComponents = _useMissingWidgets.missingComponents,
60415
60954
  hasMissing = _useMissingWidgets.hasMissing;
60416
- var _useState37 = React.useState(false),
60417
- _useState38 = _slicedToArray(_useState37, 2),
60418
- isMissingWidgetsModalOpen = _useState38[0],
60419
- setIsMissingWidgetsModalOpen = _useState38[1];
60420
- var _useState39 = React.useState(new Set()),
60955
+ var _useState39 = React.useState(false),
60421
60956
  _useState40 = _slicedToArray(_useState39, 2),
60422
- dismissedMissingForWorkspace = _useState40[0],
60423
- setDismissedMissingForWorkspace = _useState40[1];
60957
+ isMissingWidgetsModalOpen = _useState40[0],
60958
+ setIsMissingWidgetsModalOpen = _useState40[1];
60959
+ var _useState41 = React.useState(new Set()),
60960
+ _useState42 = _slicedToArray(_useState41, 2),
60961
+ dismissedMissingForWorkspace = _useState42[0],
60962
+ setDismissedMissingForWorkspace = _useState42[1];
60424
60963
 
60425
60964
  // Dashboard Config modal — bulk provider wiring for the current
60426
60965
  // workspace. Auto-opens on first load of a workspace with unresolved
60427
60966
  // providers (tracked per session via `configModalAutoOpenedFor` so
60428
60967
  // switching tabs doesn't re-fire the modal).
60429
- var _useState41 = React.useState(false),
60430
- _useState42 = _slicedToArray(_useState41, 2),
60431
- isConfigModalOpen = _useState42[0],
60432
- setIsConfigModalOpen = _useState42[1];
60433
- React.useRef(new Set());
60434
- var _useState43 = React.useState(new Set()),
60968
+ var _useState43 = React.useState(false),
60435
60969
  _useState44 = _slicedToArray(_useState43, 2),
60436
- dismissedUnresolvedForWorkspace = _useState44[0],
60437
- setDismissedUnresolvedForWorkspace = _useState44[1];
60970
+ isConfigModalOpen = _useState44[0],
60971
+ setIsConfigModalOpen = _useState44[1];
60972
+ React.useRef(new Set());
60973
+ var _useState45 = React.useState(new Set()),
60974
+ _useState46 = _slicedToArray(_useState45, 2),
60975
+ dismissedUnresolvedForWorkspace = _useState46[0],
60976
+ setDismissedUnresolvedForWorkspace = _useState46[1];
60438
60977
 
60439
60978
  // Unified App Settings Modal
60440
- var _useState45 = React.useState(false),
60441
- _useState46 = _slicedToArray(_useState45, 2),
60442
- isAppSettingsOpen = _useState46[0],
60443
- setIsAppSettingsOpen = _useState46[1];
60444
- var _useState47 = React.useState("dashboards"),
60979
+ var _useState47 = React.useState(false),
60445
60980
  _useState48 = _slicedToArray(_useState47, 2),
60446
- appSettingsInitialSection = _useState48[0],
60447
- setAppSettingsInitialSection = _useState48[1];
60448
- var _useState49 = React.useState(null),
60981
+ isAppSettingsOpen = _useState48[0],
60982
+ setIsAppSettingsOpen = _useState48[1];
60983
+ var _useState49 = React.useState("dashboards"),
60449
60984
  _useState50 = _slicedToArray(_useState49, 2),
60450
- appSettingsInitialProvider = _useState50[0],
60451
- setAppSettingsInitialProvider = _useState50[1];
60452
- var _useState51 = React.useState(false),
60985
+ appSettingsInitialSection = _useState50[0],
60986
+ setAppSettingsInitialSection = _useState50[1];
60987
+ var _useState51 = React.useState(null),
60453
60988
  _useState52 = _slicedToArray(_useState51, 2),
60454
- appSettingsCreateProvider = _useState52[0],
60455
- setAppSettingsCreateProvider = _useState52[1];
60989
+ appSettingsInitialProvider = _useState52[0],
60990
+ setAppSettingsInitialProvider = _useState52[1];
60991
+ var _useState53 = React.useState(false),
60992
+ _useState54 = _slicedToArray(_useState53, 2),
60993
+ appSettingsCreateProvider = _useState54[0],
60994
+ setAppSettingsCreateProvider = _useState54[1];
60456
60995
  // Optional pre-fills used by the cross-modal "Add new <type>"
60457
60996
  // flow dispatched from dash-electron's WidgetBuilderModal.
60458
60997
  // initialProviderType is the type id (e.g. "filesystem", "slack").
60459
60998
  // initialProviderClass routes the create flow: "mcp" opens the
60460
60999
  // catalog detail with that type pre-selected; otherwise opens
60461
61000
  // the credential create form with formType pre-filled.
60462
- var _useState53 = React.useState(null),
60463
- _useState54 = _slicedToArray(_useState53, 2),
60464
- appSettingsInitialProviderType = _useState54[0],
60465
- setAppSettingsInitialProviderType = _useState54[1];
60466
61001
  var _useState55 = React.useState(null),
60467
61002
  _useState56 = _slicedToArray(_useState55, 2),
60468
- appSettingsInitialProviderClass = _useState56[0],
60469
- setAppSettingsInitialProviderClass = _useState56[1];
61003
+ appSettingsInitialProviderType = _useState56[0],
61004
+ setAppSettingsInitialProviderType = _useState56[1];
61005
+ var _useState57 = React.useState(null),
61006
+ _useState58 = _slicedToArray(_useState57, 2),
61007
+ appSettingsInitialProviderClass = _useState58[0],
61008
+ setAppSettingsInitialProviderClass = _useState58[1];
60470
61009
  function openAppSettings() {
60471
61010
  var section = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "general";
60472
61011
  var providerName = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
@@ -60484,27 +61023,27 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60484
61023
  return _handleProfileUpdated.apply(this, arguments);
60485
61024
  } // Ref to access LayoutBuilder's current workspace without re-render cascades
60486
61025
  function _handleProfileUpdated() {
60487
- _handleProfileUpdated = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
60488
- var _window$mainApi11, profile;
60489
- return _regeneratorRuntime.wrap(function (_context2) {
60490
- while (1) switch (_context2.prev = _context2.next) {
61026
+ _handleProfileUpdated = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
61027
+ var _window$mainApi12, profile;
61028
+ return _regeneratorRuntime.wrap(function (_context3) {
61029
+ while (1) switch (_context3.prev = _context3.next) {
60491
61030
  case 0:
60492
- _context2.prev = 0;
60493
- _context2.next = 1;
60494
- 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();
61031
+ _context3.prev = 0;
61032
+ _context3.next = 1;
61033
+ 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();
60495
61034
  case 1:
60496
- profile = _context2.sent;
61035
+ profile = _context3.sent;
60497
61036
  if (profile) setAuthProfile(profile);
60498
- _context2.next = 3;
61037
+ _context3.next = 3;
60499
61038
  break;
60500
61039
  case 2:
60501
- _context2.prev = 2;
60502
- _context2["catch"](0);
61040
+ _context3.prev = 2;
61041
+ _context3["catch"](0);
60503
61042
  case 3:
60504
61043
  case "end":
60505
- return _context2.stop();
61044
+ return _context3.stop();
60506
61045
  }
60507
- }, _callee2, null, [[0, 2]]);
61046
+ }, _callee3, null, [[0, 2]]);
60508
61047
  }));
60509
61048
  return _handleProfileUpdated.apply(this, arguments);
60510
61049
  }
@@ -60541,14 +61080,14 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60541
61080
  // editing. Shapes:
60542
61081
  // { kind: "open-workspace", workspace } — sidebar switch
60543
61082
  // { kind: "cancel-edit" } — Cancel button
60544
- var _useState57 = React.useState(false),
60545
- _useState58 = _slicedToArray(_useState57, 2),
60546
- isDirty = _useState58[0],
60547
- setIsDirty = _useState58[1];
60548
- var _useState59 = React.useState(null),
61083
+ var _useState59 = React.useState(false),
60549
61084
  _useState60 = _slicedToArray(_useState59, 2),
60550
- pendingNavigation = _useState60[0],
60551
- setPendingNavigation = _useState60[1];
61085
+ isDirty = _useState60[0],
61086
+ setIsDirty = _useState60[1];
61087
+ var _useState61 = React.useState(null),
61088
+ _useState62 = _slicedToArray(_useState61, 2),
61089
+ pendingNavigation = _useState62[0],
61090
+ setPendingNavigation = _useState62[1];
60552
61091
  React.useEffect(function () {
60553
61092
  if (typeof globalThis !== "undefined") {
60554
61093
  globalThis.__dashboardIsDirty = isDirty;
@@ -60559,6 +61098,63 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60559
61098
  }
60560
61099
  };
60561
61100
  }, [isDirty]);
61101
+
61102
+ // ─── First-run onboarding gate (Phase 3A) ────────────────────────
61103
+ // Decision fires exactly once per mount after the first workspaces
61104
+ // load completes. We need to wait for `isLoadingWorkspaces` to flip
61105
+ // true→false at least once; otherwise the gate reads workspaceConfig
61106
+ // at its initial empty value and would flash the modal on every
61107
+ // launch.
61108
+ //
61109
+ // Popout windows never show the modal — they're a slave to the
61110
+ // main window's onboarding decision and don't need their own gate.
61111
+ var onboardingCheckedRef = React.useRef(false);
61112
+ React.useEffect(function () {
61113
+ if (popout) {
61114
+ setIsOnboardingOpen(false);
61115
+ return;
61116
+ }
61117
+ if (onboardingCheckedRef.current) return;
61118
+ if (isLoadingWorkspaces) return;
61119
+ onboardingCheckedRef.current = true;
61120
+ var cancelled = false;
61121
+ _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
61122
+ var _window$mainApi, _window$mainApi$getSt, status;
61123
+ return _regeneratorRuntime.wrap(function (_context) {
61124
+ while (1) switch (_context.prev = _context.next) {
61125
+ case 0:
61126
+ _context.prev = 0;
61127
+ _context.next = 1;
61128
+ 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);
61129
+ case 1:
61130
+ status = _context.sent;
61131
+ if (!cancelled) {
61132
+ _context.next = 2;
61133
+ break;
61134
+ }
61135
+ return _context.abrupt("return");
61136
+ case 2:
61137
+ if (status && status.completed === false && workspaceConfig.length === 0) {
61138
+ setIsOnboardingOpen(true);
61139
+ } else {
61140
+ setIsOnboardingOpen(false);
61141
+ }
61142
+ _context.next = 4;
61143
+ break;
61144
+ case 3:
61145
+ _context.prev = 3;
61146
+ _context["catch"](0);
61147
+ if (!cancelled) setIsOnboardingOpen(false);
61148
+ case 4:
61149
+ case "end":
61150
+ return _context.stop();
61151
+ }
61152
+ }, _callee, null, [[0, 3]]);
61153
+ }))();
61154
+ return function () {
61155
+ cancelled = true;
61156
+ };
61157
+ }, [popout, isLoadingWorkspaces, workspaceConfig.length]);
60562
61158
  React.useEffect(function () {
60563
61159
  isLoadingWorkspaces === false && loadWorkspaces();
60564
61160
  isLoadingMenuItems === false && loadMenuItems();
@@ -60573,9 +61169,9 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60573
61169
  return ws.id === popoutWorkspaceId;
60574
61170
  });
60575
61171
  if (target) {
60576
- var _window$mainApi;
61172
+ var _window$mainApi2;
60577
61173
  handleOpenTab(target);
60578
- if ((_window$mainApi = window.mainApi) !== null && _window$mainApi !== void 0 && (_window$mainApi = _window$mainApi.popout) !== null && _window$mainApi !== void 0 && _window$mainApi.setTitle) {
61174
+ if ((_window$mainApi2 = window.mainApi) !== null && _window$mainApi2 !== void 0 && (_window$mainApi2 = _window$mainApi2.popout) !== null && _window$mainApi2 !== void 0 && _window$mainApi2.setTitle) {
60579
61175
  window.mainApi.popout.setTitle(popoutWorkspaceId, target.name || "Untitled");
60580
61176
  }
60581
61177
  }
@@ -60584,15 +61180,15 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60584
61180
 
60585
61181
  // ─── Listen for workspace:saved broadcasts (MCP tools, popouts) ──
60586
61182
  React.useEffect(function () {
60587
- var _window$mainApi2;
60588
- if (!((_window$mainApi2 = window.mainApi) !== null && _window$mainApi2 !== void 0 && _window$mainApi2.on)) return;
61183
+ var _window$mainApi3;
61184
+ if (!((_window$mainApi3 = window.mainApi) !== null && _window$mainApi3 !== void 0 && _window$mainApi3.on)) return;
60589
61185
  var handler = function handler() {
60590
61186
  loadWorkspaces();
60591
61187
  };
60592
61188
  window.mainApi.on("workspace:saved", handler);
60593
61189
  return function () {
60594
- var _window$mainApi3;
60595
- if ((_window$mainApi3 = window.mainApi) !== null && _window$mainApi3 !== void 0 && _window$mainApi3.removeListener) {
61190
+ var _window$mainApi4;
61191
+ if ((_window$mainApi4 = window.mainApi) !== null && _window$mainApi4 !== void 0 && _window$mainApi4.removeListener) {
60596
61192
  window.mainApi.removeListener("workspace:saved", handler);
60597
61193
  }
60598
61194
  };
@@ -60624,9 +61220,9 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60624
61220
  // closing the builder modal — this listener only opens Settings.
60625
61221
  React.useEffect(function () {
60626
61222
  var handler = function handler(e) {
60627
- var _ref4 = (e === null || e === void 0 ? void 0 : e.detail) || {},
60628
- type = _ref4.type,
60629
- providerClass = _ref4.providerClass;
61223
+ var _ref5 = (e === null || e === void 0 ? void 0 : e.detail) || {},
61224
+ type = _ref5.type,
61225
+ providerClass = _ref5.providerClass;
60630
61226
  if (!type) return;
60631
61227
  openAppSettings("providers", null, true, type, providerClass || null);
60632
61228
  };
@@ -60646,10 +61242,10 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60646
61242
  // We record the requested ID and open it once it appears in
60647
61243
  // workspaceConfig — handles the case where the workspace was just
60648
61244
  // created and the config reload is still in flight.
60649
- var _useState61 = React.useState(null),
60650
- _useState62 = _slicedToArray(_useState61, 2),
60651
- pendingOpenWorkspaceId = _useState62[0],
60652
- setPendingOpenWorkspaceId = _useState62[1];
61245
+ var _useState63 = React.useState(null),
61246
+ _useState64 = _slicedToArray(_useState63, 2),
61247
+ pendingOpenWorkspaceId = _useState64[0],
61248
+ setPendingOpenWorkspaceId = _useState64[1];
60653
61249
  React.useEffect(function () {
60654
61250
  var handler = function handler(e) {
60655
61251
  var _e$detail2;
@@ -60677,30 +61273,30 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60677
61273
 
60678
61274
  // ─── Load recents on mount ───────────────────────────────────────
60679
61275
  React.useEffect(function () {
60680
- var _window$mainApi4;
61276
+ var _window$mainApi5;
60681
61277
  if (popout) return;
60682
- (_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) {
61278
+ (_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) {
60683
61279
  if (recents) setRecentDashboards(recents);
60684
61280
  });
60685
61281
  }, [popout]);
60686
61282
 
60687
61283
  // ─── Session save (continuous) ──────────────────────────────────
60688
61284
  React.useEffect(function () {
60689
- var _window$mainApi5;
61285
+ var _window$mainApi6;
60690
61286
  if (popout) return;
60691
61287
  var tabIds = openTabs.map(function (t) {
60692
61288
  return t.id;
60693
61289
  });
60694
- (_window$mainApi5 = window.mainApi) === null || _window$mainApi5 === void 0 || (_window$mainApi5 = _window$mainApi5.session) === null || _window$mainApi5 === void 0 || _window$mainApi5.saveState(tabIds, activeTabId);
61290
+ (_window$mainApi6 = window.mainApi) === null || _window$mainApi6 === void 0 || (_window$mainApi6 = _window$mainApi6.session) === null || _window$mainApi6 === void 0 || _window$mainApi6.saveState(tabIds, activeTabId);
60695
61291
  }, [openTabs, activeTabId, popout]);
60696
61292
 
60697
61293
  // ─── Session restore on launch ─────────────────────────────────
60698
61294
  React.useEffect(function () {
60699
- var _window$mainApi6;
61295
+ var _window$mainApi7;
60700
61296
  if (popout || workspaceConfig.length === 0 || sessionRestored.current) return;
60701
61297
  sessionRestored.current = true;
60702
- (_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) {
60703
- var _state$openTabIds, _window$mainApi7;
61298
+ (_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) {
61299
+ var _state$openTabIds, _window$mainApi8;
60704
61300
  if (!(state !== null && state !== void 0 && (_state$openTabIds = state.openTabIds) !== null && _state$openTabIds !== void 0 && _state$openTabIds.length)) return;
60705
61301
  state.openTabIds.forEach(function (wsId) {
60706
61302
  var ws = workspaceConfig.find(function (w) {
@@ -60709,7 +61305,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60709
61305
  if (ws) handleOpenTab(ws);
60710
61306
  });
60711
61307
  if (state.activeTabId) setActiveTabId(state.activeTabId);
60712
- (_window$mainApi7 = window.mainApi) === null || _window$mainApi7 === void 0 || (_window$mainApi7 = _window$mainApi7.session) === null || _window$mainApi7 === void 0 || _window$mainApi7.clearState();
61308
+ (_window$mainApi8 = window.mainApi) === null || _window$mainApi8 === void 0 || (_window$mainApi8 = _window$mainApi8.session) === null || _window$mainApi8 === void 0 || _window$mainApi8.clearState();
60713
61309
  });
60714
61310
  // eslint-disable-next-line react-hooks/exhaustive-deps
60715
61311
  }, [workspaceConfig, popout]);
@@ -60722,35 +61318,35 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60722
61318
  return _checkAuth.apply(this, arguments);
60723
61319
  }
60724
61320
  function _checkAuth() {
60725
- _checkAuth = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
60726
- var _window$mainApi8, status, _window$mainApi9, profile;
60727
- return _regeneratorRuntime.wrap(function (_context) {
60728
- while (1) switch (_context.prev = _context.next) {
61321
+ _checkAuth = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
61322
+ var _window$mainApi9, status, _window$mainApi0, profile;
61323
+ return _regeneratorRuntime.wrap(function (_context2) {
61324
+ while (1) switch (_context2.prev = _context2.next) {
60729
61325
  case 0:
60730
- _context.prev = 0;
60731
- _context.next = 1;
60732
- 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();
61326
+ _context2.prev = 0;
61327
+ _context2.next = 1;
61328
+ 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();
60733
61329
  case 1:
60734
- status = _context.sent;
61330
+ status = _context2.sent;
60735
61331
  if (!cancelled) {
60736
- _context.next = 2;
61332
+ _context2.next = 2;
60737
61333
  break;
60738
61334
  }
60739
- return _context.abrupt("return");
61335
+ return _context2.abrupt("return");
60740
61336
  case 2:
60741
61337
  if (!(status !== null && status !== void 0 && status.authenticated)) {
60742
- _context.next = 5;
61338
+ _context2.next = 5;
60743
61339
  break;
60744
61340
  }
60745
- _context.next = 3;
60746
- 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();
61341
+ _context2.next = 3;
61342
+ 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();
60747
61343
  case 3:
60748
- profile = _context.sent;
61344
+ profile = _context2.sent;
60749
61345
  if (!cancelled) {
60750
- _context.next = 4;
61346
+ _context2.next = 4;
60751
61347
  break;
60752
61348
  }
60753
- return _context.abrupt("return");
61349
+ return _context2.abrupt("return");
60754
61350
  case 4:
60755
61351
  if (profile) {
60756
61352
  setAuthProfile(profile);
@@ -60758,22 +61354,22 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60758
61354
  } else {
60759
61355
  setAuthStatus("unauthenticated");
60760
61356
  }
60761
- _context.next = 6;
61357
+ _context2.next = 6;
60762
61358
  break;
60763
61359
  case 5:
60764
61360
  setAuthStatus("unauthenticated");
60765
61361
  case 6:
60766
- _context.next = 8;
61362
+ _context2.next = 8;
60767
61363
  break;
60768
61364
  case 7:
60769
- _context.prev = 7;
60770
- _context["catch"](0);
61365
+ _context2.prev = 7;
61366
+ _context2["catch"](0);
60771
61367
  if (!cancelled) setAuthStatus("unauthenticated");
60772
61368
  case 8:
60773
61369
  case "end":
60774
- return _context.stop();
61370
+ return _context2.stop();
60775
61371
  }
60776
- }, _callee, null, [[0, 7]]);
61372
+ }, _callee2, null, [[0, 7]]);
60777
61373
  }));
60778
61374
  return _checkAuth.apply(this, arguments);
60779
61375
  }
@@ -60900,8 +61496,8 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
60900
61496
 
60901
61497
  // Track in recents
60902
61498
  if (!popout) {
60903
- var _window$mainApi0;
60904
- (_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) {
61499
+ var _window$mainApi1;
61500
+ (_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) {
60905
61501
  if (updated) setRecentDashboards(updated);
60906
61502
  });
60907
61503
  }
@@ -61276,10 +61872,10 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
61276
61872
  }
61277
61873
 
61278
61874
  // ─── Page State ──────────────────────────────────────────────────
61279
- var _useState63 = React.useState(null),
61280
- _useState64 = _slicedToArray(_useState63, 2),
61281
- activePageId = _useState64[0],
61282
- setActivePageId = _useState64[1];
61875
+ var _useState65 = React.useState(null),
61876
+ _useState66 = _slicedToArray(_useState65, 2),
61877
+ activePageId = _useState66[0],
61878
+ setActivePageId = _useState66[1];
61283
61879
 
61284
61880
  // Page history stack for goBack() — pushes the previous page id
61285
61881
  // whenever a navigation happens through navigateToPage().
@@ -61313,9 +61909,9 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
61313
61909
  // Listen for programmatic page switches via DashboardActionsApi
61314
61910
  React.useEffect(function () {
61315
61911
  function onSwitchPage(e) {
61316
- var _ref5 = e.detail || {},
61317
- pageId = _ref5.pageId,
61318
- pageName = _ref5.pageName;
61912
+ var _ref6 = e.detail || {},
61913
+ pageId = _ref6.pageId,
61914
+ pageName = _ref6.pageName;
61319
61915
  if (pageId) {
61320
61916
  navigateToPage(pageId);
61321
61917
  } else if (pageName) {
@@ -61905,70 +62501,70 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
61905
62501
  return _handleSidebarSignIn.apply(this, arguments);
61906
62502
  }
61907
62503
  function _handleSidebarSignIn() {
61908
- _handleSidebarSignIn = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
62504
+ _handleSidebarSignIn = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
61909
62505
  var flow, interval, poll;
61910
- return _regeneratorRuntime.wrap(function (_context4) {
61911
- while (1) switch (_context4.prev = _context4.next) {
62506
+ return _regeneratorRuntime.wrap(function (_context5) {
62507
+ while (1) switch (_context5.prev = _context5.next) {
61912
62508
  case 0:
61913
- _context4.prev = 0;
61914
- _context4.next = 1;
62509
+ _context5.prev = 0;
62510
+ _context5.next = 1;
61915
62511
  return window.mainApi.registryAuth.initiateLogin();
61916
62512
  case 1:
61917
- flow = _context4.sent;
62513
+ flow = _context5.sent;
61918
62514
  if (flow.verificationUrlComplete) {
61919
62515
  window.mainApi.shell.openExternal(flow.verificationUrlComplete);
61920
62516
  }
61921
62517
  interval = (flow.interval || 5) * 1000;
61922
- poll = setInterval(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
62518
+ poll = setInterval(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
61923
62519
  var result, profile;
61924
- return _regeneratorRuntime.wrap(function (_context3) {
61925
- while (1) switch (_context3.prev = _context3.next) {
62520
+ return _regeneratorRuntime.wrap(function (_context4) {
62521
+ while (1) switch (_context4.prev = _context4.next) {
61926
62522
  case 0:
61927
- _context3.prev = 0;
61928
- _context3.next = 1;
62523
+ _context4.prev = 0;
62524
+ _context4.next = 1;
61929
62525
  return window.mainApi.registryAuth.pollToken(flow.deviceCode);
61930
62526
  case 1:
61931
- result = _context3.sent;
62527
+ result = _context4.sent;
61932
62528
  if (!(result.status === "authorized")) {
61933
- _context3.next = 3;
62529
+ _context4.next = 3;
61934
62530
  break;
61935
62531
  }
61936
62532
  clearInterval(poll);
61937
- _context3.next = 2;
62533
+ _context4.next = 2;
61938
62534
  return window.mainApi.registryAuth.getProfile();
61939
62535
  case 2:
61940
- profile = _context3.sent;
62536
+ profile = _context4.sent;
61941
62537
  setAuthProfile(profile);
61942
62538
  setAuthStatus("authenticated");
61943
- _context3.next = 4;
62539
+ _context4.next = 4;
61944
62540
  break;
61945
62541
  case 3:
61946
62542
  if (result.status === "expired") {
61947
62543
  clearInterval(poll);
61948
62544
  }
61949
62545
  case 4:
61950
- _context3.next = 6;
62546
+ _context4.next = 6;
61951
62547
  break;
61952
62548
  case 5:
61953
- _context3.prev = 5;
61954
- _context3["catch"](0);
62549
+ _context4.prev = 5;
62550
+ _context4["catch"](0);
61955
62551
  clearInterval(poll);
61956
62552
  case 6:
61957
62553
  case "end":
61958
- return _context3.stop();
62554
+ return _context4.stop();
61959
62555
  }
61960
- }, _callee3, null, [[0, 5]]);
62556
+ }, _callee4, null, [[0, 5]]);
61961
62557
  })), interval);
61962
- _context4.next = 3;
62558
+ _context5.next = 3;
61963
62559
  break;
61964
62560
  case 2:
61965
- _context4.prev = 2;
61966
- _context4["catch"](0);
62561
+ _context5.prev = 2;
62562
+ _context5["catch"](0);
61967
62563
  case 3:
61968
62564
  case "end":
61969
- return _context4.stop();
62565
+ return _context5.stop();
61970
62566
  }
61971
- }, _callee4, null, [[0, 2]]);
62567
+ }, _callee5, null, [[0, 2]]);
61972
62568
  }));
61973
62569
  return _handleSidebarSignIn.apply(this, arguments);
61974
62570
  }
@@ -61976,38 +62572,38 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
61976
62572
  return _handleSidebarSignOut.apply(this, arguments);
61977
62573
  }
61978
62574
  function _handleSidebarSignOut() {
61979
- _handleSidebarSignOut = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
61980
- return _regeneratorRuntime.wrap(function (_context5) {
61981
- while (1) switch (_context5.prev = _context5.next) {
62575
+ _handleSidebarSignOut = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee6() {
62576
+ return _regeneratorRuntime.wrap(function (_context6) {
62577
+ while (1) switch (_context6.prev = _context6.next) {
61982
62578
  case 0:
61983
- _context5.prev = 0;
61984
- _context5.next = 1;
62579
+ _context6.prev = 0;
62580
+ _context6.next = 1;
61985
62581
  return window.mainApi.registryAuth.logout();
61986
62582
  case 1:
61987
62583
  setAuthStatus("unauthenticated");
61988
62584
  setAuthProfile(null);
61989
- _context5.next = 3;
62585
+ _context6.next = 3;
61990
62586
  break;
61991
62587
  case 2:
61992
- _context5.prev = 2;
61993
- _context5["catch"](0);
62588
+ _context6.prev = 2;
62589
+ _context6["catch"](0);
61994
62590
  case 3:
61995
62591
  case "end":
61996
- return _context5.stop();
62592
+ return _context6.stop();
61997
62593
  }
61998
- }, _callee5, null, [[0, 2]]);
62594
+ }, _callee6, null, [[0, 2]]);
61999
62595
  }));
62000
62596
  return _handleSidebarSignOut.apply(this, arguments);
62001
62597
  }
62002
62598
  function handlePopout() {
62003
- var _window$mainApi1;
62004
- if (workspaceSelected && (_window$mainApi1 = window.mainApi) !== null && _window$mainApi1 !== void 0 && (_window$mainApi1 = _window$mainApi1.popout) !== null && _window$mainApi1 !== void 0 && _window$mainApi1.open) {
62599
+ var _window$mainApi10;
62600
+ if (workspaceSelected && (_window$mainApi10 = window.mainApi) !== null && _window$mainApi10 !== void 0 && (_window$mainApi10 = _window$mainApi10.popout) !== null && _window$mainApi10 !== void 0 && _window$mainApi10.open) {
62005
62601
  window.mainApi.popout.open(workspaceSelected.id);
62006
62602
  }
62007
62603
  }
62008
62604
  function handleWidgetPopout(widgetId) {
62009
- var _window$mainApi10;
62010
- if (workspaceSelected && (_window$mainApi10 = window.mainApi) !== null && _window$mainApi10 !== void 0 && (_window$mainApi10 = _window$mainApi10.widgetPopout) !== null && _window$mainApi10 !== void 0 && _window$mainApi10.open) {
62605
+ var _window$mainApi11;
62606
+ if (workspaceSelected && (_window$mainApi11 = window.mainApi) !== null && _window$mainApi11 !== void 0 && (_window$mainApi11 = _window$mainApi11.widgetPopout) !== null && _window$mainApi11 !== void 0 && _window$mainApi11.open) {
62011
62607
  window.mainApi.widgetPopout.open(workspaceSelected.id, widgetId);
62012
62608
  }
62013
62609
  }
@@ -62326,7 +62922,36 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
62326
62922
  onSaveBindings: handleBulkProviderBindings,
62327
62923
  onSaveListeners: handleBulkListenerBindings,
62328
62924
  onSaveUserPrefs: handleBulkUserPrefs,
62925
+ onSkip: function onSkip() {
62926
+ // Suppress the unresolved-providers banner for this
62927
+ // workspace (session-scoped). Matches the banner's own
62928
+ // X-dismiss behavior so the user has parity between
62929
+ // "dismiss from the banner" and "dismiss from the
62930
+ // modal footer."
62931
+ if ((workspaceSelected === null || workspaceSelected === void 0 ? void 0 : workspaceSelected.id) != null) {
62932
+ setDismissedUnresolvedForWorkspace(function (prev) {
62933
+ return new Set([].concat(_toConsumableArray(prev), [workspaceSelected.id]));
62934
+ });
62935
+ }
62936
+ },
62329
62937
  initialTab: "providers"
62938
+ }), /*#__PURE__*/jsxRuntime.jsx(OnboardingModal, {
62939
+ open: isOnboardingOpen === true,
62940
+ appId: credentials === null || credentials === void 0 ? void 0 : credentials.appId,
62941
+ onDismiss: function onDismiss() {
62942
+ return setIsOnboardingOpen(false);
62943
+ },
62944
+ onComplete: function onComplete() {
62945
+ return setIsOnboardingOpen(false);
62946
+ },
62947
+ onOpenDashboard: function onOpenDashboard(ws) {
62948
+ setIsOnboardingOpen(false);
62949
+ // Refresh workspaces before opening so the just-
62950
+ // installed Kitchen Sink shows up in the sidebar list
62951
+ // alongside the open tab.
62952
+ loadWorkspaces();
62953
+ handleOpenTab(ws);
62954
+ }
62330
62955
  })]
62331
62956
  })]
62332
62957
  }), !popout && /*#__PURE__*/jsxRuntime.jsx(DashCommandPalette, {