@trops/dash-core 0.1.614 → 0.1.616

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
@@ -4657,18 +4657,17 @@ function _objectSpread$16(e) { for (var r = 1; r < arguments.length; r++) { var
4657
4657
  function _createForOfIteratorHelper$K(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray$K(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; } } }; }
4658
4658
  function _unsupportedIterableToArray$K(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray$K(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$K(r, a) : void 0; } }
4659
4659
  function _arrayLikeToArray$K(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; }
4660
- var secondaryBtnClass = "px-3 py-2 text-sm font-medium rounded bg-gray-700 hover:bg-gray-600 disabled:bg-gray-800 disabled:text-gray-500 disabled:cursor-not-allowed text-gray-100";
4661
- var primaryBtnClass = "px-3 py-2 text-sm font-medium rounded bg-blue-600 hover:bg-blue-500 disabled:bg-gray-700 disabled:text-gray-500 disabled:cursor-not-allowed text-white";
4660
+ var secondaryBtnClass$1 = "px-3 py-2 text-sm font-medium rounded bg-gray-700 hover:bg-gray-600 disabled:bg-gray-800 disabled:text-gray-500 disabled:cursor-not-allowed text-gray-100";
4661
+ var primaryBtnClass$1 = "px-3 py-2 text-sm font-medium rounded bg-blue-600 hover:bg-blue-500 disabled:bg-gray-700 disabled:text-gray-500 disabled:cursor-not-allowed text-white";
4662
4662
 
4663
4663
  /**
4664
4664
  * Flatten a single widget's `missing` blob (output of useWidgetUpdates'
4665
- * preflight computation) into an array of keyed lines the modal can
4665
+ * preflight computation) into an array of keyed lines the panel can
4666
4666
  * render as toggleable checkboxes.
4667
4667
  *
4668
4668
  * Each line carries `apply(acc)` that mutates an accumulator into the
4669
- * grant-blob shape the main process accepts. Mirrors the shape
4670
- * PreflightConsentModal uses for the dashboard-load case so the modal
4671
- * UX stays consistent (server / tool / readPath / writePath rows).
4669
+ * grant-blob shape the main process accepts (server / tool / readPath /
4670
+ * writePath rows).
4672
4671
  */
4673
4672
  function flattenPreflightLines(missing) {
4674
4673
  var lines = [];
@@ -4764,6 +4763,213 @@ function flattenPreflightLines(missing) {
4764
4763
  }
4765
4764
  return lines;
4766
4765
  }
