@trops/dash-core 0.1.256 → 0.1.259

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 CHANGED
@@ -3565,17 +3565,14 @@ var InstallProgressModal = function InstallProgressModal(_ref) {
3565
3565
  widgets = _ref$widgets === void 0 ? [] : _ref$widgets,
3566
3566
  _ref$isComplete = _ref.isComplete,
3567
3567
  isComplete = _ref$isComplete === void 0 ? false : _ref$isComplete,
3568
- onDone = _ref.onDone;
3568
+ onDone = _ref.onDone,
3569
+ _ref$onCancel = _ref.onCancel,
3570
+ onCancel = _ref$onCancel === void 0 ? null : _ref$onCancel;
3569
3571
  var _useContext = useContext(ThemeContext),
3570
3572
  currentTheme = _useContext.currentTheme;
3571
3573
  var panelStyles = getStylesForItem(themeObjects.PANEL, currentTheme, {
3572
3574
  grow: false
3573
3575
  });
3574
-
3575
- // Prevent dismissal while installation is in progress
3576
- var guardedSetIsOpen = function guardedSetIsOpen(val) {
3577
- if (isComplete) setIsOpen(val);
3578
- };
3579
3576
  var doneCount = widgets.filter(function (w) {
3580
3577
  return w.status === "installed" || w.status === "already-installed" || w.status === "failed";
3581
3578
  }).length;
@@ -3606,7 +3603,7 @@ var InstallProgressModal = function InstallProgressModal(_ref) {
3606
3603
  }
3607
3604
  return /*#__PURE__*/jsx(Modal, {
3608
3605
  isOpen: isOpen,
3609
- setIsOpen: guardedSetIsOpen,
3606
+ setIsOpen: setIsOpen,
3610
3607
  width: "w-[440px]",
3611
3608
  height: "auto",
3612
3609
  children: /*#__PURE__*/jsxs("div", {
@@ -3636,9 +3633,19 @@ var InstallProgressModal = function InstallProgressModal(_ref) {
3636
3633
  })]
3637
3634
  }, idx);
3638
3635
  })
3639
- }), /*#__PURE__*/jsx("div", {
3640
- className: "flex items-center justify-end px-5 py-3 border-t ".concat(currentTheme["border-primary-medium"] || "border-white/10"),
3641
- children: /*#__PURE__*/jsx(Button, {
3636
+ }), /*#__PURE__*/jsxs("div", {
3637
+ className: "flex items-center justify-between px-5 py-3 border-t ".concat(currentTheme["border-primary-medium"] || "border-white/10"),
3638
+ children: [/*#__PURE__*/jsx("div", {
3639
+ children: !isComplete && onCancel && /*#__PURE__*/jsx("button", {
3640
+ type: "button",
3641
+ onClick: function onClick() {
3642
+ if (onCancel) onCancel();
3643
+ setIsOpen(false);
3644
+ },
3645
+ className: "text-sm text-gray-500 hover:text-gray-300 transition-colors",
3646
+ children: "Cancel"
3647
+ })
3648
+ }), /*#__PURE__*/jsx(Button, {
3642
3649
  title: "Done",
3643
3650
  bgColor: isComplete ? "bg-blue-600" : "bg-gray-700",
3644
3651
  hoverBackgroundColor: isComplete ? "hover:bg-blue-700" : "",
@@ -3648,12 +3655,273 @@ var InstallProgressModal = function InstallProgressModal(_ref) {
3648
3655
  if (isComplete && onDone) onDone();
3649
3656
  },
3650
3657
  disabled: !isComplete
3651
- })
3658
+ })]
3652
3659
  })]
3653
3660
  })
3654
3661
  });
3655
3662
  };
3656
3663
 
