@trops/dash-core 0.1.257 → 0.1.260

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3583,17 +3583,14 @@ var InstallProgressModal = function InstallProgressModal(_ref) {
3583
3583
  widgets = _ref$widgets === void 0 ? [] : _ref$widgets,
3584
3584
  _ref$isComplete = _ref.isComplete,
3585
3585
  isComplete = _ref$isComplete === void 0 ? false : _ref$isComplete,
3586
- onDone = _ref.onDone;
3586
+ onDone = _ref.onDone,
3587
+ _ref$onCancel = _ref.onCancel,
3588
+ onCancel = _ref$onCancel === void 0 ? null : _ref$onCancel;
3587
3589
  var _useContext = React.useContext(DashReact.ThemeContext),
3588
3590
  currentTheme = _useContext.currentTheme;
3589
3591
  var panelStyles = DashReact.getStylesForItem(DashReact.themeObjects.PANEL, currentTheme, {
3590
3592
  grow: false
3591
3593
  });
3592
-
3593
- // Prevent dismissal while installation is in progress
3594
- var guardedSetIsOpen = function guardedSetIsOpen(val) {
3595
- if (isComplete) setIsOpen(val);
3596
- };
3597
3594
  var doneCount = widgets.filter(function (w) {
3598
3595
  return w.status === "installed" || w.status === "already-installed" || w.status === "failed";
3599
3596
  }).length;
@@ -3624,7 +3621,7 @@ var InstallProgressModal = function InstallProgressModal(_ref) {
3624
3621
  }
3625
3622
  return /*#__PURE__*/jsxRuntime.jsx(DashReact.Modal, {
3626
3623
  isOpen: isOpen,
3627
- setIsOpen: guardedSetIsOpen,
3624
+ setIsOpen: setIsOpen,
3628
3625
  width: "w-[440px]",
3629
3626
  height: "auto",
3630
3627
  children: /*#__PURE__*/jsxRuntime.jsxs("div", {
@@ -3654,9 +3651,19 @@ var InstallProgressModal = function InstallProgressModal(_ref) {
3654
3651
  })]
3655
3652
  }, idx);
3656
3653
  })
3657
- }), /*#__PURE__*/jsxRuntime.jsx("div", {
3658
- className: "flex items-center justify-end px-5 py-3 border-t ".concat(currentTheme["border-primary-medium"] || "border-white/10"),
3659
- children: /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
3654
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
3655
+ className: "flex items-center justify-between px-5 py-3 border-t ".concat(currentTheme["border-primary-medium"] || "border-white/10"),
3656
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
3657
+ children: !isComplete && onCancel && /*#__PURE__*/jsxRuntime.jsx("button", {
3658
+ type: "button",
3659
+ onClick: function onClick() {
3660
+ if (onCancel) onCancel();
3661
+ setIsOpen(false);
3662
+ },
3663
+ className: "text-sm text-gray-500 hover:text-gray-300 transition-colors",
3664
+ children: "Cancel"
3665
+ })
3666
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
3660
3667
  title: "Done",
3661
3668
  bgColor: isComplete ? "bg-blue-600" : "bg-gray-700",
3662
3669
  hoverBackgroundColor: isComplete ? "hover:bg-blue-700" : "",
@@ -3666,12 +3673,273 @@ var InstallProgressModal = function InstallProgressModal(_ref) {
3666
3673
  if (isComplete && onDone) onDone();
3667
3674
  },
3668
3675
  disabled: !isComplete
3669
- })
3676
+ })]
3670
3677
  })]
3671
3678
  })
3672
3679
  });
3673
3680
  };
3674
3681
 