4766
+ var WidgetPreflightReview = function WidgetPreflightReview(_ref) {
4767
+ var pendingPreflight = _ref.pendingPreflight,
4768
+ resolvePreflight = _ref.resolvePreflight;
4769
+ // Per-line checkbox state — `{ [widgetId]: { [lineKey]: bool } }`.
4770
+ // Initialized to "everything checked" on each new pendingPreflight so
4771
+ // the default action approves the full ask; the user opts OUT of
4772
+ // individual lines by unchecking.
4773
+ var _useState = React.useState({}),
4774
+ _useState2 = _slicedToArray(_useState, 2),
4775
+ preflightChecked = _useState2[0],
4776
+ setPreflightChecked = _useState2[1];
4777
+ var _useState3 = React.useState(null),
4778
+ _useState4 = _slicedToArray(_useState3, 2),
4779
+ selectedPreflightWidgetId = _useState4[0],
4780
+ setSelectedPreflightWidgetId = _useState4[1];
4781
+ React.useEffect(function () {
4782
+ var _pendingPreflight$wid;
4783
+ if (!pendingPreflight || !((_pendingPreflight$wid = pendingPreflight.widgets) !== null && _pendingPreflight$wid !== void 0 && _pendingPreflight$wid.length)) return;
4784
+ var initial = {};
4785
+ var _iterator4 = _createForOfIteratorHelper$K(pendingPreflight.widgets),
4786
+ _step4;
4787
+ try {
4788
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
4789
+ var w = _step4.value;
4790
+ initial[w.widgetId] = {};
4791
+ var _iterator5 = _createForOfIteratorHelper$K(flattenPreflightLines(w.missing)),
4792
+ _step5;
4793
+ try {
4794
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
4795
+ var ln = _step5.value;
4796
+ initial[w.widgetId][ln.key] = true;
4797
+ }
4798
+ } catch (err) {
4799
+ _iterator5.e(err);
4800
+ } finally {
4801
+ _iterator5.f();
4802
+ }
4803
+ }
4804
+ } catch (err) {
4805
+ _iterator4.e(err);
4806
+ } finally {
4807
+ _iterator4.f();
4808
+ }
4809
+ setPreflightChecked(initial);
4810
+ setSelectedPreflightWidgetId(pendingPreflight.widgets[0].widgetId);
4811
+ }, [pendingPreflight]);
4812
+ if (!pendingPreflight) return null;
4813
+ var widgets = pendingPreflight.widgets || [];
4814
+ var widgetCount = widgets.length;
4815
+ var selected = widgets.find(function (w) {
4816
+ return w.widgetId === selectedPreflightWidgetId;
4817
+ }) || widgets[0];
4818
+ var togglePreflightLine = function togglePreflightLine(widgetId, lineKey) {
4819
+ setPreflightChecked(function (prev) {
4820
+ return _objectSpread$16(_objectSpread$16({}, prev), {}, _defineProperty({}, widgetId, _objectSpread$16(_objectSpread$16({}, prev[widgetId] || {}), {}, _defineProperty({}, lineKey, !(prev[widgetId] && prev[widgetId][lineKey])))));
4821
+ });
4822
+ };
4823
+ var handlePreflightApprove = function handlePreflightApprove() {
4824
+ if (typeof resolvePreflight !== "function") return;
4825
+ // Build the per-widget addition blob from checked lines. Skip
4826
+ // widgets where the user unchecked everything.
4827
+ var acceptedByWidgetId = {};
4828
+ var _iterator6 = _createForOfIteratorHelper$K(widgets),
4829
+ _step6;
4830
+ try {
4831
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
4832
+ var w = _step6.value;
4833
+ var _lines = flattenPreflightLines(w.missing);
4834
+ var acc = {};
4835
+ var any = false;
4836
+ var _iterator7 = _createForOfIteratorHelper$K(_lines),
4837
+ _step7;
4838
+ try {
4839
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
4840
+ var _preflightChecked$w$w;
4841
+ var ln = _step7.value;
4842
+ if ((_preflightChecked$w$w = preflightChecked[w.widgetId]) !== null && _preflightChecked$w$w !== void 0 && _preflightChecked$w$w[ln.key]) {
4843
+ ln.apply(acc);
4844
+ any = true;
4845
+ }
4846
+ }
4847
+ } catch (err) {
4848
+ _iterator7.e(err);
4849
+ } finally {
4850
+ _iterator7.f();
4851
+ }
4852
+ if (any) acceptedByWidgetId[w.widgetId] = acc;
4853
+ }
4854
+ } catch (err) {
4855
+ _iterator6.e(err);
4856
+ } finally {
4857
+ _iterator6.f();
4858
+ }
4859
+ resolvePreflight({
4860
+ acceptedByWidgetId: acceptedByWidgetId
4861
+ });
4862
+ };
4863
+ var handlePreflightCancel = function handlePreflightCancel() {
4864
+ if (typeof resolvePreflight !== "function") return;
4865
+ resolvePreflight(null);
4866
+ };
4867
+ var lines = selected ? flattenPreflightLines(selected.missing) : [];
4868
+ return /*#__PURE__*/jsxRuntime.jsxs("div", {
4869
+ className: "flex flex-col w-full max-w-xl mx-auto border border-gray-700 rounded bg-gray-900",
4870
+ "data-testid": "widget-preflight-review",
4871
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
4872
+ className: "px-5 py-4 border-b border-gray-700",
4873
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
4874
+ className: "flex items-center gap-2 text-base font-semibold text-gray-100",
4875
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
4876
+ icon: "shield-halved",
4877
+ className: "text-amber-400"
4878
+ }), /*#__PURE__*/jsxRuntime.jsxs("span", {
4879
+ children: ["Review ", widgetCount, " widget", widgetCount === 1 ? "" : "s", " before installing"]
4880
+ })]
4881
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
4882
+ className: "text-xs text-gray-400 mt-1",
4883
+ children: "New versions request permissions you haven't granted yet. Approve what you're comfortable with \u2014 the rest stays denied and the install still goes through."
4884
+ })]
4885
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
4886
+ className: "px-5 py-4",
4887
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
4888
+ className: "flex flex-col gap-4",
4889
+ "data-testid": "widget-preflight-review-body",
4890
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
4891
+ className: "px-3 py-2 rounded border border-amber-700 bg-amber-900/30 text-xs text-amber-200",
4892
+ children: "These widgets need new permissions to function after the update. Review and approve before installing \u2014 anything you leave unchecked will be denied at runtime and can be granted later in Settings \u2192 Privacy & Security."
4893
+ }), selected && /*#__PURE__*/jsxRuntime.jsxs("div", {
4894
+ className: "flex border border-gray-700 rounded overflow-hidden",
4895
+ children: [/*#__PURE__*/jsxRuntime.jsx("div", {
4896
+ className: "flex flex-col w-44 border-r border-gray-700 bg-gray-900/40 max-h-64 overflow-y-auto",
4897
+ children: widgets.map(function (w) {
4898
+ var lineCount = flattenPreflightLines(w.missing).length;
4899
+ var isActive = w.widgetId === selected.widgetId;
4900
+ return /*#__PURE__*/jsxRuntime.jsxs("button", {
4901
+ type: "button",
4902
+ onClick: function onClick() {
4903
+ return setSelectedPreflightWidgetId(w.widgetId);
4904
+ },
4905
+ className: "flex items-center justify-between gap-2 px-3 py-2 text-left text-xs border-b border-gray-800 transition-colors ".concat(isActive ? "bg-blue-900/30 text-gray-100" : "text-gray-300 hover:bg-gray-800/40"),
4906
+ "data-testid": "widget-preflight-review-widget-".concat(w.widgetId),
4907
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
4908
+ className: "truncate",
4909
+ children: w.displayName
4910
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
4911
+ className: "text-xs px-1.5 py-0.5 rounded bg-amber-900/40 text-amber-300 shrink-0",
4912
+ children: lineCount
4913
+ })]
4914
+ }, w.widgetId);
4915
+ })
4916
+ }), /*#__PURE__*/jsxRuntime.jsxs("div", {
4917
+ className: "flex flex-col flex-1 min-w-0 p-3 gap-2 max-h-64 overflow-y-auto",
4918
+ children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
4919
+ className: "text-xs text-gray-400 mb-1",
4920
+ children: [/*#__PURE__*/jsxRuntime.jsx("span", {
4921
+ className: "font-semibold text-gray-200",
4922
+ children: selected.displayName
4923
+ }), " ", /*#__PURE__*/jsxRuntime.jsx("span", {
4924
+ className: "opacity-60 font-mono",
4925
+ children: selected.packageId
4926
+ })]
4927
+ }), lines.length === 0 && /*#__PURE__*/jsxRuntime.jsx("div", {
4928
+ className: "text-xs text-gray-500",
4929
+ children: "No new permissions for this widget."
4930
+ }), lines.map(function (ln) {
4931
+ var _preflightChecked$sel;
4932
+ var isChecked = !!((_preflightChecked$sel = preflightChecked[selected.widgetId]) !== null && _preflightChecked$sel !== void 0 && _preflightChecked$sel[ln.key]);
4933
+ return /*#__PURE__*/jsxRuntime.jsxs("label", {
4934
+ className: "flex items-center gap-2 text-xs text-gray-300 cursor-pointer px-2 py-1 rounded hover:bg-gray-800/40",
4935
+ children: [/*#__PURE__*/jsxRuntime.jsx("input", {
4936
+ type: "checkbox",
4937
+ checked: isChecked,
4938
+ onChange: function onChange() {
4939
+ return togglePreflightLine(selected.widgetId, ln.key);
4940
+ }
4941
+ }), /*#__PURE__*/jsxRuntime.jsx("span", {
4942
+ children: ln.label
4943
+ })]
4944
+ }, ln.key);
4945
+ })]
4946
+ })]
4947
+ })]
4948
+ })
4949
+ }), /*#__PURE__*/jsxRuntime.jsx("div", {
4950
+ className: "flex items-center justify-end px-5 py-3 border-t border-gray-700",
4951
+ children: /*#__PURE__*/jsxRuntime.jsxs("div", {
4952
+ className: "flex items-center gap-2",
4953
+ children: [/*#__PURE__*/jsxRuntime.jsx("button", {
4954
+ type: "button",
4955
+ onClick: handlePreflightCancel,
4956
+ className: secondaryBtnClass$1,
4957
+ "data-testid": "widget-preflight-review-cancel",
4958
+ children: "Cancel update"
4959
+ }), /*#__PURE__*/jsxRuntime.jsxs("button", {
4960
+ type: "button",
4961
+ onClick: handlePreflightApprove,
4962
+ className: primaryBtnClass$1,
4963
+ "data-testid": "widget-preflight-review-approve",
4964
+ children: ["Approve and install", widgetCount > 0 ? " (".concat(widgetCount, ")") : ""]
4965
+ })]
4966
+ })
4967
+ })]
4968
+ });
4969
+ };
4970
+
4971
+ var secondaryBtnClass = "px-3 py-2 text-sm font-medium rounded bg-gray-700 hover:bg-gray-600 disabled:bg-gray-800 disabled:text-gray-500 disabled:cursor-not-allowed text-gray-100";
4972
+ var primaryBtnClass = "px-3 py-2 text-sm font-medium rounded bg-blue-600 hover:bg-blue-500 disabled:bg-gray-700 disabled:text-gray-500 disabled:cursor-not-allowed text-white";
4767
4973
 