3664
+ /**
3665
+ * useRegistryAuth — reusable hook for device-code OAuth against the Dash Registry.
3666
+ *
3667
+ * Encapsulates the full auth state machine: check status, initiate login,
3668
+ * poll for token, and cancel. Cleans up the poll interval on unmount.
3669
+ *
3670
+ * @returns {{
3671
+ * isAuthenticated: boolean,
3672
+ * isAuthenticating: boolean,
3673
+ * authFlow: { userCode: string, verificationUrlComplete: string } | null,
3674
+ * authError: string | null,
3675
+ * checkAuth: () => Promise<boolean>,
3676
+ * initiateAuth: () => Promise<void>,
3677
+ * cancelAuth: () => void,
3678
+ * }}
3679
+ */
3680
+ function useRegistryAuth() {
3681
+ var _useState = useState(false),
3682
+ _useState2 = _slicedToArray(_useState, 2),
3683
+ isAuthenticated = _useState2[0],
3684
+ setIsAuthenticated = _useState2[1];
3685
+ var _useState3 = useState(false),
3686
+ _useState4 = _slicedToArray(_useState3, 2),
3687
+ isAuthenticating = _useState4[0],
3688
+ setIsAuthenticating = _useState4[1];
3689
+ var _useState5 = useState(null),
3690
+ _useState6 = _slicedToArray(_useState5, 2),
3691
+ authFlow = _useState6[0],
3692
+ setAuthFlow = _useState6[1];
3693
+ var _useState7 = useState(null),
3694
+ _useState8 = _slicedToArray(_useState7, 2),
3695
+ authError = _useState8[0],
3696
+ setAuthError = _useState8[1];
3697
+ var pollIntervalRef = useRef(null);
3698
+ var onAuthorizedRef = useRef(null);
3699
+
3700
+ // Clean up polling on unmount
3701
+ useEffect(function () {
3702
+ return function () {
3703
+ if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
3704
+ };
3705
+ }, []);
3706
+ var checkAuth = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
3707
+ var status, authed;
3708
+ return _regeneratorRuntime.wrap(function (_context) {
3709
+ while (1) switch (_context.prev = _context.next) {
3710
+ case 0:
3711
+ _context.prev = 0;
3712
+ _context.next = 1;
3713
+ return window.mainApi.registryAuth.getStatus();
3714
+ case 1:
3715
+ status = _context.sent;
3716
+ authed = !!(status !== null && status !== void 0 && status.authenticated);
3717
+ setIsAuthenticated(authed);
3718
+ return _context.abrupt("return", authed);
3719
+ case 2:
3720
+ _context.prev = 2;
3721
+ _context["catch"](0);
3722
+ return _context.abrupt("return", false);
3723
+ case 3:
3724
+ case "end":
3725
+ return _context.stop();
3726
+ }
3727
+ }, _callee, null, [[0, 2]]);
3728
+ })), []);
3729
+ var cancelAuth = useCallback(function () {
3730
+ if (pollIntervalRef.current) {
3731
+ clearInterval(pollIntervalRef.current);
3732
+ pollIntervalRef.current = null;
3733
+ }
3734
+ setIsAuthenticating(false);
3735
+ setAuthFlow(null);
3736
+ }, []);
3737
+ var initiateAuth = useCallback(/*#__PURE__*/function () {
3738
+ var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(onAuthorized) {
3739
+ var flow, interval;
3740
+ return _regeneratorRuntime.wrap(function (_context3) {
3741
+ while (1) switch (_context3.prev = _context3.next) {
3742
+ case 0:
3743
+ setAuthError(null);
3744
+ onAuthorizedRef.current = onAuthorized || null;
3745
+ _context3.prev = 1;
3746
+ _context3.next = 2;
3747
+ return window.mainApi.registryAuth.initiateLogin();
3748
+ case 2:
3749
+ flow = _context3.sent;
3750
+ setAuthFlow(flow);
3751
+ if (flow.verificationUrlComplete) {
3752
+ window.mainApi.shell.openExternal(flow.verificationUrlComplete);
3753
+ }
3754
+ setIsAuthenticating(true);
3755
+ interval = (flow.interval || 5) * 1000;
3756
+ pollIntervalRef.current = setInterval(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
3757
+ var pollResult;
3758
+ return _regeneratorRuntime.wrap(function (_context2) {
3759
+ while (1) switch (_context2.prev = _context2.next) {
3760
+ case 0:
3761
+ _context2.prev = 0;
3762
+ _context2.next = 1;
3763
+ return window.mainApi.registryAuth.pollToken(flow.deviceCode);
3764
+ case 1:
3765
+ pollResult = _context2.sent;
3766
+ if (pollResult.status === "authorized") {
3767
+ clearInterval(pollIntervalRef.current);
3768
+ pollIntervalRef.current = null;
3769
+ setIsAuthenticating(false);
3770
+ setAuthFlow(null);
3771
+ setIsAuthenticated(true);
3772
+ if (onAuthorizedRef.current) {
3773
+ onAuthorizedRef.current();
3774
+ }
3775
+ } else if (pollResult.status === "expired") {
3776
+ clearInterval(pollIntervalRef.current);
3777
+ pollIntervalRef.current = null;
3778
+ setIsAuthenticating(false);
3779
+ setAuthFlow(null);
3780
+ setAuthError("Authorization expired. Please try again.");
3781
+ }
3782
+ _context2.next = 3;
3783
+ break;
3784
+ case 2:
3785
+ _context2.prev = 2;
3786
+ _context2["catch"](0);
3787
+ clearInterval(pollIntervalRef.current);
3788
+ pollIntervalRef.current = null;
3789
+ setIsAuthenticating(false);
3790
+ case 3:
3791
+ case "end":
3792
+ return _context2.stop();
3793
+ }
3794
+ }, _callee2, null, [[0, 2]]);
3795
+ })), interval);
3796
+ _context3.next = 4;
3797
+ break;
3798
+ case 3:
3799
+ _context3.prev = 3;
3800
+ _context3["catch"](1);
3801
+ setAuthError("Could not reach the registry. Check your connection and try again.");
3802
+ case 4:
3803
+ case "end":
3804
+ return _context3.stop();
3805
+ }
3806
+ }, _callee3, null, [[1, 3]]);
3807
+ }));
3808
+ return function (_x) {
3809
+ return _ref2.apply(this, arguments);
3810
+ };
3811
+ }(), [cancelAuth]);
3812
+ return {
3813
+ isAuthenticated: isAuthenticated,
3814
+ isAuthenticating: isAuthenticating,
3815
+ authFlow: authFlow,
3816
+ authError: authError,
3817
+ checkAuth: checkAuth,
3818
+ initiateAuth: initiateAuth,
3819
+ cancelAuth: cancelAuth
3820
+ };
3821
+ }
3822
+
3823
+ var RegistryAuthPrompt = function RegistryAuthPrompt(_ref) {
3824
+ var onAuthenticated = _ref.onAuthenticated,
3825
+ _ref$onCancel = _ref.onCancel,
3826
+ onCancel = _ref$onCancel === void 0 ? null : _ref$onCancel,
3827
+ _ref$message = _ref.message,
3828
+ message = _ref$message === void 0 ? "Sign in to install from the Dash Registry." : _ref$message;
3829
+ var _useRegistryAuth = useRegistryAuth(),
3830
+ isAuthenticating = _useRegistryAuth.isAuthenticating,
3831
+ authFlow = _useRegistryAuth.authFlow,
3832
+ authError = _useRegistryAuth.authError,
3833
+ checkAuth = _useRegistryAuth.checkAuth,
3834
+ initiateAuth = _useRegistryAuth.initiateAuth,
3835
+ cancelAuth = _useRegistryAuth.cancelAuth;
3836
+ var checkedRef = useRef(false);
3837
+
3838
+ // Check auth on mount — if already authenticated, short-circuit
3839
+ useEffect(function () {
3840
+ if (checkedRef.current) return;
3841
+ checkedRef.current = true;
3842
+ checkAuth().then(function (authed) {
3843
+ if (authed && onAuthenticated) onAuthenticated();
3844
+ });
3845
+ }, [checkAuth, onAuthenticated]);
3846
+ function handleSignIn() {
3847
+ initiateAuth(function () {
3848
+ if (onAuthenticated) onAuthenticated();
3849
+ });
3850
+ }
3851
+ function handleCancel() {
3852
+ cancelAuth();
3853
+ if (onCancel) onCancel();
3854
+ }
3855
+
3856
+ // Polling state: show user code
3857
+ if (authFlow && isAuthenticating) {
3858
+ return /*#__PURE__*/jsxs("div", {
3859
+ className: "flex flex-col gap-3 p-4",
3860
+ children: [/*#__PURE__*/jsxs("div", {
3861
+ className: "bg-blue-500/10 border border-blue-500/20 rounded-lg p-4 space-y-3",
3862
+ children: [/*#__PURE__*/jsx("p", {
3863
+ className: "text-xs text-blue-300/90",
3864
+ children: "Enter this code in your browser:"
3865
+ }), /*#__PURE__*/jsx("div", {
3866
+ className: "text-center",
3867
+ children: /*#__PURE__*/jsx("span", {
3868
+ className: "text-2xl font-mono font-bold tracking-widest text-white",
3869
+ children: authFlow.userCode
3870
+ })
3871
+ }), /*#__PURE__*/jsx("p", {
3872
+ className: "text-xs text-blue-300/70 text-center",
3873
+ children: "Waiting for authorization \u2014 install will resume automatically..."
3874
+ })]
3875
+ }), onCancel && /*#__PURE__*/jsx("button", {
3876
+ type: "button",
3877
+ onClick: handleCancel,
3878
+ className: "self-center text-xs text-gray-500 hover:text-gray-300 transition-colors",
3879
+ children: "Cancel"
3880
+ })]
3881
+ });
3882
+ }
3883
+
3884
+ // Default: not-started / error state
3885
+ return /*#__PURE__*/jsxs("div", {
3886
+ className: "flex flex-col gap-3 p-4",
3887
+ children: [/*#__PURE__*/jsx("div", {
3888
+ className: "bg-yellow-500/10 border border-yellow-500/20 rounded-lg p-3",
3889
+ children: /*#__PURE__*/jsxs("div", {
3890
+ className: "flex items-start gap-2",
3891
+ children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
3892
+ icon: "lock",
3893
+ className: "h-3.5 w-3.5 text-yellow-400 mt-0.5 flex-shrink-0"
3894
+ }), /*#__PURE__*/jsx("span", {
3895
+ className: "text-sm text-yellow-300/90",
3896
+ children: message
3897
+ })]
3898
+ })
3899
+ }), /*#__PURE__*/jsx("button", {
3900
+ type: "button",
3901
+ onClick: handleSignIn,
3902
+ 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",
3903
+ children: "Sign in to Registry"
3904
+ }), authError && /*#__PURE__*/jsx("div", {
3905
+ className: "bg-red-500/10 border border-red-500/20 rounded-lg p-3",
3906
+ children: /*#__PURE__*/jsxs("div", {
3907
+ className: "flex items-start gap-2",
3908
+ children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
3909
+ icon: "circle-xmark",
3910
+ className: "h-3.5 w-3.5 text-red-400 mt-0.5 flex-shrink-0"
3911
+ }), /*#__PURE__*/jsx("span", {
3912
+ className: "text-xs text-red-300/90",
3913
+ children: authError
3914
+ })]
3915
+ })
3916
+ }), onCancel && /*#__PURE__*/jsx("button", {
3917
+ type: "button",
3918
+ onClick: handleCancel,
3919
+ className: "self-center text-xs text-gray-500 hover:text-gray-300 transition-colors",
3920
+ children: "Cancel"
3921
+ })]
3922
+ });
3923
+ };
3924
+
3657
3925
  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; } } }; }