3682
+ /**
3683
+ * useRegistryAuth — reusable hook for device-code OAuth against the Dash Registry.
3684
+ *
3685
+ * Encapsulates the full auth state machine: check status, initiate login,
3686
+ * poll for token, and cancel. Cleans up the poll interval on unmount.
3687
+ *
3688
+ * @returns {{
3689
+ * isAuthenticated: boolean,
3690
+ * isAuthenticating: boolean,
3691
+ * authFlow: { userCode: string, verificationUrlComplete: string } | null,
3692
+ * authError: string | null,
3693
+ * checkAuth: () => Promise<boolean>,
3694
+ * initiateAuth: () => Promise<void>,
3695
+ * cancelAuth: () => void,
3696
+ * }}
3697
+ */
3698
+ function useRegistryAuth() {
3699
+ var _useState = React.useState(false),
3700
+ _useState2 = _slicedToArray(_useState, 2),
3701
+ isAuthenticated = _useState2[0],
3702
+ setIsAuthenticated = _useState2[1];
3703
+ var _useState3 = React.useState(false),
3704
+ _useState4 = _slicedToArray(_useState3, 2),
3705
+ isAuthenticating = _useState4[0],
3706
+ setIsAuthenticating = _useState4[1];
3707
+ var _useState5 = React.useState(null),
3708
+ _useState6 = _slicedToArray(_useState5, 2),
3709
+ authFlow = _useState6[0],
3710
+ setAuthFlow = _useState6[1];
3711
+ var _useState7 = React.useState(null),
3712
+ _useState8 = _slicedToArray(_useState7, 2),
3713
+ authError = _useState8[0],
3714
+ setAuthError = _useState8[1];
3715
+ var pollIntervalRef = React.useRef(null);
3716
+ var onAuthorizedRef = React.useRef(null);
3717
+
3718
+ // Clean up polling on unmount
3719
+ React.useEffect(function () {
3720
+ return function () {
3721
+ if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
3722
+ };
3723
+ }, []);
3724
+ var checkAuth = React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
3725
+ var status, authed;
3726
+ return _regeneratorRuntime.wrap(function (_context) {
3727
+ while (1) switch (_context.prev = _context.next) {
3728
+ case 0:
3729
+ _context.prev = 0;
3730
+ _context.next = 1;
3731
+ return window.mainApi.registryAuth.getStatus();
3732
+ case 1:
3733
+ status = _context.sent;
3734
+ authed = !!(status !== null && status !== void 0 && status.authenticated);
3735
+ setIsAuthenticated(authed);
3736
+ return _context.abrupt("return", authed);
3737
+ case 2:
3738
+ _context.prev = 2;
3739
+ _context["catch"](0);
3740
+ return _context.abrupt("return", false);
3741
+ case 3:
3742
+ case "end":
3743
+ return _context.stop();
3744
+ }
3745
+ }, _callee, null, [[0, 2]]);
3746
+ })), []);
3747
+ var cancelAuth = React.useCallback(function () {
3748
+ if (pollIntervalRef.current) {
3749
+ clearInterval(pollIntervalRef.current);
3750
+ pollIntervalRef.current = null;
3751
+ }
3752
+ setIsAuthenticating(false);
3753
+ setAuthFlow(null);
3754
+ }, []);
3755
+ var initiateAuth = React.useCallback(/*#__PURE__*/function () {
3756
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(onAuthorized) {
3757
+ var flow, interval;
3758
+ return _regeneratorRuntime.wrap(function (_context3) {
3759
+ while (1) switch (_context3.prev = _context3.next) {
3760
+ case 0:
3761
+ setAuthError(null);
3762
+ onAuthorizedRef.current = onAuthorized || null;
3763
+ _context3.prev = 1;
3764
+ _context3.next = 2;
3765
+ return window.mainApi.registryAuth.initiateLogin();
3766
+ case 2:
3767
+ flow = _context3.sent;
3768
+ setAuthFlow(flow);
3769
+ if (flow.verificationUrlComplete) {
3770
+ window.mainApi.shell.openExternal(flow.verificationUrlComplete);
3771
+ }
3772
+ setIsAuthenticating(true);
3773
+ interval = (flow.interval || 5) * 1000;
3774
+ pollIntervalRef.current = setInterval(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
3775
+ var pollResult;
3776
+ return _regeneratorRuntime.wrap(function (_context2) {
3777
+ while (1) switch (_context2.prev = _context2.next) {
3778
+ case 0:
3779
+ _context2.prev = 0;
3780
+ _context2.next = 1;
3781
+ return window.mainApi.registryAuth.pollToken(flow.deviceCode);
3782
+ case 1:
3783
+ pollResult = _context2.sent;
3784
+ if (pollResult.status === "authorized") {
3785
+ clearInterval(pollIntervalRef.current);
3786
+ pollIntervalRef.current = null;
3787
+ setIsAuthenticating(false);
3788
+ setAuthFlow(null);
3789
+ setIsAuthenticated(true);
3790
+ if (onAuthorizedRef.current) {
3791
+ onAuthorizedRef.current();
3792
+ }
3793
+ } else if (pollResult.status === "expired") {
3794
+ clearInterval(pollIntervalRef.current);
3795
+ pollIntervalRef.current = null;
3796
+ setIsAuthenticating(false);
3797
+ setAuthFlow(null);
3798
+ setAuthError("Authorization expired. Please try again.");
3799
+ }
3800
+ _context2.next = 3;
3801
+ break;
3802
+ case 2:
3803
+ _context2.prev = 2;
3804
+ _context2["catch"](0);
3805
+ clearInterval(pollIntervalRef.current);
3806
+ pollIntervalRef.current = null;
3807
+ setIsAuthenticating(false);
3808
+ case 3:
3809
+ case "end":
3810
+ return _context2.stop();
3811
+ }
3812
+ }, _callee2, null, [[0, 2]]);
3813
+ })), interval);
3814
+ _context3.next = 4;
3815
+ break;
3816
+ case 3:
3817
+ _context3.prev = 3;
3818
+ _context3["catch"](1);
3819
+ setAuthError("Could not reach the registry. Check your connection and try again.");
3820
+ case 4:
3821
+ case "end":
3822
+ return _context3.stop();
3823
+ }
3824
+ }, _callee3, null, [[1, 3]]);
3825
+ }));
3826
+ return function (_x) {
3827
+ return _ref2.apply(this, arguments);
3828
+ };
3829
+ }(), [cancelAuth]);
3830
+ return {
3831
+ isAuthenticated: isAuthenticated,
3832
+ isAuthenticating: isAuthenticating,
3833
+ authFlow: authFlow,
3834
+ authError: authError,
3835
+ checkAuth: checkAuth,
3836
+ initiateAuth: initiateAuth,
3837
+ cancelAuth: cancelAuth
3838
+ };
3839
+ }
3840
+
3841
+ var RegistryAuthPrompt = function RegistryAuthPrompt(_ref) {
3842
+ var onAuthenticated = _ref.onAuthenticated,
3843
+ _ref$onCancel = _ref.onCancel,
3844
+ onCancel = _ref$onCancel === void 0 ? null : _ref$onCancel,
3845
+ _ref$message = _ref.message,
3846
+ message = _ref$message === void 0 ? "Sign in to install from the Dash Registry." : _ref$message;
3847
+ var _useRegistryAuth = useRegistryAuth(),
3848
+ isAuthenticating = _useRegistryAuth.isAuthenticating,
3849
+ authFlow = _useRegistryAuth.authFlow,
3850
+ authError = _useRegistryAuth.authError,
3851
+ checkAuth = _useRegistryAuth.checkAuth,
3852
+ initiateAuth = _useRegistryAuth.initiateAuth,
3853
+ cancelAuth = _useRegistryAuth.cancelAuth;
3854
+ var checkedRef = React.useRef(false);
3855
+
3856
+ // Check auth on mount — if already authenticated, short-circuit
3857
+ React.useEffect(function () {
3858
+ if (checkedRef.current) return;
3859
+ checkedRef.current = true;
3860
+ checkAuth().then(function (authed) {
3861
+ if (authed && onAuthenticated) onAuthenticated();
3862
+ });
3863
+ }, [checkAuth, onAuthenticated]);
3864
+ function handleSignIn() {
3865
+ initiateAuth(function () {
3866
+ if (onAuthenticated) onAuthenticated();
3867
+ });
3868
+ }
3869
+ function handleCancel() {
3870
+ cancelAuth();
3871
+ if (onCancel) onCancel();
3872
+ }
3873
+
3874
+ // Polling state: show user code
3875
+ if (authFlow && isAuthenticating) {
3876
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
3877
+ className: "flex flex-col gap-3 p-4",
3878
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
3879
+ className: "bg-blue-500/10 border border-blue-500/20 rounded-lg p-4 space-y-3",
3880
+ children: [/*#__PURE__*/jsxRuntime.jsx("p", {
3881
+ className: "text-xs text-blue-300/90",
3882
+ children: "Enter this code in your browser:"
3883
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
3884
+ className: "text-center",
3885
+ children: /*#__PURE__*/jsxRuntime.jsx("span", {
3886
+ className: "text-2xl font-mono font-bold tracking-widest text-white",
3887
+ children: authFlow.userCode
3888
+ })
3889
+ }), /*#__PURE__*/jsxRuntime.jsx("p", {
3890
+ className: "text-xs text-blue-300/70 text-center",
3891
+ children: "Waiting for authorization \u2014 install will resume automatically..."
3892
+ })]
3893
+ }), onCancel && /*#__PURE__*/jsxRuntime.jsx("button", {
3894
+ type: "button",
3895
+ onClick: handleCancel,
3896
+ className: "self-center text-xs text-gray-500 hover:text-gray-300 transition-colors",
3897
+ children: "Cancel"
3898
+ })]
3899
+ });
3900
+ }
3901
+
3902
+ // Default: not-started / error state
3903
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
3904
+ className: "flex flex-col gap-3 p-4",
3905
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
3906
+ className: "bg-yellow-500/10 border border-yellow-500/20 rounded-lg p-3",
3907
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
3908
+ className: "flex items-start gap-2",
3909
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
3910
+ icon: "lock",
3911
+ className: "h-3.5 w-3.5 text-yellow-400 mt-0.5 flex-shrink-0"
3912
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
3913
+ className: "text-sm text-yellow-300/90",
3914
+ children: message
3915
+ })]
3916
+ })
3917
+ }), /*#__PURE__*/jsxRuntime.jsx("button", {
3918
+ type: "button",
3919
+ onClick: handleSignIn,
3920
+ className: "px-4 py-2 rounded-lg text-sm bg-blue-500/20 border border-blue-500/30 text-blue-300 hover:bg-blue-500/30 transition-colors cursor-pointer",
3921
+ children: "Sign in to Registry"
3922
+ }), authError && /*#__PURE__*/jsxRuntime.jsx("div", {
3923
+ className: "bg-red-500/10 border border-red-500/20 rounded-lg p-3",
3924
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
3925
+ className: "flex items-start gap-2",
3926
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
3927
+ icon: "circle-xmark",
3928
+ className: "h-3.5 w-3.5 text-red-400 mt-0.5 flex-shrink-0"
3929
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
3930
+ className: "text-xs text-red-300/90",
3931
+ children: authError
3932
+ })]
3933
+ })
3934
+ }), onCancel && /*#__PURE__*/jsxRuntime.jsx("button", {
3935
+ type: "button",
3936
+ onClick: handleCancel,
3937
+ className: "self-center text-xs text-gray-500 hover:text-gray-300 transition-colors",
3938
+ children: "Cancel"
3939
+ })]
3940
+ });
3941
+ };
3942
+
3675
3943
  function _createForOfIteratorHelper$g(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$g(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
3676
3944
  function _unsupportedIterableToArray$g(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$g(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$g(r, a) : void 0; } }
3677
3945
  function _arrayLikeToArray$g(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
@@ -3702,41 +3970,27 @@ var RegistryDashboardDetail = function RegistryDashboardDetail(_ref) {
3702
3970
  _useState8 = _slicedToArray(_useState7, 2),
3703
3971
  installResult = _useState8[0],
3704
3972
  setInstallResult = _useState8[1];
3705
- var _useState9 = React.useState(null),
3973
+ var _useState9 = React.useState(false),
3706
3974
  _useState0 = _slicedToArray(_useState9, 2),
3707
- authFlow = _useState0[0],
3708
- setAuthFlow = _useState0[1];
3709
- var _useState1 = React.useState(false),
3975
+ showProgressModal = _useState0[0],
3976
+ setShowProgressModal = _useState0[1];
3977
+ var _useState1 = React.useState([]),
3710
3978
  _useState10 = _slicedToArray(_useState1, 2),
3711
- isPolling = _useState10[0],
3712
- setIsPolling = _useState10[1];
3713
- var _useState11 = React.useState(null),
3979
+ progressWidgets = _useState10[0],
3980
+ setProgressWidgets = _useState10[1];
3981
+ var _useState11 = React.useState(false),
3714
3982
  _useState12 = _slicedToArray(_useState11, 2),
3715
- authError = _useState12[0],
3716
- setAuthError = _useState12[1];
3717
- var _useState13 = React.useState(false),
3718
- _useState14 = _slicedToArray(_useState13, 2),
3719
- showProgressModal = _useState14[0],
3720
- setShowProgressModal = _useState14[1];
3721
- var _useState15 = React.useState([]),
3722
- _useState16 = _slicedToArray(_useState15, 2),
3723
- progressWidgets = _useState16[0],
3724
- setProgressWidgets = _useState16[1];
3725
- var _useState17 = React.useState(false),
3726
- _useState18 = _slicedToArray(_useState17, 2),
3727
- progressComplete = _useState18[0],
3728
- setProgressComplete = _useState18[1];
3983
+ progressComplete = _useState12[0],
3984
+ setProgressComplete = _useState12[1];
3729
3985
  var progressResultRef = React.useRef(null);
3730
- var pollIntervalRef = React.useRef(null);
3731
3986
  var cleanupProgressRef = React.useRef(null);
3732
3987
  var pkg = dashboardPackage;
3733
3988
  if (!pkg) return null;
3734
3989
 
3735
- // Clean up polling and progress listener on unmount
3990
+ // Clean up progress listener on unmount
3736
3991
  // eslint-disable-next-line react-hooks/rules-of-hooks
3737
3992
  React.useEffect(function () {
3738
3993
  return function () {
3739
- if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
3740
3994
  if (cleanupProgressRef.current) cleanupProgressRef.current();
3741
3995
  };
3742
3996
  }, []);
@@ -3750,10 +4004,6 @@ var RegistryDashboardDetail = function RegistryDashboardDetail(_ref) {
3750
4004
  setPreviewLoading(true);
3751
4005
  setPreview(null);
3752
4006
  setInstallResult(null);
3753
- setAuthFlow(null);
3754
- setIsPolling(false);
3755
- setAuthError(null);
3756
- if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
3757
4007
  (_window$mainApi = window.mainApi) === null || _window$mainApi === void 0 || (_window$mainApi = _window$mainApi.dashboardConfig) === null || _window$mainApi === void 0 || _window$mainApi.getDashboardPreview(pkg.name).then(function (result) {
3758
4008
  if (!cancelled) setPreview(result);
3759
4009
  })["catch"](function (err) {
@@ -3781,8 +4031,6 @@ var RegistryDashboardDetail = function RegistryDashboardDetail(_ref) {
3781
4031
  case 1:
3782
4032
  setIsInstalling(true);
3783
4033
  setInstallResult(null);
3784
- setAuthFlow(null);
3785
- setAuthError(null);
3786
4034
 
3787
4035
  // Initialize progress modal from widget deps
3788
4036
  deps = widgetDeps.length > 0 ? widgetDeps : [];
@@ -3890,83 +4138,6 @@ var RegistryDashboardDetail = function RegistryDashboardDetail(_ref) {
3890
4138
  }
3891
4139
  }
3892
4140
  }, [pkg.name, onInstallComplete]);
3893
- function handleSignIn() {
3894
- return _handleSignIn.apply(this, arguments);
3895
- }
3896
- function _handleSignIn() {
3897
- _handleSignIn = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
3898
- var flow, interval;
3899
- return _regeneratorRuntime.wrap(function (_context3) {
3900
- while (1) switch (_context3.prev = _context3.next) {
3901
- case 0:
3902
- setAuthError(null);
3903
- _context3.prev = 1;
3904
- _context3.next = 2;
3905
- return window.mainApi.registryAuth.initiateLogin();
3906
- case 2:
3907
- flow = _context3.sent;
3908
- setAuthFlow(flow);
3909
-
3910
- // Open verification URL in browser
3911
- if (flow.verificationUrlComplete) {
3912
- window.mainApi.shell.openExternal(flow.verificationUrlComplete);
3913
- }
3914
-
3915
- // Start polling for token
3916
- setIsPolling(true);
3917
- interval = (flow.interval || 5) * 1000;
3918
- pollIntervalRef.current = setInterval(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
3919
- var pollResult;
3920
- return _regeneratorRuntime.wrap(function (_context2) {
3921
- while (1) switch (_context2.prev = _context2.next) {
3922
- case 0:
3923
- _context2.prev = 0;
3924
- _context2.next = 1;
3925
- return window.mainApi.registryAuth.pollToken(flow.deviceCode);
3926
- case 1:
3927
- pollResult = _context2.sent;
3928
- if (pollResult.status === "authorized") {
3929
- clearInterval(pollIntervalRef.current);
3930
- pollIntervalRef.current = null;
3931
- setIsPolling(false);
3932
- setAuthFlow(null);
3933
- // DASH-136: Auto-retry install after successful auth
3934
- handleInstall();
3935
- } else if (pollResult.status === "expired") {
3936
- clearInterval(pollIntervalRef.current);
3937
- pollIntervalRef.current = null;
3938
- setIsPolling(false);
3939
- setAuthFlow(null);
3940
- setAuthError("Authorization expired. Please try again.");
3941
- }
3942
- _context2.next = 3;
3943
- break;
3944
- case 2:
3945
- _context2.prev = 2;
3946
- _context2["catch"](0);
3947
- clearInterval(pollIntervalRef.current);
3948
- pollIntervalRef.current = null;
3949
- setIsPolling(false);
3950
- case 3:
3951
- case "end":
3952
- return _context2.stop();
3953
- }
3954
- }, _callee2, null, [[0, 2]]);
3955
- })), interval);
3956
- _context3.next = 4;
3957
- break;
3958
- case 3:
3959
- _context3.prev = 3;
3960
- _context3["catch"](1);
3961
- setAuthError("Could not reach the registry. Check your connection and try again.");
3962
- case 4:
3963
- case "end":
3964
- return _context3.stop();
3965
- }
3966
- }, _callee3, null, [[1, 3]]);
3967
- }));
3968
- return _handleSignIn.apply(this, arguments);
3969
- }
3970
4141
  var widgetDeps = (preview === null || preview === void 0 ? void 0 : preview.widgets) || pkg.widgets || [];
