@trops/dash-core 0.1.602 → 0.1.604
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 +408 -52
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +408 -52
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -6519,7 +6519,7 @@ var FolderDetail = function FolderDetail(_ref) {
|
|
|
6519
6519
|
});
|
|
6520
6520
|
};
|
|
6521
6521
|
|
|
6522
|
-
var OptionCard$
|
|
6522
|
+
var OptionCard$3 = function OptionCard(_ref) {
|
|
6523
6523
|
var icon = _ref.icon,
|
|
6524
6524
|
title = _ref.title,
|
|
6525
6525
|
description = _ref.description,
|
|
@@ -6568,28 +6568,28 @@ var CreationMethodPicker = function CreationMethodPicker(_ref2) {
|
|
|
6568
6568
|
})]
|
|
6569
6569
|
}), /*#__PURE__*/jsxs("div", {
|
|
6570
6570
|
className: "flex flex-col w-2/3 p-6 pt-10 space-y-3",
|
|
6571
|
-
children: [/*#__PURE__*/jsx(OptionCard$
|
|
6571
|
+
children: [/*#__PURE__*/jsx(OptionCard$3, {
|
|
6572
6572
|
icon: "plus",
|
|
6573
6573
|
title: "New Dashboard",
|
|
6574
6574
|
description: "Start from a blank template and customize your layout",
|
|
6575
6575
|
onClick: function onClick() {
|
|
6576
6576
|
return onSelect("template");
|
|
6577
6577
|
}
|
|
6578
|
-
}), /*#__PURE__*/jsx(OptionCard$
|
|
6578
|
+
}), /*#__PURE__*/jsx(OptionCard$3, {
|
|
6579
6579
|
icon: "file-zipper",
|
|
6580
6580
|
title: "Import from File",
|
|
6581
6581
|
description: "Import a dashboard from a .zip file on your computer",
|
|
6582
6582
|
onClick: function onClick() {
|
|
6583
6583
|
return onSelect("import");
|
|
6584
6584
|
}
|
|
6585
|
-
}), /*#__PURE__*/jsx(OptionCard$
|
|
6585
|
+
}), /*#__PURE__*/jsx(OptionCard$3, {
|
|
6586
6586
|
icon: "compass",
|
|
6587
6587
|
title: "Search Registry",
|
|
6588
6588
|
description: "Browse and install dashboards from the online registry",
|
|
6589
6589
|
onClick: function onClick() {
|
|
6590
6590
|
return onSelect("registry");
|
|
6591
6591
|
}
|
|
6592
|
-
}), /*#__PURE__*/jsx(OptionCard$
|
|
6592
|
+
}), /*#__PURE__*/jsx(OptionCard$3, {
|
|
6593
6593
|
icon: "wand-magic-sparkles",
|
|
6594
6594
|
title: "Dashboard Wizard",
|
|
6595
6595
|
description: "Guided setup \u2014 pick categories, providers, and widgets step by step",
|
|
@@ -41715,6 +41715,94 @@ var DashboardDetail = function DashboardDetail(_ref2) {
|
|
|
41715
41715
|
});
|
|
41716
41716
|
};
|
|
41717
41717
|
|
|
41718
|
+
var OptionCard$2 = function OptionCard(_ref) {
|
|
41719
|
+
var icon = _ref.icon,
|
|
41720
|
+
title = _ref.title,
|
|
41721
|
+
description = _ref.description,
|
|
41722
|
+
onClick = _ref.onClick,
|
|
41723
|
+
currentTheme = _ref.currentTheme;
|
|
41724
|
+
return /*#__PURE__*/jsxs("button", {
|
|
41725
|
+
type: "button",
|
|
41726
|
+
onClick: onClick,
|
|
41727
|
+
className: "w-full flex flex-row items-center gap-4 p-4 rounded-lg text-left transition-opacity ".concat(currentTheme["bg-primary-medium"] || "bg-white/5", " hover:opacity-80"),
|
|
41728
|
+
children: [/*#__PURE__*/jsx("div", {
|
|
41729
|
+
className: "flex-shrink-0 h-8 w-8 flex items-center justify-center opacity-60",
|
|
41730
|
+
children: /*#__PURE__*/jsx(FontAwesomeIcon, {
|
|
41731
|
+
icon: icon,
|
|
41732
|
+
className: "h-5 w-5"
|
|
41733
|
+
})
|
|
41734
|
+
}), /*#__PURE__*/jsxs("div", {
|
|
41735
|
+
className: "flex flex-col min-w-0",
|
|
41736
|
+
children: [/*#__PURE__*/jsx("span", {
|
|
41737
|
+
className: "text-sm font-medium",
|
|
41738
|
+
children: title
|
|
41739
|
+
}), /*#__PURE__*/jsx("span", {
|
|
41740
|
+
className: "text-xs opacity-50 mt-0.5",
|
|
41741
|
+
children: description
|
|
41742
|
+
})]
|
|
41743
|
+
}), /*#__PURE__*/jsx("div", {
|
|
41744
|
+
className: "flex-shrink-0 ml-auto opacity-30",
|
|
41745
|
+
children: /*#__PURE__*/jsx(FontAwesomeIcon, {
|
|
41746
|
+
icon: "chevron-right",
|
|
41747
|
+
className: "h-3 w-3"
|
|
41748
|
+
})
|
|
41749
|
+
})]
|
|
41750
|
+
});
|
|
41751
|
+
};
|
|
41752
|
+
|
|
41753
|
+
/**
|
|
41754
|
+
* NewDashboardChooser — consolidated entry point for the
|
|
41755
|
+
* "New Dashboard" header button in Settings → Dashboards.
|
|
41756
|
+
*
|
|
41757
|
+
* Audit #19 fix: the prior header button was labeled "Marketplace"
|
|
41758
|
+
* which was ambiguous (it set installMode=marketplace, duplicating
|
|
41759
|
+
* the Marketplace tab in the list). Renamed to "New Dashboard"; the
|
|
41760
|
+
* chooser presents the actual creation paths as labeled cards,
|
|
41761
|
+
* matching the ThemeNewChooser pattern.
|
|
41762
|
+
*
|
|
41763
|
+
* Options:
|
|
41764
|
+
* - "marketplace" → registry browser (existing DiscoverDashboardsDetail)
|
|
41765
|
+
* - "wizard" → existing dashboard creation wizard
|
|
41766
|
+
*
|
|
41767
|
+
* The Marketplace TAB in the list view stays — it's the in-place
|
|
41768
|
+
* browse affordance, distinct from this "I want to create a new
|
|
41769
|
+
* dashboard" entry.
|
|
41770
|
+
*/
|
|
41771
|
+
var NewDashboardChooser = function NewDashboardChooser(_ref2) {
|
|
41772
|
+
var onSelect = _ref2.onSelect;
|
|
41773
|
+
var _useContext = useContext(ThemeContext),
|
|
41774
|
+
currentTheme = _useContext.currentTheme;
|
|
41775
|
+
var panelStyles = getStylesForItem(themeObjects.PANEL, currentTheme, {
|
|
41776
|
+
grow: false
|
|
41777
|
+
});
|
|
41778
|
+
return /*#__PURE__*/jsx("div", {
|
|
41779
|
+
className: "flex flex-col flex-1 min-h-0",
|
|
41780
|
+
children: /*#__PURE__*/jsxs("div", {
|
|
41781
|
+
className: "flex-1 overflow-y-auto p-6 space-y-3 ".concat(panelStyles.textColor || "text-gray-200"),
|
|
41782
|
+
children: [/*#__PURE__*/jsx("span", {
|
|
41783
|
+
className: "text-xs font-semibold opacity-50 block mb-4",
|
|
41784
|
+
children: "CREATE A DASHBOARD"
|
|
41785
|
+
}), /*#__PURE__*/jsx(OptionCard$2, {
|
|
41786
|
+
icon: "compass",
|
|
41787
|
+
title: "Search Marketplace",
|
|
41788
|
+
description: "Browse and install community dashboards from the online registry",
|
|
41789
|
+
onClick: function onClick() {
|
|
41790
|
+
return onSelect("marketplace");
|
|
41791
|
+
},
|
|
41792
|
+
currentTheme: currentTheme
|
|
41793
|
+
}), /*#__PURE__*/jsx(OptionCard$2, {
|
|
41794
|
+
icon: "wand-magic-sparkles",
|
|
41795
|
+
title: "From Wizard",
|
|
41796
|
+
description: "Build a new dashboard from a layout + theme + widgets",
|
|
41797
|
+
onClick: function onClick() {
|
|
41798
|
+
return onSelect("wizard");
|
|
41799
|
+
},
|
|
41800
|
+
currentTheme: currentTheme
|
|
41801
|
+
})]
|
|
41802
|
+
})
|
|
41803
|
+
});
|
|
41804
|
+
};
|
|
41805
|
+
|
|
41718
41806
|
function ownKeys$x(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
41719
41807
|
function _objectSpread$x(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$x(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$x(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
41720
41808
|
var DashboardsSection = function DashboardsSection(_ref) {
|
|
@@ -41760,7 +41848,9 @@ var DashboardsSection = function DashboardsSection(_ref) {
|
|
|
41760
41848
|
_useState10 = _slicedToArray(_useState1, 2),
|
|
41761
41849
|
viewMode = _useState10[0],
|
|
41762
41850
|
setViewMode = _useState10[1];
|
|
41763
|
-
// null | "marketplace"
|
|
41851
|
+
// null | "picker" | "marketplace"
|
|
41852
|
+
// picker — NewDashboardChooser (Phase 19 / audit #19)
|
|
41853
|
+
// marketplace — DiscoverDashboardsDetail (registry browser)
|
|
41764
41854
|
var _useState11 = useState(null),
|
|
41765
41855
|
_useState12 = _slicedToArray(_useState11, 2),
|
|
41766
41856
|
installMode = _useState12[0],
|
|
@@ -41846,12 +41936,16 @@ var DashboardsSection = function DashboardsSection(_ref) {
|
|
|
41846
41936
|
});
|
|
41847
41937
|
}
|
|
41848
41938
|
|
|
41849
|
-
// Respond to external create trigger from
|
|
41939
|
+
// Respond to external create trigger from the "New Dashboard"
|
|
41940
|
+
// header button. Audit #19: this now opens the consolidated
|
|
41941
|
+
// NewDashboardChooser (Marketplace + Wizard cards), matching the
|
|
41942
|
+
// ThemeNewChooser pattern. Pre-fix this went straight to
|
|
41943
|
+
// installMode="marketplace" which made the button ambiguous.
|
|
41850
41944
|
var prevCreateRequested = useRef(false);
|
|
41851
41945
|
useEffect(function () {
|
|
41852
41946
|
if (createRequested && !prevCreateRequested.current) {
|
|
41853
41947
|
setSelectedId(null);
|
|
41854
|
-
setInstallMode("
|
|
41948
|
+
setInstallMode("picker");
|
|
41855
41949
|
}
|
|
41856
41950
|
prevCreateRequested.current = createRequested;
|
|
41857
41951
|
if (createRequested && onCreateAcknowledged) {
|
|
@@ -41859,6 +41953,16 @@ var DashboardsSection = function DashboardsSection(_ref) {
|
|
|
41859
41953
|
}
|
|
41860
41954
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
41861
41955
|
}, [createRequested]);
|
|
41956
|
+
function handleChooserSelect(option) {
|
|
41957
|
+
if (option === "marketplace") {
|
|
41958
|
+
setInstallMode("marketplace");
|
|
41959
|
+
} else if (option === "wizard") {
|
|
41960
|
+
// onOpenWizard closes the Settings modal and opens the
|
|
41961
|
+
// dashboard wizard. Provided by AppSettingsModal.
|
|
41962
|
+
setInstallMode(null);
|
|
41963
|
+
if (typeof onOpenWizard === "function") onOpenWizard();
|
|
41964
|
+
}
|
|
41965
|
+
}
|
|
41862
41966
|
var selectedWorkspace = workspaces.find(function (ws) {
|
|
41863
41967
|
return ws.id === selectedId;
|
|
41864
41968
|
});
|
|
@@ -41970,7 +42074,11 @@ var DashboardsSection = function DashboardsSection(_ref) {
|
|
|
41970
42074
|
})]
|
|
41971
42075
|
});
|
|
41972
42076
|
var detailContent = null;
|
|
41973
|
-
if (installMode === "
|
|
42077
|
+
if (installMode === "picker") {
|
|
42078
|
+
detailContent = /*#__PURE__*/jsx(NewDashboardChooser, {
|
|
42079
|
+
onSelect: handleChooserSelect
|
|
42080
|
+
});
|
|
42081
|
+
} else if (installMode === "marketplace") {
|
|
41974
42082
|
detailContent = /*#__PURE__*/jsx(DiscoverDashboardsDetail, {
|
|
41975
42083
|
onBack: function onBack() {
|
|
41976
42084
|
setInstallMode(null);
|
|
@@ -48503,12 +48611,15 @@ var OptionCard = function OptionCard(_ref) {
|
|
|
48503
48611
|
};
|
|
48504
48612
|
|
|
48505
48613
|
/**
|
|
48506
|
-
* InstallWidgetPicker — the
|
|
48614
|
+
* InstallWidgetPicker — the consolidated chooser shown when the
|
|
48615
|
+
* "New Widget" header button is clicked (audit #19).
|
|
48507
48616
|
*
|
|
48508
48617
|
* Options:
|
|
48509
|
-
* 1.
|
|
48510
|
-
*
|
|
48511
|
-
*
|
|
48618
|
+
* 1. Use Widget Builder (Phase 19 — folds the inline "+ New Widget"
|
|
48619
|
+
* button's function into the chooser so there's one entry point)
|
|
48620
|
+
* 2. Search for Widgets (registry browser)
|
|
48621
|
+
* 3. Install from File (.zip)
|
|
48622
|
+
* 4. Load from Folder
|
|
48512
48623
|
*/
|
|
48513
48624
|
var InstallWidgetPicker = function InstallWidgetPicker(_ref2) {
|
|
48514
48625
|
var onSelect = _ref2.onSelect;
|
|
@@ -48523,7 +48634,15 @@ var InstallWidgetPicker = function InstallWidgetPicker(_ref2) {
|
|
|
48523
48634
|
className: "flex-1 overflow-y-auto p-6 space-y-3 ".concat(panelStyles.textColor || "text-gray-200"),
|
|
48524
48635
|
children: [/*#__PURE__*/jsx("span", {
|
|
48525
48636
|
className: "text-xs font-semibold opacity-50 block mb-4",
|
|
48526
|
-
children: "
|
|
48637
|
+
children: "CREATE A WIDGET"
|
|
48638
|
+
}), /*#__PURE__*/jsx(OptionCard, {
|
|
48639
|
+
icon: "wand-magic-sparkles",
|
|
48640
|
+
title: "Use Widget Builder",
|
|
48641
|
+
description: "Open the AI Widget Builder to create a new widget from scratch",
|
|
48642
|
+
onClick: function onClick() {
|
|
48643
|
+
return onSelect("builder");
|
|
48644
|
+
},
|
|
48645
|
+
currentTheme: currentTheme
|
|
48527
48646
|
}), /*#__PURE__*/jsx(OptionCard, {
|
|
48528
48647
|
icon: "compass",
|
|
48529
48648
|
title: "Search for Widgets",
|
|
@@ -49815,7 +49934,14 @@ var WidgetsSection = function WidgetsSection(_ref) {
|
|
|
49815
49934
|
setProgressComplete(false);
|
|
49816
49935
|
}
|
|
49817
49936
|
function handlePickerSelect(option) {
|
|
49818
|
-
if (option === "
|
|
49937
|
+
if (option === "builder") {
|
|
49938
|
+
// Audit #19: the inline "+ New Widget" button was removed in
|
|
49939
|
+
// favor of this card so there's a single entry point for new-
|
|
49940
|
+
// widget creation. Closes the picker and fires the same event
|
|
49941
|
+
// the inline button used to dispatch.
|
|
49942
|
+
setInstallMode(null);
|
|
49943
|
+
window.dispatchEvent(new Event("dash:open-widget-builder"));
|
|
49944
|
+
} else if (option === "discover") {
|
|
49819
49945
|
setInstallMode("discover");
|
|
49820
49946
|
} else if (option === "zip") {
|
|
49821
49947
|
handleInstallFromZip();
|
|
@@ -49913,23 +50039,7 @@ var WidgetsSection = function WidgetsSection(_ref) {
|
|
|
49913
50039
|
}
|
|
49914
50040
|
var listContent = /*#__PURE__*/jsxs("div", {
|
|
49915
50041
|
className: "flex flex-col h-full",
|
|
49916
|
-
children: [/*#__PURE__*/
|
|
49917
|
-
className: "flex-shrink-0 px-3 pt-2 pb-1",
|
|
49918
|
-
children: /*#__PURE__*/jsxs("button", {
|
|
49919
|
-
type: "button",
|
|
49920
|
-
onClick: function onClick() {
|
|
49921
|
-
return window.dispatchEvent(new Event("dash:open-widget-builder"));
|
|
49922
|
-
},
|
|
49923
|
-
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",
|
|
49924
|
-
"data-testid": "widgets-section-new-widget-button",
|
|
49925
|
-
children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
|
|
49926
|
-
icon: "plus",
|
|
49927
|
-
className: "text-xs"
|
|
49928
|
-
}), /*#__PURE__*/jsx("span", {
|
|
49929
|
-
children: "New Widget"
|
|
49930
|
-
})]
|
|
49931
|
-
})
|
|
49932
|
-
}), isChecking && packagesWithUpdates.length === 0 && /*#__PURE__*/jsxs("div", {
|
|
50042
|
+
children: [isChecking && packagesWithUpdates.length === 0 && /*#__PURE__*/jsxs("div", {
|
|
49933
50043
|
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",
|
|
49934
50044
|
"data-testid": "widgets-section-checking-updates",
|
|
49935
50045
|
children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
|
|
@@ -54565,7 +54675,7 @@ var AppSettingsModal = function AppSettingsModal(_ref) {
|
|
|
54565
54675
|
padding: false
|
|
54566
54676
|
}), (activeSection === "dashboards" || activeSection === "folders" || activeSection === "providers" || activeSection === "themes" || activeSection === "widgets") && /*#__PURE__*/jsx(ButtonIcon3, {
|
|
54567
54677
|
icon: "plus",
|
|
54568
|
-
text: activeSection === "dashboards" ? "
|
|
54678
|
+
text: activeSection === "dashboards" ? "New Dashboard" : activeSection === "folders" ? "New Folder" : activeSection === "providers" ? "New Provider" : activeSection === "widgets" ? "New Widget" : "New Theme",
|
|
54569
54679
|
onClick: function onClick() {
|
|
54570
54680
|
return setCreateRequested(true);
|
|
54571
54681
|
},
|
|
@@ -54782,13 +54892,41 @@ var DashboardLoaderModal = function DashboardLoaderModal(_ref) {
|
|
|
54782
54892
|
var KITCHEN_SINK_PACKAGE = "trops/kitchen-sink";
|
|
54783
54893
|
var STATE = {
|
|
54784
54894
|
WELCOME: "welcome",
|
|
54895
|
+
// AUTH_REQUIRED replaces the generic "Install Failed" screen when
|
|
54896
|
+
// the registry returns `authRequired: true`. Surfaces a
|
|
54897
|
+
// benefits-driven sign-in CTA instead of asking the user to
|
|
54898
|
+
// figure out why install died.
|
|
54899
|
+
AUTH_REQUIRED: "auth-required",
|
|
54785
54900
|
INSTALLING: "installing",
|
|
54786
54901
|
DONE: "done",
|
|
54787
54902
|
ERROR: "error"
|
|
54788
54903
|
};
|
|
54904
|
+
|
|
54905
|
+
/**
|
|
54906
|
+
* Returns the first workspace that was installed from the Kitchen
|
|
54907
|
+
* Sink package, or null. Used for the modal's dedupe check so we
|
|
54908
|
+
* never create a second Kitchen Sink when one already exists.
|
|
54909
|
+
*
|
|
54910
|
+
* Workspaces installed via the registry carry a
|
|
54911
|
+
* `_dashboardConfig.registryPackage` field — historically the
|
|
54912
|
+
* unscoped name ("kitchen-sink"), more recently the scoped form
|
|
54913
|
+
* ("trops/kitchen-sink"). Match on either trailing segment.
|
|
54914
|
+
*/
|
|
54915
|
+
function findExistingKitchenSink(workspaces) {
|
|
54916
|
+
if (!Array.isArray(workspaces)) return null;
|
|
54917
|
+
return workspaces.find(function (ws) {
|
|
54918
|
+
var _ws$_dashboardConfig;
|
|
54919
|
+
var pkg = ws === null || ws === void 0 || (_ws$_dashboardConfig = ws._dashboardConfig) === null || _ws$_dashboardConfig === void 0 ? void 0 : _ws$_dashboardConfig.registryPackage;
|
|
54920
|
+
if (typeof pkg !== "string") return false;
|
|
54921
|
+
var trailing = pkg.includes("/") ? pkg.split("/").pop() : pkg;
|
|
54922
|
+
return trailing === "kitchen-sink";
|
|
54923
|
+
}) || null;
|
|
54924
|
+
}
|
|
54789
54925
|
var OnboardingModal = function OnboardingModal(_ref) {
|
|
54790
54926
|
var open = _ref.open,
|
|
54791
54927
|
appId = _ref.appId,
|
|
54928
|
+
_ref$workspaces = _ref.workspaces,
|
|
54929
|
+
workspaces = _ref$workspaces === void 0 ? [] : _ref$workspaces,
|
|
54792
54930
|
onOpenDashboard = _ref.onOpenDashboard,
|
|
54793
54931
|
onDismiss = _ref.onDismiss,
|
|
54794
54932
|
onComplete = _ref.onComplete;
|
|
@@ -54808,6 +54946,16 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54808
54946
|
setInstallError = _useState6[1];
|
|
54809
54947
|
var installResultRef = useRef(null);
|
|
54810
54948
|
var cleanupProgressRef = useRef(null);
|
|
54949
|
+
|
|
54950
|
+
// Reused device-code OAuth state machine (same hook AppUpdatesModal
|
|
54951
|
+
// uses). `authFlow` carries the user code + verification URL once
|
|
54952
|
+
// initiateAuth fires; while non-null we render the polling panel.
|
|
54953
|
+
var _useRegistryAuth = useRegistryAuth(),
|
|
54954
|
+
isAuthenticating = _useRegistryAuth.isAuthenticating,
|
|
54955
|
+
authFlow = _useRegistryAuth.authFlow,
|
|
54956
|
+
authError = _useRegistryAuth.authError,
|
|
54957
|
+
initiateAuth = _useRegistryAuth.initiateAuth,
|
|
54958
|
+
cancelAuth = _useRegistryAuth.cancelAuth;
|
|
54811
54959
|
useEffect(function () {
|
|
54812
54960
|
if (open) {
|
|
54813
54961
|
setState(STATE.WELCOME);
|
|
@@ -54869,7 +55017,7 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54869
55017
|
})), [markCompletedAndClose, onDismiss]);
|
|
54870
55018
|
var handleInstall = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
54871
55019
|
var _window$mainApi2, _window$mainApi2$onIn;
|
|
54872
|
-
var _window$mainApi3, _window$mainApi3$inst, result, _t2;
|
|
55020
|
+
var existing, _window$mainApi3, _window$mainApi3$inst, result, _t2;
|
|
54873
55021
|
return _regeneratorRuntime.wrap(function (_context3) {
|
|
54874
55022
|
while (1) switch (_context3.prev = _context3.next) {
|
|
54875
55023
|
case 0:
|
|
@@ -54881,6 +55029,24 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54881
55029
|
setState(STATE.ERROR);
|
|
54882
55030
|
return _context3.abrupt("return");
|
|
54883
55031
|
case 1:
|
|
55032
|
+
// Dedupe: if the user already has a Kitchen Sink workspace
|
|
55033
|
+
// installed from the registry, skip the install entirely and
|
|
55034
|
+
// route them to the existing one. Without this, the modal
|
|
55035
|
+
// could be re-triggered (e.g. after clearing the
|
|
55036
|
+
// onboarding.completed flag) and would silently create
|
|
55037
|
+
// "Kitchen Sink 2", "Kitchen Sink 3", etc.
|
|
55038
|
+
existing = findExistingKitchenSink(workspaces);
|
|
55039
|
+
if (!existing) {
|
|
55040
|
+
_context3.next = 2;
|
|
55041
|
+
break;
|
|
55042
|
+
}
|
|
55043
|
+
installResultRef.current = {
|
|
55044
|
+
success: true,
|
|
55045
|
+
workspace: existing
|
|
55046
|
+
};
|
|
55047
|
+
setState(STATE.DONE);
|
|
55048
|
+
return _context3.abrupt("return");
|
|
55049
|
+
case 2:
|
|
54884
55050
|
setState(STATE.INSTALLING);
|
|
54885
55051
|
setProgressItems([]);
|
|
54886
55052
|
setInstallError(null);
|
|
@@ -54908,42 +55074,49 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54908
55074
|
return next;
|
|
54909
55075
|
});
|
|
54910
55076
|
});
|
|
54911
|
-
_context3.prev =
|
|
54912
|
-
_context3.next =
|
|
55077
|
+
_context3.prev = 3;
|
|
55078
|
+
_context3.next = 4;
|
|
54913
55079
|
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, {});
|
|
54914
|
-
case
|
|
55080
|
+
case 4:
|
|
54915
55081
|
result = _context3.sent;
|
|
54916
55082
|
if (cleanupProgressRef.current) {
|
|
54917
55083
|
cleanupProgressRef.current();
|
|
54918
55084
|
cleanupProgressRef.current = null;
|
|
54919
55085
|
}
|
|
54920
55086
|
if (!(!result || !result.success)) {
|
|
54921
|
-
_context3.next =
|
|
55087
|
+
_context3.next = 6;
|
|
54922
55088
|
break;
|
|
54923
55089
|
}
|
|
55090
|
+
if (!(result !== null && result !== void 0 && result.authRequired)) {
|
|
55091
|
+
_context3.next = 5;
|
|
55092
|
+
break;
|
|
55093
|
+
}
|
|
55094
|
+
setState(STATE.AUTH_REQUIRED);
|
|
55095
|
+
return _context3.abrupt("return");
|
|
55096
|
+
case 5:
|
|
54924
55097
|
setInstallError((result === null || result === void 0 ? void 0 : result.error) || "Failed to install Kitchen Sink. Check your internet connection and try again.");
|
|
54925
55098
|
setState(STATE.ERROR);
|
|
54926
55099
|
return _context3.abrupt("return");
|
|
54927
|
-
case
|
|
55100
|
+
case 6:
|
|
54928
55101
|
installResultRef.current = result;
|
|
54929
55102
|
setState(STATE.DONE);
|
|
54930
|
-
_context3.next =
|
|
55103
|
+
_context3.next = 8;
|
|
54931
55104
|
break;
|
|
54932
|
-
case
|
|
54933
|
-
_context3.prev =
|
|
54934
|
-
_t2 = _context3["catch"](
|
|
55105
|
+
case 7:
|
|
55106
|
+
_context3.prev = 7;
|
|
55107
|
+
_t2 = _context3["catch"](3);
|
|
54935
55108
|
if (cleanupProgressRef.current) {
|
|
54936
55109
|
cleanupProgressRef.current();
|
|
54937
55110
|
cleanupProgressRef.current = null;
|
|
54938
55111
|
}
|
|
54939
55112
|
setInstallError((_t2 === null || _t2 === void 0 ? void 0 : _t2.message) || "Installation failed.");
|
|
54940
55113
|
setState(STATE.ERROR);
|
|
54941
|
-
case
|
|
55114
|
+
case 8:
|
|
54942
55115
|
case "end":
|
|
54943
55116
|
return _context3.stop();
|
|
54944
55117
|
}
|
|
54945
|
-
}, _callee3, null, [[
|
|
54946
|
-
})), [appId]);
|
|
55118
|
+
}, _callee3, null, [[3, 7]]);
|
|
55119
|
+
})), [appId, workspaces]);
|
|
54947
55120
|
var handleOpen = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
|
|
54948
55121
|
var _installResultRef$cur;
|
|
54949
55122
|
var workspace;
|
|
@@ -54968,6 +55141,17 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54968
55141
|
handleInstall();
|
|
54969
55142
|
}, [handleInstall]);
|
|
54970
55143
|
|
|
55144
|
+
// From the AUTH_REQUIRED state: kick off device-code OAuth. The
|
|
55145
|
+
// hook opens the browser, polls in the background, and fires our
|
|
55146
|
+
// onAuthorized callback on success. We auto-retry the install
|
|
55147
|
+
// there so the user lands on the DONE state without a second
|
|
55148
|
+
// click.
|
|
55149
|
+
var handleSignIn = useCallback(function () {
|
|
55150
|
+
initiateAuth(function () {
|
|
55151
|
+
handleInstall();
|
|
55152
|
+
});
|
|
55153
|
+
}, [initiateAuth, handleInstall]);
|
|
55154
|
+
|
|
54971
55155
|
// The Modal dispatches setIsOpen(false) on Escape / backdrop click.
|
|
54972
55156
|
// Route any close attempt through handleSkip so the completion flag
|
|
54973
55157
|
// is always stamped (otherwise Escape would silently re-show the
|
|
@@ -54991,6 +55175,15 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54991
55175
|
onInstall: handleInstall,
|
|
54992
55176
|
onSkip: handleSkip,
|
|
54993
55177
|
textMuted: textMuted
|
|
55178
|
+
}), state === STATE.AUTH_REQUIRED && /*#__PURE__*/jsx(AuthRequiredBody, {
|
|
55179
|
+
onSignIn: handleSignIn,
|
|
55180
|
+
onCancelAuth: cancelAuth,
|
|
55181
|
+
onSkip: handleSkip,
|
|
55182
|
+
isAuthenticating: isAuthenticating,
|
|
55183
|
+
authFlow: authFlow,
|
|
55184
|
+
authError: authError,
|
|
55185
|
+
textMuted: textMuted,
|
|
55186
|
+
borderPanel: borderPanel
|
|
54994
55187
|
}), state === STATE.INSTALLING && /*#__PURE__*/jsx(InstallingBody, {
|
|
54995
55188
|
items: progressItems,
|
|
54996
55189
|
borderPanel: borderPanel,
|
|
@@ -55020,11 +55213,13 @@ function WelcomeBody(_ref7) {
|
|
|
55020
55213
|
}), /*#__PURE__*/jsx(Heading2, {
|
|
55021
55214
|
title: "Welcome to Dash"
|
|
55022
55215
|
})]
|
|
55023
|
-
}), /*#__PURE__*/
|
|
55216
|
+
}), /*#__PURE__*/jsx(Paragraph, {
|
|
55024
55217
|
className: "".concat(textMuted, " mb-6"),
|
|
55025
|
-
children:
|
|
55026
|
-
children: "
|
|
55027
|
-
|
|
55218
|
+
children: /*#__PURE__*/jsxs("span", {
|
|
55219
|
+
children: ["Get started with the ", /*#__PURE__*/jsx("strong", {
|
|
55220
|
+
children: "Kitchen Sink"
|
|
55221
|
+
}), " 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."]
|
|
55222
|
+
})
|
|
55028
55223
|
}), /*#__PURE__*/jsxs("div", {
|
|
55029
55224
|
className: "flex items-center justify-end gap-3 mt-2",
|
|
55030
55225
|
children: [/*#__PURE__*/jsx(Button, {
|
|
@@ -55185,6 +55380,153 @@ function ErrorBody(_ref1) {
|
|
|
55185
55380
|
})]
|
|
55186
55381
|
});
|
|
55187
55382
|
}
|
|
55383
|
+
function BenefitRow(_ref10) {
|
|
55384
|
+
var icon = _ref10.icon,
|
|
55385
|
+
title = _ref10.title,
|
|
55386
|
+
description = _ref10.description,
|
|
55387
|
+
textMuted = _ref10.textMuted;
|
|
55388
|
+
return /*#__PURE__*/jsxs("div", {
|
|
55389
|
+
className: "flex items-start gap-3",
|
|
55390
|
+
children: [/*#__PURE__*/jsx("div", {
|
|
55391
|
+
className: "flex-shrink-0 w-7 h-7 flex items-center justify-center mt-0.5",
|
|
55392
|
+
children: /*#__PURE__*/jsx(FontAwesomeIcon, {
|
|
55393
|
+
icon: icon,
|
|
55394
|
+
className: "text-base opacity-70"
|
|
55395
|
+
})
|
|
55396
|
+
}), /*#__PURE__*/jsxs("div", {
|
|
55397
|
+
className: "flex flex-col",
|
|
55398
|
+
children: [/*#__PURE__*/jsx("span", {
|
|
55399
|
+
className: "text-sm font-medium",
|
|
55400
|
+
children: title
|
|
55401
|
+
}), /*#__PURE__*/jsx("span", {
|
|
55402
|
+
className: "text-xs ".concat(textMuted),
|
|
55403
|
+
children: description
|
|
55404
|
+
})]
|
|
55405
|
+
})]
|
|
55406
|
+
});
|
|
55407
|
+
}
|
|
55408
|
+
function AuthRequiredBody(_ref11) {
|
|
55409
|
+
var onSignIn = _ref11.onSignIn,
|
|
55410
|
+
onCancelAuth = _ref11.onCancelAuth,
|
|
55411
|
+
onSkip = _ref11.onSkip,
|
|
55412
|
+
isAuthenticating = _ref11.isAuthenticating,
|
|
55413
|
+
authFlow = _ref11.authFlow,
|
|
55414
|
+
authError = _ref11.authError,
|
|
55415
|
+
textMuted = _ref11.textMuted,
|
|
55416
|
+
borderPanel = _ref11.borderPanel;
|
|
55417
|
+
// While the device-code flow is polling, swap the benefits panel
|
|
55418
|
+
// for the user-code + verification-URL display so the user knows
|
|
55419
|
+
// what to enter in the browser tab we just opened.
|
|
55420
|
+
if (isAuthenticating && authFlow) {
|
|
55421
|
+
return /*#__PURE__*/jsxs(Fragment, {
|
|
55422
|
+
children: [/*#__PURE__*/jsxs("div", {
|
|
55423
|
+
className: "flex items-center gap-3 mb-2",
|
|
55424
|
+
children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
|
|
55425
|
+
icon: "circle-notch",
|
|
55426
|
+
className: "text-2xl animate-spin"
|
|
55427
|
+
}), /*#__PURE__*/jsx(Heading2, {
|
|
55428
|
+
title: "Waiting for browser sign-in"
|
|
55429
|
+
})]
|
|
55430
|
+
}), /*#__PURE__*/jsx(Paragraph, {
|
|
55431
|
+
className: "".concat(textMuted, " mb-4"),
|
|
55432
|
+
children: /*#__PURE__*/jsx("span", {
|
|
55433
|
+
children: "We opened a browser tab where you can sign in to the Dash Registry. Enter this code if prompted:"
|
|
55434
|
+
})
|
|
55435
|
+
}), /*#__PURE__*/jsxs("div", {
|
|
55436
|
+
className: "border ".concat(borderPanel, " rounded-md p-4 mb-4 text-center"),
|
|
55437
|
+
"data-testid": "onboarding-auth-user-code",
|
|
55438
|
+
children: [/*#__PURE__*/jsx("div", {
|
|
55439
|
+
className: "text-2xl font-mono tracking-widest",
|
|
55440
|
+
children: authFlow.userCode || "—"
|
|
55441
|
+
}), /*#__PURE__*/jsx("div", {
|
|
55442
|
+
className: "text-xs ".concat(textMuted, " mt-2 break-all"),
|
|
55443
|
+
children: authFlow.verificationUrlComplete || authFlow.verificationUrl || ""
|
|
55444
|
+
})]
|
|
55445
|
+
}), /*#__PURE__*/jsx("div", {
|
|
55446
|
+
className: "flex items-center justify-end gap-3",
|
|
55447
|
+
children: /*#__PURE__*/jsx(Button, {
|
|
55448
|
+
onClick: onCancelAuth,
|
|
55449
|
+
title: "Cancel",
|
|
55450
|
+
textSize: "text-sm",
|
|
55451
|
+
padding: "py-2 px-4",
|
|
55452
|
+
backgroundColor: "bg-gray-700",
|
|
55453
|
+
textColor: "text-gray-300",
|
|
55454
|
+
hoverTextColor: "hover:text-white",
|
|
55455
|
+
hoverBackgroundColor: "hover:bg-gray-600",
|
|
55456
|
+
"data-testid": "onboarding-auth-cancel-button"
|
|
55457
|
+
})
|
|
55458
|
+
})]
|
|
55459
|
+
});
|
|
55460
|
+
}
|
|
55461
|
+
return /*#__PURE__*/jsxs(Fragment, {
|
|
55462
|
+
children: [/*#__PURE__*/jsxs("div", {
|
|
55463
|
+
className: "flex items-center gap-3 mb-2",
|
|
55464
|
+
children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
|
|
55465
|
+
icon: "user-plus",
|
|
55466
|
+
className: "text-2xl"
|
|
55467
|
+
}), /*#__PURE__*/jsx(Heading2, {
|
|
55468
|
+
title: "Sign in to the Dash Registry"
|
|
55469
|
+
})]
|
|
55470
|
+
}), /*#__PURE__*/jsx(Paragraph, {
|
|
55471
|
+
className: "".concat(textMuted, " mb-5"),
|
|
55472
|
+
children: /*#__PURE__*/jsx("span", {
|
|
55473
|
+
children: "A free Dash account unlocks the community ecosystem. Sign in to continue installing Kitchen Sink \u2014 and to use everything else the registry offers."
|
|
55474
|
+
})
|
|
55475
|
+
}), /*#__PURE__*/jsxs("div", {
|
|
55476
|
+
className: "grid grid-cols-1 sm:grid-cols-2 gap-4 mb-6",
|
|
55477
|
+
children: [/*#__PURE__*/jsx(BenefitRow, {
|
|
55478
|
+
icon: "cube",
|
|
55479
|
+
title: "Install widgets",
|
|
55480
|
+
description: "Browse and one-click install community widgets",
|
|
55481
|
+
textMuted: textMuted
|
|
55482
|
+
}), /*#__PURE__*/jsx(BenefitRow, {
|
|
55483
|
+
icon: "table-cells",
|
|
55484
|
+
title: "Discover dashboards",
|
|
55485
|
+
description: "Like Kitchen Sink \u2014 curated starters built by others",
|
|
55486
|
+
textMuted: textMuted
|
|
55487
|
+
}), /*#__PURE__*/jsx(BenefitRow, {
|
|
55488
|
+
icon: "palette",
|
|
55489
|
+
title: "Apply themes",
|
|
55490
|
+
description: "Community-built themes for any taste",
|
|
55491
|
+
textMuted: textMuted
|
|
55492
|
+
}), /*#__PURE__*/jsx(BenefitRow, {
|
|
55493
|
+
icon: "upload",
|
|
55494
|
+
title: "Publish your own",
|
|
55495
|
+
description: "Share your widgets and dashboards with the Dash community",
|
|
55496
|
+
textMuted: textMuted
|
|
55497
|
+
})]
|
|
55498
|
+
}), authError && /*#__PURE__*/jsx(Paragraph, {
|
|
55499
|
+
className: "text-red-400 mb-4",
|
|
55500
|
+
children: /*#__PURE__*/jsx("span", {
|
|
55501
|
+
children: authError
|
|
55502
|
+
})
|
|
55503
|
+
}), /*#__PURE__*/jsxs("div", {
|
|
55504
|
+
className: "flex items-center justify-end gap-3 mt-2",
|
|
55505
|
+
children: [/*#__PURE__*/jsx(Button, {
|
|
55506
|
+
onClick: onSkip,
|
|
55507
|
+
title: "Skip for now",
|
|
55508
|
+
textSize: "text-sm",
|
|
55509
|
+
padding: "py-2 px-4",
|
|
55510
|
+
backgroundColor: "bg-gray-700",
|
|
55511
|
+
textColor: "text-gray-300",
|
|
55512
|
+
hoverTextColor: "hover:text-white",
|
|
55513
|
+
hoverBackgroundColor: "hover:bg-gray-600",
|
|
55514
|
+
"data-testid": "onboarding-auth-skip-button"
|
|
55515
|
+
}), /*#__PURE__*/jsx(Button, {
|
|
55516
|
+
onClick: onSignIn,
|
|
55517
|
+
title: "Sign in to Registry",
|
|
55518
|
+
textSize: "text-sm",
|
|
55519
|
+
padding: "py-2 px-4",
|
|
55520
|
+
backgroundColor: "bg-blue-600",
|
|
55521
|
+
textColor: "text-white",
|
|
55522
|
+
hoverTextColor: "hover:text-white",
|
|
55523
|
+
hoverBackgroundColor: "hover:bg-blue-500",
|
|
55524
|
+
icon: "arrow-up-right-from-square",
|
|
55525
|
+
"data-testid": "onboarding-auth-signin-button"
|
|
55526
|
+
})]
|
|
55527
|
+
})]
|
|
55528
|
+
});
|
|
55529
|
+
}
|
|
55188
55530
|
|
|
55189
55531
|
var DashCommandPalette = function DashCommandPalette(_ref) {
|
|
55190
55532
|
var isOpen = _ref.isOpen,
|
|
@@ -61198,7 +61540,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61198
61540
|
onboardingCheckedRef.current = true;
|
|
61199
61541
|
var cancelled = false;
|
|
61200
61542
|
_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
61201
|
-
var _window$mainApi, _window$mainApi$getSt, status;
|
|
61543
|
+
var _window$mainApi, _window$mainApi$getSt, status, alreadyHasKitchenSink;
|
|
61202
61544
|
return _regeneratorRuntime.wrap(function (_context) {
|
|
61203
61545
|
while (1) switch (_context.prev = _context.next) {
|
|
61204
61546
|
case 0:
|
|
@@ -61213,7 +61555,20 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61213
61555
|
}
|
|
61214
61556
|
return _context.abrupt("return");
|
|
61215
61557
|
case 2:
|
|
61216
|
-
|
|
61558
|
+
// Defense-in-depth: even if `workspaceConfig.length === 0`
|
|
61559
|
+
// briefly reads true during a race between `isLoadingWorkspaces`
|
|
61560
|
+
// and the workspace array populating, don't show the modal
|
|
61561
|
+
// if the user already has a Kitchen Sink dashboard installed
|
|
61562
|
+
// from the registry. Same dedupe rule the modal's install
|
|
61563
|
+
// path applies.
|
|
61564
|
+
alreadyHasKitchenSink = workspaceConfig.some(function (ws) {
|
|
61565
|
+
var _ws$_dashboardConfig;
|
|
61566
|
+
var pkg = ws === null || ws === void 0 || (_ws$_dashboardConfig = ws._dashboardConfig) === null || _ws$_dashboardConfig === void 0 ? void 0 : _ws$_dashboardConfig.registryPackage;
|
|
61567
|
+
if (typeof pkg !== "string") return false;
|
|
61568
|
+
var trailing = pkg.includes("/") ? pkg.split("/").pop() : pkg;
|
|
61569
|
+
return trailing === "kitchen-sink";
|
|
61570
|
+
});
|
|
61571
|
+
if (status && status.completed === false && workspaceConfig.length === 0 && !alreadyHasKitchenSink) {
|
|
61217
61572
|
setIsOnboardingOpen(true);
|
|
61218
61573
|
} else {
|
|
61219
61574
|
setIsOnboardingOpen(false);
|
|
@@ -63017,6 +63372,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
63017
63372
|
}), /*#__PURE__*/jsx(OnboardingModal, {
|
|
63018
63373
|
open: isOnboardingOpen === true,
|
|
63019
63374
|
appId: credentials === null || credentials === void 0 ? void 0 : credentials.appId,
|
|
63375
|
+
workspaces: workspaceConfig,
|
|
63020
63376
|
onDismiss: function onDismiss() {
|
|
63021
63377
|
return setIsOnboardingOpen(false);
|
|
63022
63378
|
},
|