3658
3926
  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; } }
3659
3927
  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; }
@@ -3684,41 +3952,27 @@ var RegistryDashboardDetail = function RegistryDashboardDetail(_ref) {
3684
3952
  _useState8 = _slicedToArray(_useState7, 2),
3685
3953
  installResult = _useState8[0],
3686
3954
  setInstallResult = _useState8[1];
3687
- var _useState9 = useState(null),
3955
+ var _useState9 = useState(false),
3688
3956
  _useState0 = _slicedToArray(_useState9, 2),
3689
- authFlow = _useState0[0],
3690
- setAuthFlow = _useState0[1];
3691
- var _useState1 = useState(false),
3957
+ showProgressModal = _useState0[0],
3958
+ setShowProgressModal = _useState0[1];
3959
+ var _useState1 = useState([]),
3692
3960
  _useState10 = _slicedToArray(_useState1, 2),
3693
- isPolling = _useState10[0],
3694
- setIsPolling = _useState10[1];
3695
- var _useState11 = useState(null),
3961
+ progressWidgets = _useState10[0],
3962
+ setProgressWidgets = _useState10[1];
3963
+ var _useState11 = useState(false),
3696
3964
  _useState12 = _slicedToArray(_useState11, 2),
3697
- authError = _useState12[0],
3698
- setAuthError = _useState12[1];
3699
- var _useState13 = useState(false),
3700
- _useState14 = _slicedToArray(_useState13, 2),
3701
- showProgressModal = _useState14[0],
3702
- setShowProgressModal = _useState14[1];
3703
- var _useState15 = useState([]),
3704
- _useState16 = _slicedToArray(_useState15, 2),
3705
- progressWidgets = _useState16[0],
3706
- setProgressWidgets = _useState16[1];
3707
- var _useState17 = useState(false),
3708
- _useState18 = _slicedToArray(_useState17, 2),
3709
- progressComplete = _useState18[0],
3710
- setProgressComplete = _useState18[1];
3965
+ progressComplete = _useState12[0],
3966
+ setProgressComplete = _useState12[1];
3711
3967
  var progressResultRef = useRef(null);
3712
- var pollIntervalRef = useRef(null);
3713
3968
  var cleanupProgressRef = useRef(null);
3714
3969
  var pkg = dashboardPackage;
3715
3970
  if (!pkg) return null;
3716
3971
 
3717
- // Clean up polling and progress listener on unmount
3972
+ // Clean up progress listener on unmount
3718
3973
  // eslint-disable-next-line react-hooks/rules-of-hooks
3719
3974
  useEffect(function () {
3720
3975
  return function () {
3721
- if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
3722
3976
  if (cleanupProgressRef.current) cleanupProgressRef.current();
3723
3977
  };
3724
3978
  }, []);
@@ -3732,10 +3986,6 @@ var RegistryDashboardDetail = function RegistryDashboardDetail(_ref) {
3732
3986
  setPreviewLoading(true);
3733
3987
  setPreview(null);
3734
3988
  setInstallResult(null);
3735
- setAuthFlow(null);
3736
- setIsPolling(false);
3737
- setAuthError(null);
3738
- if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
3739
3989
  (_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) {
3740
3990
  if (!cancelled) setPreview(result);
3741
3991
  })["catch"](function (err) {
@@ -3763,8 +4013,6 @@ var RegistryDashboardDetail = function RegistryDashboardDetail(_ref) {
3763
4013
  case 1:
3764
4014
  setIsInstalling(true);
3765
4015
  setInstallResult(null);
3766
- setAuthFlow(null);
3767
- setAuthError(null);
3768
4016
 
3769
4017
  // Initialize progress modal from widget deps
3770
4018
  deps = widgetDeps.length > 0 ? widgetDeps : [];
@@ -3872,83 +4120,6 @@ var RegistryDashboardDetail = function RegistryDashboardDetail(_ref) {
3872
4120
  }
3873
4121
  }
3874
4122
  }, [pkg.name, onInstallComplete]);
3875
- function handleSignIn() {
3876
- return _handleSignIn.apply(this, arguments);
3877
- }
3878
- function _handleSignIn() {
3879
- _handleSignIn = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
3880
- var flow, interval;
3881
- return _regeneratorRuntime.wrap(function (_context3) {
3882
- while (1) switch (_context3.prev = _context3.next) {
3883
- case 0:
3884
- setAuthError(null);
3885
- _context3.prev = 1;
3886
- _context3.next = 2;
3887
- return window.mainApi.registryAuth.initiateLogin();
3888
- case 2:
3889
- flow = _context3.sent;
3890
- setAuthFlow(flow);
3891
-
3892
- // Open verification URL in browser
3893
- if (flow.verificationUrlComplete) {
3894
- window.mainApi.shell.openExternal(flow.verificationUrlComplete);
3895
- }
3896
-
3897
- // Start polling for token
3898
- setIsPolling(true);
3899
- interval = (flow.interval || 5) * 1000;
3900
- pollIntervalRef.current = setInterval(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
3901
- var pollResult;
3902
- return _regeneratorRuntime.wrap(function (_context2) {
3903
- while (1) switch (_context2.prev = _context2.next) {
3904
- case 0:
3905
- _context2.prev = 0;
3906
- _context2.next = 1;
3907
- return window.mainApi.registryAuth.pollToken(flow.deviceCode);
3908
- case 1:
3909
- pollResult = _context2.sent;
3910
- if (pollResult.status === "authorized") {
3911
- clearInterval(pollIntervalRef.current);
3912
- pollIntervalRef.current = null;
3913
- setIsPolling(false);
3914
- setAuthFlow(null);
3915
- // DASH-136: Auto-retry install after successful auth
3916
- handleInstall();
3917
- } else if (pollResult.status === "expired") {
3918
- clearInterval(pollIntervalRef.current);
3919
- pollIntervalRef.current = null;
3920
- setIsPolling(false);
3921
- setAuthFlow(null);
3922
- setAuthError("Authorization expired. Please try again.");
3923
- }
3924
- _context2.next = 3;
3925
- break;
3926
- case 2:
3927
- _context2.prev = 2;
3928
- _context2["catch"](0);
3929
- clearInterval(pollIntervalRef.current);
3930
- pollIntervalRef.current = null;
3931
- setIsPolling(false);
3932
- case 3:
3933
- case "end":
3934
- return _context2.stop();
3935
- }
3936
- }, _callee2, null, [[0, 2]]);
3937
- })), interval);
3938
- _context3.next = 4;
3939
- break;
3940
- case 3:
3941
- _context3.prev = 3;
3942
- _context3["catch"](1);
3943
- setAuthError("Could not reach the registry. Check your connection and try again.");
3944
- case 4:
3945
- case "end":
3946
- return _context3.stop();
3947
- }
3948
- }, _callee3, null, [[1, 3]]);
3949
- }));
3950
- return _handleSignIn.apply(this, arguments);
3951
- }
3952
4123
  var widgetDeps = (preview === null || preview === void 0 ? void 0 : preview.widgets) || pkg.widgets || [];
3953
4124
  var providers = (preview === null || preview === void 0 ? void 0 : preview.providers) || [];
3954
4125
 
@@ -4192,55 +4363,15 @@ var RegistryDashboardDetail = function RegistryDashboardDetail(_ref) {
4192
4363
  children: installResult.message
4193
4364
  })]
4194
4365
  })