3971
4142
  var providers = (preview === null || preview === void 0 ? void 0 : preview.providers) || [];
3972
4143
 
@@ -4210,55 +4381,15 @@ var RegistryDashboardDetail = function RegistryDashboardDetail(_ref) {
4210
4381
  children: installResult.message
4211
4382
  })]
4212
4383
  })
4213
- }), (installResult === null || installResult === void 0 ? void 0 : installResult.status) === "auth" && /*#__PURE__*/jsxRuntime.jsxs("div", {
4214
- className: "space-y-3",
4215
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
4216
- className: "bg-yellow-500/10 border border-yellow-500/20 rounded-lg p-3",
4217
- children: /*#__PURE__*/jsxRuntime.jsxs("div", {
4218
- className: "flex items-start gap-2",
4219
- children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
4220
- icon: "lock",
4221
- className: "h-3.5 w-3.5 text-yellow-400 mt-0.5 flex-shrink-0"
4222
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
4223
- className: "text-sm text-yellow-300/90",
4224
- children: installResult.message
4225
- })]
4226
- })
4227
- }), !authFlow && !isPolling && /*#__PURE__*/jsxRuntime.jsxs(jsxRuntime.Fragment, {
4228
- children: [/*#__PURE__*/jsxRuntime.jsx("button", {
4229
- type: "button",
4230
- onClick: handleSignIn,
4231
- className: "px-4 py-2 rounded-lg text-sm bg-blue-500/20 border border-blue-500/30 text-blue-300 hover:bg-blue-500/30 transition-colors cursor-pointer",
4232
- children: "Sign in to Registry"
4233
- }), authError && /*#__PURE__*/jsxRuntime.jsx("div", {
4234
- className: "bg-red-500/10 border border-red-500/20 rounded-lg p-3",
4235
- children: /*#__PURE__*/jsxRuntime.jsxs("div", {
4236
- className: "flex items-start gap-2",
4237
- children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
4238
- icon: "circle-xmark",
4239
- className: "h-3.5 w-3.5 text-red-400 mt-0.5 flex-shrink-0"
4240
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
4241
- className: "text-xs text-red-300/90",
4242
- children: authError
4243
- })]
4244
- })
4245
- })]
4246
- }), authFlow && isPolling && /*#__PURE__*/jsxRuntime.jsxs("div", {
4247
- className: "bg-blue-500/10 border border-blue-500/20 rounded-lg p-4 space-y-3",
4248
- children: [/*#__PURE__*/jsxRuntime.jsx("p", {
4249
- className: "text-xs text-blue-300/90",
4250
- children: "Enter this code in your browser:"
4251
- }), /*#__PURE__*/jsxRuntime.jsx("div", {
4252
- className: "text-center",
4253
- children: /*#__PURE__*/jsxRuntime.jsx("span", {
4254
- className: "text-2xl font-mono font-bold tracking-widest text-white",
4255
- children: authFlow.userCode
4256
- })
4257
- }), /*#__PURE__*/jsxRuntime.jsx("p", {
4258
- className: "text-xs text-blue-300/70 text-center",
4259
- children: "Waiting for authorization \u2014 install will resume automatically..."
4260
- })]
4261
- })]
4384
+ }), (installResult === null || installResult === void 0 ? void 0 : installResult.status) === "auth" && /*#__PURE__*/jsxRuntime.jsx(RegistryAuthPrompt, {
4385
+ onAuthenticated: function onAuthenticated() {
4386
+ setInstallResult(null);
4387
+ handleInstall();
4388
+ },
4389
+ onCancel: function onCancel() {
4390
+ return setInstallResult(null);
4391
+ },
4392
+ message: installResult.message
4262
4393
  })]
