@trops/dash-core 0.1.603 → 0.1.605
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 +397 -31
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +397 -31
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -2549,6 +2549,27 @@ var ThemeWrapper = function ThemeWrapper(_ref) {
|
|
|
2549
2549
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2550
2550
|
}, [chosenTheme, themeVariant, themeName, themesForApplication, rawThemes]);
|
|
2551
2551
|
|
|
2552
|
+
// Broadcast the app-level theme to a SEPARATE global so
|
|
2553
|
+
// components rendered OUTSIDE the React theme tree
|
|
2554
|
+
// (WidgetBuilderModal, AppUpdatesModal — they live as siblings
|
|
2555
|
+
// of DashboardStage in dash-electron's Dash.js render) can fall
|
|
2556
|
+
// back to it when no dashboard-specific override is in play.
|
|
2557
|
+
//
|
|
2558
|
+
// We can't share the same global with DashboardThemeProvider's
|
|
2559
|
+
// per-workspace broadcast because React commits child effects
|
|
2560
|
+
// BEFORE parent effects — ThemeWrapper would always run last
|
|
2561
|
+
// and silently overwrite the workspace theme. Two separate
|
|
2562
|
+
// globals avoid the race: consumers read
|
|
2563
|
+
// `__dashThemeContext` (workspace) first, fall back to
|
|
2564
|
+
// `__dashAppThemeContext` (app-level) when no workspace is open.
|
|
2565
|
+
useEffect(function () {
|
|
2566
|
+
if (typeof window === "undefined") return undefined;
|
|
2567
|
+
if (contextValue !== null && contextValue !== void 0 && contextValue.currentTheme) {
|
|
2568
|
+
window.__dashAppThemeContext = contextValue;
|
|
2569
|
+
window.dispatchEvent(new Event("dash:theme-changed"));
|
|
2570
|
+
}
|
|
2571
|
+
}, [contextValue]);
|
|
2572
|
+
|
|
2552
2573
|
// Write the active theme's CSS custom properties to :root so any
|
|
2553
2574
|
// hex-channel tokens (`bg-[var(--primary-700)]` etc. emitted by
|
|
2554
2575
|
// ThemeModel) resolve app-wide. Without this, saving a hex theme
|
|
@@ -5725,6 +5746,45 @@ function ThemeBroadcast(_ref) {
|
|
|
5725
5746
|
return null;
|
|
5726
5747
|
}
|
|
5727
5748
|
|
|
5749
|
+
/**
|
|
5750
|
+
* Writes the dashboard theme's cssVars to `:root` while mounted, and
|
|
5751
|
+
* restores the previous values on unmount / theme switch.
|
|
5752
|
+
*
|
|
5753
|
+
* ThemeWrapper writes the APP theme's cssVars at the top of the tree.
|
|
5754
|
+
* Without this helper, a dashboard that overrides the app theme with a
|
|
5755
|
+
* hex-channel theme (like "Slack Generic") would carry the right class
|
|
5756
|
+
* names (`bg-[var(--primary-900)]`) but the `--primary-900` variable
|
|
5757
|
+
* on :root would still be the APP theme's value — or undefined if the
|
|
5758
|
+
* app theme is named-family. Hex-themed surfaces then render with no
|
|
5759
|
+
* background. This effect closes that gap by promoting the dashboard
|
|
5760
|
+
* theme's cssVars to :root for the duration of its mount.
|
|
5761
|
+
*/
|
|
5762
|
+
function DashboardCssVarsBridge(_ref2) {
|
|
5763
|
+
var cssVars = _ref2.cssVars;
|
|
5764
|
+
useEffect(function () {
|
|
5765
|
+
if (!cssVars || typeof document === "undefined") return undefined;
|
|
5766
|
+
var root = document.documentElement;
|
|
5767
|
+
var previous = {};
|
|
5768
|
+
var keys = Object.keys(cssVars);
|
|
5769
|
+
for (var _i = 0, _keys = keys; _i < _keys.length; _i++) {
|
|
5770
|
+
var key = _keys[_i];
|
|
5771
|
+
previous[key] = root.style.getPropertyValue(key);
|
|
5772
|
+
root.style.setProperty(key, cssVars[key]);
|
|
5773
|
+
}
|
|
5774
|
+
return function () {
|
|
5775
|
+
for (var _i2 = 0, _keys2 = keys; _i2 < _keys2.length; _i2++) {
|
|
5776
|
+
var _key = _keys2[_i2];
|
|
5777
|
+
if (previous[_key]) {
|
|
5778
|
+
root.style.setProperty(_key, previous[_key]);
|
|
5779
|
+
} else {
|
|
5780
|
+
root.style.removeProperty(_key);
|
|
5781
|
+
}
|
|
5782
|
+
}
|
|
5783
|
+
};
|
|
5784
|
+
}, [cssVars]);
|
|
5785
|
+
return null;
|
|
5786
|
+
}
|
|
5787
|
+
|
|
5728
5788
|
/**
|
|
5729
5789
|
* DashboardThemeProvider
|
|
5730
5790
|
*
|
|
@@ -5735,9 +5795,10 @@ function ThemeBroadcast(_ref) {
|
|
|
5735
5795
|
* App chrome (navbar, tab bar, sidebar) stays OUTSIDE this wrapper
|
|
5736
5796
|
* and keeps the app theme.
|
|
5737
5797
|
*/
|
|
5738
|
-
var DashboardThemeProvider = function DashboardThemeProvider(
|
|
5739
|
-
var
|
|
5740
|
-
|
|
5798
|
+
var DashboardThemeProvider = function DashboardThemeProvider(_ref3) {
|
|
5799
|
+
var _contextValue$current;
|
|
5800
|
+
var themeKey = _ref3.themeKey,
|
|
5801
|
+
children = _ref3.children;
|
|
5741
5802
|
var parentContext = useContext(ThemeContext);
|
|
5742
5803
|
var themes = parentContext.themes,
|
|
5743
5804
|
themeVariant = parentContext.themeVariant;
|
|
@@ -5769,6 +5830,8 @@ var DashboardThemeProvider = function DashboardThemeProvider(_ref2) {
|
|
|
5769
5830
|
value: contextValue,
|
|
5770
5831
|
children: [/*#__PURE__*/jsx(ThemeBroadcast, {
|
|
5771
5832
|
ctx: contextValue
|
|
5833
|
+
}), /*#__PURE__*/jsx(DashboardCssVarsBridge, {
|
|
5834
|
+
cssVars: contextValue === null || contextValue === void 0 || (_contextValue$current = contextValue.currentTheme) === null || _contextValue$current === void 0 ? void 0 : _contextValue$current.cssVars
|
|
5772
5835
|
}), children]
|
|
5773
5836
|
});
|
|
5774
5837
|
};
|
|
@@ -28958,6 +29021,36 @@ var WorkspaceModel = function WorkspaceModel(workspaceItem) {
|
|
|
28958
29021
|
function ownKeys$H(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; }
|
|
28959
29022
|
function _objectSpread$H(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys$H(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys$H(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
28960
29023
|
|
|
29024
|
+
/**
|
|
29025
|
+
* Last-resort family for ANY channel whose value can't be resolved
|
|
29026
|
+
* (unknown name, missing palette entry, missing shade, …). Picked
|
|
29027
|
+
* because it's universally safelist-covered, has every shade from
|
|
29028
|
+
* 50..950, and is visually neutral — so a misconfigured theme
|
|
29029
|
+
* renders "muted" rather than blank/transparent.
|
|
29030
|
+
*
|
|
29031
|
+
* Slack Generic etc. exposed this: when a channel value was missing
|
|
29032
|
+
* or unrecognized, ThemeModel silently emitted `bg-undefined-700`
|
|
29033
|
+
* (not in any safelist) → Tailwind dropped the class → the
|
|
29034
|
+
* dropdown popover rendered transparent. Falling back here means
|
|
29035
|
+
* no token can be "missing" by the time `getStylesForItem` reads it.
|
|
29036
|
+
*/
|
|
29037
|
+
var FALLBACK_FAMILY = "gray";
|
|
29038
|
+
|
|
29039
|
+
/**
|
|
29040
|
+
* Resolve a channel value to a safelist-covered Tailwind family
|
|
29041
|
+
* name. Returns the original value when it's a hex (the caller
|
|
29042
|
+
* handles those via CSS variables) or a recognized palette family;
|
|
29043
|
+
* otherwise returns FALLBACK_FAMILY so the resulting class always
|
|
29044
|
+
* renders.
|
|
29045
|
+
*/
|
|
29046
|
+
function resolveChannelFamily(channelValue) {
|
|
29047
|
+
if (isHexColor$1(channelValue)) return channelValue;
|
|
29048
|
+
if (typeof channelValue === "string" && channelValue.length > 0 && TAILWIND_PALETTE && TAILWIND_PALETTE[channelValue]) {
|
|
29049
|
+
return channelValue;
|
|
29050
|
+
}
|
|
29051
|
+
return FALLBACK_FAMILY;
|
|
29052
|
+
}
|
|
29053
|
+
|
|
28961
29054
|
/**
|
|
28962
29055
|
* getNextLevel
|
|
28963
29056
|
* Need to generate the levels for tailwind
|
|
@@ -28976,6 +29069,11 @@ function invert(shade) {
|
|
|
28976
29069
|
* shade. Routes to the arbitrary-value syntax (`bg-[var(--type-shade)]`)
|
|
28977
29070
|
* when the channel's value is a hex.
|
|
28978
29071
|
*
|
|
29072
|
+
* Layer 1 fallback (audit follow-up to the Slack Generic bug): if
|
|
29073
|
+
* `channelValue` isn't a hex AND isn't a recognized Tailwind palette
|
|
29074
|
+
* family, fall back to FALLBACK_FAMILY so the emitted class is
|
|
29075
|
+
* always safelist-covered and never resolves to `bg-undefined-700`.
|
|
29076
|
+
*
|
|
28979
29077
|
* @param {"bg"|"text"|"border"} prefix
|
|
28980
29078
|
* @param {string} type channel name (primary | secondary | …)
|
|
28981
29079
|
* @param {number} shade tailwind shade (100..950)
|
|
@@ -28985,10 +29083,11 @@ function invert(shade) {
|
|
|
28985
29083
|
function classFor(prefix, type, shade, channelValue) {
|
|
28986
29084
|
var hover = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
|
|
28987
29085
|
var h = hover ? "hover:" : "";
|
|
28988
|
-
|
|
29086
|
+
var resolved = resolveChannelFamily(channelValue);
|
|
29087
|
+
if (isHexColor$1(resolved)) {
|
|
28989
29088
|
return "".concat(h).concat(prefix, "-[var(--").concat(type, "-").concat(shade, ")]");
|
|
28990
29089
|
}
|
|
28991
|
-
return "".concat(h).concat(prefix, "-").concat(
|
|
29090
|
+
return "".concat(h).concat(prefix, "-").concat(resolved, "-").concat(shade);
|
|
28992
29091
|
}
|
|
28993
29092
|
|
|
28994
29093
|
/**
|
|
@@ -29001,8 +29100,10 @@ function classFor(prefix, type, shade, channelValue) {
|
|
|
29001
29100
|
* produce a `var(--{type}-{shade})` reference that resolves against
|
|
29002
29101
|
* the CSS custom properties ThemePreviewProvider writes to :root.
|
|
29003
29102
|
*
|
|
29004
|
-
*
|
|
29005
|
-
*
|
|
29103
|
+
* Layer 1 fallback: when the channel value or shade can't be
|
|
29104
|
+
* resolved, fall back to FALLBACK_FAMILY's shade so cssValue is
|
|
29105
|
+
* never null. Pairs with classFor's same fallback to guarantee
|
|
29106
|
+
* every (type, shade) tuple yields a renderable token.
|
|
29006
29107
|
*/
|
|
29007
29108
|
function cssValueFor(type, shade, channelValue) {
|
|
29008
29109
|
if (isHexColor$1(channelValue)) {
|
|
@@ -29015,12 +29116,17 @@ function cssValueFor(type, shade, channelValue) {
|
|
|
29015
29116
|
var _hex = shades[shade] || shades[String(shade)];
|
|
29016
29117
|
if (_hex) return _hex;
|
|
29017
29118
|
}
|
|
29018
|
-
return
|
|
29119
|
+
return fallbackCssValue(shade);
|
|
29019
29120
|
}
|
|
29020
29121
|
var family = TAILWIND_PALETTE && TAILWIND_PALETTE[channelValue];
|
|
29021
|
-
if (!family) return
|
|
29122
|
+
if (!family) return fallbackCssValue(shade);
|
|
29022
29123
|
var hex = family[shade] || family[String(shade)];
|
|
29023
|
-
return hex ||
|
|
29124
|
+
return hex || fallbackCssValue(shade);
|
|
29125
|
+
}
|
|
29126
|
+
function fallbackCssValue(shade) {
|
|
29127
|
+
var fallback = TAILWIND_PALETTE && TAILWIND_PALETTE[FALLBACK_FAMILY];
|
|
29128
|
+
if (!fallback) return null;
|
|
29129
|
+
return fallback[shade] || fallback[String(shade)] || null;
|
|
29024
29130
|
}
|
|
29025
29131
|
function gradientFor(direction, type, fromShade, viaShade, toShade, channelValue) {
|
|
29026
29132
|
if (isHexColor$1(channelValue)) {
|
|
@@ -35205,11 +35311,25 @@ var ChannelEditorModal = function ChannelEditorModal(_ref) {
|
|
|
35205
35311
|
var nearest = useMemo(function () {
|
|
35206
35312
|
return nearestSwatch(selectedHex, families);
|
|
35207
35313
|
}, [selectedHex, families]);
|
|
35314
|
+
|
|
35315
|
+
// Auto-switch the family tab when the underlying selected color
|
|
35316
|
+
// changes (user picked a different channel/shade or the theme
|
|
35317
|
+
// mutated). Track the last hex we synced for so we don't fight
|
|
35318
|
+
// the user's manual tab clicks — without this guard, every
|
|
35319
|
+
// re-render rebuilds `nearest` as a new object reference and the
|
|
35320
|
+
// effect snaps activeFamily back to the family containing the
|
|
35321
|
+
// current color, making it impossible to browse other families.
|
|
35322
|
+
var lastSyncedHexRef = useRef(null);
|
|
35208
35323
|
useEffect(function () {
|
|
35209
|
-
if (!isOpen)
|
|
35324
|
+
if (!isOpen) {
|
|
35325
|
+
lastSyncedHexRef.current = null;
|
|
35326
|
+
return;
|
|
35327
|
+
}
|
|
35328
|
+
if (lastSyncedHexRef.current === selectedHex) return;
|
|
35329
|
+
lastSyncedHexRef.current = selectedHex;
|
|
35210
35330
|
if (nearest) setActiveFamily(nearest.family);
|
|
35211
35331
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
35212
|
-
}, [isOpen, nearest]);
|
|
35332
|
+
}, [isOpen, selectedHex, nearest]);
|
|
35213
35333
|
function expandChannel(channelKey) {
|
|
35214
35334
|
setActiveChannel(channelKey);
|
|
35215
35335
|
setActiveSlot("base");
|
|
@@ -54892,13 +55012,41 @@ var DashboardLoaderModal = function DashboardLoaderModal(_ref) {
|
|
|
54892
55012
|
var KITCHEN_SINK_PACKAGE = "trops/kitchen-sink";
|
|
54893
55013
|
var STATE = {
|
|
54894
55014
|
WELCOME: "welcome",
|
|
55015
|
+
// AUTH_REQUIRED replaces the generic "Install Failed" screen when
|
|
55016
|
+
// the registry returns `authRequired: true`. Surfaces a
|
|
55017
|
+
// benefits-driven sign-in CTA instead of asking the user to
|
|
55018
|
+
// figure out why install died.
|
|
55019
|
+
AUTH_REQUIRED: "auth-required",
|
|
54895
55020
|
INSTALLING: "installing",
|
|
54896
55021
|
DONE: "done",
|
|
54897
55022
|
ERROR: "error"
|
|
54898
55023
|
};
|
|
55024
|
+
|
|
55025
|
+
/**
|
|
55026
|
+
* Returns the first workspace that was installed from the Kitchen
|
|
55027
|
+
* Sink package, or null. Used for the modal's dedupe check so we
|
|
55028
|
+
* never create a second Kitchen Sink when one already exists.
|
|
55029
|
+
*
|
|
55030
|
+
* Workspaces installed via the registry carry a
|
|
55031
|
+
* `_dashboardConfig.registryPackage` field — historically the
|
|
55032
|
+
* unscoped name ("kitchen-sink"), more recently the scoped form
|
|
55033
|
+
* ("trops/kitchen-sink"). Match on either trailing segment.
|
|
55034
|
+
*/
|
|
55035
|
+
function findExistingKitchenSink(workspaces) {
|
|
55036
|
+
if (!Array.isArray(workspaces)) return null;
|
|
55037
|
+
return workspaces.find(function (ws) {
|
|
55038
|
+
var _ws$_dashboardConfig;
|
|
55039
|
+
var pkg = ws === null || ws === void 0 || (_ws$_dashboardConfig = ws._dashboardConfig) === null || _ws$_dashboardConfig === void 0 ? void 0 : _ws$_dashboardConfig.registryPackage;
|
|
55040
|
+
if (typeof pkg !== "string") return false;
|
|
55041
|
+
var trailing = pkg.includes("/") ? pkg.split("/").pop() : pkg;
|
|
55042
|
+
return trailing === "kitchen-sink";
|
|
55043
|
+
}) || null;
|
|
55044
|
+
}
|
|
54899
55045
|
var OnboardingModal = function OnboardingModal(_ref) {
|
|
54900
55046
|
var open = _ref.open,
|
|
54901
55047
|
appId = _ref.appId,
|
|
55048
|
+
_ref$workspaces = _ref.workspaces,
|
|
55049
|
+
workspaces = _ref$workspaces === void 0 ? [] : _ref$workspaces,
|
|
54902
55050
|
onOpenDashboard = _ref.onOpenDashboard,
|
|
54903
55051
|
onDismiss = _ref.onDismiss,
|
|
54904
55052
|
onComplete = _ref.onComplete;
|
|
@@ -54918,6 +55066,16 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54918
55066
|
setInstallError = _useState6[1];
|
|
54919
55067
|
var installResultRef = useRef(null);
|
|
54920
55068
|
var cleanupProgressRef = useRef(null);
|
|
55069
|
+
|
|
55070
|
+
// Reused device-code OAuth state machine (same hook AppUpdatesModal
|
|
55071
|
+
// uses). `authFlow` carries the user code + verification URL once
|
|
55072
|
+
// initiateAuth fires; while non-null we render the polling panel.
|
|
55073
|
+
var _useRegistryAuth = useRegistryAuth(),
|
|
55074
|
+
isAuthenticating = _useRegistryAuth.isAuthenticating,
|
|
55075
|
+
authFlow = _useRegistryAuth.authFlow,
|
|
55076
|
+
authError = _useRegistryAuth.authError,
|
|
55077
|
+
initiateAuth = _useRegistryAuth.initiateAuth,
|
|
55078
|
+
cancelAuth = _useRegistryAuth.cancelAuth;
|
|
54921
55079
|
useEffect(function () {
|
|
54922
55080
|
if (open) {
|
|
54923
55081
|
setState(STATE.WELCOME);
|
|
@@ -54979,7 +55137,7 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54979
55137
|
})), [markCompletedAndClose, onDismiss]);
|
|
54980
55138
|
var handleInstall = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
54981
55139
|
var _window$mainApi2, _window$mainApi2$onIn;
|
|
54982
|
-
var _window$mainApi3, _window$mainApi3$inst, result, _t2;
|
|
55140
|
+
var existing, _window$mainApi3, _window$mainApi3$inst, result, _t2;
|
|
54983
55141
|
return _regeneratorRuntime.wrap(function (_context3) {
|
|
54984
55142
|
while (1) switch (_context3.prev = _context3.next) {
|
|
54985
55143
|
case 0:
|
|
@@ -54991,6 +55149,24 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54991
55149
|
setState(STATE.ERROR);
|
|
54992
55150
|
return _context3.abrupt("return");
|
|
54993
55151
|
case 1:
|
|
55152
|
+
// Dedupe: if the user already has a Kitchen Sink workspace
|
|
55153
|
+
// installed from the registry, skip the install entirely and
|
|
55154
|
+
// route them to the existing one. Without this, the modal
|
|
55155
|
+
// could be re-triggered (e.g. after clearing the
|
|
55156
|
+
// onboarding.completed flag) and would silently create
|
|
55157
|
+
// "Kitchen Sink 2", "Kitchen Sink 3", etc.
|
|
55158
|
+
existing = findExistingKitchenSink(workspaces);
|
|
55159
|
+
if (!existing) {
|
|
55160
|
+
_context3.next = 2;
|
|
55161
|
+
break;
|
|
55162
|
+
}
|
|
55163
|
+
installResultRef.current = {
|
|
55164
|
+
success: true,
|
|
55165
|
+
workspace: existing
|
|
55166
|
+
};
|
|
55167
|
+
setState(STATE.DONE);
|
|
55168
|
+
return _context3.abrupt("return");
|
|
55169
|
+
case 2:
|
|
54994
55170
|
setState(STATE.INSTALLING);
|
|
54995
55171
|
setProgressItems([]);
|
|
54996
55172
|
setInstallError(null);
|
|
@@ -55018,42 +55194,49 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
55018
55194
|
return next;
|
|
55019
55195
|
});
|
|
55020
55196
|
});
|
|
55021
|
-
_context3.prev =
|
|
55022
|
-
_context3.next =
|
|
55197
|
+
_context3.prev = 3;
|
|
55198
|
+
_context3.next = 4;
|
|
55023
55199
|
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, {});
|
|
55024
|
-
case
|
|
55200
|
+
case 4:
|
|
55025
55201
|
result = _context3.sent;
|
|
55026
55202
|
if (cleanupProgressRef.current) {
|
|
55027
55203
|
cleanupProgressRef.current();
|
|
55028
55204
|
cleanupProgressRef.current = null;
|
|
55029
55205
|
}
|
|
55030
55206
|
if (!(!result || !result.success)) {
|
|
55031
|
-
_context3.next =
|
|
55207
|
+
_context3.next = 6;
|
|
55208
|
+
break;
|
|
55209
|
+
}
|
|
55210
|
+
if (!(result !== null && result !== void 0 && result.authRequired)) {
|
|
55211
|
+
_context3.next = 5;
|
|
55032
55212
|
break;
|
|
55033
55213
|
}
|
|
55214
|
+
setState(STATE.AUTH_REQUIRED);
|
|
55215
|
+
return _context3.abrupt("return");
|
|
55216
|
+
case 5:
|
|
55034
55217
|
setInstallError((result === null || result === void 0 ? void 0 : result.error) || "Failed to install Kitchen Sink. Check your internet connection and try again.");
|
|
55035
55218
|
setState(STATE.ERROR);
|
|
55036
55219
|
return _context3.abrupt("return");
|
|
55037
|
-
case
|
|
55220
|
+
case 6:
|
|
55038
55221
|
installResultRef.current = result;
|
|
55039
55222
|
setState(STATE.DONE);
|
|
55040
|
-
_context3.next =
|
|
55223
|
+
_context3.next = 8;
|
|
55041
55224
|
break;
|
|
55042
|
-
case
|
|
55043
|
-
_context3.prev =
|
|
55044
|
-
_t2 = _context3["catch"](
|
|
55225
|
+
case 7:
|
|
55226
|
+
_context3.prev = 7;
|
|
55227
|
+
_t2 = _context3["catch"](3);
|
|
55045
55228
|
if (cleanupProgressRef.current) {
|
|
55046
55229
|
cleanupProgressRef.current();
|
|
55047
55230
|
cleanupProgressRef.current = null;
|
|
55048
55231
|
}
|
|
55049
55232
|
setInstallError((_t2 === null || _t2 === void 0 ? void 0 : _t2.message) || "Installation failed.");
|
|
55050
55233
|
setState(STATE.ERROR);
|
|
55051
|
-
case
|
|
55234
|
+
case 8:
|
|
55052
55235
|
case "end":
|
|
55053
55236
|
return _context3.stop();
|
|
55054
55237
|
}
|
|
55055
|
-
}, _callee3, null, [[
|
|
55056
|
-
})), [appId]);
|
|
55238
|
+
}, _callee3, null, [[3, 7]]);
|
|
55239
|
+
})), [appId, workspaces]);
|
|
55057
55240
|
var handleOpen = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
|
|
55058
55241
|
var _installResultRef$cur;
|
|
55059
55242
|
var workspace;
|
|
@@ -55078,6 +55261,17 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
55078
55261
|
handleInstall();
|
|
55079
55262
|
}, [handleInstall]);
|
|
55080
55263
|
|
|
55264
|
+
// From the AUTH_REQUIRED state: kick off device-code OAuth. The
|
|
55265
|
+
// hook opens the browser, polls in the background, and fires our
|
|
55266
|
+
// onAuthorized callback on success. We auto-retry the install
|
|
55267
|
+
// there so the user lands on the DONE state without a second
|
|
55268
|
+
// click.
|
|
55269
|
+
var handleSignIn = useCallback(function () {
|
|
55270
|
+
initiateAuth(function () {
|
|
55271
|
+
handleInstall();
|
|
55272
|
+
});
|
|
55273
|
+
}, [initiateAuth, handleInstall]);
|
|
55274
|
+
|
|
55081
55275
|
// The Modal dispatches setIsOpen(false) on Escape / backdrop click.
|
|
55082
55276
|
// Route any close attempt through handleSkip so the completion flag
|
|
55083
55277
|
// is always stamped (otherwise Escape would silently re-show the
|
|
@@ -55101,6 +55295,15 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
55101
55295
|
onInstall: handleInstall,
|
|
55102
55296
|
onSkip: handleSkip,
|
|
55103
55297
|
textMuted: textMuted
|
|
55298
|
+
}), state === STATE.AUTH_REQUIRED && /*#__PURE__*/jsx(AuthRequiredBody, {
|
|
55299
|
+
onSignIn: handleSignIn,
|
|
55300
|
+
onCancelAuth: cancelAuth,
|
|
55301
|
+
onSkip: handleSkip,
|
|
55302
|
+
isAuthenticating: isAuthenticating,
|
|
55303
|
+
authFlow: authFlow,
|
|
55304
|
+
authError: authError,
|
|
55305
|
+
textMuted: textMuted,
|
|
55306
|
+
borderPanel: borderPanel
|
|
55104
55307
|
}), state === STATE.INSTALLING && /*#__PURE__*/jsx(InstallingBody, {
|
|
55105
55308
|
items: progressItems,
|
|
55106
55309
|
borderPanel: borderPanel,
|
|
@@ -55130,11 +55333,13 @@ function WelcomeBody(_ref7) {
|
|
|
55130
55333
|
}), /*#__PURE__*/jsx(Heading2, {
|
|
55131
55334
|
title: "Welcome to Dash"
|
|
55132
55335
|
})]
|
|
55133
|
-
}), /*#__PURE__*/
|
|
55336
|
+
}), /*#__PURE__*/jsx(Paragraph, {
|
|
55134
55337
|
className: "".concat(textMuted, " mb-6"),
|
|
55135
|
-
children:
|
|
55136
|
-
children: "
|
|
55137
|
-
|
|
55338
|
+
children: /*#__PURE__*/jsxs("span", {
|
|
55339
|
+
children: ["Get started with the ", /*#__PURE__*/jsx("strong", {
|
|
55340
|
+
children: "Kitchen Sink"
|
|
55341
|
+
}), " 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."]
|
|
55342
|
+
})
|
|
55138
55343
|
}), /*#__PURE__*/jsxs("div", {
|
|
55139
55344
|
className: "flex items-center justify-end gap-3 mt-2",
|
|
55140
55345
|
children: [/*#__PURE__*/jsx(Button, {
|
|
@@ -55295,6 +55500,153 @@ function ErrorBody(_ref1) {
|
|
|
55295
55500
|
})]
|
|
55296
55501
|
});
|
|
55297
55502
|
}
|
|
55503
|
+
function BenefitRow(_ref10) {
|
|
55504
|
+
var icon = _ref10.icon,
|
|
55505
|
+
title = _ref10.title,
|
|
55506
|
+
description = _ref10.description,
|
|
55507
|
+
textMuted = _ref10.textMuted;
|
|
55508
|
+
return /*#__PURE__*/jsxs("div", {
|
|
55509
|
+
className: "flex items-start gap-3",
|
|
55510
|
+
children: [/*#__PURE__*/jsx("div", {
|
|
55511
|
+
className: "flex-shrink-0 w-7 h-7 flex items-center justify-center mt-0.5",
|
|
55512
|
+
children: /*#__PURE__*/jsx(FontAwesomeIcon, {
|
|
55513
|
+
icon: icon,
|
|
55514
|
+
className: "text-base opacity-70"
|
|
55515
|
+
})
|
|
55516
|
+
}), /*#__PURE__*/jsxs("div", {
|
|
55517
|
+
className: "flex flex-col",
|
|
55518
|
+
children: [/*#__PURE__*/jsx("span", {
|
|
55519
|
+
className: "text-sm font-medium",
|
|
55520
|
+
children: title
|
|
55521
|
+
}), /*#__PURE__*/jsx("span", {
|
|
55522
|
+
className: "text-xs ".concat(textMuted),
|
|
55523
|
+
children: description
|
|
55524
|
+
})]
|
|
55525
|
+
})]
|
|
55526
|
+
});
|
|
55527
|
+
}
|
|
55528
|
+
function AuthRequiredBody(_ref11) {
|
|
55529
|
+
var onSignIn = _ref11.onSignIn,
|
|
55530
|
+
onCancelAuth = _ref11.onCancelAuth,
|
|
55531
|
+
onSkip = _ref11.onSkip,
|
|
55532
|
+
isAuthenticating = _ref11.isAuthenticating,
|
|
55533
|
+
authFlow = _ref11.authFlow,
|
|
55534
|
+
authError = _ref11.authError,
|
|
55535
|
+
textMuted = _ref11.textMuted,
|
|
55536
|
+
borderPanel = _ref11.borderPanel;
|
|
55537
|
+
// While the device-code flow is polling, swap the benefits panel
|
|
55538
|
+
// for the user-code + verification-URL display so the user knows
|
|
55539
|
+
// what to enter in the browser tab we just opened.
|
|
55540
|
+
if (isAuthenticating && authFlow) {
|
|
55541
|
+
return /*#__PURE__*/jsxs(Fragment, {
|
|
55542
|
+
children: [/*#__PURE__*/jsxs("div", {
|
|
55543
|
+
className: "flex items-center gap-3 mb-2",
|
|
55544
|
+
children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
|
|
55545
|
+
icon: "circle-notch",
|
|
55546
|
+
className: "text-2xl animate-spin"
|
|
55547
|
+
}), /*#__PURE__*/jsx(Heading2, {
|
|
55548
|
+
title: "Waiting for browser sign-in"
|
|
55549
|
+
})]
|
|
55550
|
+
}), /*#__PURE__*/jsx(Paragraph, {
|
|
55551
|
+
className: "".concat(textMuted, " mb-4"),
|
|
55552
|
+
children: /*#__PURE__*/jsx("span", {
|
|
55553
|
+
children: "We opened a browser tab where you can sign in to the Dash Registry. Enter this code if prompted:"
|
|
55554
|
+
})
|
|
55555
|
+
}), /*#__PURE__*/jsxs("div", {
|
|
55556
|
+
className: "border ".concat(borderPanel, " rounded-md p-4 mb-4 text-center"),
|
|
55557
|
+
"data-testid": "onboarding-auth-user-code",
|
|
55558
|
+
children: [/*#__PURE__*/jsx("div", {
|
|
55559
|
+
className: "text-2xl font-mono tracking-widest",
|
|
55560
|
+
children: authFlow.userCode || "—"
|
|
55561
|
+
}), /*#__PURE__*/jsx("div", {
|
|
55562
|
+
className: "text-xs ".concat(textMuted, " mt-2 break-all"),
|
|
55563
|
+
children: authFlow.verificationUrlComplete || authFlow.verificationUrl || ""
|
|
55564
|
+
})]
|
|
55565
|
+
}), /*#__PURE__*/jsx("div", {
|
|
55566
|
+
className: "flex items-center justify-end gap-3",
|
|
55567
|
+
children: /*#__PURE__*/jsx(Button, {
|
|
55568
|
+
onClick: onCancelAuth,
|
|
55569
|
+
title: "Cancel",
|
|
55570
|
+
textSize: "text-sm",
|
|
55571
|
+
padding: "py-2 px-4",
|
|
55572
|
+
backgroundColor: "bg-gray-700",
|
|
55573
|
+
textColor: "text-gray-300",
|
|
55574
|
+
hoverTextColor: "hover:text-white",
|
|
55575
|
+
hoverBackgroundColor: "hover:bg-gray-600",
|
|
55576
|
+
"data-testid": "onboarding-auth-cancel-button"
|
|
55577
|
+
})
|
|
55578
|
+
})]
|
|
55579
|
+
});
|
|
55580
|
+
}
|
|
55581
|
+
return /*#__PURE__*/jsxs(Fragment, {
|
|
55582
|
+
children: [/*#__PURE__*/jsxs("div", {
|
|
55583
|
+
className: "flex items-center gap-3 mb-2",
|
|
55584
|
+
children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
|
|
55585
|
+
icon: "user-plus",
|
|
55586
|
+
className: "text-2xl"
|
|
55587
|
+
}), /*#__PURE__*/jsx(Heading2, {
|
|
55588
|
+
title: "Sign in to the Dash Registry"
|
|
55589
|
+
})]
|
|
55590
|
+
}), /*#__PURE__*/jsx(Paragraph, {
|
|
55591
|
+
className: "".concat(textMuted, " mb-5"),
|
|
55592
|
+
children: /*#__PURE__*/jsx("span", {
|
|
55593
|
+
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."
|
|
55594
|
+
})
|
|
55595
|
+
}), /*#__PURE__*/jsxs("div", {
|
|
55596
|
+
className: "grid grid-cols-1 sm:grid-cols-2 gap-4 mb-6",
|
|
55597
|
+
children: [/*#__PURE__*/jsx(BenefitRow, {
|
|
55598
|
+
icon: "cube",
|
|
55599
|
+
title: "Install widgets",
|
|
55600
|
+
description: "Browse and one-click install community widgets",
|
|
55601
|
+
textMuted: textMuted
|
|
55602
|
+
}), /*#__PURE__*/jsx(BenefitRow, {
|
|
55603
|
+
icon: "table-cells",
|
|
55604
|
+
title: "Discover dashboards",
|
|
55605
|
+
description: "Like Kitchen Sink \u2014 curated starters built by others",
|
|
55606
|
+
textMuted: textMuted
|
|
55607
|
+
}), /*#__PURE__*/jsx(BenefitRow, {
|
|
55608
|
+
icon: "palette",
|
|
55609
|
+
title: "Apply themes",
|
|
55610
|
+
description: "Community-built themes for any taste",
|
|
55611
|
+
textMuted: textMuted
|
|
55612
|
+
}), /*#__PURE__*/jsx(BenefitRow, {
|
|
55613
|
+
icon: "upload",
|
|
55614
|
+
title: "Publish your own",
|
|
55615
|
+
description: "Share your widgets and dashboards with the Dash community",
|
|
55616
|
+
textMuted: textMuted
|
|
55617
|
+
})]
|
|
55618
|
+
}), authError && /*#__PURE__*/jsx(Paragraph, {
|
|
55619
|
+
className: "text-red-400 mb-4",
|
|
55620
|
+
children: /*#__PURE__*/jsx("span", {
|
|
55621
|
+
children: authError
|
|
55622
|
+
})
|
|
55623
|
+
}), /*#__PURE__*/jsxs("div", {
|
|
55624
|
+
className: "flex items-center justify-end gap-3 mt-2",
|
|
55625
|
+
children: [/*#__PURE__*/jsx(Button, {
|
|
55626
|
+
onClick: onSkip,
|
|
55627
|
+
title: "Skip for now",
|
|
55628
|
+
textSize: "text-sm",
|
|
55629
|
+
padding: "py-2 px-4",
|
|
55630
|
+
backgroundColor: "bg-gray-700",
|
|
55631
|
+
textColor: "text-gray-300",
|
|
55632
|
+
hoverTextColor: "hover:text-white",
|
|
55633
|
+
hoverBackgroundColor: "hover:bg-gray-600",
|
|
55634
|
+
"data-testid": "onboarding-auth-skip-button"
|
|
55635
|
+
}), /*#__PURE__*/jsx(Button, {
|
|
55636
|
+
onClick: onSignIn,
|
|
55637
|
+
title: "Sign in to Registry",
|
|
55638
|
+
textSize: "text-sm",
|
|
55639
|
+
padding: "py-2 px-4",
|
|
55640
|
+
backgroundColor: "bg-blue-600",
|
|
55641
|
+
textColor: "text-white",
|
|
55642
|
+
hoverTextColor: "hover:text-white",
|
|
55643
|
+
hoverBackgroundColor: "hover:bg-blue-500",
|
|
55644
|
+
icon: "arrow-up-right-from-square",
|
|
55645
|
+
"data-testid": "onboarding-auth-signin-button"
|
|
55646
|
+
})]
|
|
55647
|
+
})]
|
|
55648
|
+
});
|
|
55649
|
+
}
|
|
55298
55650
|
|
|
55299
55651
|
var DashCommandPalette = function DashCommandPalette(_ref) {
|
|
55300
55652
|
var isOpen = _ref.isOpen,
|
|
@@ -61308,7 +61660,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61308
61660
|
onboardingCheckedRef.current = true;
|
|
61309
61661
|
var cancelled = false;
|
|
61310
61662
|
_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
61311
|
-
var _window$mainApi, _window$mainApi$getSt, status;
|
|
61663
|
+
var _window$mainApi, _window$mainApi$getSt, status, alreadyHasKitchenSink;
|
|
61312
61664
|
return _regeneratorRuntime.wrap(function (_context) {
|
|
61313
61665
|
while (1) switch (_context.prev = _context.next) {
|
|
61314
61666
|
case 0:
|
|
@@ -61323,7 +61675,20 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61323
61675
|
}
|
|
61324
61676
|
return _context.abrupt("return");
|
|
61325
61677
|
case 2:
|
|
61326
|
-
|
|
61678
|
+
// Defense-in-depth: even if `workspaceConfig.length === 0`
|
|
61679
|
+
// briefly reads true during a race between `isLoadingWorkspaces`
|
|
61680
|
+
// and the workspace array populating, don't show the modal
|
|
61681
|
+
// if the user already has a Kitchen Sink dashboard installed
|
|
61682
|
+
// from the registry. Same dedupe rule the modal's install
|
|
61683
|
+
// path applies.
|
|
61684
|
+
alreadyHasKitchenSink = workspaceConfig.some(function (ws) {
|
|
61685
|
+
var _ws$_dashboardConfig;
|
|
61686
|
+
var pkg = ws === null || ws === void 0 || (_ws$_dashboardConfig = ws._dashboardConfig) === null || _ws$_dashboardConfig === void 0 ? void 0 : _ws$_dashboardConfig.registryPackage;
|
|
61687
|
+
if (typeof pkg !== "string") return false;
|
|
61688
|
+
var trailing = pkg.includes("/") ? pkg.split("/").pop() : pkg;
|
|
61689
|
+
return trailing === "kitchen-sink";
|
|
61690
|
+
});
|
|
61691
|
+
if (status && status.completed === false && workspaceConfig.length === 0 && !alreadyHasKitchenSink) {
|
|
61327
61692
|
setIsOnboardingOpen(true);
|
|
61328
61693
|
} else {
|
|
61329
61694
|
setIsOnboardingOpen(false);
|
|
@@ -63127,6 +63492,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
63127
63492
|
}), /*#__PURE__*/jsx(OnboardingModal, {
|
|
63128
63493
|
open: isOnboardingOpen === true,
|
|
63129
63494
|
appId: credentials === null || credentials === void 0 ? void 0 : credentials.appId,
|
|
63495
|
+
workspaces: workspaceConfig,
|
|
63130
63496
|
onDismiss: function onDismiss() {
|
|
63131
63497
|
return setIsOnboardingOpen(false);
|
|
63132
63498
|
},
|