4195
- }), (installResult === null || installResult === void 0 ? void 0 : installResult.status) === "auth" && /*#__PURE__*/jsxs("div", {
4196
- className: "space-y-3",
4197
- children: [/*#__PURE__*/jsx("div", {
4198
- className: "bg-yellow-500/10 border border-yellow-500/20 rounded-lg p-3",
4199
- children: /*#__PURE__*/jsxs("div", {
4200
- className: "flex items-start gap-2",
4201
- children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
4202
- icon: "lock",
4203
- className: "h-3.5 w-3.5 text-yellow-400 mt-0.5 flex-shrink-0"
4204
- }), /*#__PURE__*/jsx("span", {
4205
- className: "text-sm text-yellow-300/90",
4206
- children: installResult.message
4207
- })]
4208
- })
4209
- }), !authFlow && !isPolling && /*#__PURE__*/jsxs(Fragment, {
4210
- children: [/*#__PURE__*/jsx("button", {
4211
- type: "button",
4212
- onClick: handleSignIn,
4213
- 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",
4214
- children: "Sign in to Registry"
4215
- }), authError && /*#__PURE__*/jsx("div", {
4216
- className: "bg-red-500/10 border border-red-500/20 rounded-lg p-3",
4217
- children: /*#__PURE__*/jsxs("div", {
4218
- className: "flex items-start gap-2",
4219
- children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
4220
- icon: "circle-xmark",
4221
- className: "h-3.5 w-3.5 text-red-400 mt-0.5 flex-shrink-0"
4222
- }), /*#__PURE__*/jsx("span", {
4223
- className: "text-xs text-red-300/90",
4224
- children: authError
4225
- })]
4226
- })
4227
- })]
4228
- }), authFlow && isPolling && /*#__PURE__*/jsxs("div", {
4229
- className: "bg-blue-500/10 border border-blue-500/20 rounded-lg p-4 space-y-3",
4230
- children: [/*#__PURE__*/jsx("p", {
4231
- className: "text-xs text-blue-300/90",
4232
- children: "Enter this code in your browser:"
4233
- }), /*#__PURE__*/jsx("div", {
4234
- className: "text-center",
4235
- children: /*#__PURE__*/jsx("span", {
4236
- className: "text-2xl font-mono font-bold tracking-widest text-white",
4237
- children: authFlow.userCode
4238
- })
4239
- }), /*#__PURE__*/jsx("p", {
4240
- className: "text-xs text-blue-300/70 text-center",
4241
- children: "Waiting for authorization \u2014 install will resume automatically..."
4242
- })]
4243
- })]
4366
+ }), (installResult === null || installResult === void 0 ? void 0 : installResult.status) === "auth" && /*#__PURE__*/jsx(RegistryAuthPrompt, {
4367
+ onAuthenticated: function onAuthenticated() {
4368
+ setInstallResult(null);
4369
+ handleInstall();
4370
+ },
4371
+ onCancel: function onCancel() {
4372
+ return setInstallResult(null);
4373
+ },
4374
+ message: installResult.message
4244
4375
  })]
4245
4376
  }), (installResult === null || installResult === void 0 ? void 0 : installResult.status) !== "success" && (installResult === null || installResult === void 0 ? void 0 : installResult.status) !== "auth" && /*#__PURE__*/jsx("div", {
4246
4377
  className: "flex items-center justify-end px-6 py-3 border-t ".concat(currentTheme["border-primary-medium"]),
@@ -5669,6 +5800,23 @@ var LayoutQuickAddMenu = function LayoutQuickAddMenu(_ref) {
5669
5800
  });
5670
5801
  };
5671
5802
 
5803
+ /**
5804
+ * Strip the Electron IPC error prefix from error messages.
5805
+ *
5806
+ * Raw IPC errors look like:
5807
+ * "Error invoking remote method 'widget:install': Error: Failed to fetch: Unauthorized"
5808
+ *
5809
+ * This extracts just the meaningful part after the last "Error: " prefix.
5810
+ *
5811
+ * @param {string} message - Raw error message
5812
+ * @returns {string} Cleaned error message
5813
+ */
5814
+ function cleanIpcError(message) {
5815
+ if (!message || typeof message !== "string") return message;
5816
+ var match = message.match(/Error invoking remote method '[^']+': (?:Error: )?(.*)/);
5817
+ return match ? match[1] : message;
5818
+ }
5819
+
5672
5820
  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; } } }; }
5673
5821
  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; } }
5674
5822
  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; }
@@ -5730,8 +5878,12 @@ var useRegistrySearch = function useRegistrySearch() {
5730
5878
  setInstallError = _useState12[1];
5731
5879
  var _useState13 = useState(false),
5732
5880
  _useState14 = _slicedToArray(_useState13, 2),
5733
- showAllPackages = _useState14[0],
5734
- setShowAllPackages = _useState14[1];
5881
+ needsAuth = _useState14[0],
5882
+ setNeedsAuth = _useState14[1];
5883
+ var _useState15 = useState(false),
5884
+ _useState16 = _slicedToArray(_useState15, 2),
5885
+ showAllPackages = _useState16[0],
5886
+ setShowAllPackages = _useState16[1];
5735
5887
 
5736
5888
  // Discover app capabilities from window.mainApi
5737
5889
  var appCapabilities = useMemo(function () {
@@ -5896,9 +6048,12 @@ var useRegistrySearch = function useRegistrySearch() {
5896
6048
  };
5897
6049
  // eslint-disable-next-line react-hooks/exhaustive-deps
5898
6050
  }, [searchQuery, showAllPackages]);
6051
+ var clearNeedsAuth = useCallback(function () {
6052
+ return setNeedsAuth(false);
6053
+ }, []);
5899
6054
  var installPackage = useCallback(/*#__PURE__*/function () {
5900
6055
  var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(widget) {
5901
- var packageName, packageScope, downloadUrl, packageVersion, scopedId, resolvedUrl, _t2;
6056
+ var _window$mainApi2, status, packageName, packageScope, downloadUrl, packageVersion, scopedId, resolvedUrl, msg, _t3;
5902
6057
  return _regeneratorRuntime.wrap(function (_context2) {
5903
6058
  while (1) switch (_context2.prev = _context2.next) {
5904
6059
  case 0:
@@ -5910,28 +6065,53 @@ var useRegistrySearch = function useRegistrySearch() {
5910
6065
  case 1:
5911
6066
  setIsInstalling(true);
5912
6067
  setInstallError(null);
6068
+ setNeedsAuth(false);
5913
6069
  _context2.prev = 2;
6070
+ _context2.prev = 3;
6071
+ _context2.next = 4;
6072
+ 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();
6073
+ case 4:
6074
+ status = _context2.sent;
6075
+ if (status !== null && status !== void 0 && status.authenticated) {
6076
+ _context2.next = 5;
6077
+ break;
6078
+ }
6079
+ setNeedsAuth(true);
6080
+ setIsInstalling(false);
6081
+ return _context2.abrupt("return");
6082
+ case 5:
6083
+ _context2.next = 7;
6084
+ break;
6085
+ case 6:
6086
+ _context2.prev = 6;
6087
+ _context2["catch"](3);
6088
+ case 7:
5914
6089
  packageName = widget.packageName, packageScope = widget.packageScope, downloadUrl = widget.downloadUrl, packageVersion = widget.packageVersion; // Build scoped ID (e.g. "@trops/slack") for the install key
5915
6090
  scopedId = packageScope ? "@".concat(packageScope.replace(/^@/, ""), "/").concat(packageName) : packageName; // Resolve placeholders in the download URL
5916
6091
  resolvedUrl = downloadUrl.replace(/\{version\}/g, packageVersion).replace(/\{name\}/g, packageName);
5917
- _context2.next = 3;
6092
+ _context2.next = 8;
5918
6093
  return window.mainApi.widgets.install(scopedId, resolvedUrl);
5919
- case 3:
5920
- _context2.next = 5;
6094
+ case 8:
6095
+ _context2.next = 10;
5921
6096
  break;
5922
- case 4:
5923
- _context2.prev = 4;
5924
- _t2 = _context2["catch"](2);
5925
- setInstallError(_t2.message || "Failed to install package");
5926
- case 5:
5927
- _context2.prev = 5;
6097
+ case 9:
6098
+ _context2.prev = 9;
6099
+ _t3 = _context2["catch"](2);
6100
+ msg = cleanIpcError(_t3.message || "Failed to install package");
6101
+ if (msg.toLowerCase().includes("unauthorized") || msg.toLowerCase().includes("authentication required")) {
6102
+ setNeedsAuth(true);
6103
+ } else {
6104
+ setInstallError(msg);
6105
+ }
6106
+ case 10:
6107
+ _context2.prev = 10;
5928
6108
  setIsInstalling(false);
5929
- return _context2.finish(5);
5930
- case 6:
6109
+ return _context2.finish(10);
6110
+ case 11:
5931
6111
  case "end":
5932
6112
  return _context2.stop();
5933
6113
  }
5934
- }, _callee2, null, [[2, 4, 5, 6]]);
6114
+ }, _callee2, null, [[2, 9, 10, 11], [3, 6]]);
5935
6115
  }));
