@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.esm.js CHANGED
@@ -2,7 +2,7 @@ import _slicedToArray from '@babel/runtime/helpers/slicedToArray';
2
2
  import _typeof from '@babel/runtime/helpers/typeof';
3
3
  import _defineProperty from '@babel/runtime/helpers/defineProperty';
4
4
  import * as DashReact from '@trops/dash-react';
5
- import { isObject, ThemeContext, Modal, FontAwesomeIcon, deepCopy, MainSection, getUUID, getStylesForItem, themeObjects, Heading, SearchInput, ButtonIcon, SubHeading3, InputText, Button, Tag, Button3, Button2, Paragraph, Sidebar, Panel, Stepper, Tag3, Card2, Card3, Heading3, MenuItem3, FormLabel, SelectMenu, Switch, SelectInput, CodeEditorVS, SettingsModal, SubHeading2, tailwindHeightFractions, Menu3, Panel3, ButtonIcon2, DropdownPanel, MenuItem2, DragComponent, ConfirmationModal, DropComponent, getStyleName, capitalizeFirstLetter, isHexColor as isHexColor$1, deriveShades, colorTypes, TAILWIND_PALETTE, Toggle, normalizeHex as normalizeHex$1, contrastRatio, Caption2, Caption, getColorFamilies, getCuratedColorGrid, DashPanel, hexToRgb as hexToRgb$1, themeVariants, SubHeading, Heading2, Paragraph2, Paragraph3, ButtonIcon3, Tag2, Alert, Alert2, Alert3, Toast, Toast2, Toast3, ProgressBar, ProgressBar2, ProgressBar3, MenuItem, Breadcrumbs, Breadcrumbs2, Breadcrumbs3, Caption3, Code, Code2, Code3, Divider, Divider2, Divider3, DashPanel2, DashPanel3, Tabs, Tabs2, Tabs3, Accordion, Accordion2, Accordion3, Toggle2, Toggle3, TextArea, Checkbox, Slider, RadioGroup, AlertBanner, StatusBadge as StatusBadge$1, Skeleton, StatCard, DataList, EmptyState, Card, Panel2, ThemeFromUrlPane, CodeEditorInline, Icon2, AlgoliaSearchBox, CommandPalette, useSidebar, Navbar, withRouter, Menu as Menu$1 } from '@trops/dash-react';
5
+ import { isObject, ThemeContext, FontAwesomeIcon, Modal, deepCopy, MainSection, getUUID, getStylesForItem, themeObjects, Heading, SearchInput, ButtonIcon, SubHeading3, InputText, Button, Tag, Button3, Button2, Paragraph, Sidebar, Panel, Stepper, Tag3, Card2, Card3, Heading3, MenuItem3, FormLabel, SelectMenu, Switch, SelectInput, CodeEditorVS, SettingsModal, SubHeading2, tailwindHeightFractions, Menu3, Panel3, ButtonIcon2, DropdownPanel, MenuItem2, DragComponent, ConfirmationModal, DropComponent, getStyleName, capitalizeFirstLetter, isHexColor as isHexColor$1, deriveShades, colorTypes, TAILWIND_PALETTE, Toggle, normalizeHex as normalizeHex$1, contrastRatio, Caption2, Caption, getColorFamilies, getCuratedColorGrid, DashPanel, hexToRgb as hexToRgb$1, themeVariants, SubHeading, Heading2, Paragraph2, Paragraph3, ButtonIcon3, Tag2, Alert, Alert2, Alert3, Toast, Toast2, Toast3, ProgressBar, ProgressBar2, ProgressBar3, MenuItem, Breadcrumbs, Breadcrumbs2, Breadcrumbs3, Caption3, Code, Code2, Code3, Divider, Divider2, Divider3, DashPanel2, DashPanel3, Tabs, Tabs2, Tabs3, Accordion, Accordion2, Accordion3, Toggle2, Toggle3, TextArea, Checkbox, Slider, RadioGroup, AlertBanner, StatusBadge as StatusBadge$1, Skeleton, StatCard, DataList, EmptyState, Card, Panel2, ThemeFromUrlPane, CodeEditorInline, Icon2, AlgoliaSearchBox, CommandPalette, useSidebar, Navbar, withRouter, Menu as Menu$1 } from '@trops/dash-react';
6
6
  export * from '@trops/dash-react';
7
7
  export { FontAwesomeIcon, ThemeContext } from '@trops/dash-react';