4768
4974
  /**
4769
4975
  * AppUpdatesModal — top-level "updates available" prompt the app shell
@@ -4800,7 +5006,6 @@ function flattenPreflightLines(missing) {
4800
5006
  * "shown for this session" so the same launch doesn't nag).
4801
5007
  */
4802
5008
  var AppUpdatesModal = function AppUpdatesModal(_ref) {
4803
- var _pendingPreflight$wid3, _pendingPreflight$wid4;
4804
5009
  var isOpen = _ref.isOpen,
4805
5010
  setIsOpen = _ref.setIsOpen,
4806
5011
  _ref$widgetUpdates = _ref.widgetUpdates,
@@ -4873,54 +5078,7 @@ var AppUpdatesModal = function AppUpdatesModal(_ref) {
4873
5078
  if (isOpen) return;
4874
5079
  setLastRunResult(null);
4875
5080
  setIsUpdatingWidgets(false);
4876
- setPreflightChecked({});
4877
- setSelectedPreflightWidgetId(null);
4878
5081
  }, [isOpen]);
4879
-
4880
- // Preflight checkbox state — `{ [widgetId]: { [lineKey]: bool } }`.
4881
- // Initialized to "everything checked" on each new pendingPreflight
4882
- // so the default action approves the full ask; the user opts OUT of
4883
- // individual lines by unchecking. Mirror of how
4884
- // PreflightConsentModal seeds its checks.
4885
- var _useState7 = React.useState({}),
4886
- _useState8 = _slicedToArray(_useState7, 2),
4887
- preflightChecked = _useState8[0],
4888
- setPreflightChecked = _useState8[1];
4889
- var _useState9 = React.useState(null),
4890
- _useState0 = _slicedToArray(_useState9, 2),
4891
- selectedPreflightWidgetId = _useState0[0],
4892
- setSelectedPreflightWidgetId = _useState0[1];
4893
- React.useEffect(function () {
4894
- var _pendingPreflight$wid;
4895
- if (!pendingPreflight || !((_pendingPreflight$wid = pendingPreflight.widgets) !== null && _pendingPreflight$wid !== void 0 && _pendingPreflight$wid.length)) return;
4896
- var initial = {};
4897
- var _iterator4 = _createForOfIteratorHelper$K(pendingPreflight.widgets),
4898
- _step4;
4899
- try {
4900
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
4901
- var w = _step4.value;
4902
- initial[w.widgetId] = {};
4903
- var _iterator5 = _createForOfIteratorHelper$K(flattenPreflightLines(w.missing)),
4904
- _step5;
4905
- try {
4906
- for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
4907
- var ln = _step5.value;
4908
- initial[w.widgetId][ln.key] = true;
4909
- }
4910
- } catch (err) {
4911
- _iterator5.e(err);
4912
- } finally {
4913
- _iterator5.f();
4914
- }
4915
- }
4916
- } catch (err) {
4917
- _iterator4.e(err);
4918
- } finally {
4919
- _iterator4.f();
4920
- }
4921
- setPreflightChecked(initial);
4922
- setSelectedPreflightWidgetId(pendingPreflight.widgets[0].widgetId);
4923
- }, [pendingPreflight]);
4924
5082
  var totalUpdates = widgetUpdates.length + dashboardUpdates.length;