5936
6116
  return function (_x2) {
5937
6117
  return _ref3.apply(this, arguments);
@@ -5949,6 +6129,8 @@ var useRegistrySearch = function useRegistrySearch() {
5949
6129
  setSearchQuery: setSearchQuery,
5950
6130
  isInstalling: isInstalling,
5951
6131
  installError: installError,
6132
+ needsAuth: needsAuth,
6133
+ clearNeedsAuth: clearNeedsAuth,
5952
6134
  search: search,
5953
6135
  installPackage: installPackage,
5954
6136
  retry: retry,
@@ -16323,6 +16505,10 @@ var EnhancedWidgetDropdown = function EnhancedWidgetDropdown(_ref) {
16323
16505
  _useState64 = _slicedToArray(_useState63, 2),
16324
16506
  installError = _useState64[0],
16325
16507
  setInstallError = _useState64[1];
16508
+ var _useState65 = useState(false),
16509
+ _useState66 = _slicedToArray(_useState65, 2),
16510
+ needsAuth = _useState66[0],
16511
+ setNeedsAuth = _useState66[1];
16326
16512
 
16327
16513
  // Phase 3: Recent Widgets - localStorage functions
16328
16514
  var loadRecentWidgets = function loadRecentWidgets() {
@@ -16917,7 +17103,7 @@ var EnhancedWidgetDropdown = function EnhancedWidgetDropdown(_ref) {
16917
17103
  // Install a package from the registry
16918
17104
  var handleInstallPackage = /*#__PURE__*/function () {
16919
17105
  var _ref3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
16920
- var packageName, downloadUrl, packageVersion, resolvedUrl, _t2;
17106
+ var _window$mainApi, status, packageName, downloadUrl, packageVersion, resolvedUrl, msg, _t3;
16921
17107
  return _regeneratorRuntime.wrap(function (_context2) {
16922
17108
  while (1) switch (_context2.prev = _context2.next) {
16923
17109
  case 0:
@@ -16929,32 +17115,57 @@ var EnhancedWidgetDropdown = function EnhancedWidgetDropdown(_ref) {
16929
17115
  case 1:
16930
17116
  setIsInstalling(true);
16931
17117
  setInstallError(null);
17118
+ setNeedsAuth(false);
16932
17119
  _context2.prev = 2;
17120
+ _context2.prev = 3;
17121
+ _context2.next = 4;
17122
+ 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();
17123
+ case 4:
17124
+ status = _context2.sent;
17125
+ if (status !== null && status !== void 0 && status.authenticated) {
17126
+ _context2.next = 5;
17127
+ break;
17128
+ }
17129
+ setNeedsAuth(true);
17130
+ setIsInstalling(false);
17131
+ return _context2.abrupt("return");
17132
+ case 5:
17133
+ _context2.next = 7;
17134
+ break;
17135
+ case 6:
17136
+ _context2.prev = 6;
17137
+ _context2["catch"](3);
17138
+ case 7:
16933
17139
  packageName = selectedWidget.packageName, downloadUrl = selectedWidget.downloadUrl, packageVersion = selectedWidget.packageVersion; // Resolve version placeholder in download URL
16934
17140
  resolvedUrl = downloadUrl.replace(/\{version\}/g, packageVersion).replace(/\{name\}/g, packageName);
16935
- _context2.next = 3;
17141
+ _context2.next = 8;
16936
17142
  return window.mainApi.widgets.install(packageName, resolvedUrl);
16937
- case 3:
17143
+ case 8:
16938
17144
 
16939
17145
  // Switch to Installed tab after successful install
16940
17146
  setSelectedSource("Installed");
16941
17147
  setSelectedWidget(null);
16942
17148
  setSelectedPackage(null);
16943
- _context2.next = 5;
17149
+ _context2.next = 10;
16944
17150
  break;
16945
- case 4:
16946
- _context2.prev = 4;
16947
- _t2 = _context2["catch"](2);
16948
- setInstallError(_t2.message || "Failed to install package");
16949
- case 5:
16950
- _context2.prev = 5;
17151
+ case 9:
17152
+ _context2.prev = 9;
17153
+ _t3 = _context2["catch"](2);
17154
+ msg = cleanIpcError(_t3.message || "Failed to install package");
17155
+ if (msg.toLowerCase().includes("unauthorized") || msg.toLowerCase().includes("authentication required")) {
17156
+ setNeedsAuth(true);
17157
+ } else {
17158
+ setInstallError(msg);
17159
+ }
17160
+ case 10:
17161
+ _context2.prev = 10;
16951
17162
  setIsInstalling(false);
16952
- return _context2.finish(5);
16953
- case 6:
17163
+ return _context2.finish(10);
17164
+ case 11:
16954
17165
  case "end":
16955
17166
  return _context2.stop();
16956
17167
  }
16957
- }, _callee2, null, [[2, 4, 5, 6]]);
17168
+ }, _callee2, null, [[2, 9, 10, 11], [3, 6]]);
16958
17169
  }));
16959
17170
  return function handleInstallPackage() {
16960
17171
  return _ref3.apply(this, arguments);
@@ -17273,6 +17484,18 @@ var EnhancedWidgetDropdown = function EnhancedWidgetDropdown(_ref) {
17273
17484
  className: "text-xs text-red-400",
17274
17485
  children: installError
17275
17486
  })
17487
+ }), needsAuth && /*#__PURE__*/jsx("div", {
17488
+ className: "mt-3",
17489
+ children: /*#__PURE__*/jsx(RegistryAuthPrompt, {
17490
+ onAuthenticated: function onAuthenticated() {
17491
+ setNeedsAuth(false);
17492
+ handleInstallPackage();
17493
+ },
17494
+ onCancel: function onCancel() {
17495
+ return setNeedsAuth(false);
17496
+ },
17497
+ message: "Sign in to install this widget from the Dash Registry."
17498
+ })
17276
17499
  })]
17277
17500
  });
17278
17501
  };
