@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.js
CHANGED
|
@@ -2567,6 +2567,27 @@ var ThemeWrapper = function ThemeWrapper(_ref) {
|
|
|
2567
2567
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2568
2568
|
}, [chosenTheme, themeVariant, themeName, themesForApplication, rawThemes]);
|
|
2569
2569
|
|
|
2570
|
+
// Broadcast the app-level theme to a SEPARATE global so
|
|
2571
|
+
// components rendered OUTSIDE the React theme tree
|
|
2572
|
+
// (WidgetBuilderModal, AppUpdatesModal — they live as siblings
|
|
2573
|
+
// of DashboardStage in dash-electron's Dash.js render) can fall
|
|
2574
|
+
// back to it when no dashboard-specific override is in play.
|
|
2575
|
+
//
|
|
2576
|
+
// We can't share the same global with DashboardThemeProvider's
|
|
2577
|
+
// per-workspace broadcast because React commits child effects
|
|
2578
|
+
// BEFORE parent effects — ThemeWrapper would always run last
|
|
2579
|
+
// and silently overwrite the workspace theme. Two separate
|
|
2580
|
+
// globals avoid the race: consumers read
|
|
2581
|
+
// `__dashThemeContext` (workspace) first, fall back to
|
|
2582
|
+
// `__dashAppThemeContext` (app-level) when no workspace is open.
|
|
2583
|
+
React.useEffect(function () {
|
|
2584
|
+
if (typeof window === "undefined") return undefined;
|
|
2585
|
+
if (contextValue !== null && contextValue !== void 0 && contextValue.currentTheme) {
|
|
2586
|
+
window.__dashAppThemeContext = contextValue;
|
|
2587
|
+
window.dispatchEvent(new Event("dash:theme-changed"));
|
|
2588
|
+
}
|
|
2589
|
+
}, [contextValue]);
|
|
2590
|
+
|
|
2570
2591
|
// Write the active theme's CSS custom properties to :root so any
|
|
2571
2592
|
// hex-channel tokens (`bg-[var(--primary-700)]` etc. emitted by
|
|
2572
2593
|
// ThemeModel) resolve app-wide. Without this, saving a hex theme
|
|
@@ -5743,6 +5764,45 @@ function ThemeBroadcast(_ref) {
|
|
|
5743
5764
|
return null;
|
|
5744
5765
|
}
|
|
5745
5766
|
|
|
5767
|
+
/**
|
|
5768
|
+
* Writes the dashboard theme's cssVars to `:root` while mounted, and
|
|
5769
|
+
* restores the previous values on unmount / theme switch.
|
|
5770
|
+
*
|
|
5771
|
+
* ThemeWrapper writes the APP theme's cssVars at the top of the tree.
|
|
5772
|
+
* Without this helper, a dashboard that overrides the app theme with a
|
|
5773
|
+
* hex-channel theme (like "Slack Generic") would carry the right class
|
|
5774
|
+
* names (`bg-[var(--primary-900)]`) but the `--primary-900` variable
|
|
5775
|
+
* on :root would still be the APP theme's value — or undefined if the
|
|
5776
|
+
* app theme is named-family. Hex-themed surfaces then render with no
|
|
5777
|
+
* background. This effect closes that gap by promoting the dashboard
|
|
5778
|
+
* theme's cssVars to :root for the duration of its mount.
|
|
5779
|
+
*/
|
|
5780
|
+
function DashboardCssVarsBridge(_ref2) {
|
|
5781
|
+
var cssVars = _ref2.cssVars;
|
|
5782
|
+
React.useEffect(function () {
|
|
5783
|
+
if (!cssVars || typeof document === "undefined") return undefined;
|
|
5784
|
+
var root = document.documentElement;
|
|
5785
|
+
var previous = {};
|
|
5786
|
+
var keys = Object.keys(cssVars);
|
|
5787
|
+
for (var _i = 0, _keys = keys; _i < _keys.length; _i++) {
|
|
5788
|
+
var key = _keys[_i];
|
|
5789
|
+
previous[key] = root.style.getPropertyValue(key);
|
|
5790
|
+
root.style.setProperty(key, cssVars[key]);
|
|
5791
|
+
}
|
|
5792
|
+
return function () {
|
|
5793
|
+
for (var _i2 = 0, _keys2 = keys; _i2 < _keys2.length; _i2++) {
|
|
5794
|
+
var _key = _keys2[_i2];
|
|
5795
|
+
if (previous[_key]) {
|
|
5796
|
+
root.style.setProperty(_key, previous[_key]);
|
|
5797
|
+
} else {
|
|
5798
|
+
root.style.removeProperty(_key);
|
|
5799
|
+
}
|
|
5800
|
+
}
|
|
5801
|
+
};
|
|
5802
|
+
}, [cssVars]);
|
|
5803
|
+
return null;
|
|
5804
|
+
}
|
|
5805
|
+
|
|
5746
5806
|
/**
|
|
5747
5807
|
* DashboardThemeProvider
|
|
5748
5808
|
*
|
|
@@ -5753,9 +5813,10 @@ function ThemeBroadcast(_ref) {
|
|
|
5753
5813
|
* App chrome (navbar, tab bar, sidebar) stays OUTSIDE this wrapper
|
|
5754
5814
|
* and keeps the app theme.
|
|
5755
5815
|
*/
|
|
5756
|
-
var DashboardThemeProvider = function DashboardThemeProvider(
|
|
5757
|
-
var
|
|
5758
|
-
|
|
5816
|
+
var DashboardThemeProvider = function DashboardThemeProvider(_ref3) {
|
|
5817
|
+
var _contextValue$current;
|
|
5818
|
+
var themeKey = _ref3.themeKey,
|
|
5819
|
+
children = _ref3.children;
|
|
5759
5820
|
var parentContext = React.useContext(DashReact.ThemeContext);
|
|
5760
5821
|
var themes = parentContext.themes,
|
|
5761
5822
|
themeVariant = parentContext.themeVariant;
|
|
@@ -5787,6 +5848,8 @@ var DashboardThemeProvider = function DashboardThemeProvider(_ref2) {
|
|
|
5787
5848
|
value: contextValue,
|
|
5788
5849
|
children: [/*#__PURE__*/jsxRuntime.jsx(ThemeBroadcast, {
|
|
5789
5850
|
ctx: contextValue
|
|
5851
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashboardCssVarsBridge, {
|
|
5852
|
+
cssVars: contextValue === null || contextValue === void 0 || (_contextValue$current = contextValue.currentTheme) === null || _contextValue$current === void 0 ? void 0 : _contextValue$current.cssVars
|
|
5790
5853
|
}), children]
|
|
5791
5854
|
});
|
|
5792
5855
|
};
|
|
@@ -28976,6 +29039,36 @@ var WorkspaceModel = function WorkspaceModel(workspaceItem) {
|
|
|
28976
29039
|
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; }
|
|
28977
29040
|
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; }
|
|
28978
29041
|
|
|
29042
|
+
/**
|
|
29043
|
+
* Last-resort family for ANY channel whose value can't be resolved
|
|
29044
|
+
* (unknown name, missing palette entry, missing shade, …). Picked
|
|
29045
|
+
* because it's universally safelist-covered, has every shade from
|
|
29046
|
+
* 50..950, and is visually neutral — so a misconfigured theme
|
|
29047
|
+
* renders "muted" rather than blank/transparent.
|
|
29048
|
+
*
|
|
29049
|
+
* Slack Generic etc. exposed this: when a channel value was missing
|
|
29050
|
+
* or unrecognized, ThemeModel silently emitted `bg-undefined-700`
|
|
29051
|
+
* (not in any safelist) → Tailwind dropped the class → the
|
|
29052
|
+
* dropdown popover rendered transparent. Falling back here means
|
|
29053
|
+
* no token can be "missing" by the time `getStylesForItem` reads it.
|
|
29054
|
+
*/
|
|
29055
|
+
var FALLBACK_FAMILY = "gray";
|
|
29056
|
+
|
|
29057
|
+
/**
|
|
29058
|
+
* Resolve a channel value to a safelist-covered Tailwind family
|
|
29059
|
+
* name. Returns the original value when it's a hex (the caller
|
|
29060
|
+
* handles those via CSS variables) or a recognized palette family;
|
|
29061
|
+
* otherwise returns FALLBACK_FAMILY so the resulting class always
|
|
29062
|
+
* renders.
|
|
29063
|
+
*/
|
|
29064
|
+
function resolveChannelFamily(channelValue) {
|
|
29065
|
+
if (DashReact.isHexColor(channelValue)) return channelValue;
|
|
29066
|
+
if (typeof channelValue === "string" && channelValue.length > 0 && DashReact.TAILWIND_PALETTE && DashReact.TAILWIND_PALETTE[channelValue]) {
|
|
29067
|
+
return channelValue;
|
|
29068
|
+
}
|
|
29069
|
+
return FALLBACK_FAMILY;
|
|
29070
|
+
}
|
|
29071
|
+
|
|
28979
29072
|
/**
|
|
28980
29073
|
* getNextLevel
|
|
28981
29074
|
* Need to generate the levels for tailwind
|
|
@@ -28994,6 +29087,11 @@ function invert(shade) {
|
|
|
28994
29087
|
* shade. Routes to the arbitrary-value syntax (`bg-[var(--type-shade)]`)
|
|
28995
29088
|
* when the channel's value is a hex.
|
|
28996
29089
|
*
|
|
29090
|
+
* Layer 1 fallback (audit follow-up to the Slack Generic bug): if
|
|
29091
|
+
* `channelValue` isn't a hex AND isn't a recognized Tailwind palette
|
|
29092
|
+
* family, fall back to FALLBACK_FAMILY so the emitted class is
|
|
29093
|
+
* always safelist-covered and never resolves to `bg-undefined-700`.
|
|
29094
|
+
*
|
|
28997
29095
|
* @param {"bg"|"text"|"border"} prefix
|
|
28998
29096
|
* @param {string} type channel name (primary | secondary | …)
|
|
28999
29097
|
* @param {number} shade tailwind shade (100..950)
|
|
@@ -29003,10 +29101,11 @@ function invert(shade) {
|
|
|
29003
29101
|
function classFor(prefix, type, shade, channelValue) {
|
|
29004
29102
|
var hover = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : false;
|
|
29005
29103
|
var h = hover ? "hover:" : "";
|
|
29006
|
-
|
|
29104
|
+
var resolved = resolveChannelFamily(channelValue);
|
|
29105
|
+
if (DashReact.isHexColor(resolved)) {
|
|
29007
29106
|
return "".concat(h).concat(prefix, "-[var(--").concat(type, "-").concat(shade, ")]");
|
|
29008
29107
|
}
|
|
29009
|
-
return "".concat(h).concat(prefix, "-").concat(
|
|
29108
|
+
return "".concat(h).concat(prefix, "-").concat(resolved, "-").concat(shade);
|
|
29010
29109
|
}
|
|
29011
29110
|
|
|
29012
29111
|
/**
|
|
@@ -29019,8 +29118,10 @@ function classFor(prefix, type, shade, channelValue) {
|
|
|
29019
29118
|
* produce a `var(--{type}-{shade})` reference that resolves against
|
|
29020
29119
|
* the CSS custom properties ThemePreviewProvider writes to :root.
|
|
29021
29120
|
*
|
|
29022
|
-
*
|
|
29023
|
-
*
|
|
29121
|
+
* Layer 1 fallback: when the channel value or shade can't be
|
|
29122
|
+
* resolved, fall back to FALLBACK_FAMILY's shade so cssValue is
|
|
29123
|
+
* never null. Pairs with classFor's same fallback to guarantee
|
|
29124
|
+
* every (type, shade) tuple yields a renderable token.
|
|
29024
29125
|
*/
|
|
29025
29126
|
function cssValueFor(type, shade, channelValue) {
|
|
29026
29127
|
if (DashReact.isHexColor(channelValue)) {
|
|
@@ -29033,12 +29134,17 @@ function cssValueFor(type, shade, channelValue) {
|
|
|
29033
29134
|
var _hex = shades[shade] || shades[String(shade)];
|
|
29034
29135
|
if (_hex) return _hex;
|
|
29035
29136
|
}
|
|
29036
|
-
return
|
|
29137
|
+
return fallbackCssValue(shade);
|
|
29037
29138
|
}
|
|
29038
29139
|
var family = DashReact.TAILWIND_PALETTE && DashReact.TAILWIND_PALETTE[channelValue];
|
|
29039
|
-
if (!family) return
|
|
29140
|
+
if (!family) return fallbackCssValue(shade);
|
|
29040
29141
|
var hex = family[shade] || family[String(shade)];
|
|
29041
|
-
return hex ||
|
|
29142
|
+
return hex || fallbackCssValue(shade);
|
|
29143
|
+
}
|
|
29144
|
+
function fallbackCssValue(shade) {
|
|
29145
|
+
var fallback = DashReact.TAILWIND_PALETTE && DashReact.TAILWIND_PALETTE[FALLBACK_FAMILY];
|
|
29146
|
+
if (!fallback) return null;
|
|
29147
|
+
return fallback[shade] || fallback[String(shade)] || null;
|
|
29042
29148
|
}
|
|
29043
29149
|
function gradientFor(direction, type, fromShade, viaShade, toShade, channelValue) {
|
|
29044
29150
|
if (DashReact.isHexColor(channelValue)) {
|
|
@@ -35223,11 +35329,25 @@ var ChannelEditorModal = function ChannelEditorModal(_ref) {
|
|
|
35223
35329
|
var nearest = React.useMemo(function () {
|
|
35224
35330
|
return nearestSwatch(selectedHex, families);
|
|
35225
35331
|
}, [selectedHex, families]);
|
|
35332
|
+
|
|
35333
|
+
// Auto-switch the family tab when the underlying selected color
|
|
35334
|
+
// changes (user picked a different channel/shade or the theme
|
|
35335
|
+
// mutated). Track the last hex we synced for so we don't fight
|
|
35336
|
+
// the user's manual tab clicks — without this guard, every
|
|
35337
|
+
// re-render rebuilds `nearest` as a new object reference and the
|
|
35338
|
+
// effect snaps activeFamily back to the family containing the
|
|
35339
|
+
// current color, making it impossible to browse other families.
|
|
35340
|
+
var lastSyncedHexRef = React.useRef(null);
|
|
35226
35341
|
React.useEffect(function () {
|
|
35227
|
-
if (!isOpen)
|
|
35342
|
+
if (!isOpen) {
|
|
35343
|
+
lastSyncedHexRef.current = null;
|
|
35344
|
+
return;
|
|
35345
|
+
}
|
|
35346
|
+
if (lastSyncedHexRef.current === selectedHex) return;
|
|
35347
|
+
lastSyncedHexRef.current = selectedHex;
|
|
35228
35348
|
if (nearest) setActiveFamily(nearest.family);
|
|
35229
35349
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
35230
|
-
}, [isOpen, nearest]);
|
|
35350
|
+
}, [isOpen, selectedHex, nearest]);
|
|
35231
35351
|
function expandChannel(channelKey) {
|
|
35232
35352
|
setActiveChannel(channelKey);
|
|
35233
35353
|
setActiveSlot("base");
|
|
@@ -54910,13 +55030,41 @@ var DashboardLoaderModal = function DashboardLoaderModal(_ref) {
|
|
|
54910
55030
|
var KITCHEN_SINK_PACKAGE = "trops/kitchen-sink";
|
|
54911
55031
|
var STATE = {
|
|
54912
55032
|
WELCOME: "welcome",
|
|
55033
|
+
// AUTH_REQUIRED replaces the generic "Install Failed" screen when
|
|
55034
|
+
// the registry returns `authRequired: true`. Surfaces a
|
|
55035
|
+
// benefits-driven sign-in CTA instead of asking the user to
|
|
55036
|
+
// figure out why install died.
|
|
55037
|
+
AUTH_REQUIRED: "auth-required",
|
|
54913
55038
|
INSTALLING: "installing",
|
|
54914
55039
|
DONE: "done",
|
|
54915
55040
|
ERROR: "error"
|
|
54916
55041
|
};
|
|
55042
|
+
|
|
55043
|
+
/**
|
|
55044
|
+
* Returns the first workspace that was installed from the Kitchen
|
|
55045
|
+
* Sink package, or null. Used for the modal's dedupe check so we
|
|
55046
|
+
* never create a second Kitchen Sink when one already exists.
|
|
55047
|
+
*
|
|
55048
|
+
* Workspaces installed via the registry carry a
|
|
55049
|
+
* `_dashboardConfig.registryPackage` field — historically the
|
|
55050
|
+
* unscoped name ("kitchen-sink"), more recently the scoped form
|
|
55051
|
+
* ("trops/kitchen-sink"). Match on either trailing segment.
|
|
55052
|
+
*/
|
|
55053
|
+
function findExistingKitchenSink(workspaces) {
|
|
55054
|
+
if (!Array.isArray(workspaces)) return null;
|
|
55055
|
+
return workspaces.find(function (ws) {
|
|
55056
|
+
var _ws$_dashboardConfig;
|
|
55057
|
+
var pkg = ws === null || ws === void 0 || (_ws$_dashboardConfig = ws._dashboardConfig) === null || _ws$_dashboardConfig === void 0 ? void 0 : _ws$_dashboardConfig.registryPackage;
|
|
55058
|
+
if (typeof pkg !== "string") return false;
|
|
55059
|
+
var trailing = pkg.includes("/") ? pkg.split("/").pop() : pkg;
|
|
55060
|
+
return trailing === "kitchen-sink";
|
|
55061
|
+
}) || null;
|
|
55062
|
+
}
|
|
54917
55063
|
var OnboardingModal = function OnboardingModal(_ref) {
|
|
54918
55064
|
var open = _ref.open,
|
|
54919
55065
|
appId = _ref.appId,
|
|
55066
|
+
_ref$workspaces = _ref.workspaces,
|
|
55067
|
+
workspaces = _ref$workspaces === void 0 ? [] : _ref$workspaces,
|
|
54920
55068
|
onOpenDashboard = _ref.onOpenDashboard,
|
|
54921
55069
|
onDismiss = _ref.onDismiss,
|
|
54922
55070
|
onComplete = _ref.onComplete;
|
|
@@ -54936,6 +55084,16 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54936
55084
|
setInstallError = _useState6[1];
|
|
54937
55085
|
var installResultRef = React.useRef(null);
|
|
54938
55086
|
var cleanupProgressRef = React.useRef(null);
|
|
55087
|
+
|
|
55088
|
+
// Reused device-code OAuth state machine (same hook AppUpdatesModal
|
|
55089
|
+
// uses). `authFlow` carries the user code + verification URL once
|
|
55090
|
+
// initiateAuth fires; while non-null we render the polling panel.
|
|
55091
|
+
var _useRegistryAuth = useRegistryAuth(),
|
|
55092
|
+
isAuthenticating = _useRegistryAuth.isAuthenticating,
|
|
55093
|
+
authFlow = _useRegistryAuth.authFlow,
|
|
55094
|
+
authError = _useRegistryAuth.authError,
|
|
55095
|
+
initiateAuth = _useRegistryAuth.initiateAuth,
|
|
55096
|
+
cancelAuth = _useRegistryAuth.cancelAuth;
|
|
54939
55097
|
React.useEffect(function () {
|
|
54940
55098
|
if (open) {
|
|
54941
55099
|
setState(STATE.WELCOME);
|
|
@@ -54997,7 +55155,7 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
54997
55155
|
})), [markCompletedAndClose, onDismiss]);
|
|
54998
55156
|
var handleInstall = React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
|
|
54999
55157
|
var _window$mainApi2, _window$mainApi2$onIn;
|
|
55000
|
-
var _window$mainApi3, _window$mainApi3$inst, result, _t2;
|
|
55158
|
+
var existing, _window$mainApi3, _window$mainApi3$inst, result, _t2;
|
|
55001
55159
|
return _regeneratorRuntime.wrap(function (_context3) {
|
|
55002
55160
|
while (1) switch (_context3.prev = _context3.next) {
|
|
55003
55161
|
case 0:
|
|
@@ -55009,6 +55167,24 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
55009
55167
|
setState(STATE.ERROR);
|
|
55010
55168
|
return _context3.abrupt("return");
|
|
55011
55169
|
case 1:
|
|
55170
|
+
// Dedupe: if the user already has a Kitchen Sink workspace
|
|
55171
|
+
// installed from the registry, skip the install entirely and
|
|
55172
|
+
// route them to the existing one. Without this, the modal
|
|
55173
|
+
// could be re-triggered (e.g. after clearing the
|
|
55174
|
+
// onboarding.completed flag) and would silently create
|
|
55175
|
+
// "Kitchen Sink 2", "Kitchen Sink 3", etc.
|
|
55176
|
+
existing = findExistingKitchenSink(workspaces);
|
|
55177
|
+
if (!existing) {
|
|
55178
|
+
_context3.next = 2;
|
|
55179
|
+
break;
|
|
55180
|
+
}
|
|
55181
|
+
installResultRef.current = {
|
|
55182
|
+
success: true,
|
|
55183
|
+
workspace: existing
|
|
55184
|
+
};
|
|
55185
|
+
setState(STATE.DONE);
|
|
55186
|
+
return _context3.abrupt("return");
|
|
55187
|
+
case 2:
|
|
55012
55188
|
setState(STATE.INSTALLING);
|
|
55013
55189
|
setProgressItems([]);
|
|
55014
55190
|
setInstallError(null);
|
|
@@ -55036,42 +55212,49 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
55036
55212
|
return next;
|
|
55037
55213
|
});
|
|
55038
55214
|
});
|
|
55039
|
-
_context3.prev =
|
|
55040
|
-
_context3.next =
|
|
55215
|
+
_context3.prev = 3;
|
|
55216
|
+
_context3.next = 4;
|
|
55041
55217
|
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, {});
|
|
55042
|
-
case
|
|
55218
|
+
case 4:
|
|
55043
55219
|
result = _context3.sent;
|
|
55044
55220
|
if (cleanupProgressRef.current) {
|
|
55045
55221
|
cleanupProgressRef.current();
|
|
55046
55222
|
cleanupProgressRef.current = null;
|
|
55047
55223
|
}
|
|
55048
55224
|
if (!(!result || !result.success)) {
|
|
55049
|
-
_context3.next =
|
|
55225
|
+
_context3.next = 6;
|
|
55226
|
+
break;
|
|
55227
|
+
}
|
|
55228
|
+
if (!(result !== null && result !== void 0 && result.authRequired)) {
|
|
55229
|
+
_context3.next = 5;
|
|
55050
55230
|
break;
|
|
55051
55231
|
}
|
|
55232
|
+
setState(STATE.AUTH_REQUIRED);
|
|
55233
|
+
return _context3.abrupt("return");
|
|
55234
|
+
case 5:
|
|
55052
55235
|
setInstallError((result === null || result === void 0 ? void 0 : result.error) || "Failed to install Kitchen Sink. Check your internet connection and try again.");
|
|
55053
55236
|
setState(STATE.ERROR);
|
|
55054
55237
|
return _context3.abrupt("return");
|
|
55055
|
-
case
|
|
55238
|
+
case 6:
|
|
55056
55239
|
installResultRef.current = result;
|
|
55057
55240
|
setState(STATE.DONE);
|
|
55058
|
-
_context3.next =
|
|
55241
|
+
_context3.next = 8;
|
|
55059
55242
|
break;
|
|
55060
|
-
case
|
|
55061
|
-
_context3.prev =
|
|
55062
|
-
_t2 = _context3["catch"](
|
|
55243
|
+
case 7:
|
|
55244
|
+
_context3.prev = 7;
|
|
55245
|
+
_t2 = _context3["catch"](3);
|
|
55063
55246
|
if (cleanupProgressRef.current) {
|
|
55064
55247
|
cleanupProgressRef.current();
|
|
55065
55248
|
cleanupProgressRef.current = null;
|
|
55066
55249
|
}
|
|
55067
55250
|
setInstallError((_t2 === null || _t2 === void 0 ? void 0 : _t2.message) || "Installation failed.");
|
|
55068
55251
|
setState(STATE.ERROR);
|
|
55069
|
-
case
|
|
55252
|
+
case 8:
|
|
55070
55253
|
case "end":
|
|
55071
55254
|
return _context3.stop();
|
|
55072
55255
|
}
|
|
55073
|
-
}, _callee3, null, [[
|
|
55074
|
-
})), [appId]);
|
|
55256
|
+
}, _callee3, null, [[3, 7]]);
|
|
55257
|
+
})), [appId, workspaces]);
|
|
55075
55258
|
var handleOpen = React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
|
|
55076
55259
|
var _installResultRef$cur;
|
|
55077
55260
|
var workspace;
|
|
@@ -55096,6 +55279,17 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
55096
55279
|
handleInstall();
|
|
55097
55280
|
}, [handleInstall]);
|
|
55098
55281
|
|
|
55282
|
+
// From the AUTH_REQUIRED state: kick off device-code OAuth. The
|
|
55283
|
+
// hook opens the browser, polls in the background, and fires our
|
|
55284
|
+
// onAuthorized callback on success. We auto-retry the install
|
|
55285
|
+
// there so the user lands on the DONE state without a second
|
|
55286
|
+
// click.
|
|
55287
|
+
var handleSignIn = React.useCallback(function () {
|
|
55288
|
+
initiateAuth(function () {
|
|
55289
|
+
handleInstall();
|
|
55290
|
+
});
|
|
55291
|
+
}, [initiateAuth, handleInstall]);
|
|
55292
|
+
|
|
55099
55293
|
// The Modal dispatches setIsOpen(false) on Escape / backdrop click.
|
|
55100
55294
|
// Route any close attempt through handleSkip so the completion flag
|
|
55101
55295
|
// is always stamped (otherwise Escape would silently re-show the
|
|
@@ -55119,6 +55313,15 @@ var OnboardingModal = function OnboardingModal(_ref) {
|
|
|
55119
55313
|
onInstall: handleInstall,
|
|
55120
55314
|
onSkip: handleSkip,
|
|
55121
55315
|
textMuted: textMuted
|
|
55316
|
+
}), state === STATE.AUTH_REQUIRED && /*#__PURE__*/jsxRuntime.jsx(AuthRequiredBody, {
|
|
55317
|
+
onSignIn: handleSignIn,
|
|
55318
|
+
onCancelAuth: cancelAuth,
|
|
55319
|
+
onSkip: handleSkip,
|
|
55320
|
+
isAuthenticating: isAuthenticating,
|
|
55321
|
+
authFlow: authFlow,
|
|
55322
|
+
authError: authError,
|
|
55323
|
+
textMuted: textMuted,
|
|
55324
|
+
borderPanel: borderPanel
|
|
55122
55325
|
}), state === STATE.INSTALLING && /*#__PURE__*/jsxRuntime.jsx(InstallingBody, {
|
|
55123
55326
|
items: progressItems,
|
|
55124
55327
|
borderPanel: borderPanel,
|
|
@@ -55148,11 +55351,13 @@ function WelcomeBody(_ref7) {
|
|
|
55148
55351
|
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Heading2, {
|
|
55149
55352
|
title: "Welcome to Dash"
|
|
55150
55353
|
})]
|
|
55151
|
-
}), /*#__PURE__*/jsxRuntime.
|
|
55354
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Paragraph, {
|
|
55152
55355
|
className: "".concat(textMuted, " mb-6"),
|
|
55153
|
-
children:
|
|
55154
|
-
children: "
|
|
55155
|
-
|
|
55356
|
+
children: /*#__PURE__*/jsxRuntime.jsxs("span", {
|
|
55357
|
+
children: ["Get started with the ", /*#__PURE__*/jsxRuntime.jsx("strong", {
|
|
55358
|
+
children: "Kitchen Sink"
|
|
55359
|
+
}), " 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."]
|
|
55360
|
+
})
|
|
55156
55361
|
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55157
55362
|
className: "flex items-center justify-end gap-3 mt-2",
|
|
55158
55363
|
children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
|
|
@@ -55313,6 +55518,153 @@ function ErrorBody(_ref1) {
|
|
|
55313
55518
|
})]
|
|
55314
55519
|
});
|
|
55315
55520
|
}
|
|
55521
|
+
function BenefitRow(_ref10) {
|
|
55522
|
+
var icon = _ref10.icon,
|
|
55523
|
+
title = _ref10.title,
|
|
55524
|
+
description = _ref10.description,
|
|
55525
|
+
textMuted = _ref10.textMuted;
|
|
55526
|
+
return /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55527
|
+
className: "flex items-start gap-3",
|
|
55528
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
55529
|
+
className: "flex-shrink-0 w-7 h-7 flex items-center justify-center mt-0.5",
|
|
55530
|
+
children: /*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
|
|
55531
|
+
icon: icon,
|
|
55532
|
+
className: "text-base opacity-70"
|
|
55533
|
+
})
|
|
55534
|
+
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55535
|
+
className: "flex flex-col",
|
|
55536
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("span", {
|
|
55537
|
+
className: "text-sm font-medium",
|
|
55538
|
+
children: title
|
|
55539
|
+
}), /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
55540
|
+
className: "text-xs ".concat(textMuted),
|
|
55541
|
+
children: description
|
|
55542
|
+
})]
|
|
55543
|
+
})]
|
|
55544
|
+
});
|
|
55545
|
+
}
|
|
55546
|
+
function AuthRequiredBody(_ref11) {
|
|
55547
|
+
var onSignIn = _ref11.onSignIn,
|
|
55548
|
+
onCancelAuth = _ref11.onCancelAuth,
|
|
55549
|
+
onSkip = _ref11.onSkip,
|
|
55550
|
+
isAuthenticating = _ref11.isAuthenticating,
|
|
55551
|
+
authFlow = _ref11.authFlow,
|
|
55552
|
+
authError = _ref11.authError,
|
|
55553
|
+
textMuted = _ref11.textMuted,
|
|
55554
|
+
borderPanel = _ref11.borderPanel;
|
|
55555
|
+
// While the device-code flow is polling, swap the benefits panel
|
|
55556
|
+
// for the user-code + verification-URL display so the user knows
|
|
55557
|
+
// what to enter in the browser tab we just opened.
|
|
55558
|
+
if (isAuthenticating && authFlow) {
|
|
55559
|
+
return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
55560
|
+
children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55561
|
+
className: "flex items-center gap-3 mb-2",
|
|
55562
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
|
|
55563
|
+
icon: "circle-notch",
|
|
55564
|
+
className: "text-2xl animate-spin"
|
|
55565
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Heading2, {
|
|
55566
|
+
title: "Waiting for browser sign-in"
|
|
55567
|
+
})]
|
|
55568
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Paragraph, {
|
|
55569
|
+
className: "".concat(textMuted, " mb-4"),
|
|
55570
|
+
children: /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
55571
|
+
children: "We opened a browser tab where you can sign in to the Dash Registry. Enter this code if prompted:"
|
|
55572
|
+
})
|
|
55573
|
+
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55574
|
+
className: "border ".concat(borderPanel, " rounded-md p-4 mb-4 text-center"),
|
|
55575
|
+
"data-testid": "onboarding-auth-user-code",
|
|
55576
|
+
children: [/*#__PURE__*/jsxRuntime.jsx("div", {
|
|
55577
|
+
className: "text-2xl font-mono tracking-widest",
|
|
55578
|
+
children: authFlow.userCode || "—"
|
|
55579
|
+
}), /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
55580
|
+
className: "text-xs ".concat(textMuted, " mt-2 break-all"),
|
|
55581
|
+
children: authFlow.verificationUrlComplete || authFlow.verificationUrl || ""
|
|
55582
|
+
})]
|
|
55583
|
+
}), /*#__PURE__*/jsxRuntime.jsx("div", {
|
|
55584
|
+
className: "flex items-center justify-end gap-3",
|
|
55585
|
+
children: /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
|
|
55586
|
+
onClick: onCancelAuth,
|
|
55587
|
+
title: "Cancel",
|
|
55588
|
+
textSize: "text-sm",
|
|
55589
|
+
padding: "py-2 px-4",
|
|
55590
|
+
backgroundColor: "bg-gray-700",
|
|
55591
|
+
textColor: "text-gray-300",
|
|
55592
|
+
hoverTextColor: "hover:text-white",
|
|
55593
|
+
hoverBackgroundColor: "hover:bg-gray-600",
|
|
55594
|
+
"data-testid": "onboarding-auth-cancel-button"
|
|
55595
|
+
})
|
|
55596
|
+
})]
|
|
55597
|
+
});
|
|
55598
|
+
}
|
|
55599
|
+
return /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
55600
|
+
children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55601
|
+
className: "flex items-center gap-3 mb-2",
|
|
55602
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
|
|
55603
|
+
icon: "user-plus",
|
|
55604
|
+
className: "text-2xl"
|
|
55605
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Heading2, {
|
|
55606
|
+
title: "Sign in to the Dash Registry"
|
|
55607
|
+
})]
|
|
55608
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Paragraph, {
|
|
55609
|
+
className: "".concat(textMuted, " mb-5"),
|
|
55610
|
+
children: /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
55611
|
+
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."
|
|
55612
|
+
})
|
|
55613
|
+
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55614
|
+
className: "grid grid-cols-1 sm:grid-cols-2 gap-4 mb-6",
|
|
55615
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(BenefitRow, {
|
|
55616
|
+
icon: "cube",
|
|
55617
|
+
title: "Install widgets",
|
|
55618
|
+
description: "Browse and one-click install community widgets",
|
|
55619
|
+
textMuted: textMuted
|
|
55620
|
+
}), /*#__PURE__*/jsxRuntime.jsx(BenefitRow, {
|
|
55621
|
+
icon: "table-cells",
|
|
55622
|
+
title: "Discover dashboards",
|
|
55623
|
+
description: "Like Kitchen Sink \u2014 curated starters built by others",
|
|
55624
|
+
textMuted: textMuted
|
|
55625
|
+
}), /*#__PURE__*/jsxRuntime.jsx(BenefitRow, {
|
|
55626
|
+
icon: "palette",
|
|
55627
|
+
title: "Apply themes",
|
|
55628
|
+
description: "Community-built themes for any taste",
|
|
55629
|
+
textMuted: textMuted
|
|
55630
|
+
}), /*#__PURE__*/jsxRuntime.jsx(BenefitRow, {
|
|
55631
|
+
icon: "upload",
|
|
55632
|
+
title: "Publish your own",
|
|
55633
|
+
description: "Share your widgets and dashboards with the Dash community",
|
|
55634
|
+
textMuted: textMuted
|
|
55635
|
+
})]
|
|
55636
|
+
}), authError && /*#__PURE__*/jsxRuntime.jsx(DashReact.Paragraph, {
|
|
55637
|
+
className: "text-red-400 mb-4",
|
|
55638
|
+
children: /*#__PURE__*/jsxRuntime.jsx("span", {
|
|
55639
|
+
children: authError
|
|
55640
|
+
})
|
|
55641
|
+
}), /*#__PURE__*/jsxRuntime.jsxs("div", {
|
|
55642
|
+
className: "flex items-center justify-end gap-3 mt-2",
|
|
55643
|
+
children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
|
|
55644
|
+
onClick: onSkip,
|
|
55645
|
+
title: "Skip for now",
|
|
55646
|
+
textSize: "text-sm",
|
|
55647
|
+
padding: "py-2 px-4",
|
|
55648
|
+
backgroundColor: "bg-gray-700",
|
|
55649
|
+
textColor: "text-gray-300",
|
|
55650
|
+
hoverTextColor: "hover:text-white",
|
|
55651
|
+
hoverBackgroundColor: "hover:bg-gray-600",
|
|
55652
|
+
"data-testid": "onboarding-auth-skip-button"
|
|
55653
|
+
}), /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
|
|
55654
|
+
onClick: onSignIn,
|
|
55655
|
+
title: "Sign in to Registry",
|
|
55656
|
+
textSize: "text-sm",
|
|
55657
|
+
padding: "py-2 px-4",
|
|
55658
|
+
backgroundColor: "bg-blue-600",
|
|
55659
|
+
textColor: "text-white",
|
|
55660
|
+
hoverTextColor: "hover:text-white",
|
|
55661
|
+
hoverBackgroundColor: "hover:bg-blue-500",
|
|
55662
|
+
icon: "arrow-up-right-from-square",
|
|
55663
|
+
"data-testid": "onboarding-auth-signin-button"
|
|
55664
|
+
})]
|
|
55665
|
+
})]
|
|
55666
|
+
});
|
|
55667
|
+
}
|
|
55316
55668
|
|
|
55317
55669
|
var DashCommandPalette = function DashCommandPalette(_ref) {
|
|
55318
55670
|
var isOpen = _ref.isOpen,
|
|
@@ -61326,7 +61678,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61326
61678
|
onboardingCheckedRef.current = true;
|
|
61327
61679
|
var cancelled = false;
|
|
61328
61680
|
_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
61329
|
-
var _window$mainApi, _window$mainApi$getSt, status;
|
|
61681
|
+
var _window$mainApi, _window$mainApi$getSt, status, alreadyHasKitchenSink;
|
|
61330
61682
|
return _regeneratorRuntime.wrap(function (_context) {
|
|
61331
61683
|
while (1) switch (_context.prev = _context.next) {
|
|
61332
61684
|
case 0:
|
|
@@ -61341,7 +61693,20 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
61341
61693
|
}
|
|
61342
61694
|
return _context.abrupt("return");
|
|
61343
61695
|
case 2:
|
|
61344
|
-
|
|
61696
|
+
// Defense-in-depth: even if `workspaceConfig.length === 0`
|
|
61697
|
+
// briefly reads true during a race between `isLoadingWorkspaces`
|
|
61698
|
+
// and the workspace array populating, don't show the modal
|
|
61699
|
+
// if the user already has a Kitchen Sink dashboard installed
|
|
61700
|
+
// from the registry. Same dedupe rule the modal's install
|
|
61701
|
+
// path applies.
|
|
61702
|
+
alreadyHasKitchenSink = workspaceConfig.some(function (ws) {
|
|
61703
|
+
var _ws$_dashboardConfig;
|
|
61704
|
+
var pkg = ws === null || ws === void 0 || (_ws$_dashboardConfig = ws._dashboardConfig) === null || _ws$_dashboardConfig === void 0 ? void 0 : _ws$_dashboardConfig.registryPackage;
|
|
61705
|
+
if (typeof pkg !== "string") return false;
|
|
61706
|
+
var trailing = pkg.includes("/") ? pkg.split("/").pop() : pkg;
|
|
61707
|
+
return trailing === "kitchen-sink";
|
|
61708
|
+
});
|
|
61709
|
+
if (status && status.completed === false && workspaceConfig.length === 0 && !alreadyHasKitchenSink) {
|
|
61345
61710
|
setIsOnboardingOpen(true);
|
|
61346
61711
|
} else {
|
|
61347
61712
|
setIsOnboardingOpen(false);
|
|
@@ -63145,6 +63510,7 @@ var DashboardStageInner = function DashboardStageInner(_ref3) {
|
|
|
63145
63510
|
}), /*#__PURE__*/jsxRuntime.jsx(OnboardingModal, {
|
|
63146
63511
|
open: isOnboardingOpen === true,
|
|
63147
63512
|
appId: credentials === null || credentials === void 0 ? void 0 : credentials.appId,
|
|
63513
|
+
workspaces: workspaceConfig,
|
|
63148
63514
|
onDismiss: function onDismiss() {
|
|
63149
63515
|
return setIsOnboardingOpen(false);
|
|
63150
63516
|
},
|