8
8
  import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray';
@@ -4639,18 +4639,17 @@ function _objectSpread$16(e) { for (var r = 1; r < arguments.length; r++) { var
4639
4639
  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; } } }; }
4640
4640
  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; } }
4641
4641
  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; }
4642
- 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";
4643
- 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";
4642
+ 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";
4643
+ 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";
4644
4644
 
4645
4645
  /**
4646
4646
  * Flatten a single widget's `missing` blob (output of useWidgetUpdates'
4647
- * preflight computation) into an array of keyed lines the modal can
4647
+ * preflight computation) into an array of keyed lines the panel can
4648
4648
  * render as toggleable checkboxes.
4649
4649
  *
4650
4650
  * Each line carries `apply(acc)` that mutates an accumulator into the
4651
- * grant-blob shape the main process accepts. Mirrors the shape
4652
- * PreflightConsentModal uses for the dashboard-load case so the modal
4653
- * UX stays consistent (server / tool / readPath / writePath rows).
4651
+ * grant-blob shape the main process accepts (server / tool / readPath /
4652
+ * writePath rows).
4654
4653
  */
4655
4654
  function flattenPreflightLines(missing) {
4656
4655
  var lines = [];
@@ -4746,6 +4745,213 @@ function flattenPreflightLines(missing) {
4746
4745
  }
4747
4746
  return lines;
4748
4747
  }