4925
5083
  // Single source of truth for "user needs to sign in before we can
4926
5084
  // run the batch": either the proactive check found no session, or
@@ -4993,59 +5151,6 @@ var AppUpdatesModal = function AppUpdatesModal(_ref) {
4993
5151
  setIsOpen(false);
4994
5152
  };
4995
5153
 
4996
- // --- Preflight handlers ---
4997
- var togglePreflightLine = function togglePreflightLine(widgetId, lineKey) {
4998
- setPreflightChecked(function (prev) {
4999
- return _objectSpread$16(_objectSpread$16({}, prev), {}, _defineProperty({}, widgetId, _objectSpread$16(_objectSpread$16({}, prev[widgetId] || {}), {}, _defineProperty({}, lineKey, !(prev[widgetId] && prev[widgetId][lineKey])))));
5000
- });
5001
- };
5002
- var handlePreflightApprove = function handlePreflightApprove() {
5003
- if (typeof resolvePreflight !== "function" || !pendingPreflight) return;
5004
- // Build the per-widget addition blob from checked lines. Skip
5005
- // widgets where the user unchecked everything (mergeMcpGrants
5006
- // would no-op them anyway, but explicit is cheaper than
5007
- // mysterious).
5008
- var acceptedByWidgetId = {};
5009
- var _iterator6 = _createForOfIteratorHelper$K(pendingPreflight.widgets),
5010
- _step6;
5011
- try {
5012
- for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
5013
- var w = _step6.value;
5014
- var lines = flattenPreflightLines(w.missing);
5015
- var acc = {};
5016
- var any = false;
5017
- var _iterator7 = _createForOfIteratorHelper$K(lines),
5018
- _step7;
5019
- try {
5020
- for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
5021
- var _preflightChecked$w$w;
5022
- var ln = _step7.value;
5023
- if ((_preflightChecked$w$w = preflightChecked[w.widgetId]) !== null && _preflightChecked$w$w !== void 0 && _preflightChecked$w$w[ln.key]) {
5024
- ln.apply(acc);
5025
- any = true;
5026
- }
5027
- }
5028
- } catch (err) {
5029
- _iterator7.e(err);
5030
- } finally {
5031
- _iterator7.f();
5032
- }
5033
- if (any) acceptedByWidgetId[w.widgetId] = acc;
5034
- }
5035
- } catch (err) {
5036
- _iterator6.e(err);
5037
- } finally {
5038
- _iterator6.f();
5039
- }
5040
- resolvePreflight({
5041
- acceptedByWidgetId: acceptedByWidgetId
5042
- });
5043
- };
5044
- var handlePreflightCancel = function handlePreflightCancel() {
5045
- if (typeof resolvePreflight !== "function") return;
5046
- resolvePreflight(null);
5047
- };
5048
-
5049
5154
  // The three render modes: checking, up-to-date, or updates-available.