@@ -23125,7 +23348,13 @@ var RegistryPackageDetail = function RegistryPackageDetail(_ref) {
23125
23348
  _ref$installError = _ref.installError,
23126
23349
  installError = _ref$installError === void 0 ? null : _ref$installError,
23127
23350
  _ref$isInstalled = _ref.isInstalled,
23128
- isInstalled = _ref$isInstalled === void 0 ? false : _ref$isInstalled;
23351
+ isInstalled = _ref$isInstalled === void 0 ? false : _ref$isInstalled,
23352
+ _ref$showAuth = _ref.showAuth,
23353
+ showAuth = _ref$showAuth === void 0 ? false : _ref$showAuth,
23354
+ _ref$onAuthSuccess = _ref.onAuthSuccess,
23355
+ onAuthSuccess = _ref$onAuthSuccess === void 0 ? null : _ref$onAuthSuccess,
23356
+ _ref$onAuthCancel = _ref.onAuthCancel,
23357
+ onAuthCancel = _ref$onAuthCancel === void 0 ? null : _ref$onAuthCancel;
23129
23358
  var _useContext = useContext(ThemeContext),
23130
23359
  currentTheme = _useContext.currentTheme;
23131
23360
  var panelStyles = getStylesForItem(themeObjects.PANEL, currentTheme, {
@@ -23261,7 +23490,11 @@ var RegistryPackageDetail = function RegistryPackageDetail(_ref) {
23261
23490
  children: installError
23262
23491
  })
23263
23492
  })]