4748
+ var WidgetPreflightReview = function WidgetPreflightReview(_ref) {
4749
+ var pendingPreflight = _ref.pendingPreflight,
4750
+ resolvePreflight = _ref.resolvePreflight;
4751
+ // Per-line checkbox state — `{ [widgetId]: { [lineKey]: bool } }`.
4752
+ // Initialized to "everything checked" on each new pendingPreflight so
4753
+ // the default action approves the full ask; the user opts OUT of
4754
+ // individual lines by unchecking.
4755
+ var _useState = useState({}),
4756
+ _useState2 = _slicedToArray(_useState, 2),
4757
+ preflightChecked = _useState2[0],
4758
+ setPreflightChecked = _useState2[1];
4759
+ var _useState3 = useState(null),
4760
+ _useState4 = _slicedToArray(_useState3, 2),
4761
+ selectedPreflightWidgetId = _useState4[0],
4762
+ setSelectedPreflightWidgetId = _useState4[1];
4763
+ useEffect(function () {
4764
+ var _pendingPreflight$wid;
4765
+ if (!pendingPreflight || !((_pendingPreflight$wid = pendingPreflight.widgets) !== null && _pendingPreflight$wid !== void 0 && _pendingPreflight$wid.length)) return;
4766
+ var initial = {};
4767
+ var _iterator4 = _createForOfIteratorHelper$K(pendingPreflight.widgets),
4768
+ _step4;
4769
+ try {
4770
+ for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
4771
+ var w = _step4.value;
4772
+ initial[w.widgetId] = {};
4773
+ var _iterator5 = _createForOfIteratorHelper$K(flattenPreflightLines(w.missing)),
4774
+ _step5;
4775
+ try {
4776
+ for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
4777
+ var ln = _step5.value;
4778
+ initial[w.widgetId][ln.key] = true;
4779
+ }
4780
+ } catch (err) {
4781
+ _iterator5.e(err);
4782
+ } finally {
4783
+ _iterator5.f();
4784
+ }
4785
+ }
4786
+ } catch (err) {
4787
+ _iterator4.e(err);
4788
+ } finally {
4789
+ _iterator4.f();
4790
+ }
4791
+ setPreflightChecked(initial);
4792
+ setSelectedPreflightWidgetId(pendingPreflight.widgets[0].widgetId);
4793
+ }, [pendingPreflight]);
4794
+ if (!pendingPreflight) return null;
4795
+ var widgets = pendingPreflight.widgets || [];
4796
+ var widgetCount = widgets.length;
4797
+ var selected = widgets.find(function (w) {
4798
+ return w.widgetId === selectedPreflightWidgetId;
4799
+ }) || widgets[0];
4800
+ var togglePreflightLine = function togglePreflightLine(widgetId, lineKey) {
4801
+ setPreflightChecked(function (prev) {
4802
+ return _objectSpread$16(_objectSpread$16({}, prev), {}, _defineProperty({}, widgetId, _objectSpread$16(_objectSpread$16({}, prev[widgetId] || {}), {}, _defineProperty({}, lineKey, !(prev[widgetId] && prev[widgetId][lineKey])))));
4803
+ });
4804
+ };
4805
+ var handlePreflightApprove = function handlePreflightApprove() {
4806
+ if (typeof resolvePreflight !== "function") return;
4807
+ // Build the per-widget addition blob from checked lines. Skip
4808
+ // widgets where the user unchecked everything.
4809
+ var acceptedByWidgetId = {};
4810
+ var _iterator6 = _createForOfIteratorHelper$K(widgets),
4811
+ _step6;
4812
+ try {
4813
+ for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
4814
+ var w = _step6.value;
4815
+ var _lines = flattenPreflightLines(w.missing);
4816
+ var acc = {};
4817
+ var any = false;
4818
+ var _iterator7 = _createForOfIteratorHelper$K(_lines),
4819
+ _step7;
4820
+ try {
4821
+ for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
4822
+ var _preflightChecked$w$w;
4823
+ var ln = _step7.value;
4824
+ if ((_preflightChecked$w$w = preflightChecked[w.widgetId]) !== null && _preflightChecked$w$w !== void 0 && _preflightChecked$w$w[ln.key]) {
4825
+ ln.apply(acc);
4826
+ any = true;
4827
+ }
4828
+ }
4829
+ } catch (err) {
4830
+ _iterator7.e(err);
4831
+ } finally {
4832
+ _iterator7.f();
4833
+ }
4834
+ if (any) acceptedByWidgetId[w.widgetId] = acc;
4835
+ }
4836
+ } catch (err) {
4837
+ _iterator6.e(err);
4838
+ } finally {
4839
+ _iterator6.f();
4840
+ }
4841
+ resolvePreflight({
4842
+ acceptedByWidgetId: acceptedByWidgetId
4843
+ });
4844
+ };
4845
+ var handlePreflightCancel = function handlePreflightCancel() {
4846
+ if (typeof resolvePreflight !== "function") return;
4847
+ resolvePreflight(null);
4848
+ };
4849
+ var lines = selected ? flattenPreflightLines(selected.missing) : [];
4850
+ return /*#__PURE__*/jsxs("div", {
4851
+ className: "flex flex-col w-full max-w-xl mx-auto border border-gray-700 rounded bg-gray-900",
4852
+ "data-testid": "widget-preflight-review",
4853
+ children: [/*#__PURE__*/jsxs("div", {
4854
+ className: "px-5 py-4 border-b border-gray-700",
4855
+ children: [/*#__PURE__*/jsxs("div", {
4856
+ className: "flex items-center gap-2 text-base font-semibold text-gray-100",
4857
+ children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
4858
+ icon: "shield-halved",
4859
+ className: "text-amber-400"
4860
+ }), /*#__PURE__*/jsxs("span", {
4861
+ children: ["Review ", widgetCount, " widget", widgetCount === 1 ? "" : "s", " before installing"]
4862
+ })]
4863
+ }), /*#__PURE__*/jsx("div", {
4864
+ className: "text-xs text-gray-400 mt-1",
4865
+ 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."
4866
+ })]
4867
+ }), /*#__PURE__*/jsx("div", {
4868
+ className: "px-5 py-4",
4869
+ children: /*#__PURE__*/jsxs("div", {
4870
+ className: "flex flex-col gap-4",
4871
+ "data-testid": "widget-preflight-review-body",
4872
+ children: [/*#__PURE__*/jsx("div", {
4873
+ className: "px-3 py-2 rounded border border-amber-700 bg-amber-900/30 text-xs text-amber-200",
4874
+ 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."
4875
+ }), selected && /*#__PURE__*/jsxs("div", {
4876
+ className: "flex border border-gray-700 rounded overflow-hidden",
4877
+ children: [/*#__PURE__*/jsx("div", {
4878
+ className: "flex flex-col w-44 border-r border-gray-700 bg-gray-900/40 max-h-64 overflow-y-auto",
4879
+ children: widgets.map(function (w) {
4880
+ var lineCount = flattenPreflightLines(w.missing).length;
4881
+ var isActive = w.widgetId === selected.widgetId;
4882
+ return /*#__PURE__*/jsxs("button", {
4883
+ type: "button",
4884
+ onClick: function onClick() {
4885
+ return setSelectedPreflightWidgetId(w.widgetId);
4886
+ },
4887
+ 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"),
4888
+ "data-testid": "widget-preflight-review-widget-".concat(w.widgetId),
4889
+ children: [/*#__PURE__*/jsx("span", {
4890
+ className: "truncate",
4891
+ children: w.displayName
4892
+ }), /*#__PURE__*/jsx("span", {
4893
+ className: "text-xs px-1.5 py-0.5 rounded bg-amber-900/40 text-amber-300 shrink-0",
4894
+ children: lineCount
4895
+ })]
4896
+ }, w.widgetId);
4897
+ })
4898
+ }), /*#__PURE__*/jsxs("div", {
4899
+ className: "flex flex-col flex-1 min-w-0 p-3 gap-2 max-h-64 overflow-y-auto",
4900
+ children: [/*#__PURE__*/jsxs("div", {
4901
+ className: "text-xs text-gray-400 mb-1",
4902
+ children: [/*#__PURE__*/jsx("span", {
4903
+ className: "font-semibold text-gray-200",
4904
+ children: selected.displayName
4905
+ }), " ", /*#__PURE__*/jsx("span", {
4906
+ className: "opacity-60 font-mono",
4907
+ children: selected.packageId
4908
+ })]
4909
+ }), lines.length === 0 && /*#__PURE__*/jsx("div", {
4910
+ className: "text-xs text-gray-500",
4911
+ children: "No new permissions for this widget."
4912
+ }), lines.map(function (ln) {
4913
+ var _preflightChecked$sel;
4914
+ var isChecked = !!((_preflightChecked$sel = preflightChecked[selected.widgetId]) !== null && _preflightChecked$sel !== void 0 && _preflightChecked$sel[ln.key]);
4915
+ return /*#__PURE__*/jsxs("label", {
4916
+ className: "flex items-center gap-2 text-xs text-gray-300 cursor-pointer px-2 py-1 rounded hover:bg-gray-800/40",
4917
+ children: [/*#__PURE__*/jsx("input", {
4918
+ type: "checkbox",
4919
+ checked: isChecked,
4920
+ onChange: function onChange() {
4921
+ return togglePreflightLine(selected.widgetId, ln.key);
4922
+ }
4923
+ }), /*#__PURE__*/jsx("span", {
4924
+ children: ln.label
4925
+ })]
4926
+ }, ln.key);
4927
+ })]
4928
+ })]
4929
+ })]
4930
+ })
4931
+ }), /*#__PURE__*/jsx("div", {
4932
+ className: "flex items-center justify-end px-5 py-3 border-t border-gray-700",
4933
+ children: /*#__PURE__*/jsxs("div", {
4934
+ className: "flex items-center gap-2",
4935
+ children: [/*#__PURE__*/jsx("button", {
4936
+ type: "button",
4937
+ onClick: handlePreflightCancel,
4938
+ className: secondaryBtnClass$1,
4939
+ "data-testid": "widget-preflight-review-cancel",
4940
+ children: "Cancel update"
4941
+ }), /*#__PURE__*/jsxs("button", {
4942
+ type: "button",
4943
+ onClick: handlePreflightApprove,
4944
+ className: primaryBtnClass$1,
4945
+ "data-testid": "widget-preflight-review-approve",
4946
+ children: ["Approve and install", widgetCount > 0 ? " (".concat(widgetCount, ")") : ""]
4947
+ })]
4948
+ })
4949
+ })]
4950
+ });
4951
+ };
4952
+
4953
+ 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";
4954
+ 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";
4749
4955
 
