@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.js
CHANGED
|
@@ -6537,7 +6537,7 @@ var FolderDetail = function FolderDetail(_ref) {
|
|
|
6537
6537
|
});
|
|
6538
6538
|
};
|
|
6539
6539
|
|
|
6540
|
-
var OptionCard$
|
|
6540
|
+
var OptionCard$3 = function OptionCard(_ref) {
|
|
6541
6541
|
var icon = _ref.icon,
|
|
6542
6542
|
title = _ref.title,
|
|
6543
6543
|
description = _ref.description,
|
|
@@ -6586,28 +6586,28 @@ var CreationMethodPicker = function CreationMethodPicker(_ref2) {
|
|
|
6586
6586
|
})]
|
|
6587
6587
|
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
6588
6588
|
className: "flex flex-col w-2/3 p-6 pt-10 space-y-3",
|
|
6589
|
-
children: [/*#__PURE__*/jsxRuntime.jsx(OptionCard$
|
|
6589
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(OptionCard$3, {
|
|
6590
6590
|
icon: "plus",
|
|
6591
6591
|
title: "New Dashboard",
|
|
6592
6592
|
description: "Start from a blank template and customize your layout",
|
|
6593
6593
|
onClick: function onClick() {
|
|
6594
6594
|
return onSelect("template");
|
|
6595
6595
|
}
|
|
6596
|
-
}), /*#__PURE__*/jsxRuntime.jsx(OptionCard$
|
|
6596
|
+
}), /*#__PURE__*/jsxRuntime.jsx(OptionCard$3, {
|
|
6597
6597
|
icon: "file-zipper",
|
|
6598
6598
|
title: "Import from File",
|
|
6599
6599
|
description: "Import a dashboard from a .zip file on your computer",
|
|
6600
6600
|
onClick: function onClick() {
|
|
6601
6601
|
return onSelect("import");
|
|
6602
6602
|
}
|
|
6603
|
-
}), /*#__PURE__*/jsxRuntime.jsx(OptionCard$
|
|
6603
|
+
}), /*#__PURE__*/jsxRuntime.jsx(OptionCard$3, {
|
|
6604
6604
|
icon: "compass",
|
|
6605
6605
|
title: "Search Registry",
|
|
6606
6606
|
description: "Browse and install dashboards from the online registry",
|
|
6607
6607
|
onClick: function onClick() {
|
|
6608
6608
|
return onSelect("registry");
|
|
6609
6609
|
}
|
|
6610
|
-
}), /*#__PURE__*/jsxRuntime.jsx(OptionCard$
|
|
6610
|
+
}), /*#__PURE__*/jsxRuntime.jsx(OptionCard$3, {
|
|
6611
6611
|
icon: "wand-magic-sparkles",
|
|
6612
6612
|
title: "Dashboard Wizard",
|
|
6613
6613
|
description: "Guided setup \u2014 pick categories, providers, and widgets step by step",
|
|
@@ -41733,6 +41733,94 @@ var DashboardDetail = function DashboardDetail(_ref2) {
|
|
|
41733
41733
|
});
|
|
41734
41734
|
};
|
|
41735
41735
|
|
|
41736
|
+
var OptionCard$2 = function OptionCard(_ref) {
|
|
41737
|
+
var icon = _ref.icon,
|
|
41738
|
+
title = _ref.title,
|
|
41739
|
+
description = _ref.description,
|
|
41740
|
+
onClick = _ref.onClick,
|
|
41741
|
+
currentTheme = _ref.currentTheme;
|
|
41742
|
+
return /*#__PURE__*/jsxRuntime.jsxs("button", {
|
|
41743
|
+
type: "button",
|
|
41744
|
+
onClick: onClick,
|
|
41745
|
+
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"),
|
|
41746
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
41747
|
+
className: "flex-shrink-0 h-8 w-8 flex items-center justify-center opacity-60",
|
|
41748
|
+
children: /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
|
|
41749
|
+
icon: icon,
|
|
41750
|
+
className: "h-5 w-5"
|
|
41751
|
+
})
|
|
41752
|
+
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
41753
|
+
className: "flex flex-col min-w-0",
|
|
41754
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("span", {
|
|
41755
|
+
className: "text-sm font-medium",
|
|
41756
|
+
children: title
|
|
41757
|
+
}), /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
41758
|
+
className: "text-xs opacity-50 mt-0.5",
|
|
41759
|
+
children: description
|
|
41760
|
+
})]
|
|
41761
|
+
}), /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
41762
|
+
className: "flex-shrink-0 ml-auto opacity-30",
|
|
41763
|
+
children: /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
|
|
41764
|
+
icon: "chevron-right",
|
|
41765
|
+
className: "h-3 w-3"
|
|
41766
|
+
})
|
|
41767
|
+
})]
|
|
41768
|
+
});
|
|
41769
|
+
};
|
|
41770
|
+
|
|
41771
|
+
/**
|
|
41772
|
+
* NewDashboardChooser — consolidated entry point for the
|
|
41773
|
+
* "New Dashboard" header button in Settings → Dashboards.
|
|
41774
|
+
*
|
|
41775
|
+
* Audit #19 fix: the prior header button was labeled "Marketplace"
|
|
41776
|
+
* which was ambiguous (it set installMode=marketplace, duplicating
|
|
41777
|
+
* the Marketplace tab in the list). Renamed to "New Dashboard"; the
|
|
41778
|
+
* chooser presents the actual creation paths as labeled cards,
|
|
41779
|
+
* matching the ThemeNewChooser pattern.
|
|
41780
|
+
*
|
|
41781
|
+
* Options:
|
|
41782
|
+
* - "marketplace" → registry browser (existing DiscoverDashboardsDetail)
|
|
41783
|
+
* - "wizard" → existing dashboard creation wizard
|
|
41784
|
+
*
|
|
41785
|
+
* The Marketplace TAB in the list view stays — it's the in-place
|
|
41786
|
+
* browse affordance, distinct from this "I want to create a new
|
|
41787
|
+
* dashboard" entry.
|
|
41788
|
+
*/
|
|
41789
|
+
var NewDashboardChooser = function NewDashboardChooser(_ref2) {
|
|
41790
|
+
var onSelect = _ref2.onSelect;
|
|
41791
|
+
var _useContext = React.useContext(DashReact.ThemeContext),
|
|
41792
|
+
currentTheme = _useContext.currentTheme;
|
|
41793
|
+
var panelStyles = DashReact.getStylesForItem(DashReact.themeObjects.PANEL, currentTheme, {
|
|
41794
|
+
grow: false
|
|
41795
|
+
});
|
|
41796
|
+
return /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
41797
|
+
className: "flex flex-col flex-1 min-h-0",
|
|
41798
|
+
children: /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
41799
|
+
className: "flex-1 overflow-y-auto p-6 space-y-3 ".concat(panelStyles.textColor || "text-gray-200"),
|
|
41800
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("span", {
|
|
41801
|
+
className: "text-xs font-semibold opacity-50 block mb-4",
|
|
41802
|
+
children: "CREATE A DASHBOARD"
|
|
41803
|
+
}), /*#__PURE__*/jsxRuntime.jsx(OptionCard$2, {
|
|
41804
|
+
icon: "compass",
|
|
41805
|
+
title: "Search Marketplace",
|
|
41806
|
+
description: "Browse and install community dashboards from the online registry",
|
|
41807
|
+
onClick: function onClick() {
|
|
41808
|
+
return onSelect("marketplace");
|
|
41809
|
+
},
|
|
41810
|
+
currentTheme: currentTheme
|
|
41811
|
+
}), /*#__PURE__*/jsxRuntime.jsx(OptionCard$2, {
|
|
41812
|
+
icon: "wand-magic-sparkles",
|
|
41813
|
+
title: "From Wizard",
|
|
41814
|
+
description: "Build a new dashboard from a layout + theme + widgets",
|
|
41815
|
+
onClick: function onClick() {
|
|
41816
|
+
return onSelect("wizard");
|
|
41817
|
+
},
|
|
41818
|
+
currentTheme: currentTheme
|
|
41819
|
+
})]
|
|
41820
|
+
})
|
|
41821
|
+
});
|
|
41822
|
+
};
|
|
41823
|
+
|
|
41736
41824
|
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; }
|
|
41737
41825
|
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; }
|
|
41738
41826
|
var DashboardsSection = function DashboardsSection(_ref) {
|
|
@@ -41778,7 +41866,9 @@ var DashboardsSection = function DashboardsSection(_ref) {
|
|
|
41778
41866
|
_useState10 = _slicedToArray(_useState1, 2),
|
|
41779
41867
|
viewMode = _useState10[0],
|
|
41780
41868
|
setViewMode = _useState10[1];
|
|
41781
|
-
// null | "marketplace"
|
|
41869
|
+
// null | "picker" | "marketplace"
|
|
41870
|
+
// picker — NewDashboardChooser (Phase 19 / audit #19)
|
|
41871
|
+
// marketplace — DiscoverDashboardsDetail (registry browser)
|
|
41782
41872
|
var _useState11 = React.useState(null),
|
|
41783
41873
|
_useState12 = _slicedToArray(_useState11, 2),
|
|
41784
41874
|
installMode = _useState12[0],
|
|
@@ -41864,12 +41954,16 @@ var DashboardsSection = function DashboardsSection(_ref) {
|
|
|
41864
41954
|
});
|
|
41865
41955
|
}
|
|
41866
41956
|
|
|
41867
|
-
// Respond to external create trigger from
|
|
41957
|
+
// Respond to external create trigger from the "New Dashboard"
|
|
41958
|
+
// header button. Audit #19: this now opens the consolidated
|
|
41959
|
+
// NewDashboardChooser (Marketplace + Wizard cards), matching the
|
|
41960
|
+
// ThemeNewChooser pattern. Pre-fix this went straight to
|
|
41961
|
+
// installMode="marketplace" which made the button ambiguous.
|
|
41868
41962
|
var prevCreateRequested = React.useRef(false);
|
|
41869
41963
|
React.useEffect(function () {
|
|
41870
41964
|
if (createRequested && !prevCreateRequested.current) {
|
|
41871
41965
|
setSelectedId(null);
|
|
41872
|
-
setInstallMode("
|
|
41966
|
+
setInstallMode("picker");
|
|
41873
41967
|
}
|
|
41874
41968
|
prevCreateRequested.current = createRequested;
|
|
41875
41969
|
if (createRequested && onCreateAcknowledged) {
|
|
@@ -41877,6 +41971,16 @@ var DashboardsSection = function DashboardsSection(_ref) {
|
|
|
41877
41971
|
}
|
|
41878
41972
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
41879
41973
|
}, [createRequested]);
|
|
41974
|
+
function handleChooserSelect(option) {
|
|
41975
|
+
if (option === "marketplace") {
|
|
41976
|
+
setInstallMode("marketplace");
|
|
41977
|
+
} else if (option === "wizard") {
|
|
41978
|
+
// onOpenWizard closes the Settings modal and opens the
|
|
41979
|
+
// dashboard wizard. Provided by AppSettingsModal.
|
|
41980
|
+
setInstallMode(null);
|
|
41981
|
+
if (typeof onOpenWizard === "function") onOpenWizard();
|
|
41982
|
+
}
|
|
41983
|
+
}
|
|
41880
41984
|
var selectedWorkspace = workspaces.find(function (ws) {
|
|
41881
41985
|
return ws.id === selectedId;
|
|
41882
41986
|
});
|
|
@@ -41988,7 +42092,11 @@ var DashboardsSection = function DashboardsSection(_ref) {
|
|
|
41988
42092
|
})]
|
|
41989
42093
|
});
|
|
41990
42094
|
var detailContent = null;
|
|
41991
|
-
if (installMode === "
|
|
42095
|
+
if (installMode === "picker") {
|
|
42096
|
+
detailContent = /*#__PURE__*/jsxRuntime.jsx(NewDashboardChooser, {
|
|
42097
|
+
onSelect: handleChooserSelect
|
|
42098
|
+
});
|
|
42099
|
+
} else if (installMode === "marketplace") {
|
|
41992
42100
|
detailContent = /*#__PURE__*/jsxRuntime.jsx(DiscoverDashboardsDetail, {
|
|
41993
42101
|
onBack: function onBack() {
|
|
41994
42102
|
setInstallMode(null);
|
|
@@ -48521,12 +48629,15 @@ var OptionCard = function OptionCard(_ref) {
|
|
|
48521
48629
|
};
|
|
48522
48630
|
|
|
48523
48631
|
/**
|
|
48524
|
-
* InstallWidgetPicker — the
|
|
48632
|
+
* InstallWidgetPicker — the consolidated chooser shown when the
|
|
48633
|
+
* "New Widget" header button is clicked (audit #19).
|
|
48525
48634
|
*
|
|
48526
48635
|
* Options:
|
|
48527
|
-
* 1.
|
|
48528
|
-
*
|
|
48529
|
-
*
|
|
48636
|
+
* 1. Use Widget Builder (Phase 19 — folds the inline "+ New Widget"
|
|
48637
|
+
* button's function into the chooser so there's one entry point)
|
|
48638
|
+
* 2. Search for Widgets (registry browser)
|
|
48639
|
+
* 3. Install from File (.zip)
|
|
48640
|
+
* 4. Load from Folder
|
|
48530
48641
|
*/
|
|
48531
48642
|
var InstallWidgetPicker = function InstallWidgetPicker(_ref2) {
|
|
48532
48643
|
var onSelect = _ref2.onSelect;
|
|
@@ -48541,7 +48652,15 @@ var InstallWidgetPicker = function InstallWidgetPicker(_ref2) {
|
|
|
48541
48652
|
className: "flex-1 overflow-y-auto p-6 space-y-3 ".concat(panelStyles.textColor || "text-gray-200"),
|
|
48542
48653
|
children: [/*#__PURE__*/jsxRuntime.jsx("span", {
|
|
48543
48654
|
className: "text-xs font-semibold opacity-50 block mb-4",
|
|
48544
|
-
children: "
|
|
48655
|
+
children: "CREATE A WIDGET"
|
|
48656
|
+
}), /*#__PURE__*/jsxRuntime.jsx(OptionCard, {
|
|
48657
|
+
icon: "wand-magic-sparkles",
|
|
48658
|
+
title: "Use Widget Builder",
|
|
48659
|
+
description: "Open the AI Widget Builder to create a new widget from scratch",
|
|
48660
|
+
onClick: function onClick() {
|
|
48661
|
+
return onSelect("builder");
|
|
48662
|
+
},
|
|
48663
|
+
currentTheme: currentTheme
|
|
48545
48664
|
}), /*#__PURE__*/jsxRuntime.jsx(OptionCard, {
|
|
48546
48665
|
icon: "compass",
|
|
48547
48666
|
title: "Search for Widgets",
|
|
@@ -49833,7 +49952,14 @@ var WidgetsSection = function WidgetsSection(_ref) {
|
|
|
49833
49952
|
setProgressComplete(false);
|
|
49834
49953
|
}
|
|
49835
49954
|
function handlePickerSelect(option) {
|
|
49836
|
-
if (option === "
|
|
49955
|
+
if (option === "builder") {
|
|
49956
|
+
// Audit #19: the inline "+ New Widget" button was removed in
|
|
49957
|
+
// favor of this card so there's a single entry point for new-
|
|
49958
|
+
// widget creation. Closes the picker and fires the same event
|
|
49959
|
+
// the inline button used to dispatch.
|
|
49960
|
+
setInstallMode(null);
|
|
49961
|
+
window.dispatchEvent(new Event("dash:open-widget-builder"));
|
|
49962
|
+
} else if (option === "discover") {
|
|
49837
49963
|
setInstallMode("discover");
|
|
49838
49964
|
} else if (option === "zip") {
|
|
49839
49965
|
handleInstallFromZip();
|
|
@@ -49931,23 +50057,7 @@ var WidgetsSection = function WidgetsSection(_ref) {
|
|
|
49931
50057
|
}
|
|
49932
50058
|
var listContent = /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
49933
50059
|
className: "flex flex-col h-full",
|
|
49934
|
-
children: [/*#__PURE__*/jsxRuntime.
|
|
49935
|
-
className: "flex-shrink-0 px-3 pt-2 pb-1",
|
|
49936
|
-
children: /*#__PURE__*/jsxRuntime.jsxs("button", {
|
|
49937
|
-
type: "button",
|
|
49938
|
-
onClick: function onClick() {
|
|
49939
|
-
return window.dispatchEvent(new Event("dash:open-widget-builder"));
|
|
49940
|
-
},
|
|
49941
|
-
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",
|
|
49942
|
-
"data-testid": "widgets-section-new-widget-button",
|
|
49943
|
-
children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
|
|
49944
|
-
icon: "plus",
|
|
49945
|
-
className: "text-xs"
|
|
49946
|
-
}), /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
49947
|
-
children: "New Widget"
|
|
49948
|
-
})]
|
|
49949
|
-
})
|
|
49950
|
-
}), isChecking && packagesWithUpdates.length === 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
50060
|
+
children: [isChecking && packagesWithUpdates.length === 0 && /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
49951
50061
|
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",
|
|
49952
50062
|
"data-testid": "widgets-section-checking-updates",
|
|
49953
50063
|
children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
|
|
@@ -54583,7 +54693,7 @@ var AppSettingsModal = function AppSettingsModal(_ref) {
|
|
|
54583
54693
|
padding: false
|
|
54584
54694
|
}), (activeSection === "dashboards" || activeSection === "folders" || activeSection === "providers" || activeSection === "themes" || activeSection === "widgets") && /*#__PURE__*/jsxRuntime.jsx(DashReact.ButtonIcon3, {
|
|
54585
54695
|
icon: "plus",
|
|
54586
|
-
text: activeSection === "dashboards" ? "
|
|
54696
|
+
text: activeSection === "dashboards" ? "New Dashboard" : activeSection === "folders" ? "New Folder" : activeSection === "providers" ? "New Provider" : activeSection === "widgets" ? "New Widget" : "New Theme",
|
|
54587
54697
|
onClick: function onClick() {
|
|
54588
54698
|
return setCreateRequested(true);
|
|
54589
54699
|
},
|
|
@@ -54800,13 +54910,41 @@ var DashboardLoaderModal = function DashboardLoaderModal(_ref) {
|
|
|
54800
54910
|
var KITCHEN_SINK_PACKAGE = "trops/kitchen-sink";
|
|
54801
54911
|
var STATE = {
|
|
54802
54912
|
WELCOME: "welcome",
|
|
54913
|
+
// AUTH_REQUIRED replaces the generic "Install Failed" screen when
|
|
54914
|
+
// the registry returns `authRequired: true`. Surfaces a
|
|
54915
|
+
// benefits-driven sign-in CTA instead of asking the user to
|
|
54916
|
+
// figure out why install died.
|
|
54917
|
+
AUTH_REQUIRED: "auth-required",
|
|
54803
54918
|
INSTALLING: "installing",
|
|
54804
54919
|
DONE: "done",
|
|
54805
54920
|
ERROR: "error"
|
|
54806
54921
|
};
|
|
54922
|
+
|
|
54923
|
+
/**
|
|
54924
|
+
* Returns the first workspace that was installed from the Kitchen
|
|
54925
|
+
* Sink package, or null. Used for the modal's dedupe check so we
|
|
54926
|
+
* never create a second Kitchen Sink when one already exists.
|
|
54927
|
+
*
|
|
54928
|
+
* Workspaces installed via the registry carry a
|
|
54929
|
+
* `_dashboardConfig.registryPackage` field — historically the
|
|
54930
|
+
* unscoped name ("kitchen-sink"), more recently the scoped form
|
|
54931
|
+
* ("trops/kitchen-sink"). Match on either trailing segment.
|
|
54932
|
+
*/
|
|
54933
|
+
function findExistingKitchenSink(workspaces) {
|
|
54934
|
+
if (!Array.isArray(workspaces)) return null;
|
|
54935
|
+
return workspaces.find(function (ws) {
|
|
54936
|
+
var _ws$_dashboardConfig;
|
|
54937
|
+
var pkg = ws === null || ws === void 0 || (_ws$_dashboardConfig = ws._dashboardConfig) === null || _ws$_dashboardConfig === void 0 ? void 0 : _ws$_dashboardConfig.registryPackage;
|
|
54938
|
+
if (typeof pkg !== "string") return false;
|
|
54939
|
+
var trailing = pkg.includes("/") ? pkg.split("/").pop() : pkg;
|
|
54940
|
+
return trailing === "kitchen-sink";
|
|
54941
|
+
}) || null;
|
|
54942
|
+
}
|
|
54807
54943
|
var OnboardingModal = function OnboardingModal(_ref) {
|
|
54808
54944
|
var open = _ref.open,
|
|
54809
54945
|
appId = _ref.appId,
|
|
54946
|
+
_ref$workspaces = _ref.workspaces,
|
|
54947
|
+
workspaces = _ref$workspaces === void 0 ? [] : _ref$workspaces,
|
|
54810
54948
|
onOpenDashboard = _ref.onOpenDashboard,
|
|
54811
54949
|
onDismiss = _ref.onDismiss,
|
|
54812
54950
|
onComplete = _ref.onComplete;
|
|
@@ -54826,6 +54964,16 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54826
54964
|
setInstallError = _useState6[1];
|
|
54827
54965
|
var installResultRef = React.useRef(null);
|
|
54828
54966
|
var cleanupProgressRef = React.useRef(null);
|
|
54967
|
+
|
|
54968
|
+
// Reused device-code OAuth state machine (same hook AppUpdatesModal
|
|
54969
|
+
// uses). `authFlow` carries the user code + verification URL once
|
|
54970
|
+
// initiateAuth fires; while non-null we render the polling panel.
|
|
54971
|
+
var _useRegistryAuth = useRegistryAuth(),
|
|
54972
|
+
isAuthenticating = _useRegistryAuth.isAuthenticating,
|
|
54973
|
+
authFlow = _useRegistryAuth.authFlow,
|
|
54974
|
+
authError = _useRegistryAuth.authError,
|
|
54975
|
+
initiateAuth = _useRegistryAuth.initiateAuth,
|
|
54976
|
+
cancelAuth = _useRegistryAuth.cancelAuth;
|
|
54829
54977
|
React.useEffect(function () {
|
|
54830
54978
|
if (open) {
|
|
54831
54979
|
setState(STATE.WELCOME);
|
|
@@ -54887,7 +55035,7 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54887
55035
|
})), [markCompletedAndClose, onDismiss]);
|
|
54888
55036
|
var handleInstall = React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
54889
55037
|
var _window$mainApi2, _window$mainApi2$onIn;
|
|
54890
|
-
var _window$mainApi3, _window$mainApi3$inst, result, _t2;
|
|
55038
|
+
var existing, _window$mainApi3, _window$mainApi3$inst, result, _t2;
|
|
54891
55039
|
return _regeneratorRuntime.wrap(function (_context3) {
|
|
54892
55040
|
while (1) switch (_context3.prev = _context3.next) {
|
|
54893
55041
|
case 0:
|
|
@@ -54899,6 +55047,24 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54899
55047
|
setState(STATE.ERROR);
|
|
54900
55048
|
return _context3.abrupt("return");
|
|
54901
55049
|
case 1:
|
|
55050
|
+
// Dedupe: if the user already has a Kitchen Sink workspace
|
|
55051
|
+
// installed from the registry, skip the install entirely and
|
|
55052
|
+
// route them to the existing one. Without this, the modal
|
|
55053
|
+
// could be re-triggered (e.g. after clearing the
|
|
55054
|
+
// onboarding.completed flag) and would silently create
|
|
55055
|
+
// "Kitchen Sink 2", "Kitchen Sink 3", etc.
|
|
55056
|
+
existing = findExistingKitchenSink(workspaces);
|
|
55057
|
+
if (!existing) {
|
|
55058
|
+
_context3.next = 2;
|
|
55059
|
+
break;
|
|
55060
|
+
}
|
|
55061
|
+
installResultRef.current = {
|
|
55062
|
+
success: true,
|
|
55063
|
+
workspace: existing
|
|
55064
|
+
};
|
|
55065
|
+
setState(STATE.DONE);
|
|
55066
|
+
return _context3.abrupt("return");
|
|
55067
|
+
case 2:
|
|
54902
55068
|
setState(STATE.INSTALLING);
|
|
54903
55069
|
setProgressItems([]);
|
|
54904
55070
|
setInstallError(null);
|
|
@@ -54926,42 +55092,49 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54926
55092
|
return next;
|
|
54927
55093
|
});
|
|
54928
55094
|
});
|
|
54929
|
-
_context3.prev =
|
|
54930
|
-
_context3.next =
|
|
55095
|
+
_context3.prev = 3;
|
|
55096
|
+
_context3.next = 4;
|
|
54931
55097
|
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, {});
|
|
54932
|
-
case
|
|
55098
|
+
case 4:
|
|
54933
55099
|
result = _context3.sent;
|
|
54934
55100
|
if (cleanupProgressRef.current) {
|
|
54935
55101
|
cleanupProgressRef.current();
|
|
54936
55102
|
cleanupProgressRef.current = null;
|
|
54937
55103
|
}
|
|
54938
55104
|
if (!(!result || !result.success)) {
|
|
54939
|
-
_context3.next =
|
|
55105
|
+
_context3.next = 6;
|
|
54940
55106
|
break;
|
|
54941
55107
|
}
|
|
55108
|
+
if (!(result !== null && result !== void 0 && result.authRequired)) {
|
|
55109
|
+
_context3.next = 5;
|
|
55110
|
+
break;
|
|
55111
|
+
}
|
|
55112
|
+
setState(STATE.AUTH_REQUIRED);
|
|
55113
|
+
return _context3.abrupt("return");
|
|
55114
|
+
case 5:
|
|
54942
55115
|
setInstallError((result === null || result === void 0 ? void 0 : result.error) || "Failed to install Kitchen Sink. Check your internet connection and try again.");
|
|
54943
55116
|
setState(STATE.ERROR);
|
|
54944
55117
|
return _context3.abrupt("return");
|
|
54945
|
-
case
|
|
55118
|
+
case 6:
|
|
54946
55119
|
installResultRef.current = result;
|
|
54947
55120
|
setState(STATE.DONE);
|
|
54948
|
-
_context3.next =
|
|
55121
|
+
_context3.next = 8;
|
|
54949
55122
|
break;
|
|
54950
|
-
case
|
|
54951
|
-
_context3.prev =
|
|
54952
|
-
_t2 = _context3["catch"](
|
|
55123
|
+
case 7:
|
|
55124
|
+
_context3.prev = 7;
|
|
55125
|
+
_t2 = _context3["catch"](3);
|
|
54953
55126
|
if (cleanupProgressRef.current) {
|
|
54954
55127
|
cleanupProgressRef.current();
|
|
54955
55128
|
cleanupProgressRef.current = null;
|
|
54956
55129
|
}
|
|
54957
55130
|
setInstallError((_t2 === null || _t2 === void 0 ? void 0 : _t2.message) || "Installation failed.");
|
|
54958
55131
|
setState(STATE.ERROR);
|
|
54959
|
-
case
|
|
55132
|
+
case 8:
|
|
54960
55133
|
case "end":
|
|
54961
55134
|
return _context3.stop();
|
|
54962
55135
|
}
|
|
54963
|
-
}, _callee3, null, [[
|
|
54964
|
-
})), [appId]);
|
|
55136
|
+
}, _callee3, null, [[3, 7]]);
|
|
55137
|
+
})), [appId, workspaces]);
|
|
54965
55138
|
var handleOpen = React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
|
|
54966
55139
|
var _installResultRef$cur;
|
|
54967
55140
|
var workspace;
|
|
@@ -54986,6 +55159,17 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54986
55159
|
handleInstall();
|
|
54987
55160
|
}, [handleInstall]);
|
|
54988
55161
|
|
|
55162
|
+
// From the AUTH_REQUIRED state: kick off device-code OAuth. The
|
|
55163
|
+
// hook opens the browser, polls in the background, and fires our
|
|
55164
|
+
// onAuthorized callback on success. We auto-retry the install
|
|
55165
|
+
// there so the user lands on the DONE state without a second
|
|
55166
|
+
// click.
|
|
55167
|
+
var handleSignIn = React.useCallback(function () {
|
|
55168
|
+
initiateAuth(function () {
|
|
55169
|
+
handleInstall();
|
|
55170
|
+
});
|
|
55171
|
+
}, [initiateAuth, handleInstall]);
|
|
55172
|
+
|
|
54989
55173
|
// The Modal dispatches setIsOpen(false) on Escape / backdrop click.
|
|
54990
55174
|
// Route any close attempt through handleSkip so the completion flag
|
|
54991
55175
|
// is always stamped (otherwise Escape would silently re-show the
|
|
@@ -55009,6 +55193,15 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
55009
55193
|
onInstall: handleInstall,
|
|
55010
55194
|
onSkip: handleSkip,
|
|
55011
55195
|
textMuted: textMuted
|
|
55196
|
+
}), state === STATE.AUTH_REQUIRED && /*#__PURE__*/jsxRuntime.jsx(AuthRequiredBody, {
|
|
55197
|
+
onSignIn: handleSignIn,
|
|
55198
|
+
onCancelAuth: cancelAuth,
|
|
55199
|
+
onSkip: handleSkip,
|
|
55200
|
+
isAuthenticating: isAuthenticating,
|
|
55201
|
+
authFlow: authFlow,
|
|
55202
|
+
authError: authError,
|
|
55203
|
+
textMuted: textMuted,
|
|
55204
|
+
borderPanel: borderPanel
|
|
55012
55205
|
}), state === STATE.INSTALLING && /*#__PURE__*/jsxRuntime.jsx(InstallingBody, {
|
|
55013
55206
|
items: progressItems,
|
|
55014
55207
|
borderPanel: borderPanel,
|
|
@@ -55038,11 +55231,13 @@ function WelcomeBody(_ref7) {
|
|
|
55038
55231
|
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Heading2, {
|
|
55039
55232
|
title: "Welcome to Dash"
|
|
55040
55233
|
})]
|
|
55041
|
-
}), /*#__PURE__*/jsxRuntime.
|
|
55234
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Paragraph, {
|
|
55042
55235
|
className: "".concat(textMuted, " mb-6"),
|
|
55043
|
-
children:
|
|
55044
|
-
children: "
|
|
55045
|
-
|
|
55236
|
+
children: /*#__PURE__*/jsxRuntime.jsxs("span", {
|
|
55237
|
+
children: ["Get started with the ", /*#__PURE__*/jsxRuntime.jsx("strong", {
|
|
55238
|
+
children: "Kitchen Sink"
|
|
55239
|
+
}), " 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."]
|
|
55240
|
+
})
|
|
55046
55241
|
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55047
55242
|
className: "flex items-center justify-end gap-3 mt-2",
|
|
55048
55243
|
children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
|
|
@@ -55203,6 +55398,153 @@ function ErrorBody(_ref1) {
|
|
|
55203
55398
|
})]
|
|
55204
55399
|
});
|
|
55205
55400
|
}
|
|
55401
|
+
function BenefitRow(_ref10) {
|
|
55402
|
+
var icon = _ref10.icon,
|
|
55403
|
+
title = _ref10.title,
|
|
55404
|
+
description = _ref10.description,
|
|
55405
|
+
textMuted = _ref10.textMuted;
|
|
55406
|
+
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55407
|
+
className: "flex items-start gap-3",
|
|
55408
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
55409
|
+
className: "flex-shrink-0 w-7 h-7 flex items-center justify-center mt-0.5",
|
|
55410
|
+
children: /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
|
|
55411
|
+
icon: icon,
|
|
55412
|
+
className: "text-base opacity-70"
|
|
55413
|
+
})
|
|
55414
|
+
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55415
|
+
className: "flex flex-col",
|
|
55416
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("span", {
|
|
55417
|
+
className: "text-sm font-medium",
|
|
55418
|
+
children: title
|
|
55419
|
+
}), /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
55420
|
+
className: "text-xs ".concat(textMuted),
|
|
55421
|
+
children: description
|
|
55422
|
+
})]
|
|
55423
|
+
})]
|
|
55424
|
+
});
|
|
55425
|
+
}
|
|
55426
|
+
function AuthRequiredBody(_ref11) {
|
|
55427
|
+
var onSignIn = _ref11.onSignIn,
|
|
55428
|
+
onCancelAuth = _ref11.onCancelAuth,
|
|
55429
|
+
onSkip = _ref11.onSkip,
|
|
55430
|
+
isAuthenticating = _ref11.isAuthenticating,
|
|
55431
|
+
authFlow = _ref11.authFlow,
|
|
55432
|
+
authError = _ref11.authError,
|
|
55433
|
+
textMuted = _ref11.textMuted,
|
|
55434
|
+
borderPanel = _ref11.borderPanel;
|
|
55435
|
+
// While the device-code flow is polling, swap the benefits panel
|
|
55436
|
+
// for the user-code + verification-URL display so the user knows
|
|
55437
|
+
// what to enter in the browser tab we just opened.
|
|
55438
|
+
if (isAuthenticating && authFlow) {
|
|
55439
|
+
return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
55440
|
+
children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55441
|
+
className: "flex items-center gap-3 mb-2",
|
|
55442
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
|
|
55443
|
+
icon: "circle-notch",
|
|
55444
|
+
className: "text-2xl animate-spin"
|
|
55445
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Heading2, {
|
|
55446
|
+
title: "Waiting for browser sign-in"
|
|
55447
|
+
})]
|
|
55448
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Paragraph, {
|
|
55449
|
+
className: "".concat(textMuted, " mb-4"),
|
|
55450
|
+
children: /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
55451
|
+
children: "We opened a browser tab where you can sign in to the Dash Registry. Enter this code if prompted:"
|
|
55452
|
+
})
|
|
55453
|
+
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55454
|
+
className: "border ".concat(borderPanel, " rounded-md p-4 mb-4 text-center"),
|
|
55455
|
+
"data-testid": "onboarding-auth-user-code",
|
|
55456
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
55457
|
+
className: "text-2xl font-mono tracking-widest",
|
|
55458
|
+
children: authFlow.userCode || "—"
|
|
55459
|
+
}), /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
55460
|
+
className: "text-xs ".concat(textMuted, " mt-2 break-all"),
|
|
55461
|
+
children: authFlow.verificationUrlComplete || authFlow.verificationUrl || ""
|
|
55462
|
+
})]
|
|
55463
|
+
}), /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
55464
|
+
className: "flex items-center justify-end gap-3",
|
|
55465
|
+
children: /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
|
|
55466
|
+
onClick: onCancelAuth,
|
|
55467
|
+
title: "Cancel",
|
|
55468
|
+
textSize: "text-sm",
|
|
55469
|
+
padding: "py-2 px-4",
|
|
55470
|
+
backgroundColor: "bg-gray-700",
|
|
55471
|
+
textColor: "text-gray-300",
|
|
55472
|
+
hoverTextColor: "hover:text-white",
|
|
55473
|
+
hoverBackgroundColor: "hover:bg-gray-600",
|
|
55474
|
+
"data-testid": "onboarding-auth-cancel-button"
|
|
55475
|
+
})
|
|
55476
|
+
})]
|
|
55477
|
+
});
|
|
55478
|
+
}
|
|
55479
|
+
return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
55480
|
+
children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55481
|
+
className: "flex items-center gap-3 mb-2",
|
|
55482
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
|
|
55483
|
+
icon: "user-plus",
|
|
55484
|
+
className: "text-2xl"
|
|
55485
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Heading2, {
|
|
55486
|
+
title: "Sign in to the Dash Registry"
|
|
55487
|
+
})]
|
|
55488
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Paragraph, {
|
|
55489
|
+
className: "".concat(textMuted, " mb-5"),
|
|
55490
|
+
children: /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
55491
|
+
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."
|
|
55492
|
+
})
|
|
55493
|
+
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55494
|
+
className: "grid grid-cols-1 sm:grid-cols-2 gap-4 mb-6",
|
|
55495
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(BenefitRow, {
|
|
55496
|
+
icon: "cube",
|
|
55497
|
+
title: "Install widgets",
|
|
55498
|
+
description: "Browse and one-click install community widgets",
|
|
55499
|
+
textMuted: textMuted
|
|
55500
|
+
}), /*#__PURE__*/jsxRuntime.jsx(BenefitRow, {
|
|
55501
|
+
icon: "table-cells",
|
|
55502
|
+
title: "Discover dashboards",
|
|
55503
|
+
description: "Like Kitchen Sink \u2014 curated starters built by others",
|
|
55504
|
+
textMuted: textMuted
|
|
55505
|
+
}), /*#__PURE__*/jsxRuntime.jsx(BenefitRow, {
|
|
55506
|
+
icon: "palette",
|
|
55507
|
+
title: "Apply themes",
|
|
55508
|
+
description: "Community-built themes for any taste",
|
|
55509
|
+
textMuted: textMuted
|
|
55510
|
+
}), /*#__PURE__*/jsxRuntime.jsx(BenefitRow, {
|
|
55511
|
+
icon: "upload",
|
|
55512
|
+
title: "Publish your own",
|
|
55513
|
+
description: "Share your widgets and dashboards with the Dash community",
|
|
55514
|
+
textMuted: textMuted
|
|
55515
|
+
})]
|
|
55516
|
+
}), authError && /*#__PURE__*/jsxRuntime.jsx(DashReact.Paragraph, {
|
|
55517
|
+
className: "text-red-400 mb-4",
|
|
55518
|
+
children: /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
55519
|
+
children: authError
|
|
55520
|
+
})
|
|
55521
|
+
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55522
|
+
className: "flex items-center justify-end gap-3 mt-2",
|
|
55523
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
|
|
55524
|
+
onClick: onSkip,
|
|
55525
|
+
title: "Skip for now",
|
|
55526
|
+
textSize: "text-sm",
|
|
55527
|
+
padding: "py-2 px-4",
|
|
55528
|
+
backgroundColor: "bg-gray-700",
|
|
55529
|
+
textColor: "text-gray-300",
|
|
55530
|
+
hoverTextColor: "hover:text-white",
|
|
55531
|
+
hoverBackgroundColor: "hover:bg-gray-600",
|
|
55532
|
+
"data-testid": "onboarding-auth-skip-button"
|
|
55533
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
|
|
55534
|
+
onClick: onSignIn,
|
|
55535
|
+
title: "Sign in to Registry",
|
|
55536
|
+
textSize: "text-sm",
|
|
55537
|
+
padding: "py-2 px-4",
|
|
55538
|
+
backgroundColor: "bg-blue-600",
|
|
55539
|
+
textColor: "text-white",
|
|
55540
|
+
hoverTextColor: "hover:text-white",
|
|
55541
|
+
hoverBackgroundColor: "hover:bg-blue-500",
|
|
55542
|
+
icon: "arrow-up-right-from-square",
|
|
55543
|
+
"data-testid": "onboarding-auth-signin-button"
|
|
55544
|
+
})]
|
|
55545
|
+
})]
|
|
55546
|
+
});
|
|
55547
|
+
}
|
|
55206
55548
|
|
|
55207
55549
|
var DashCommandPalette = function DashCommandPalette(_ref) {
|
|
55208
55550
|
var isOpen = _ref.isOpen,
|
|
@@ -61216,7 +61558,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61216
61558
|
onboardingCheckedRef.current = true;
|
|
61217
61559
|
var cancelled = false;
|
|
61218
61560
|
_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
61219
|
-
var _window$mainApi, _window$mainApi$getSt, status;
|
|
61561
|
+
var _window$mainApi, _window$mainApi$getSt, status, alreadyHasKitchenSink;
|
|
61220
61562
|
return _regeneratorRuntime.wrap(function (_context) {
|
|
61221
61563
|
while (1) switch (_context.prev = _context.next) {
|
|
61222
61564
|
case 0:
|
|
@@ -61231,7 +61573,20 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61231
61573
|
}
|
|
61232
61574
|
return _context.abrupt("return");
|
|
61233
61575
|
case 2:
|
|
61234
|
-
|
|
61576
|
+
// Defense-in-depth: even if `workspaceConfig.length === 0`
|
|
61577
|
+
// briefly reads true during a race between `isLoadingWorkspaces`
|
|
61578
|
+
// and the workspace array populating, don't show the modal
|
|
61579
|
+
// if the user already has a Kitchen Sink dashboard installed
|
|
61580
|
+
// from the registry. Same dedupe rule the modal's install
|
|
61581
|
+
// path applies.
|
|
61582
|
+
alreadyHasKitchenSink = workspaceConfig.some(function (ws) {
|
|
61583
|
+
var _ws$_dashboardConfig;
|
|
61584
|
+
var pkg = ws === null || ws === void 0 || (_ws$_dashboardConfig = ws._dashboardConfig) === null || _ws$_dashboardConfig === void 0 ? void 0 : _ws$_dashboardConfig.registryPackage;
|
|
61585
|
+
if (typeof pkg !== "string") return false;
|
|
61586
|
+
var trailing = pkg.includes("/") ? pkg.split("/").pop() : pkg;
|
|
61587
|
+
return trailing === "kitchen-sink";
|
|
61588
|
+
});
|
|
61589
|
+
if (status && status.completed === false && workspaceConfig.length === 0 && !alreadyHasKitchenSink) {
|
|
61235
61590
|
setIsOnboardingOpen(true);
|
|
61236
61591
|
} else {
|
|
61237
61592
|
setIsOnboardingOpen(false);
|
|
@@ -63035,6 +63390,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
63035
63390
|
}), /*#__PURE__*/jsxRuntime.jsx(OnboardingModal, {
|
|
63036
63391
|
open: isOnboardingOpen === true,
|
|
63037
63392
|
appId: credentials === null || credentials === void 0 ? void 0 : credentials.appId,
|
|
63393
|
+
workspaces: workspaceConfig,
|
|
63038
63394
|
onDismiss: function onDismiss() {
|
|
63039
63395
|
return setIsOnboardingOpen(false);
|
|
63040
63396
|
},
|