5050
5155
  // Each gets its own clear visual identity so the user reads the
5051
5156
  // current state in one glance. The result banner (set after a
@@ -5114,79 +5219,7 @@ var AppUpdatesModal = function AppUpdatesModal(_ref) {
5114
5219
  })]
5115
5220
  });
5116
5221
  };
5117
- var renderPreflightBody = function renderPreflightBody() {
5118
- if (!pendingPreflight) return null;
5119
- var widgets = pendingPreflight.widgets || [];
5120
- var selected = widgets.find(function (w) {
5121
- return w.widgetId === selectedPreflightWidgetId;
5122
- }) || widgets[0];
5123
- if (!selected) return null;
5124
- var lines = flattenPreflightLines(selected.missing);
5125
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
5126
- className: "flex flex-col gap-4",
5127
- "data-testid": "app-updates-modal-preflight",
5128
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
5129
- className: "px-3 py-2 rounded border border-amber-700 bg-amber-900/30 text-xs text-amber-200",
5130
- children: "These widgets need new permissions to function after the update. Review and approve before installing \u2014 anything you leave unchecked will be denied at runtime and can be granted later in Settings \u2192 Privacy & Security."
5131
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
5132
- className: "flex border border-gray-700 rounded overflow-hidden",
5133
- children: [/*#__PURE__*/jsxRuntime.jsx("div", {
5134
- className: "flex flex-col w-44 border-r border-gray-700 bg-gray-900/40 max-h-64 overflow-y-auto",
5135
- children: widgets.map(function (w) {
5136
- var lineCount = flattenPreflightLines(w.missing).length;
5137
- var isActive = w.widgetId === selected.widgetId;
5138
- return /*#__PURE__*/jsxRuntime.jsxs("button", {
5139
- type: "button",
5140
- onClick: function onClick() {
5141
- return setSelectedPreflightWidgetId(w.widgetId);
5142
- },
5143
- className: "flex items-center justify-between gap-2 px-3 py-2 text-left text-xs border-b border-gray-800 transition-colors ".concat(isActive ? "bg-blue-900/30 text-gray-100" : "text-gray-300 hover:bg-gray-800/40"),
5144
- "data-testid": "app-updates-modal-preflight-widget-".concat(w.widgetId),
5145
- children: [/*#__PURE__*/jsxRuntime.jsx("span", {
5146
- className: "truncate",
5147
- children: w.displayName
5148
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
5149
- className: "text-xs px-1.5 py-0.5 rounded bg-amber-900/40 text-amber-300 shrink-0",
5150
- children: lineCount
5151
- })]
5152
- }, w.widgetId);
5153
- })
5154
- }), /*#__PURE__*/jsxRuntime.jsxs("div", {
5155
- className: "flex flex-col flex-1 min-w-0 p-3 gap-2 max-h-64 overflow-y-auto",
5156
- children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
5157
- className: "text-xs text-gray-400 mb-1",
5158
- children: [/*#__PURE__*/jsxRuntime.jsx("span", {
5159
- className: "font-semibold text-gray-200",
5160
- children: selected.displayName
5161
- }), " ", /*#__PURE__*/jsxRuntime.jsx("span", {
5162
- className: "opacity-60 font-mono",
5163
- children: selected.packageId
5164
- })]
5165
- }), lines.length === 0 && /*#__PURE__*/jsxRuntime.jsx("div", {
5166
- className: "text-xs text-gray-500",
5167
- children: "No new permissions for this widget."
5168
- }), lines.map(function (ln) {
5169
- var _preflightChecked$sel;
5170
- var isChecked = !!((_preflightChecked$sel = preflightChecked[selected.widgetId]) !== null && _preflightChecked$sel !== void 0 && _preflightChecked$sel[ln.key]);
5171
- return /*#__PURE__*/jsxRuntime.jsxs("label", {
5172
- className: "flex items-center gap-2 text-xs text-gray-300 cursor-pointer px-2 py-1 rounded hover:bg-gray-800/40",
5173
- children: [/*#__PURE__*/jsxRuntime.jsx("input", {
5174
- type: "checkbox",
5175
- checked: isChecked,
5176
- onChange: function onChange() {
5177
- return togglePreflightLine(selected.widgetId, ln.key);
5178
- }
5179
- }), /*#__PURE__*/jsxRuntime.jsx("span", {
5180
- children: ln.label
5181
- })]
5182
- }, ln.key);
5183
- })]
5184
- })]
5185
- })]
5186
- });
5187
- };
5188
5222
  var renderBody = function renderBody() {
5189
- if (pendingPreflight) return renderPreflightBody();
5190
5223
  if (isChecking && totalUpdates === 0) {
5191
5224
  return /*#__PURE__*/jsxRuntime.jsxs("div", {
5192
5225
  className: "flex flex-col gap-4",
@@ -5287,26 +5320,6 @@ var AppUpdatesModal = function AppUpdatesModal(_ref) {
5287
5320
  // "Close"; preflight → "Cancel update" + "Approve and install";
5288
5321
  // updates-found → "Remind me later" + per-category action buttons.
5289
5322
  var renderFooter = function renderFooter() {
5290
- if (pendingPreflight) {
5291
- var _pendingPreflight$wid2;
5292
- var widgetCount = ((_pendingPreflight$wid2 = pendingPreflight.widgets) === null || _pendingPreflight$wid2 === void 0 ? void 0 : _pendingPreflight$wid2.length) || 0;
5293
- return /*#__PURE__*/jsxRuntime.jsxs("div", {
5294
- className: "flex items-center gap-2",
5295
- children: [/*#__PURE__*/jsxRuntime.jsx("button", {
5296
- type: "button",
5297
- onClick: handlePreflightCancel,
5298
- className: secondaryBtnClass,
5299
- "data-testid": "app-updates-modal-preflight-cancel",
5300
- children: "Cancel update"
5301
- }), /*#__PURE__*/jsxRuntime.jsxs("button", {
5302
- type: "button",
5303
- onClick: handlePreflightApprove,
5304
- className: primaryBtnClass,
5305
- "data-testid": "app-updates-modal-preflight-approve",
5306
- children: ["Approve and install", widgetCount > 0 ? " (".concat(widgetCount, ")") : ""]
5307
- })]
5308
- });
5309
- }
5310
5323
  if (isChecking && totalUpdates === 0) {
5311
5324
  return /*#__PURE__*/jsxRuntime.jsx("button", {
5312
5325
  type: "button",
@@ -5368,6 +5381,23 @@ var AppUpdatesModal = function AppUpdatesModal(_ref) {
5368
5381
  }))]
5369
5382
  });
5370
5383
  };
5384
+
5385
+ // Preflight consent is its own dialog. When the batch suspends for
5386
+ // permission approval, render the shared WidgetPreflightReview inside
5387
+ // this modal's shell (same Modal chrome as before the extraction) and
5388
+ // short-circuit the normal updates/checking/up-to-date body. The
5389
+ // hook clears pendingPreflight when the user resolves, returning the
5390
+ // modal to its normal mode.
5391
+ if (pendingPreflight) {
5392
+ return /*#__PURE__*/jsxRuntime.jsx(DashReact.Modal, {
5393
+ isOpen: isOpen,
5394
+ setIsOpen: setIsOpen,
5395
+ children: /*#__PURE__*/jsxRuntime.jsx(WidgetPreflightReview, {
5396
+ pendingPreflight: pendingPreflight,
5397
+ resolvePreflight: resolvePreflight
5398
+ })
5399
+ });
5400
+ }
5371
5401
  return /*#__PURE__*/jsxRuntime.jsx(DashReact.Modal, {
5372
5402
  isOpen: isOpen,
5373
5403
  setIsOpen: setIsOpen,
@@ -5379,15 +5409,12 @@ var AppUpdatesModal = function AppUpdatesModal(_ref) {
5379
5409
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
5380
5410
  className: "flex items-center gap-2 text-base font-semibold text-gray-100",
5381
5411
  children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
5382
- icon: pendingPreflight ? "shield-halved" : isChecking && totalUpdates === 0 ? "spinner" : hasChecked && totalUpdates === 0 ? "circle-check" : "arrow-up",
5383
- className: pendingPreflight ? "text-amber-400" : isChecking && totalUpdates === 0 ? "text-blue-400 animate-spin" : hasChecked && totalUpdates === 0 ? "text-emerald-400" : "text-blue-400"
5412
+ icon: isChecking && totalUpdates === 0 ? "spinner" : hasChecked && totalUpdates === 0 ? "circle-check" : "arrow-up",
5413
+ className: isChecking && totalUpdates === 0 ? "text-blue-400 animate-spin" : hasChecked && totalUpdates === 0 ? "text-emerald-400" : "text-blue-400"
5384
5414
  }), /*#__PURE__*/jsxRuntime.jsx("span", {
5385
- children: pendingPreflight ? "Review ".concat(((_pendingPreflight$wid3 = pendingPreflight.widgets) === null || _pendingPreflight$wid3 === void 0 ? void 0 : _pendingPreflight$wid3.length) || 0, " widget").concat((((_pendingPreflight$wid4 = pendingPreflight.widgets) === null || _pendingPreflight$wid4 === void 0 ? void 0 : _pendingPreflight$wid4.length) || 0) === 1 ? "" : "s", " before installing") : isChecking && totalUpdates === 0 ? "Checking for updates" : hasChecked && totalUpdates === 0 ? "Up to date" : "".concat(totalUpdates, " update").concat(totalUpdates === 1 ? "" : "s", " available")
5415
+ children: isChecking && totalUpdates === 0 ? "Checking for updates" : hasChecked && totalUpdates === 0 ? "Up to date" : "".concat(totalUpdates, " update").concat(totalUpdates === 1 ? "" : "s", " available")
5386
5416
  })]
5387
- }), pendingPreflight ? /*#__PURE__*/jsxRuntime.jsx("div", {
5388
- className: "text-xs text-gray-400 mt-1",
5389
- children: "New versions request permissions you haven't granted yet. Approve what you're comfortable with \u2014 the rest stays denied and the install still goes through."
5390
- }) : totalUpdates > 0 && /*#__PURE__*/jsxRuntime.jsx("div", {
5417
+ }), totalUpdates > 0 && /*#__PURE__*/jsxRuntime.jsx("div", {
5391
5418
  className: "text-xs text-gray-400 mt-1",
5392
5419
  children: needsSignIn && widgetUpdates.length > 0 ? "Sign in to the registry to install ".concat(widgetUpdates.length, " widget package update").concat(widgetUpdates.length === 1 ? "" : "s", ".") : widgetUpdates.length > 0 && dashboardUpdates.length > 0 ? "".concat(widgetUpdates.length, " widget package").concat(widgetUpdates.length === 1 ? "" : "s", " and ").concat(dashboardUpdates.length, " dashboard").concat(dashboardUpdates.length === 1 ? "" : "s", " have newer versions on the registry.") : widgetUpdates.length > 0 ? "".concat(widgetUpdates.length, " widget package").concat(widgetUpdates.length === 1 ? "" : "s", " have newer versions on the registry.") : "".concat(dashboardUpdates.length, " dashboard").concat(dashboardUpdates.length === 1 ? "" : "s", " have newer versions on the registry.")
5393
5420
  })]