4750
4956
  /**
4751
4957
  * AppUpdatesModal — top-level "updates available" prompt the app shell
@@ -4782,7 +4988,6 @@ function flattenPreflightLines(missing) {
4782
4988
  * "shown for this session" so the same launch doesn't nag).
4783
4989
  */
4784
4990
  var AppUpdatesModal = function AppUpdatesModal(_ref) {
4785
- var _pendingPreflight$wid3, _pendingPreflight$wid4;
4786
4991
  var isOpen = _ref.isOpen,
4787
4992
  setIsOpen = _ref.setIsOpen,
4788
4993
  _ref$widgetUpdates = _ref.widgetUpdates,
@@ -4855,54 +5060,7 @@ var AppUpdatesModal = function AppUpdatesModal(_ref) {
4855
5060
  if (isOpen) return;
4856
5061
  setLastRunResult(null);
4857
5062
  setIsUpdatingWidgets(false);
4858
- setPreflightChecked({});
4859
- setSelectedPreflightWidgetId(null);
4860
5063
  }, [isOpen]);
4861
-
4862
- // Preflight checkbox state — `{ [widgetId]: { [lineKey]: bool } }`.
4863
- // Initialized to "everything checked" on each new pendingPreflight
4864
- // so the default action approves the full ask; the user opts OUT of
4865
- // individual lines by unchecking. Mirror of how
4866
- // PreflightConsentModal seeds its checks.
4867
- var _useState7 = useState({}),
4868
- _useState8 = _slicedToArray(_useState7, 2),
4869
- preflightChecked = _useState8[0],
4870
- setPreflightChecked = _useState8[1];
4871
- var _useState9 = useState(null),
4872
- _useState0 = _slicedToArray(_useState9, 2),
4873
- selectedPreflightWidgetId = _useState0[0],
4874
- setSelectedPreflightWidgetId = _useState0[1];
4875
- useEffect(function () {
4876
- var _pendingPreflight$wid;
4877
- if (!pendingPreflight || !((_pendingPreflight$wid = pendingPreflight.widgets) !== null && _pendingPreflight$wid !== void 0 && _pendingPreflight$wid.length)) return;
4878
- var initial = {};
4879
- var _iterator4 = _createForOfIteratorHelper$K(pendingPreflight.widgets),
4880
- _step4;
4881
- try {
4882
- for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
4883
- var w = _step4.value;
4884
- initial[w.widgetId] = {};
4885
- var _iterator5 = _createForOfIteratorHelper$K(flattenPreflightLines(w.missing)),
4886
- _step5;
4887
- try {
4888
- for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
4889
- var ln = _step5.value;
4890
- initial[w.widgetId][ln.key] = true;
4891
- }
4892
- } catch (err) {
4893
- _iterator5.e(err);
4894
- } finally {
4895
- _iterator5.f();
4896
- }
4897
- }
4898
- } catch (err) {
4899
- _iterator4.e(err);
4900
- } finally {
4901
- _iterator4.f();
4902
- }
4903
- setPreflightChecked(initial);
4904
- setSelectedPreflightWidgetId(pendingPreflight.widgets[0].widgetId);
4905
- }, [pendingPreflight]);
4906
5064
  var totalUpdates = widgetUpdates.length + dashboardUpdates.length;