4263
4394
  }), (installResult === null || installResult === void 0 ? void 0 : installResult.status) !== "success" && (installResult === null || installResult === void 0 ? void 0 : installResult.status) !== "auth" && /*#__PURE__*/jsxRuntime.jsx("div", {
4264
4395
  className: "flex items-center justify-end px-6 py-3 border-t ".concat(currentTheme["border-primary-medium"]),
@@ -4506,7 +4637,8 @@ var LayoutManagerModal = function LayoutManagerModal(_ref) {
4506
4637
  onOpenWizard = _ref$onOpenWizard === void 0 ? null : _ref$onOpenWizard;
4507
4638
  var _useContext = React.useContext(DashReact.ThemeContext),
4508
4639
  themes = _useContext.themes,
4509
- appThemeKey = _useContext.themeKey;
4640
+ appThemeKey = _useContext.themeKey,
4641
+ loadThemes = _useContext.loadThemes;
4510
4642
  var _useState = React.useState(null),
4511
4643
  _useState2 = _slicedToArray(_useState, 2),
4512
4644
  creationMethod = _useState2[0],
@@ -4713,6 +4845,7 @@ var LayoutManagerModal = function LayoutManagerModal(_ref) {
4713
4845
  result = _context2.sent;
4714
4846
  if (result && result.success) {
4715
4847
  onReloadWorkspaces && onReloadWorkspaces();
4848
+ loadThemes();
4716
4849
  if (onOpenWorkspace && result.workspace) {
4717
4850
  onOpenWorkspace(result.workspace);
4718
4851
  }
@@ -4742,6 +4875,7 @@ var LayoutManagerModal = function LayoutManagerModal(_ref) {
4742
4875
  return window.mainApi.workspace.saveWorkspaceForApplication(appId, updatedWorkspace);
4743
4876
  case 8:
4744
4877
  onReloadWorkspaces && onReloadWorkspaces();
4878
+ loadThemes();
4745
4879
  if (onOpenWorkspace) {
4746
4880
  onOpenWorkspace(updatedWorkspace);
4747
4881
  }
@@ -5687,6 +5821,23 @@ var LayoutQuickAddMenu = function LayoutQuickAddMenu(_ref) {
5687
5821
  });
5688
5822
  };
5689
5823
 
5824
+ /**
5825
+ * Strip the Electron IPC error prefix from error messages.
5826
+ *
5827
+ * Raw IPC errors look like:
5828
+ * "Error invoking remote method 'widget:install': Error: Failed to fetch: Unauthorized"
5829
+ *
5830
+ * This extracts just the meaningful part after the last "Error: " prefix.
5831
+ *
5832
+ * @param {string} message - Raw error message
5833
+ * @returns {string} Cleaned error message
5834
+ */
5835
+ function cleanIpcError(message) {
5836
+ if (!message || typeof message !== "string") return message;
5837
+ var match = message.match(/Error invoking remote method '[^']+': (?:Error: )?(.*)/);
5838
+ return match ? match[1] : message;
5839
+ }
5840
+
5690
5841
  function _createForOfIteratorHelper$f(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$f(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t["return"] || t["return"](); } finally { if (u) throw o; } } }; }
5691
5842
  function _unsupportedIterableToArray$f(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$f(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray$f(r, a) : void 0; } }
5692
5843
  function _arrayLikeToArray$f(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
@@ -5748,8 +5899,12 @@ var useRegistrySearch = function useRegistrySearch() {
5748
5899
  setInstallError = _useState12[1];
5749
5900
  var _useState13 = React.useState(false),
5750
5901
  _useState14 = _slicedToArray(_useState13, 2),
5751
- showAllPackages = _useState14[0],
5752
- setShowAllPackages = _useState14[1];
5902
+ needsAuth = _useState14[0],
5903
+ setNeedsAuth = _useState14[1];
5904
+ var _useState15 = React.useState(false),
5905
+ _useState16 = _slicedToArray(_useState15, 2),
5906
+ showAllPackages = _useState16[0],
5907
+ setShowAllPackages = _useState16[1];
5753
5908
 
5754
5909
  // Discover app capabilities from window.mainApi
5755
5910
  var appCapabilities = React.useMemo(function () {
@@ -5914,9 +6069,12 @@ var useRegistrySearch = function useRegistrySearch() {
5914
6069
  };
5915
6070
  // eslint-disable-next-line react-hooks/exhaustive-deps
5916
6071
  }, [searchQuery, showAllPackages]);
6072
+ var clearNeedsAuth = React.useCallback(function () {
6073
+ return setNeedsAuth(false);
6074
+ }, []);
5917
6075
  var installPackage = React.useCallback(/*#__PURE__*/function () {
5918
6076
  var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(widget) {
5919
- var packageName, packageScope, downloadUrl, packageVersion, scopedId, resolvedUrl, _t2;
6077
+ var _window$mainApi2, status, packageName, packageScope, downloadUrl, packageVersion, scopedId, resolvedUrl, msg, _t3;
5920
6078
  return _regeneratorRuntime.wrap(function (_context2) {
5921
6079
  while (1) switch (_context2.prev = _context2.next) {
5922
6080
  case 0:
@@ -5928,28 +6086,53 @@ var useRegistrySearch = function useRegistrySearch() {
5928
6086
  case 1:
5929
6087
  setIsInstalling(true);
5930
6088
  setInstallError(null);
6089
+ setNeedsAuth(false);
5931
6090
  _context2.prev = 2;
6091
+ _context2.prev = 3;
6092
+ _context2.next = 4;
6093
+ return (_window$mainApi2 = window.mainApi) === null || _window$mainApi2 === void 0 || (_window$mainApi2 = _window$mainApi2.registryAuth) === null || _window$mainApi2 === void 0 ? void 0 : _window$mainApi2.getStatus();
6094
+ case 4:
6095
+ status = _context2.sent;
6096
+ if (status !== null && status !== void 0 && status.authenticated) {
6097
+ _context2.next = 5;
6098
+ break;
6099
+ }
6100
+ setNeedsAuth(true);
6101
+ setIsInstalling(false);
6102
+ return _context2.abrupt("return");
6103
+ case 5:
6104
+ _context2.next = 7;
6105
+ break;
6106
+ case 6:
6107
+ _context2.prev = 6;
6108
+ _context2["catch"](3);
6109
+ case 7:
5932
6110
  packageName = widget.packageName, packageScope = widget.packageScope, downloadUrl = widget.downloadUrl, packageVersion = widget.packageVersion; // Build scoped ID (e.g. "@trops/slack") for the install key
5933
6111
  scopedId = packageScope ? "@".concat(packageScope.replace(/^@/, ""), "/").concat(packageName) : packageName; // Resolve placeholders in the download URL
5934
6112
  resolvedUrl = downloadUrl.replace(/\{version\}/g, packageVersion).replace(/\{name\}/g, packageName);
5935
- _context2.next = 3;
6113
+ _context2.next = 8;
5936
6114
  return window.mainApi.widgets.install(scopedId, resolvedUrl);
5937
- case 3:
5938
- _context2.next = 5;
6115
+ case 8:
6116
+ _context2.next = 10;
5939
6117
  break;
5940
- case 4:
5941
- _context2.prev = 4;
5942
- _t2 = _context2["catch"](2);
5943
- setInstallError(_t2.message || "Failed to install package");
5944
- case 5:
5945
- _context2.prev = 5;
6118
+ case 9:
6119
+ _context2.prev = 9;
6120
+ _t3 = _context2["catch"](2);
6121
+ msg = cleanIpcError(_t3.message || "Failed to install package");
6122
+ if (msg.toLowerCase().includes("unauthorized") || msg.toLowerCase().includes("authentication required")) {
6123
+ setNeedsAuth(true);
6124
+ } else {
6125
+ setInstallError(msg);
6126
+ }
6127
+ case 10:
6128
+ _context2.prev = 10;
5946
6129
  setIsInstalling(false);
5947
- return _context2.finish(5);
5948
- case 6:
6130
+ return _context2.finish(10);
6131
+ case 11:
5949
6132
  case "end":
5950
6133
  return _context2.stop();
5951
6134
  }
5952
- }, _callee2, null, [[2, 4, 5, 6]]);
6135
+ }, _callee2, null, [[2, 9, 10, 11], [3, 6]]);
5953
6136
  }));
5954
6137
  return function (_x2) {
5955
6138
  return _ref3.apply(this, arguments);
@@ -5967,6 +6150,8 @@ var useRegistrySearch = function useRegistrySearch() {
5967
6150
  setSearchQuery: setSearchQuery,
5968
6151
  isInstalling: isInstalling,
5969
6152
  installError: installError,
6153
+ needsAuth: needsAuth,
6154
+ clearNeedsAuth: clearNeedsAuth,
5970
6155
  search: search,
5971
6156
  installPackage: installPackage,
5972
6157
  retry: retry,
@@ -16341,6 +16526,10 @@ var EnhancedWidgetDropdown = function EnhancedWidgetDropdown(_ref) {
16341
16526
  _useState64 = _slicedToArray(_useState63, 2),
16342
16527
  installError = _useState64[0],
16343
16528
  setInstallError = _useState64[1];
16529
+ var _useState65 = React.useState(false),
16530
+ _useState66 = _slicedToArray(_useState65, 2),
16531
+ needsAuth = _useState66[0],
16532
+ setNeedsAuth = _useState66[1];
16344
16533
 
16345
16534
  // Phase 3: Recent Widgets - localStorage functions
16346
16535
  var loadRecentWidgets = function loadRecentWidgets() {
@@ -16935,7 +17124,7 @@ var EnhancedWidgetDropdown = function EnhancedWidgetDropdown(_ref) {
16935
17124
  // Install a package from the registry
16936
17125
  var handleInstallPackage = /*#__PURE__*/function () {
16937
17126
  var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
16938
- var packageName, downloadUrl, packageVersion, resolvedUrl, _t2;
17127
+ var _window$mainApi, status, packageName, downloadUrl, packageVersion, resolvedUrl, msg, _t3;
16939
17128
  return _regeneratorRuntime.wrap(function (_context2) {
16940
17129
  while (1) switch (_context2.prev = _context2.next) {
16941
17130
  case 0:
@@ -16947,32 +17136,57 @@ var EnhancedWidgetDropdown = function EnhancedWidgetDropdown(_ref) {
16947
17136
  case 1:
16948
17137
  setIsInstalling(true);
16949
17138
  setInstallError(null);
17139
+ setNeedsAuth(false);
16950
17140
  _context2.prev = 2;
17141
+ _context2.prev = 3;
17142
+ _context2.next = 4;
17143
+ return (_window$mainApi = window.mainApi) === null || _window$mainApi === void 0 || (_window$mainApi = _window$mainApi.registryAuth) === null || _window$mainApi === void 0 ? void 0 : _window$mainApi.getStatus();
17144
+ case 4:
17145
+ status = _context2.sent;
17146
+ if (status !== null && status !== void 0 && status.authenticated) {
17147
+ _context2.next = 5;
17148
+ break;
17149
+ }
17150
+ setNeedsAuth(true);
17151
+ setIsInstalling(false);
17152
+ return _context2.abrupt("return");
17153
+ case 5:
17154
+ _context2.next = 7;
17155
+ break;
17156
+ case 6:
17157
+ _context2.prev = 6;
17158
+ _context2["catch"](3);
17159
+ case 7:
16951
17160
  packageName = selectedWidget.packageName, downloadUrl = selectedWidget.downloadUrl, packageVersion = selectedWidget.packageVersion; // Resolve version placeholder in download URL
16952
17161
  resolvedUrl = downloadUrl.replace(/\{version\}/g, packageVersion).replace(/\{name\}/g, packageName);
16953
- _context2.next = 3;
17162
+ _context2.next = 8;
16954
17163
  return window.mainApi.widgets.install(packageName, resolvedUrl);
16955
- case 3:
17164
+ case 8:
16956
17165
 
16957
17166
  // Switch to Installed tab after successful install
16958
17167
  setSelectedSource("Installed");
16959
17168
  setSelectedWidget(null);
16960
17169
  setSelectedPackage(null);
16961
- _context2.next = 5;
17170
+ _context2.next = 10;
16962
17171
  break;
16963
- case 4:
16964
- _context2.prev = 4;
16965
- _t2 = _context2["catch"](2);
16966
- setInstallError(_t2.message || "Failed to install package");
16967
- case 5:
16968
- _context2.prev = 5;
17172
+ case 9:
17173
+ _context2.prev = 9;
17174
+ _t3 = _context2["catch"](2);
17175
+ msg = cleanIpcError(_t3.message || "Failed to install package");
17176
+ if (msg.toLowerCase().includes("unauthorized") || msg.toLowerCase().includes("authentication required")) {
17177
+ setNeedsAuth(true);
17178
+ } else {
17179
+ setInstallError(msg);
17180
+ }
17181
+ case 10:
17182
+ _context2.prev = 10;
16969
17183
  setIsInstalling(false);
16970
- return _context2.finish(5);
16971
- case 6:
17184
+ return _context2.finish(10);
17185
+ case 11:
16972
17186
  case "end":
16973
17187
  return _context2.stop();
16974
17188
  }
16975
- }, _callee2, null, [[2, 4, 5, 6]]);
17189
+ }, _callee2, null, [[2, 9, 10, 11], [3, 6]]);
16976
17190
  }));
16977
17191
  return function handleInstallPackage() {
16978
17192
  return _ref3.apply(this, arguments);
@@ -17291,6 +17505,18 @@ var EnhancedWidgetDropdown = function EnhancedWidgetDropdown(_ref) {
17291
17505
  className: "text-xs text-red-400",
17292
17506
  children: installError
17293
17507
  })
17508
+ }), needsAuth && /*#__PURE__*/jsxRuntime.jsx("div", {
17509
+ className: "mt-3",
17510
+ children: /*#__PURE__*/jsxRuntime.jsx(RegistryAuthPrompt, {
17511
+ onAuthenticated: function onAuthenticated() {
17512
+ setNeedsAuth(false);
17513
+ handleInstallPackage();
17514
+ },
17515
+ onCancel: function onCancel() {
17516
+ return setNeedsAuth(false);
17517
+ },
17518
+ message: "Sign in to install this widget from the Dash Registry."
17519
+ })
17294
17520
  })]
17295
17521
  });