23264
- }), /*#__PURE__*/jsx("div", {
23493
+ }), showAuth && /*#__PURE__*/jsx(RegistryAuthPrompt, {
23494
+ onAuthenticated: onAuthSuccess,
23495
+ onCancel: onAuthCancel,
23496
+ message: "Sign in to install this widget from the Dash Registry."
23497
+ }), !showAuth && /*#__PURE__*/jsx("div", {
23265
23498
  className: "flex items-center justify-end px-6 py-3 border-t ".concat(currentTheme["border-primary-medium"]),
23266
23499
  children: /*#__PURE__*/jsx(Button, {
23267
23500
  title: isInstalled ? "Installed" : isInstalling ? "Installing..." : "Install Package",
@@ -23276,267 +23509,6 @@ var RegistryPackageDetail = function RegistryPackageDetail(_ref) {
23276
23509
  });
23277
23510
  };
23278
23511
 
23279
- /**
23280
- * useRegistryAuth — reusable hook for device-code OAuth against the Dash Registry.
23281
- *
23282
- * Encapsulates the full auth state machine: check status, initiate login,
23283
- * poll for token, and cancel. Cleans up the poll interval on unmount.
23284
- *
23285
- * @returns {{
23286
- * isAuthenticated: boolean,
23287
- * isAuthenticating: boolean,
23288
- * authFlow: { userCode: string, verificationUrlComplete: string } | null,
23289
- * authError: string | null,
23290
- * checkAuth: () => Promise<boolean>,
23291
- * initiateAuth: () => Promise<void>,
23292
- * cancelAuth: () => void,
23293
- * }}
23294
- */
23295
- function useRegistryAuth() {
23296
- var _useState = useState(false),
23297
- _useState2 = _slicedToArray(_useState, 2),
23298
- isAuthenticated = _useState2[0],
23299
- setIsAuthenticated = _useState2[1];
23300
- var _useState3 = useState(false),
23301
- _useState4 = _slicedToArray(_useState3, 2),
23302
- isAuthenticating = _useState4[0],
23303
- setIsAuthenticating = _useState4[1];
23304
- var _useState5 = useState(null),
23305
- _useState6 = _slicedToArray(_useState5, 2),
23306
- authFlow = _useState6[0],
23307
- setAuthFlow = _useState6[1];
23308
- var _useState7 = useState(null),
23309
- _useState8 = _slicedToArray(_useState7, 2),
23310
- authError = _useState8[0],
23311
- setAuthError = _useState8[1];
23312
- var pollIntervalRef = useRef(null);
23313
- var onAuthorizedRef = useRef(null);
23314
-
23315
- // Clean up polling on unmount
23316
- useEffect(function () {
23317
- return function () {
23318
- if (pollIntervalRef.current) clearInterval(pollIntervalRef.current);
23319
- };
23320
- }, []);
23321
- var checkAuth = useCallback(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
23322
- var status, authed;
23323
- return _regeneratorRuntime.wrap(function (_context) {
23324
- while (1) switch (_context.prev = _context.next) {
23325
- case 0:
23326
- _context.prev = 0;
23327
- _context.next = 1;
23328
- return window.mainApi.registryAuth.getStatus();
23329
- case 1:
23330
- status = _context.sent;
23331
- authed = !!(status !== null && status !== void 0 && status.authenticated);
23332
- setIsAuthenticated(authed);
23333
- return _context.abrupt("return", authed);
23334
- case 2:
23335
- _context.prev = 2;
23336
- _context["catch"](0);
23337
- return _context.abrupt("return", false);
23338
- case 3:
23339
- case "end":
23340
- return _context.stop();
23341
- }
23342
- }, _callee, null, [[0, 2]]);
23343
- })), []);
23344
- var cancelAuth = useCallback(function () {
23345
- if (pollIntervalRef.current) {
23346
- clearInterval(pollIntervalRef.current);
23347
- pollIntervalRef.current = null;
23348
- }
23349
- setIsAuthenticating(false);
23350
- setAuthFlow(null);
23351
- }, []);
23352
- var initiateAuth = useCallback(/*#__PURE__*/function () {
23353
- var _ref2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3(onAuthorized) {
23354
- var flow, interval;
23355
- return _regeneratorRuntime.wrap(function (_context3) {
23356
- while (1) switch (_context3.prev = _context3.next) {
23357
- case 0:
23358
- setAuthError(null);
23359
- onAuthorizedRef.current = onAuthorized || null;
23360
- _context3.prev = 1;
23361
- _context3.next = 2;
23362
- return window.mainApi.registryAuth.initiateLogin();
23363
- case 2:
23364
- flow = _context3.sent;
23365
- setAuthFlow(flow);
23366
- if (flow.verificationUrlComplete) {
23367
- window.mainApi.shell.openExternal(flow.verificationUrlComplete);
23368
- }
23369
- setIsAuthenticating(true);
23370
- interval = (flow.interval || 5) * 1000;
23371
- pollIntervalRef.current = setInterval(/*#__PURE__*/_asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
23372
- var pollResult;
23373
- return _regeneratorRuntime.wrap(function (_context2) {
23374
- while (1) switch (_context2.prev = _context2.next) {
23375
- case 0:
23376
- _context2.prev = 0;
23377
- _context2.next = 1;
23378
- return window.mainApi.registryAuth.pollToken(flow.deviceCode);
23379
- case 1:
23380
- pollResult = _context2.sent;
23381
- if (pollResult.status === "authorized") {
23382
- clearInterval(pollIntervalRef.current);
23383
- pollIntervalRef.current = null;
23384
- setIsAuthenticating(false);
23385
- setAuthFlow(null);
23386
- setIsAuthenticated(true);
23387
- if (onAuthorizedRef.current) {
23388
- onAuthorizedRef.current();
23389
- }
23390
- } else if (pollResult.status === "expired") {
23391
- clearInterval(pollIntervalRef.current);
23392
- pollIntervalRef.current = null;
23393
- setIsAuthenticating(false);
23394
- setAuthFlow(null);
23395
- setAuthError("Authorization expired. Please try again.");
23396
- }
23397
- _context2.next = 3;
23398
- break;
23399
- case 2:
23400
- _context2.prev = 2;
23401
- _context2["catch"](0);
23402
- clearInterval(pollIntervalRef.current);
23403
- pollIntervalRef.current = null;
23404
- setIsAuthenticating(false);
23405
- case 3:
23406
- case "end":
23407
- return _context2.stop();
23408
- }
23409
- }, _callee2, null, [[0, 2]]);
23410
- })), interval);
23411
- _context3.next = 4;
23412
- break;
23413
- case 3:
23414
- _context3.prev = 3;
23415
- _context3["catch"](1);
23416
- setAuthError("Could not reach the registry. Check your connection and try again.");
23417
- case 4:
23418
- case "end":
23419
- return _context3.stop();
23420
- }
23421
- }, _callee3, null, [[1, 3]]);
23422
- }));
23423
- return function (_x) {
23424
- return _ref2.apply(this, arguments);
23425
- };
23426
- }(), [cancelAuth]);
23427
- return {
23428
- isAuthenticated: isAuthenticated,
23429
- isAuthenticating: isAuthenticating,
23430
- authFlow: authFlow,
23431
- authError: authError,
23432
- checkAuth: checkAuth,
23433
- initiateAuth: initiateAuth,
23434
- cancelAuth: cancelAuth
23435
- };
23436
- }
23437
-
23438
- var RegistryAuthPrompt = function RegistryAuthPrompt(_ref) {
23439
- var onAuthenticated = _ref.onAuthenticated,
23440
- _ref$onCancel = _ref.onCancel,
23441
- onCancel = _ref$onCancel === void 0 ? null : _ref$onCancel,
23442
- _ref$message = _ref.message,
23443
- message = _ref$message === void 0 ? "Sign in to install from the Dash Registry." : _ref$message;
23444
- var _useRegistryAuth = useRegistryAuth(),
23445
- isAuthenticating = _useRegistryAuth.isAuthenticating,
23446
- authFlow = _useRegistryAuth.authFlow,
23447
- authError = _useRegistryAuth.authError,
23448
- checkAuth = _useRegistryAuth.checkAuth,
23449
- initiateAuth = _useRegistryAuth.initiateAuth,
23450
- cancelAuth = _useRegistryAuth.cancelAuth;
23451
- var checkedRef = useRef(false);
23452
-
23453
- // Check auth on mount — if already authenticated, short-circuit
23454
- useEffect(function () {
23455
- if (checkedRef.current) return;
23456
- checkedRef.current = true;
23457
- checkAuth().then(function (authed) {
23458
- if (authed && onAuthenticated) onAuthenticated();
23459
- });
23460
- }, [checkAuth, onAuthenticated]);
23461
- function handleSignIn() {
23462
- initiateAuth(function () {
23463
- if (onAuthenticated) onAuthenticated();
23464
- });
23465
- }
23466
- function handleCancel() {
23467
- cancelAuth();
23468
- if (onCancel) onCancel();
23469
- }
23470
-
23471
- // Polling state: show user code
23472
- if (authFlow && isAuthenticating) {
23473
- return /*#__PURE__*/jsxs("div", {
23474
- className: "flex flex-col gap-3 p-4",
23475
- children: [/*#__PURE__*/jsxs("div", {
23476
- className: "bg-blue-500/10 border border-blue-500/20 rounded-lg p-4 space-y-3",
23477
- children: [/*#__PURE__*/jsx("p", {
23478
- className: "text-xs text-blue-300/90",
23479
- children: "Enter this code in your browser:"
23480
- }), /*#__PURE__*/jsx("div", {
23481
- className: "text-center",
23482
- children: /*#__PURE__*/jsx("span", {
23483
- className: "text-2xl font-mono font-bold tracking-widest text-white",
23484
- children: authFlow.userCode
23485
- })
23486
- }), /*#__PURE__*/jsx("p", {
23487
- className: "text-xs text-blue-300/70 text-center",
23488
- children: "Waiting for authorization \u2014 install will resume automatically..."
23489
- })]
23490
- }), onCancel && /*#__PURE__*/jsx("button", {
23491
- type: "button",
23492
- onClick: handleCancel,
23493
- className: "self-center text-xs text-gray-500 hover:text-gray-300 transition-colors",
23494
- children: "Cancel"
23495
- })]
23496
- });
23497
- }
23498
-
23499
- // Default: not-started / error state
23500
- return /*#__PURE__*/jsxs("div", {
23501
- className: "flex flex-col gap-3 p-4",
23502
- children: [/*#__PURE__*/jsx("div", {
23503
- className: "bg-yellow-500/10 border border-yellow-500/20 rounded-lg p-3",
23504
- children: /*#__PURE__*/jsxs("div", {
23505
- className: "flex items-start gap-2",
23506
- children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
23507
- icon: "lock",
23508
- className: "h-3.5 w-3.5 text-yellow-400 mt-0.5 flex-shrink-0"
23509
- }), /*#__PURE__*/jsx("span", {
23510
- className: "text-sm text-yellow-300/90",
23511
- children: message
23512
- })]
23513
- })
23514
- }), /*#__PURE__*/jsx("button", {
23515
- type: "button",
23516
- onClick: handleSignIn,
23517
- 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",
23518
- children: "Sign in to Registry"
23519
- }), authError && /*#__PURE__*/jsx("div", {
23520
- className: "bg-red-500/10 border border-red-500/20 rounded-lg p-3",
23521
- children: /*#__PURE__*/jsxs("div", {
23522
- className: "flex items-start gap-2",
23523
- children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
23524
- icon: "circle-xmark",
23525
- className: "h-3.5 w-3.5 text-red-400 mt-0.5 flex-shrink-0"
23526
- }), /*#__PURE__*/jsx("span", {
23527
- className: "text-xs text-red-300/90",
23528
- children: authError
23529
- })]
23530
- })
23531
- }), onCancel && /*#__PURE__*/jsx("button", {
23532
- type: "button",
23533
- onClick: handleCancel,
23534
- className: "self-center text-xs text-gray-500 hover:text-gray-300 transition-colors",
23535
- children: "Cancel"
23536
- })]
23537
- });
23538
- };
23539
-
23540
23512
  function getWidgetSearchQuery(componentKey) {
23541
23513
  var parts = componentKey.split(".");
23542
23514
  if (parts.length >= 3) {
@@ -25353,7 +25325,7 @@ var _renderLayout = function renderLayout(_ref) {
25353
25325
 
25354
25326
  // if (gridLayout) console.log("rendering grid ", child, childLayout);
25355
25327
 
25356
- return hasChildren === 1 && canHaveChildren === true ? /*#__PURE__*/jsx(LayoutGridContainer, {
25328
+ return hasChildren === 1 && canHaveChildren === true || component === "LayoutGridContainer" ? /*#__PURE__*/jsx(LayoutGridContainer, {
25357
25329
  uuid: uuid,
25358
25330
  id: id,
25359
25331
  item: childLayout,
@@ -44632,6 +44604,8 @@ var DiscoverWidgetsDetail = function DiscoverWidgetsDetail(_ref) {
44632
44604
  setSearchQuery = _useRegistrySearch.setSearchQuery,
44633
44605
  isInstalling = _useRegistrySearch.isInstalling,
44634
44606
  installError = _useRegistrySearch.installError,
44607
+ needsAuth = _useRegistrySearch.needsAuth,
44608
+ clearNeedsAuth = _useRegistrySearch.clearNeedsAuth,
44635
44609
  installPackage = _useRegistrySearch.installPackage,
44636
44610
  retry = _useRegistrySearch.retry,
44637
44611
  showAllPackages = _useRegistrySearch.showAllPackages,
@@ -44832,7 +44806,13 @@ var DiscoverWidgetsDetail = function DiscoverWidgetsDetail(_ref) {
44832
44806
  installError: installError,
44833
44807
  isInstalled: selectedWidget ? isPackageInstalled(packages.find(function (p) {
44834
44808
  return p.name === selectedPackageName;
44835
- }) || {}) : false
44809
+ }) || {}) : false,
44810
+ showAuth: needsAuth,
44811
+ onAuthSuccess: function onAuthSuccess() {
44812
+ clearNeedsAuth();
44813
+ installPackage(selectedWidget);
44814
+ },
44815
+ onAuthCancel: clearNeedsAuth
44836
44816
  })]
44837
44817
  });
44838
44818
  }