4907
5065
  // Single source of truth for "user needs to sign in before we can
4908
5066
  // run the batch": either the proactive check found no session, or
@@ -4975,59 +5133,6 @@ var AppUpdatesModal = function AppUpdatesModal(_ref) {
4975
5133
  setIsOpen(false);
4976
5134
  };
4977
5135
 
4978
- // --- Preflight handlers ---
4979
- var togglePreflightLine = function togglePreflightLine(widgetId, lineKey) {
4980
- setPreflightChecked(function (prev) {
4981
- return _objectSpread$16(_objectSpread$16({}, prev), {}, _defineProperty({}, widgetId, _objectSpread$16(_objectSpread$16({}, prev[widgetId] || {}), {}, _defineProperty({}, lineKey, !(prev[widgetId] && prev[widgetId][lineKey])))));
4982
- });
4983
- };
4984
- var handlePreflightApprove = function handlePreflightApprove() {
4985
- if (typeof resolvePreflight !== "function" || !pendingPreflight) return;
4986
- // Build the per-widget addition blob from checked lines. Skip
4987
- // widgets where the user unchecked everything (mergeMcpGrants
4988
- // would no-op them anyway, but explicit is cheaper than
4989
- // mysterious).
4990
- var acceptedByWidgetId = {};
4991
- var _iterator6 = _createForOfIteratorHelper$K(pendingPreflight.widgets),
4992
- _step6;
4993
- try {
4994
- for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
4995
- var w = _step6.value;
4996
- var lines = flattenPreflightLines(w.missing);
4997
- var acc = {};
4998
- var any = false;
4999
- var _iterator7 = _createForOfIteratorHelper$K(lines),
5000
- _step7;
5001
- try {
5002
- for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
5003
- var _preflightChecked$w$w;
5004
- var ln = _step7.value;
5005
- if ((_preflightChecked$w$w = preflightChecked[w.widgetId]) !== null && _preflightChecked$w$w !== void 0 && _preflightChecked$w$w[ln.key]) {
5006
- ln.apply(acc);
5007
- any = true;
5008
- }
5009
- }
5010
- } catch (err) {
5011
- _iterator7.e(err);
5012
- } finally {
5013
- _iterator7.f();
5014
- }
5015
- if (any) acceptedByWidgetId[w.widgetId] = acc;
5016
- }
5017
- } catch (err) {
5018
- _iterator6.e(err);
5019
- } finally {
5020
- _iterator6.f();
5021
- }
5022
- resolvePreflight({
5023
- acceptedByWidgetId: acceptedByWidgetId
5024
- });
5025
- };
5026
- var handlePreflightCancel = function handlePreflightCancel() {
5027
- if (typeof resolvePreflight !== "function") return;
5028
- resolvePreflight(null);
5029
- };
5030
-
5031
5136
  // The three render modes: checking, up-to-date, or updates-available.