17296
17522
  };
@@ -23143,7 +23369,13 @@ var RegistryPackageDetail = function RegistryPackageDetail(_ref) {
23143
23369
  _ref$installError = _ref.installError,
23144
23370
  installError = _ref$installError === void 0 ? null : _ref$installError,
23145
23371
  _ref$isInstalled = _ref.isInstalled,
23146
- isInstalled = _ref$isInstalled === void 0 ? false : _ref$isInstalled;
23372
+ isInstalled = _ref$isInstalled === void 0 ? false : _ref$isInstalled,
23373
+ _ref$showAuth = _ref.showAuth,
23374
+ showAuth = _ref$showAuth === void 0 ? false : _ref$showAuth,
23375
+ _ref$onAuthSuccess = _ref.onAuthSuccess,
23376
+ onAuthSuccess = _ref$onAuthSuccess === void 0 ? null : _ref$onAuthSuccess,
23377
+ _ref$onAuthCancel = _ref.onAuthCancel,
23378
+ onAuthCancel = _ref$onAuthCancel === void 0 ? null : _ref$onAuthCancel;
23147
23379
  var _useContext = React.useContext(DashReact.ThemeContext),
23148
23380
  currentTheme = _useContext.currentTheme;
23149
23381
  var panelStyles = DashReact.getStylesForItem(DashReact.themeObjects.PANEL, currentTheme, {
@@ -23279,7 +23511,11 @@ var RegistryPackageDetail = function RegistryPackageDetail(_ref) {
23279
23511
  children: installError
23280
23512
  })
23281
23513
  })]