@@ -48091,6 +48071,10 @@ var SidebarDiscoverContent = function SidebarDiscoverContent(_ref2) {
48091
48071
  _useState2 = _slicedToArray(_useState, 2),
48092
48072
  selectedPackageName = _useState2[0],
48093
48073
  setSelectedPackageName = _useState2[1];
48074
+ var _useState3 = useState(null),
48075
+ _useState4 = _slicedToArray(_useState3, 2),
48076
+ pendingInstallPkg = _useState4[0],
48077
+ setPendingInstallPkg = _useState4[1];
48094
48078
 
48095
48079
  // Check if a package is installed by name or scope/name
48096
48080
  var isPackageInstalled = useCallback(function (pkg) {
@@ -48135,19 +48119,22 @@ var SidebarDiscoverContent = function SidebarDiscoverContent(_ref2) {
48135
48119
  }
48136
48120
  return _context.abrupt("return");
48137
48121
  case 1:
48122
+ setPendingInstallPkg(pkg);
48138
48123
  installable = {
48139
48124
  isRegistry: true,
48140
48125
  packageName: pkg.name,
48126
+ packageScope: pkg.scope || null,
48141
48127
  downloadUrl: pkg.downloadUrl || "",
48142
48128
  packageVersion: pkg.version || ""
48143
48129
  };
48144
48130
  _context.next = 2;
48145
48131
  return registry.installPackage(installable);
48146
48132
  case 2:
48147
- // If no install error, signal success
48148
- if (!registry.installError) {
48133
+ // If no install error and no auth needed, signal success
48134
+ if (!registry.installError && !registry.needsAuth) {
48149
48135
  onInstallSuccess(pkg.displayName || pkg.name);
48150
48136
  setSelectedPackageName(null);
48137
+ setPendingInstallPkg(null);
48151
48138
  }
48152
48139
  case 3:
48153
48140
  case "end":
@@ -48242,8 +48229,21 @@ var SidebarDiscoverContent = function SidebarDiscoverContent(_ref2) {
48242
48229
  }), registry.installError && /*#__PURE__*/jsx("div", {
48243
48230
  className: "text-xs text-red-400 bg-red-500/10 rounded px-2 py-1.5 mb-3",
48244
48231
  children: registry.installError
48232
+ }), registry.needsAuth && /*#__PURE__*/jsx("div", {
48233
+ className: "mb-3",
48234
+ children: /*#__PURE__*/jsx(RegistryAuthPrompt, {
48235
+ onAuthenticated: function onAuthenticated() {
48236
+ registry.clearNeedsAuth();
48237
+ if (pendingInstallPkg) handleInstall(pendingInstallPkg);
48238
+ },
48239
+ onCancel: function onCancel() {
48240
+ registry.clearNeedsAuth();
48241
+ setPendingInstallPkg(null);
48242
+ },
48243
+ message: "Sign in to install this widget from the Dash Registry."
48244
+ })
48245
48245
  })]
48246
- }), /*#__PURE__*/jsx("div", {
48246
+ }), !registry.needsAuth && /*#__PURE__*/jsx("div", {
48247
48247
  className: "px-3 py-2 flex-shrink-0",
48248
48248
  children: /*#__PURE__*/jsx("button", {
48249
48249
  type: "button",
@@ -48371,45 +48371,45 @@ var WidgetSidebar = function WidgetSidebar(_ref4) {
48371
48371
  currentTheme = _useContext.currentTheme;
48372
48372
 
48373
48373
  // Tab state
48374
- var _useState3 = useState("installed"),
48375
- _useState4 = _slicedToArray(_useState3, 2),
48376
- activeTab = _useState4[0],
48377
- setActiveTab = _useState4[1]; // "installed" | "discover"
48378
- var _useState5 = useState(null),
48374
+ var _useState5 = useState("installed"),
48379
48375
  _useState6 = _slicedToArray(_useState5, 2),
48380
- installSuccess = _useState6[0],
48381
- setInstallSuccess = _useState6[1];
48376
+ activeTab = _useState6[0],
48377
+ setActiveTab = _useState6[1]; // "installed" | "discover"
48378
+ var _useState7 = useState(null),
48379
+ _useState8 = _slicedToArray(_useState7, 2),
48380
+ installSuccess = _useState8[0],
48381
+ setInstallSuccess = _useState8[1];
48382
48382
 
48383
48383
  // Registry hook (only active when discover tab is shown)
48384
48384
  var registry = useRegistrySearch();
48385
48385
 
48386
48386
  // Filter state
48387
- var _useState7 = useState(""),
48388
- _useState8 = _slicedToArray(_useState7, 2),
48389
- searchQuery = _useState8[0],
48390
- setSearchQuery = _useState8[1];
48391
- var _useState9 = useState("all"),
48387
+ var _useState9 = useState(""),
48392
48388
  _useState0 = _slicedToArray(_useState9, 2),
48393
- filterAuthor = _useState0[0],
48394
- setFilterAuthor = _useState0[1];
48389
+ searchQuery = _useState0[0],
48390
+ setSearchQuery = _useState0[1];
48395
48391
  var _useState1 = useState("all"),
48396
48392
  _useState10 = _slicedToArray(_useState1, 2),
48397
- filterProvider = _useState10[0],
48398
- setFilterProvider = _useState10[1];
48393
+ filterAuthor = _useState10[0],
48394
+ setFilterAuthor = _useState10[1];
48399
48395
  var _useState11 = useState("all"),
48400
48396
  _useState12 = _slicedToArray(_useState11, 2),
48401
- filterHasEvents = _useState12[0],
48402
- setFilterHasEvents = _useState12[1];
48397
+ filterProvider = _useState12[0],
48398
+ setFilterProvider = _useState12[1];
48403
48399
  var _useState13 = useState("all"),
48404
48400
  _useState14 = _slicedToArray(_useState13, 2),
48405
- filterHasHandlers = _useState14[0],
48406
- setFilterHasHandlers = _useState14[1];
48401
+ filterHasEvents = _useState14[0],
48402
+ setFilterHasEvents = _useState14[1];
48403
+ var _useState15 = useState("all"),
48404
+ _useState16 = _slicedToArray(_useState15, 2),
48405
+ filterHasHandlers = _useState16[0],
48406
+ setFilterHasHandlers = _useState16[1];
48407
48407
 
48408
48408
  // Counter to trigger re-computation when installed widgets change
48409
- var _useState15 = useState(0),
48410
- _useState16 = _slicedToArray(_useState15, 2),
48411
- widgetVersion = _useState16[0],
48412
- setWidgetVersion = _useState16[1];
48409
+ var _useState17 = useState(0),
48410
+ _useState18 = _slicedToArray(_useState17, 2),
48411
+ widgetVersion = _useState18[0],
48412
+ setWidgetVersion = _useState18[1];
48413
48413
  useEffect(function () {
48414
48414
  var handleWidgetsUpdated = function handleWidgetsUpdated() {
48415
48415
  return setWidgetVersion(function (v) {
@@ -48437,10 +48437,10 @@ var WidgetSidebar = function WidgetSidebar(_ref4) {
48437
48437
 
48438
48438
  // Set of installed package identifiers for "Installed" badge in Discover tab.
48439
48439
  // Stores folder names, package names, and "author/name" keys for matching.
48440
- var _useState17 = useState(new Set()),
48441
- _useState18 = _slicedToArray(_useState17, 2),
48442
- installedPackageNames = _useState18[0],
48443
- setInstalledPackageNames = _useState18[1];
48440
+ var _useState19 = useState(new Set()),
48441
+ _useState20 = _slicedToArray(_useState19, 2),
48442
+ installedPackageNames = _useState20[0],
48443
+ setInstalledPackageNames = _useState20[1];
48444
48444
  useEffect(function () {
48445
48445
  var cancelled = false;
48446
48446
  var loadInstalled = /*#__PURE__*/function () {