5032
5137
  // Each gets its own clear visual identity so the user reads the
5033
5138
  // current state in one glance. The result banner (set after a
@@ -5096,79 +5201,7 @@ var AppUpdatesModal = function AppUpdatesModal(_ref) {
5096
5201
  })]
5097
5202
  });
5098
5203
  };
5099
- var renderPreflightBody = function renderPreflightBody() {
5100
- if (!pendingPreflight) return null;
5101
- var widgets = pendingPreflight.widgets || [];
5102
- var selected = widgets.find(function (w) {
5103
- return w.widgetId === selectedPreflightWidgetId;
5104
- }) || widgets[0];
5105
- if (!selected) return null;
5106
- var lines = flattenPreflightLines(selected.missing);
5107
- return /*#__PURE__*/jsxs("div", {
5108
- className: "flex flex-col gap-4",
5109
- "data-testid": "app-updates-modal-preflight",
5110
- children: [/*#__PURE__*/jsx("div", {
5111
- className: "px-3 py-2 rounded border border-amber-700 bg-amber-900/30 text-xs text-amber-200",
5112
- 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."
5113
- }), /*#__PURE__*/jsxs("div", {
5114
- className: "flex border border-gray-700 rounded overflow-hidden",
5115
- children: [/*#__PURE__*/jsx("div", {
5116
- className: "flex flex-col w-44 border-r border-gray-700 bg-gray-900/40 max-h-64 overflow-y-auto",
5117
- children: widgets.map(function (w) {
5118
- var lineCount = flattenPreflightLines(w.missing).length;
5119
- var isActive = w.widgetId === selected.widgetId;
5120
- return /*#__PURE__*/jsxs("button", {
5121
- type: "button",
5122
- onClick: function onClick() {
5123
- return setSelectedPreflightWidgetId(w.widgetId);
5124
- },
5125
- 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"),
5126
- "data-testid": "app-updates-modal-preflight-widget-".concat(w.widgetId),
5127
- children: [/*#__PURE__*/jsx("span", {
5128
- className: "truncate",
5129
- children: w.displayName
5130
- }), /*#__PURE__*/jsx("span", {
5131
- className: "text-xs px-1.5 py-0.5 rounded bg-amber-900/40 text-amber-300 shrink-0",
5132
- children: lineCount
5133
- })]
5134
- }, w.widgetId);
5135
- })
5136
- }), /*#__PURE__*/jsxs("div", {
5137
- className: "flex flex-col flex-1 min-w-0 p-3 gap-2 max-h-64 overflow-y-auto",
5138
- children: [/*#__PURE__*/jsxs("div", {
5139
- className: "text-xs text-gray-400 mb-1",
5140
- children: [/*#__PURE__*/jsx("span", {
5141
- className: "font-semibold text-gray-200",
5142
- children: selected.displayName
5143
- }), " ", /*#__PURE__*/jsx("span", {
5144
- className: "opacity-60 font-mono",
5145
- children: selected.packageId
5146
- })]
5147
- }), lines.length === 0 && /*#__PURE__*/jsx("div", {
5148
- className: "text-xs text-gray-500",
5149
- children: "No new permissions for this widget."
5150
- }), lines.map(function (ln) {
5151
- var _preflightChecked$sel;
5152
- var isChecked = !!((_preflightChecked$sel = preflightChecked[selected.widgetId]) !== null && _preflightChecked$sel !== void 0 && _preflightChecked$sel[ln.key]);
5153
- return /*#__PURE__*/jsxs("label", {
5154
- className: "flex items-center gap-2 text-xs text-gray-300 cursor-pointer px-2 py-1 rounded hover:bg-gray-800/40",
5155
- children: [/*#__PURE__*/jsx("input", {
5156
- type: "checkbox",
5157
- checked: isChecked,
5158
- onChange: function onChange() {
5159
- return togglePreflightLine(selected.widgetId, ln.key);
5160
- }
5161
- }), /*#__PURE__*/jsx("span", {
5162
- children: ln.label
5163
- })]
5164
- }, ln.key);
5165
- })]
5166
- })]
5167
- })]
5168
- });
5169
- };
5170
5204
  var renderBody = function renderBody() {
5171
- if (pendingPreflight) return renderPreflightBody();
5172
5205
  if (isChecking && totalUpdates === 0) {
5173
5206
  return /*#__PURE__*/jsxs("div", {
5174
5207
  className: "flex flex-col gap-4",
@@ -5269,26 +5302,6 @@ var AppUpdatesModal = function AppUpdatesModal(_ref) {
5269
5302
  // "Close"; preflight → "Cancel update" + "Approve and install";
5270
5303
  // updates-found → "Remind me later" + per-category action buttons.
5271
5304
  var renderFooter = function renderFooter() {
5272
- if (pendingPreflight) {
5273
- var _pendingPreflight$wid2;
5274
- var widgetCount = ((_pendingPreflight$wid2 = pendingPreflight.widgets) === null || _pendingPreflight$wid2 === void 0 ? void 0 : _pendingPreflight$wid2.length) || 0;
5275
- return /*#__PURE__*/jsxs("div", {
5276
- className: "flex items-center gap-2",
5277
- children: [/*#__PURE__*/jsx("button", {
5278
- type: "button",
5279
- onClick: handlePreflightCancel,
5280
- className: secondaryBtnClass,
5281
- "data-testid": "app-updates-modal-preflight-cancel",
5282
- children: "Cancel update"
5283
- }), /*#__PURE__*/jsxs("button", {
5284
- type: "button",
5285
- onClick: handlePreflightApprove,
5286
- className: primaryBtnClass,
5287
- "data-testid": "app-updates-modal-preflight-approve",
5288
- children: ["Approve and install", widgetCount > 0 ? " (".concat(widgetCount, ")") : ""]
5289
- })]
5290
- });
5291
- }
5292
5305
  if (isChecking && totalUpdates === 0) {
5293
5306
  return /*#__PURE__*/jsx("button", {
5294
5307
  type: "button",
@@ -5350,6 +5363,23 @@ var AppUpdatesModal = function AppUpdatesModal(_ref) {
5350
5363
  }))]
5351
5364
  });
5352
5365
  };
5366
+
5367
+ // Preflight consent is its own dialog. When the batch suspends for
5368
+ // permission approval, render the shared WidgetPreflightReview inside
5369
+ // this modal's shell (same Modal chrome as before the extraction) and
5370
+ // short-circuit the normal updates/checking/up-to-date body. The
5371
+ // hook clears pendingPreflight when the user resolves, returning the
5372
+ // modal to its normal mode.
5373
+ if (pendingPreflight) {
5374
+ return /*#__PURE__*/jsx(Modal, {
5375
+ isOpen: isOpen,
5376
+ setIsOpen: setIsOpen,
5377
+ children: /*#__PURE__*/jsx(WidgetPreflightReview, {
5378
+ pendingPreflight: pendingPreflight,
5379
+ resolvePreflight: resolvePreflight
5380
+ })
5381
+ });
5382
+ }
5353
5383
  return /*#__PURE__*/jsx(Modal, {
5354
5384
  isOpen: isOpen,
5355
5385
  setIsOpen: setIsOpen,
@@ -5361,15 +5391,12 @@ var AppUpdatesModal = function AppUpdatesModal(_ref) {
5361
5391
  children: [/*#__PURE__*/jsxs("div", {
5362
5392
  className: "flex items-center gap-2 text-base font-semibold text-gray-100",
5363
5393
  children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
5364
- icon: pendingPreflight ? "shield-halved" : isChecking && totalUpdates === 0 ? "spinner" : hasChecked && totalUpdates === 0 ? "circle-check" : "arrow-up",
5365
- className: pendingPreflight ? "text-amber-400" : isChecking && totalUpdates === 0 ? "text-blue-400 animate-spin" : hasChecked && totalUpdates === 0 ? "text-emerald-400" : "text-blue-400"
5394
+ icon: isChecking && totalUpdates === 0 ? "spinner" : hasChecked && totalUpdates === 0 ? "circle-check" : "arrow-up",
5395
+ className: isChecking && totalUpdates === 0 ? "text-blue-400 animate-spin" : hasChecked && totalUpdates === 0 ? "text-emerald-400" : "text-blue-400"
5366
5396
  }), /*#__PURE__*/jsx("span", {
5367
- 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")
5397
+ children: isChecking && totalUpdates === 0 ? "Checking for updates" : hasChecked && totalUpdates === 0 ? "Up to date" : "".concat(totalUpdates, " update").concat(totalUpdates === 1 ? "" : "s", " available")
5368
5398
  })]
5369
- }), pendingPreflight ? /*#__PURE__*/jsx("div", {
5370
- className: "text-xs text-gray-400 mt-1",
5371
- 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."
5372
- }) : totalUpdates > 0 && /*#__PURE__*/jsx("div", {
5399
+ }), totalUpdates > 0 && /*#__PURE__*/jsx("div", {
5373
5400
  className: "text-xs text-gray-400 mt-1",
5374
5401
  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.")
5375
5402
  })]
@@ -49964,8 +49991,15 @@ var UpdateAllWidgetsModal = function UpdateAllWidgetsModal(_ref) {
49964
49991
  }), /*#__PURE__*/jsxs("div", {
49965
49992
  className: "flex items-center justify-between px-5 py-3 border-t border-gray-700",
49966
49993
  children: [/*#__PURE__*/jsxs("div", {
49967
- className: "text-xs text-gray-500",
49968
- children: [runSummary && "Run complete: ".concat(runSummary.done, " succeeded, ").concat(runSummary.failed, " failed."), isBatchUpdating && "Updating selected packages…"]
49994
+ className: "text-xs text-gray-500 flex items-center gap-2",
49995
+ children: [runSummary && "Run complete: ".concat(runSummary.done, " succeeded, ").concat(runSummary.failed, " failed."), isBatchUpdating && /*#__PURE__*/jsxs("span", {
49996
+ className: "flex items-center gap-2 text-blue-300",
49997
+ "data-testid": "update-all-batch-spinner",
49998
+ children: [/*#__PURE__*/jsx(FontAwesomeIcon, {
49999
+ icon: "spinner",
50000
+ className: "animate-spin"
50001
+ }), "Updating selected packages\u2026"]
50002
+ })]
49969
50003
  }), /*#__PURE__*/jsxs("div", {
49970
50004
  className: "flex gap-2",
49971
50005
  children: [/*#__PURE__*/jsx(Button, {
@@ -50018,7 +50052,9 @@ var WidgetsSection = function WidgetsSection(_ref) {
50018
50052
  isUpdating = _useWidgetUpdates.isUpdating,
50019
50053
  needsAuth = _useWidgetUpdates.needsAuth,
50020
50054
  clearNeedsAuth = _useWidgetUpdates.clearNeedsAuth,
50021
- updateError = _useWidgetUpdates.updateError;
50055
+ updateError = _useWidgetUpdates.updateError,
50056
+ pendingPreflight = _useWidgetUpdates.pendingPreflight,
50057
+ resolvePreflight = _useWidgetUpdates.resolvePreflight;
50022
50058
 
50023
50059
  // "Update all" modal visibility — opened from the footer when there
50024
50060
  // are package-level updates available; closed by the user (or by
@@ -50969,6 +51005,17 @@ var WidgetsSection = function WidgetsSection(_ref) {
50969
51005
  batchStatus: batchStatus,
50970
51006
  isBatchUpdating: isBatchUpdating,
50971
51007
  onConfirm: updatePackages
51008
+ }), /*#__PURE__*/jsx(Modal, {
51009
+ isOpen: !!pendingPreflight,
51010
+ setIsOpen: function setIsOpen(open) {
51011
+ if (!open && typeof resolvePreflight === "function") {
51012
+ resolvePreflight(null);
51013
+ }
51014
+ },
51015
+ children: /*#__PURE__*/jsx(WidgetPreflightReview, {
51016
+ pendingPreflight: pendingPreflight,
51017
+ resolvePreflight: resolvePreflight
51018
+ })
50972
51019
  })]
50973
51020
  });
50974
51021
  };