23282
- }), /*#__PURE__*/jsxRuntime.jsx("div", {
23514
+ }), showAuth && /*#__PURE__*/jsxRuntime.jsx(RegistryAuthPrompt, {
23515
+ onAuthenticated: onAuthSuccess,
23516
+ onCancel: onAuthCancel,
23517
+ message: "Sign in to install this widget from the Dash Registry."
23518
+ }), !showAuth && /*#__PURE__*/jsxRuntime.jsx("div", {
23283
23519
  className: "flex items-center justify-end px-6 py-3 border-t ".concat(currentTheme["border-primary-medium"]),
23284
23520
  children: /*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
23285
23521
  title: isInstalled ? "Installed" : isInstalling ? "Installing..." : "Install Package",
@@ -23294,267 +23530,6 @@ var RegistryPackageDetail = function RegistryPackageDetail(_ref) {
23294
23530
  });
23295
23531
  };
23296
23532
 
23297
- /**
23298
- * useRegistryAuth — reusable hook for device-code OAuth against the Dash Registry.
23299
- *
23300
- * Encapsulates the full auth state machine: check status, initiate login,
23301
- * poll for token, and cancel. Cleans up the poll interval on unmount.
23302
- *
23303
- * @returns {{
23304
- * isAuthenticated: boolean,
23305
- * isAuthenticating: boolean,
23306
- * authFlow: { userCode: string, verificationUrlComplete: string } | null,
23307
- * authError: string | null,
23308
- * checkAuth: () => Promise<boolean>,
23309
- * initiateAuth: () => Promise<void>,
23310
- * cancelAuth: () => void,
23311
- * }}
23312
- */
23313
- function useRegistryAuth() {
23314
- var _useState = React.useState(false),
23315
- _useState2 = _slicedToArray(_useState, 2),
23316
- isAuthenticated = _useState2[0],
23317
- setIsAuthenticated = _useState2[1];
23318
- var _useState3 = React.useState(false),
23319
- _useState4 = _slicedToArray(_useState3, 2),
23320
- isAuthenticating = _useState4[0],
23321
- setIsAuthenticating = _useState4[1];
23322
- var _useState5 = React.useState(null),
23323
- _useState6 = _slicedToArray(_useState5, 2),
23324
- authFlow = _useState6[0],
23325
- setAuthFlow = _useState6[1];
23326
- var _useState7 = React.useState(null),
23327
- _useState8 = _slicedToArray(_useState7, 2),
23328
- authError = _useState8[0],
23329
- setAuthError = _useState8[1];
23330
- var pollIntervalRef = React.useRef(null);
23331
- var onAuthorizedRef = React.useRef(null);
23332
-
23333
- // Clean up polling on unmount
23334
- React.useEffect(function () {
23335
- return function () {
23336
- if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
23337
- };
23338
- }, []);
23339
- var checkAuth = React.useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
23340
- var status, authed;
23341
- return _regeneratorRuntime.wrap(function (_context) {
23342
- while (1) switch (_context.prev = _context.next) {
23343
- case 0:
23344
- _context.prev = 0;
23345
- _context.next = 1;
23346
- return window.mainApi.registryAuth.getStatus();
23347
- case 1:
23348
- status = _context.sent;
23349
- authed = !!(status !== null && status !== void 0 && status.authenticated);
23350
- setIsAuthenticated(authed);
23351
- return _context.abrupt("return", authed);
23352
- case 2:
23353
- _context.prev = 2;
23354
- _context["catch"](0);
23355
- return _context.abrupt("return", false);
23356
- case 3:
23357
- case "end":
23358
- return _context.stop();
23359
- }
23360
- }, _callee, null, [[0, 2]]);
23361
- })), []);
23362
- var cancelAuth = React.useCallback(function () {
23363
- if (pollIntervalRef.current) {
23364
- clearInterval(pollIntervalRef.current);
23365
- pollIntervalRef.current = null;
23366
- }
23367
- setIsAuthenticating(false);
23368
- setAuthFlow(null);
23369
- }, []);
23370
- var initiateAuth = React.useCallback(/*#__PURE__*/function () {
23371
- var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(onAuthorized) {
23372
- var flow, interval;
23373
- return _regeneratorRuntime.wrap(function (_context3) {
23374
- while (1) switch (_context3.prev = _context3.next) {
23375
- case 0:
23376
- setAuthError(null);
23377
- onAuthorizedRef.current = onAuthorized || null;
23378
- _context3.prev = 1;
23379
- _context3.next = 2;
23380
- return window.mainApi.registryAuth.initiateLogin();
23381
- case 2:
23382
- flow = _context3.sent;
23383
- setAuthFlow(flow);
23384
- if (flow.verificationUrlComplete) {
23385
- window.mainApi.shell.openExternal(flow.verificationUrlComplete);
23386
- }
23387
- setIsAuthenticating(true);
23388
- interval = (flow.interval || 5) * 1000;
23389
- pollIntervalRef.current = setInterval(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
23390
- var pollResult;
23391
- return _regeneratorRuntime.wrap(function (_context2) {
23392
- while (1) switch (_context2.prev = _context2.next) {
23393
- case 0:
23394
- _context2.prev = 0;
23395
- _context2.next = 1;
23396
- return window.mainApi.registryAuth.pollToken(flow.deviceCode);
23397
- case 1:
23398
- pollResult = _context2.sent;
23399
- if (pollResult.status === "authorized") {
23400
- clearInterval(pollIntervalRef.current);
23401
- pollIntervalRef.current = null;
23402
- setIsAuthenticating(false);
23403
- setAuthFlow(null);
23404
- setIsAuthenticated(true);
23405
- if (onAuthorizedRef.current) {
23406
- onAuthorizedRef.current();
23407
- }
23408
- } else if (pollResult.status === "expired") {
23409
- clearInterval(pollIntervalRef.current);
23410
- pollIntervalRef.current = null;
23411
- setIsAuthenticating(false);
23412
- setAuthFlow(null);
23413
- setAuthError("Authorization expired. Please try again.");
23414
- }
23415
- _context2.next = 3;
23416
- break;
23417
- case 2:
23418
- _context2.prev = 2;
23419
- _context2["catch"](0);
23420
- clearInterval(pollIntervalRef.current);
23421
- pollIntervalRef.current = null;
23422
- setIsAuthenticating(false);
23423
- case 3:
23424
- case "end":
23425
- return _context2.stop();
23426
- }
23427
- }, _callee2, null, [[0, 2]]);
23428
- })), interval);
23429
- _context3.next = 4;
23430
- break;
23431
- case 3:
23432
- _context3.prev = 3;
23433
- _context3["catch"](1);
23434
- setAuthError("Could not reach the registry. Check your connection and try again.");
23435
- case 4:
23436
- case "end":
23437
- return _context3.stop();
23438
- }
23439
- }, _callee3, null, [[1, 3]]);
23440
- }));
23441
- return function (_x) {
23442
- return _ref2.apply(this, arguments);
23443
- };
23444
- }(), [cancelAuth]);
23445
- return {
23446
- isAuthenticated: isAuthenticated,
23447
- isAuthenticating: isAuthenticating,
23448
- authFlow: authFlow,
23449
- authError: authError,
23450
- checkAuth: checkAuth,
23451
- initiateAuth: initiateAuth,
23452
- cancelAuth: cancelAuth
23453
- };
23454
- }
23455
-
23456
- var RegistryAuthPrompt = function RegistryAuthPrompt(_ref) {
23457
- var onAuthenticated = _ref.onAuthenticated,
23458
- _ref$onCancel = _ref.onCancel,
23459
- onCancel = _ref$onCancel === void 0 ? null : _ref$onCancel,
23460
- _ref$message = _ref.message,
23461
- message = _ref$message === void 0 ? "Sign in to install from the Dash Registry." : _ref$message;
23462
- var _useRegistryAuth = useRegistryAuth(),
23463
- isAuthenticating = _useRegistryAuth.isAuthenticating,
23464
- authFlow = _useRegistryAuth.authFlow,
23465
- authError = _useRegistryAuth.authError,
23466
- checkAuth = _useRegistryAuth.checkAuth,
23467
- initiateAuth = _useRegistryAuth.initiateAuth,
23468
- cancelAuth = _useRegistryAuth.cancelAuth;
23469
- var checkedRef = React.useRef(false);
23470
-
23471
- // Check auth on mount — if already authenticated, short-circuit
23472
- React.useEffect(function () {
23473
- if (checkedRef.current) return;
23474
- checkedRef.current = true;
23475
- checkAuth().then(function (authed) {
23476
- if (authed && onAuthenticated) onAuthenticated();
23477
- });
23478
- }, [checkAuth, onAuthenticated]);
23479
- function handleSignIn() {
23480
- initiateAuth(function () {
23481
- if (onAuthenticated) onAuthenticated();
23482
- });
23483
- }
23484
- function handleCancel() {
23485
- cancelAuth();
23486
- if (onCancel) onCancel();
23487
- }
23488
-
23489
- // Polling state: show user code
23490
- if (authFlow && isAuthenticating) {
23491
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
23492
- className: "flex flex-col gap-3 p-4",
23493
- children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
23494
- className: "bg-blue-500/10 border border-blue-500/20 rounded-lg p-4 space-y-3",
23495
- children: [/*#__PURE__*/jsxRuntime.jsx("p", {
23496
- className: "text-xs text-blue-300/90",
23497
- children: "Enter this code in your browser:"
23498
- }), /*#__PURE__*/jsxRuntime.jsx("div", {
23499
- className: "text-center",
23500
- children: /*#__PURE__*/jsxRuntime.jsx("span", {
23501
- className: "text-2xl font-mono font-bold tracking-widest text-white",
23502
- children: authFlow.userCode
23503
- })
23504
- }), /*#__PURE__*/jsxRuntime.jsx("p", {
23505
- className: "text-xs text-blue-300/70 text-center",
23506
- children: "Waiting for authorization \u2014 install will resume automatically..."
23507
- })]
23508
- }), onCancel && /*#__PURE__*/jsxRuntime.jsx("button", {
23509
- type: "button",
23510
- onClick: handleCancel,
23511
- className: "self-center text-xs text-gray-500 hover:text-gray-300 transition-colors",
23512
- children: "Cancel"
23513
- })]
23514
- });
23515
- }
23516
-
23517
- // Default: not-started / error state
23518
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
23519
- className: "flex flex-col gap-3 p-4",
23520
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
23521
- className: "bg-yellow-500/10 border border-yellow-500/20 rounded-lg p-3",
23522
- children: /*#__PURE__*/jsxRuntime.jsxs("div", {
23523
- className: "flex items-start gap-2",
23524
- children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
23525
- icon: "lock",
23526
- className: "h-3.5 w-3.5 text-yellow-400 mt-0.5 flex-shrink-0"
23527
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
23528
- className: "text-sm text-yellow-300/90",
23529
- children: message
23530
- })]
23531
- })
23532
- }), /*#__PURE__*/jsxRuntime.jsx("button", {
23533
- type: "button",
23534
- onClick: handleSignIn,
23535
- className: "px-4 py-2 rounded-lg text-sm bg-blue-500/20 border border-blue-500/30 text-blue-300 hover:bg-blue-500/30 transition-colors cursor-pointer",
23536
- children: "Sign in to Registry"
23537
- }), authError && /*#__PURE__*/jsxRuntime.jsx("div", {
23538
- className: "bg-red-500/10 border border-red-500/20 rounded-lg p-3",
23539
- children: /*#__PURE__*/jsxRuntime.jsxs("div", {
23540
- className: "flex items-start gap-2",
23541
- children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
23542
- icon: "circle-xmark",
23543
- className: "h-3.5 w-3.5 text-red-400 mt-0.5 flex-shrink-0"
23544
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
23545
- className: "text-xs text-red-300/90",
23546
- children: authError
23547
- })]
23548
- })
23549
- }), onCancel && /*#__PURE__*/jsxRuntime.jsx("button", {
23550
- type: "button",
23551
- onClick: handleCancel,
23552
- className: "self-center text-xs text-gray-500 hover:text-gray-300 transition-colors",
23553
- children: "Cancel"
23554
- })]
23555
- });
23556
- };
23557
-
23558
23533
  function getWidgetSearchQuery(componentKey) {
23559
23534
  var parts = componentKey.split(".");
23560
23535
  if (parts.length >= 3) {
@@ -38980,7 +38955,8 @@ var DashboardsSection = function DashboardsSection(_ref) {
38980
38955
  setInstallMode = _useState12[1];
38981
38956
  var appId = credentials === null || credentials === void 0 ? void 0 : credentials.appId;
38982
38957
  var _useContext = React.useContext(DashReact.ThemeContext),
38983
- currentTheme = _useContext.currentTheme;
38958
+ currentTheme = _useContext.currentTheme,
38959
+ loadThemes = _useContext.loadThemes;
38984
38960
  var headerStyles = DashReact.getStylesForItem(DashReact.themeObjects.PANEL_HEADER, currentTheme, {
38985
38961
  grow: false
38986
38962
  });
@@ -39191,6 +39167,7 @@ var DashboardsSection = function DashboardsSection(_ref) {
39191
39167
  appId: appId,
39192
39168
  onInstallComplete: function onInstallComplete() {
39193
39169
  onReloadWorkspaces && onReloadWorkspaces();
39170
+ loadThemes();
39194
39171
  }
39195
39172
  });
39196
39173
  } else if (selectedWorkspace) {
@@ -44650,6 +44627,8 @@ var DiscoverWidgetsDetail = function DiscoverWidgetsDetail(_ref) {
44650
44627
  setSearchQuery = _useRegistrySearch.setSearchQuery,
44651
44628
  isInstalling = _useRegistrySearch.isInstalling,
44652
44629
  installError = _useRegistrySearch.installError,
44630
+ needsAuth = _useRegistrySearch.needsAuth,
44631
+ clearNeedsAuth = _useRegistrySearch.clearNeedsAuth,
44653
44632
  installPackage = _useRegistrySearch.installPackage,
44654
44633
  retry = _useRegistrySearch.retry,
44655
44634
  showAllPackages = _useRegistrySearch.showAllPackages,
@@ -44850,7 +44829,13 @@ var DiscoverWidgetsDetail = function DiscoverWidgetsDetail(_ref) {
44850
44829
  installError: installError,
44851
44830
  isInstalled: selectedWidget ? isPackageInstalled(packages.find(function (p) {
44852
44831
  return p.name === selectedPackageName;
44853
- }) || {}) : false
44832
+ }) || {}) : false,
44833
+ showAuth: needsAuth,
44834
+ onAuthSuccess: function onAuthSuccess() {
44835
+ clearNeedsAuth();
44836
+ installPackage(selectedWidget);
44837
+ },
44838
+ onAuthCancel: clearNeedsAuth
44854
44839
  })]