@@ -49982,8 +50009,15 @@ var UpdateAllWidgetsModal = function UpdateAllWidgetsModal(_ref) {
49982
50009
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
49983
50010
  className: "flex items-center justify-between px-5 py-3 border-t border-gray-700",
49984
50011
  children: [/*#__PURE__*/jsxRuntime.jsxs("div", {
49985
- className: "text-xs text-gray-500",
49986
- children: [runSummary && "Run complete: ".concat(runSummary.done, " succeeded, ").concat(runSummary.failed, " failed."), isBatchUpdating && "Updating selected packages…"]
50012
+ className: "text-xs text-gray-500 flex items-center gap-2",
50013
+ children: [runSummary && "Run complete: ".concat(runSummary.done, " succeeded, ").concat(runSummary.failed, " failed."), isBatchUpdating && /*#__PURE__*/jsxRuntime.jsxs("span", {
50014
+ className: "flex items-center gap-2 text-blue-300",
50015
+ "data-testid": "update-all-batch-spinner",
50016
+ children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.FontAwesomeIcon, {
50017
+ icon: "spinner",
50018
+ className: "animate-spin"
50019
+ }), "Updating selected packages\u2026"]
50020
+ })]
49987
50021
  }), /*#__PURE__*/jsxRuntime.jsxs("div", {
49988
50022
  className: "flex gap-2",
49989
50023
  children: [/*#__PURE__*/jsxRuntime.jsx(DashReact.Button, {
@@ -50036,7 +50070,9 @@ var WidgetsSection = function WidgetsSection(_ref) {
50036
50070
  isUpdating = _useWidgetUpdates.isUpdating,
50037
50071
  needsAuth = _useWidgetUpdates.needsAuth,
50038
50072
  clearNeedsAuth = _useWidgetUpdates.clearNeedsAuth,
50039
- updateError = _useWidgetUpdates.updateError;
50073
+ updateError = _useWidgetUpdates.updateError,
50074
+ pendingPreflight = _useWidgetUpdates.pendingPreflight,
50075
+ resolvePreflight = _useWidgetUpdates.resolvePreflight;
50040
50076
 
50041
50077
  // "Update all" modal visibility — opened from the footer when there
50042
50078
  // are package-level updates available; closed by the user (or by
@@ -50987,6 +51023,17 @@ var WidgetsSection = function WidgetsSection(_ref) {
50987
51023
  batchStatus: batchStatus,
50988
51024
  isBatchUpdating: isBatchUpdating,
50989
51025
  onConfirm: updatePackages
51026
+ }), /*#__PURE__*/jsxRuntime.jsx(DashReact.Modal, {
51027
+ isOpen: !!pendingPreflight,
51028
+ setIsOpen: function setIsOpen(open) {
51029
+ if (!open && typeof resolvePreflight === "function") {
51030
+ resolvePreflight(null);
51031
+ }
51032
+ },
51033
+ children: /*#__PURE__*/jsxRuntime.jsx(WidgetPreflightReview, {
51034
+ pendingPreflight: pendingPreflight,
51035
+ resolvePreflight: resolvePreflight
51036
+ })
50990
51037
  })]
50991
51038
  });
50992
51039
  };