44855
44840
  });
44856
44841
  }
@@ -48109,6 +48094,10 @@ var SidebarDiscoverContent = function SidebarDiscoverContent(_ref2) {
48109
48094
  _useState2 = _slicedToArray(_useState, 2),
48110
48095
  selectedPackageName = _useState2[0],
48111
48096
  setSelectedPackageName = _useState2[1];
48097
+ var _useState3 = React.useState(null),
48098
+ _useState4 = _slicedToArray(_useState3, 2),
48099
+ pendingInstallPkg = _useState4[0],
48100
+ setPendingInstallPkg = _useState4[1];
48112
48101
 
48113
48102
  // Check if a package is installed by name or scope/name
48114
48103
  var isPackageInstalled = React.useCallback(function (pkg) {
@@ -48153,19 +48142,22 @@ var SidebarDiscoverContent = function SidebarDiscoverContent(_ref2) {
48153
48142
  }
48154
48143
  return _context.abrupt("return");
48155
48144
  case 1:
48145
+ setPendingInstallPkg(pkg);
48156
48146
  installable = {
48157
48147
  isRegistry: true,
48158
48148
  packageName: pkg.name,
48149
+ packageScope: pkg.scope || null,
48159
48150
  downloadUrl: pkg.downloadUrl || "",
48160
48151
  packageVersion: pkg.version || ""
48161
48152
  };
48162
48153
  _context.next = 2;
48163
48154
  return registry.installPackage(installable);
48164
48155
  case 2:
48165
- // If no install error, signal success
48166
- if (!registry.installError) {
48156
+ // If no install error and no auth needed, signal success
48157
+ if (!registry.installError && !registry.needsAuth) {
48167
48158
  onInstallSuccess(pkg.displayName || pkg.name);
48168
48159
  setSelectedPackageName(null);
48160
+ setPendingInstallPkg(null);
48169
48161
  }
48170
48162
  case 3:
48171
48163
  case "end":
@@ -48260,8 +48252,21 @@ var SidebarDiscoverContent = function SidebarDiscoverContent(_ref2) {
48260
48252
  }), registry.installError && /*#__PURE__*/jsxRuntime.jsx("div", {
48261
48253
  className: "text-xs text-red-400 bg-red-500/10 rounded px-2 py-1.5 mb-3",
48262
48254
  children: registry.installError
48255
+ }), registry.needsAuth && /*#__PURE__*/jsxRuntime.jsx("div", {
48256
+ className: "mb-3",
48257
+ children: /*#__PURE__*/jsxRuntime.jsx(RegistryAuthPrompt, {
48258
+ onAuthenticated: function onAuthenticated() {
48259
+ registry.clearNeedsAuth();
48260
+ if (pendingInstallPkg) handleInstall(pendingInstallPkg);
48261
+ },
48262
+ onCancel: function onCancel() {
48263
+ registry.clearNeedsAuth();
48264
+ setPendingInstallPkg(null);
48265
+ },
48266
+ message: "Sign in to install this widget from the Dash Registry."
48267
+ })
48263
48268
  })]
48264
- }), /*#__PURE__*/jsxRuntime.jsx("div", {
48269
+ }), !registry.needsAuth && /*#__PURE__*/jsxRuntime.jsx("div", {
48265
48270
  className: "px-3 py-2 flex-shrink-0",
48266
48271
  children: /*#__PURE__*/jsxRuntime.jsx("button", {
48267
48272
  type: "button",
@@ -48389,45 +48394,45 @@ var WidgetSidebar = function WidgetSidebar(_ref4) {
48389
48394
  currentTheme = _useContext.currentTheme;
48390
48395
 
48391
48396
  // Tab state
48392
- var _useState3 = React.useState("installed"),
48393
- _useState4 = _slicedToArray(_useState3, 2),
48394
- activeTab = _useState4[0],
48395
- setActiveTab = _useState4[1]; // "installed" | "discover"
48396
- var _useState5 = React.useState(null),
48397
+ var _useState5 = React.useState("installed"),
48397
48398
  _useState6 = _slicedToArray(_useState5, 2),
48398
- installSuccess = _useState6[0],
48399
- setInstallSuccess = _useState6[1];
48399
+ activeTab = _useState6[0],
48400
+ setActiveTab = _useState6[1]; // "installed" | "discover"
48401
+ var _useState7 = React.useState(null),
48402
+ _useState8 = _slicedToArray(_useState7, 2),
48403
+ installSuccess = _useState8[0],
48404
+ setInstallSuccess = _useState8[1];
48400
48405
 
48401
48406
  // Registry hook (only active when discover tab is shown)
48402
48407
  var registry = useRegistrySearch();
48403
48408
 
48404
48409
  // Filter state
48405
- var _useState7 = React.useState(""),
48406
- _useState8 = _slicedToArray(_useState7, 2),
48407
- searchQuery = _useState8[0],
48408
- setSearchQuery = _useState8[1];
48409
- var _useState9 = React.useState("all"),
48410
+ var _useState9 = React.useState(""),
48410
48411
  _useState0 = _slicedToArray(_useState9, 2),
48411
- filterAuthor = _useState0[0],
48412
- setFilterAuthor = _useState0[1];
48412
+ searchQuery = _useState0[0],
48413
+ setSearchQuery = _useState0[1];
48413
48414
  var _useState1 = React.useState("all"),
48414
48415
  _useState10 = _slicedToArray(_useState1, 2),
48415
- filterProvider = _useState10[0],
48416
- setFilterProvider = _useState10[1];
48416
+ filterAuthor = _useState10[0],
48417
+ setFilterAuthor = _useState10[1];
48417
48418
  var _useState11 = React.useState("all"),
48418
48419
  _useState12 = _slicedToArray(_useState11, 2),
48419
- filterHasEvents = _useState12[0],
48420
- setFilterHasEvents = _useState12[1];
48420
+ filterProvider = _useState12[0],
48421
+ setFilterProvider = _useState12[1];
48421
48422
  var _useState13 = React.useState("all"),
48422
48423
  _useState14 = _slicedToArray(_useState13, 2),
48423
- filterHasHandlers = _useState14[0],
48424
- setFilterHasHandlers = _useState14[1];
48424
+ filterHasEvents = _useState14[0],
48425
+ setFilterHasEvents = _useState14[1];
48426
+ var _useState15 = React.useState("all"),
48427
+ _useState16 = _slicedToArray(_useState15, 2),
48428
+ filterHasHandlers = _useState16[0],
48429
+ setFilterHasHandlers = _useState16[1];
48425
48430
 
48426
48431
  // Counter to trigger re-computation when installed widgets change
48427
- var _useState15 = React.useState(0),
48428
- _useState16 = _slicedToArray(_useState15, 2),
48429
- widgetVersion = _useState16[0],
48430
- setWidgetVersion = _useState16[1];
48432
+ var _useState17 = React.useState(0),
48433
+ _useState18 = _slicedToArray(_useState17, 2),
48434
+ widgetVersion = _useState18[0],
48435
+ setWidgetVersion = _useState18[1];
48431
48436
  React.useEffect(function () {
48432
48437
  var handleWidgetsUpdated = function handleWidgetsUpdated() {
48433
48438
  return setWidgetVersion(function (v) {
@@ -48455,10 +48460,10 @@ var WidgetSidebar = function WidgetSidebar(_ref4) {
48455
48460
 
48456
48461
  // Set of installed package identifiers for "Installed" badge in Discover tab.
48457
48462
  // Stores folder names, package names, and "author/name" keys for matching.
48458
- var _useState17 = React.useState(new Set()),
48459
- _useState18 = _slicedToArray(_useState17, 2),
48460
- installedPackageNames = _useState18[0],
48461
- setInstalledPackageNames = _useState18[1];
48463
+ var _useState19 = React.useState(new Set()),
48464
+ _useState20 = _slicedToArray(_useState19, 2),
48465
+ installedPackageNames = _useState20[0],
48466
+ setInstalledPackageNames = _useState20[1];
48462
48467
  React.useEffect(function () {
48463
48468
  var cancelled = false;
48464
48469
  var loadInstalled = /*#__PURE__*/function () {