@meetreeve/ui 0.11.0 → 0.13.0

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.mjs CHANGED
@@ -417,6 +417,44 @@ function useResponsivePlaceholder(desktop, mobile) {
417
417
  return isDesktop ? desktop : mobile ?? desktop;
418
418
  }
419
419
 
420
+ // src/info-tip.tsx
421
+ import { Popover } from "@base-ui/react/popover";
422
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
423
+ function InfoTip({ children, label = "More information", side = "top", align = "center", className }) {
424
+ return /* @__PURE__ */ jsxs3(Popover.Root, { children: [
425
+ /* @__PURE__ */ jsx3(
426
+ Popover.Trigger,
427
+ {
428
+ openOnHover: true,
429
+ delay: 150,
430
+ closeDelay: 100,
431
+ "aria-label": label,
432
+ style: TOUCH_TARGET_STYLE,
433
+ className: cn(
434
+ "group -my-3.5 inline-flex shrink-0 cursor-help items-center justify-center rounded-full align-middle text-muted-foreground outline-none transition-colors hover:text-foreground data-[popup-open]:text-foreground",
435
+ className
436
+ ),
437
+ children: /* @__PURE__ */ jsx3(
438
+ "span",
439
+ {
440
+ "aria-hidden": "true",
441
+ className: "inline-flex size-4 items-center justify-center rounded-full border border-current text-[0.625rem] font-semibold leading-none group-focus-visible:ring-2 group-focus-visible:ring-ring/50",
442
+ children: "?"
443
+ }
444
+ )
445
+ }
446
+ ),
447
+ /* @__PURE__ */ jsx3(Popover.Portal, { children: /* @__PURE__ */ jsx3(Popover.Positioner, { side, align, sideOffset: 8, collisionPadding: 16, className: "z-50", children: /* @__PURE__ */ jsx3(
448
+ Popover.Popup,
449
+ {
450
+ "aria-label": label,
451
+ className: "max-w-[min(20rem,calc(100vw-2rem))] origin-[var(--transform-origin)] rounded-md border border-border bg-popover px-3 py-2 text-left text-xs font-normal leading-relaxed text-popover-foreground shadow-md outline-none transition-[opacity,transform] duration-150 ease-out data-[ending-style]:scale-95 data-[ending-style]:opacity-0 data-[starting-style]:scale-95 data-[starting-style]:opacity-0 motion-reduce:transition-none",
452
+ children: /* @__PURE__ */ jsx3(Popover.Description, { children })
453
+ }
454
+ ) }) })
455
+ ] });
456
+ }
457
+
420
458
  // src/app-sidebar.tsx
421
459
  import { useCallback as useCallback3, useEffect as useEffect5, useId as useId3, useMemo, useRef as useRef4, useState as useState6 } from "react";
422
460
  import { Menu as Menu2, PanelLeftClose, PanelLeftOpen, X as X2 } from "lucide-react";
@@ -699,7 +737,7 @@ function useLadderRung(ladder, containerRef, options = {}) {
699
737
 
700
738
  // src/ladder/flyout.tsx
701
739
  import { useCallback as useCallback2, useEffect as useEffect4, useId as useId2, useLayoutEffect as useLayoutEffect2, useRef as useRef3, useState as useState5 } from "react";
702
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
740
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
703
741
  var PANEL_GAP = 4;
704
742
  function Flyout({
705
743
  label,
@@ -763,7 +801,7 @@ function Flyout({
763
801
  useEffect4(() => {
764
802
  if (clickOpen && panelPosition) firstItemRef.current?.focus();
765
803
  }, [clickOpen, panelPosition]);
766
- return /* @__PURE__ */ jsxs3(
804
+ return /* @__PURE__ */ jsxs4(
767
805
  "div",
768
806
  {
769
807
  "data-testid": "ladder-flyout",
@@ -771,7 +809,7 @@ function Flyout({
771
809
  onMouseEnter: () => setHoverOpen(true),
772
810
  onMouseLeave: () => setHoverOpen(false),
773
811
  children: [
774
- /* @__PURE__ */ jsxs3(
812
+ /* @__PURE__ */ jsxs4(
775
813
  "button",
776
814
  {
777
815
  ref: triggerRef,
@@ -794,7 +832,7 @@ function Flyout({
794
832
  active ? "bg-sidebar-accent text-sidebar-accent-foreground" : "text-sidebar-foreground/70 hover:bg-sidebar-foreground/5 hover:text-sidebar-foreground"
795
833
  ),
796
834
  children: [
797
- /* @__PURE__ */ jsx3(
835
+ /* @__PURE__ */ jsx4(
798
836
  Icon,
799
837
  {
800
838
  className: cn(
@@ -805,11 +843,11 @@ function Flyout({
805
843
  "aria-hidden": "true"
806
844
  }
807
845
  ),
808
- /* @__PURE__ */ jsx3("span", { className: cn("truncate", collapsed && "sr-only"), children: label })
846
+ /* @__PURE__ */ jsx4("span", { className: cn("truncate", collapsed && "sr-only"), children: label })
809
847
  ]
810
848
  }
811
849
  ),
812
- open && panelPosition && /* @__PURE__ */ jsx3(
850
+ open && panelPosition && /* @__PURE__ */ jsx4(
813
851
  "div",
814
852
  {
815
853
  ref: panelRef,
@@ -831,7 +869,7 @@ function Flyout({
831
869
  // silently loses the focus-on-open behavior (a console ref
832
870
  // warning, not a crash) — same tradeoff any Link-injection
833
871
  // pattern accepts; not a regression from today's plain `<a>`.
834
- /* @__PURE__ */ jsx3(
872
+ /* @__PURE__ */ jsx4(
835
873
  LinkEl,
836
874
  {
837
875
  ref: i === 0 ? firstItemRef : void 0,
@@ -855,7 +893,7 @@ function Flyout({
855
893
  }
856
894
 
857
895
  // src/app-sidebar.tsx
858
- import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
896
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
859
897
  var DEFAULT_COLLAPSE_STORAGE_KEY = "reeve-sidebar-collapsed";
860
898
  var COLLAPSED_WIDTH_CLASS = "w-14";
861
899
  var EXPANDED_WIDTH_CLASS = "w-64";
@@ -873,7 +911,7 @@ function NavLink({
873
911
  }) {
874
912
  const Icon = resolveIcon(icon);
875
913
  const LinkEl = linkComponent ?? "a";
876
- return /* @__PURE__ */ jsxs4(
914
+ return /* @__PURE__ */ jsxs5(
877
915
  LinkEl,
878
916
  {
879
917
  href,
@@ -893,7 +931,7 @@ function NavLink({
893
931
  active ? "bg-sidebar-accent text-sidebar-accent-foreground" : "text-sidebar-foreground/70 hover:bg-sidebar-foreground/5 hover:text-sidebar-foreground"
894
932
  ),
895
933
  children: [
896
- /* @__PURE__ */ jsx4(
934
+ /* @__PURE__ */ jsx5(
897
935
  Icon,
898
936
  {
899
937
  className: cn(
@@ -904,7 +942,7 @@ function NavLink({
904
942
  "aria-hidden": "true"
905
943
  }
906
944
  ),
907
- /* @__PURE__ */ jsx4("span", { className: cn("truncate", collapsed && "sr-only"), children: label })
945
+ /* @__PURE__ */ jsx5("span", { className: cn("truncate", collapsed && "sr-only"), children: label })
908
946
  ]
909
947
  }
910
948
  );
@@ -992,7 +1030,7 @@ function AppSidebar({
992
1030
  function renderAppItem(item, testIdPrefix, collapsedRow = false) {
993
1031
  const def = moduleMap.get(item.moduleId);
994
1032
  if (!def) return null;
995
- return /* @__PURE__ */ jsx4(
1033
+ return /* @__PURE__ */ jsx5(
996
1034
  NavLink,
997
1035
  {
998
1036
  href: def.href,
@@ -1018,7 +1056,7 @@ function AppSidebar({
1018
1056
  };
1019
1057
  });
1020
1058
  const active = children.some((c) => c.active);
1021
- return /* @__PURE__ */ jsx4(
1059
+ return /* @__PURE__ */ jsx5(
1022
1060
  Flyout,
1023
1061
  {
1024
1062
  label: item.label,
@@ -1036,7 +1074,7 @@ function AppSidebar({
1036
1074
  function brandBlockFor(collapsedMode) {
1037
1075
  if (!brand) return null;
1038
1076
  if (collapsedMode) {
1039
- return /* @__PURE__ */ jsxs4(
1077
+ return /* @__PURE__ */ jsxs5(
1040
1078
  "a",
1041
1079
  {
1042
1080
  href: brand.href,
@@ -1044,28 +1082,28 @@ function AppSidebar({
1044
1082
  title: brand.label,
1045
1083
  className: "flex items-center justify-center border-b border-sidebar-border px-1 py-4",
1046
1084
  children: [
1047
- /* @__PURE__ */ jsx4("span", { className: "sr-only", children: brand.label }),
1048
- /* @__PURE__ */ jsx4(BrandGlyph, { brand: { name: brand.label }, size: "xl" })
1085
+ /* @__PURE__ */ jsx5("span", { className: "sr-only", children: brand.label }),
1086
+ /* @__PURE__ */ jsx5(BrandGlyph, { brand: { name: brand.label }, size: "xl" })
1049
1087
  ]
1050
1088
  }
1051
1089
  );
1052
1090
  }
1053
- return /* @__PURE__ */ jsxs4(
1091
+ return /* @__PURE__ */ jsxs5(
1054
1092
  "a",
1055
1093
  {
1056
1094
  href: brand.href,
1057
1095
  "data-testid": "app-sidebar-brand",
1058
1096
  className: "flex items-center gap-2.5 border-b border-sidebar-border px-5 py-4 text-sidebar-foreground",
1059
1097
  children: [
1060
- /* @__PURE__ */ jsx4("span", { className: "grid size-7 place-items-center rounded-md bg-sidebar-primary text-sidebar-primary-foreground", children: /* @__PURE__ */ jsx4("span", { className: "font-mono text-sm font-bold", children: (brand.label[0] ?? "r").toUpperCase() }) }),
1061
- /* @__PURE__ */ jsx4("span", { className: "truncate text-sm font-semibold tracking-tight", children: brand.label })
1098
+ /* @__PURE__ */ jsx5("span", { className: "grid size-7 place-items-center rounded-md bg-sidebar-primary text-sidebar-primary-foreground", children: /* @__PURE__ */ jsx5("span", { className: "font-mono text-sm font-bold", children: (brand.label[0] ?? "r").toUpperCase() }) }),
1099
+ /* @__PURE__ */ jsx5("span", { className: "truncate text-sm font-semibold tracking-tight", children: brand.label })
1062
1100
  ]
1063
1101
  }
1064
1102
  );
1065
1103
  }
1066
1104
  function topItemBlock(testId, collapsedMode = false) {
1067
1105
  if (!topItem) return null;
1068
- return /* @__PURE__ */ jsx4("div", { className: cn("px-3 pt-4", collapsedMode && "flex justify-center px-0"), children: /* @__PURE__ */ jsx4(
1106
+ return /* @__PURE__ */ jsx5("div", { className: cn("px-3 pt-4", collapsedMode && "flex justify-center px-0"), children: /* @__PURE__ */ jsx5(
1069
1107
  NavLink,
1070
1108
  {
1071
1109
  href: topItem.href,
@@ -1078,8 +1116,8 @@ function AppSidebar({
1078
1116
  }
1079
1117
  ) });
1080
1118
  }
1081
- return /* @__PURE__ */ jsxs4(Fragment2, { children: [
1082
- !isDesktop && /* @__PURE__ */ jsx4(
1119
+ return /* @__PURE__ */ jsxs5(Fragment2, { children: [
1120
+ !isDesktop && /* @__PURE__ */ jsx5(
1083
1121
  "button",
1084
1122
  {
1085
1123
  ref: mobileTriggerRef,
@@ -1091,11 +1129,11 @@ function AppSidebar({
1091
1129
  onClick: () => setMobileOpen((v) => !v),
1092
1130
  style: TOUCH_TARGET_STYLE,
1093
1131
  className: "flex items-center justify-center rounded-md border border-border p-2 text-foreground",
1094
- children: mobileOpen ? /* @__PURE__ */ jsx4(X2, { className: "h-5 w-5", "aria-hidden": "true" }) : /* @__PURE__ */ jsx4(Menu2, { className: "h-5 w-5", "aria-hidden": "true" })
1132
+ children: mobileOpen ? /* @__PURE__ */ jsx5(X2, { className: "h-5 w-5", "aria-hidden": "true" }) : /* @__PURE__ */ jsx5(Menu2, { className: "h-5 w-5", "aria-hidden": "true" })
1095
1133
  }
1096
1134
  ),
1097
- !isDesktop && mobileOpen && /* @__PURE__ */ jsxs4("div", { className: "fixed inset-0 z-50", children: [
1098
- /* @__PURE__ */ jsx4(
1135
+ !isDesktop && mobileOpen && /* @__PURE__ */ jsxs5("div", { className: "fixed inset-0 z-50", children: [
1136
+ /* @__PURE__ */ jsx5(
1099
1137
  "div",
1100
1138
  {
1101
1139
  "data-testid": "app-sidebar-mobile-scrim",
@@ -1104,7 +1142,7 @@ function AppSidebar({
1104
1142
  onClick: () => setMobileOpen(false)
1105
1143
  }
1106
1144
  ),
1107
- /* @__PURE__ */ jsxs4(
1145
+ /* @__PURE__ */ jsxs5(
1108
1146
  "div",
1109
1147
  {
1110
1148
  ref: mobileDrawerRef,
@@ -1115,7 +1153,7 @@ function AppSidebar({
1115
1153
  "data-testid": "app-sidebar-mobile-drawer",
1116
1154
  className: "absolute inset-y-0 left-0 flex w-72 flex-col overflow-y-auto border-r border-sidebar-border bg-sidebar",
1117
1155
  children: [
1118
- /* @__PURE__ */ jsx4("div", { className: "sticky top-0 z-10 flex justify-end bg-sidebar p-2", children: /* @__PURE__ */ jsx4(
1156
+ /* @__PURE__ */ jsx5("div", { className: "sticky top-0 z-10 flex justify-end bg-sidebar p-2", children: /* @__PURE__ */ jsx5(
1119
1157
  "button",
1120
1158
  {
1121
1159
  ref: mobileCloseRef,
@@ -1125,19 +1163,19 @@ function AppSidebar({
1125
1163
  onClick: () => setMobileOpen(false),
1126
1164
  style: TOUCH_TARGET_STYLE,
1127
1165
  className: "flex items-center justify-center rounded-md p-2 text-sidebar-foreground/70 hover:bg-sidebar-foreground/5 hover:text-sidebar-foreground",
1128
- children: /* @__PURE__ */ jsx4(X2, { className: "h-5 w-5", "aria-hidden": "true" })
1166
+ children: /* @__PURE__ */ jsx5(X2, { className: "h-5 w-5", "aria-hidden": "true" })
1129
1167
  }
1130
1168
  ) }),
1131
1169
  brandBlockFor(false),
1132
1170
  topItemBlock("app-sidebar-mobile-top-item"),
1133
- /* @__PURE__ */ jsx4("nav", { className: "flex-1 px-3 py-4", children: /* @__PURE__ */ jsx4("div", { className: "flex flex-col gap-0.5", children: rung0.items.map(
1171
+ /* @__PURE__ */ jsx5("nav", { className: "flex-1 px-3 py-4", children: /* @__PURE__ */ jsx5("div", { className: "flex flex-col gap-0.5", children: rung0.items.map(
1134
1172
  (item) => item.type === "app" ? renderAppItem(item, "app-sidebar-mobile-navlink") : null
1135
1173
  ) }) })
1136
1174
  ]
1137
1175
  }
1138
1176
  )
1139
1177
  ] }),
1140
- /* @__PURE__ */ jsxs4(
1178
+ /* @__PURE__ */ jsxs5(
1141
1179
  "aside",
1142
1180
  {
1143
1181
  "data-testid": "app-sidebar-desktop",
@@ -1152,18 +1190,18 @@ function AppSidebar({
1152
1190
  children: [
1153
1191
  brandBlockFor(collapsed),
1154
1192
  topItemBlock("app-sidebar-top-item", collapsed),
1155
- /* @__PURE__ */ jsx4(
1193
+ /* @__PURE__ */ jsx5(
1156
1194
  "nav",
1157
1195
  {
1158
1196
  ref: containerRef,
1159
1197
  "data-testid": "app-sidebar-nav",
1160
1198
  className: "flex-1 overflow-y-auto px-3 py-4",
1161
- children: /* @__PURE__ */ jsx4("div", { className: "flex flex-col gap-0.5", children: rung.items.map(
1199
+ children: /* @__PURE__ */ jsx5("div", { className: "flex flex-col gap-0.5", children: rung.items.map(
1162
1200
  (item) => item.type === "app" ? renderAppItem(item, "app-sidebar-navlink", collapsed) : renderGroupItem(item, collapsed)
1163
1201
  ) })
1164
1202
  }
1165
1203
  ),
1166
- collapsible && /* @__PURE__ */ jsx4("div", { className: "border-t border-sidebar-border px-2 py-2", children: /* @__PURE__ */ jsxs4(
1204
+ collapsible && /* @__PURE__ */ jsx5("div", { className: "border-t border-sidebar-border px-2 py-2", children: /* @__PURE__ */ jsxs5(
1167
1205
  "button",
1168
1206
  {
1169
1207
  type: "button",
@@ -1177,8 +1215,8 @@ function AppSidebar({
1177
1215
  collapsed && "justify-center px-0"
1178
1216
  ),
1179
1217
  children: [
1180
- collapsed ? /* @__PURE__ */ jsx4(PanelLeftOpen, { className: "size-4 shrink-0", strokeWidth: 1.5, "aria-hidden": "true" }) : /* @__PURE__ */ jsx4(PanelLeftClose, { className: "size-4 shrink-0", strokeWidth: 1.5, "aria-hidden": "true" }),
1181
- /* @__PURE__ */ jsx4("span", { className: cn("truncate", collapsed && "sr-only"), children: collapsed ? "Expand sidebar" : "Collapse sidebar" })
1218
+ collapsed ? /* @__PURE__ */ jsx5(PanelLeftOpen, { className: "size-4 shrink-0", strokeWidth: 1.5, "aria-hidden": "true" }) : /* @__PURE__ */ jsx5(PanelLeftClose, { className: "size-4 shrink-0", strokeWidth: 1.5, "aria-hidden": "true" }),
1219
+ /* @__PURE__ */ jsx5("span", { className: cn("truncate", collapsed && "sr-only"), children: collapsed ? "Expand sidebar" : "Collapse sidebar" })
1182
1220
  ]
1183
1221
  }
1184
1222
  ) })
@@ -1217,19 +1255,19 @@ function groupItemsByOrg(rows, get) {
1217
1255
 
1218
1256
  // src/lib/dropdown-menu.tsx
1219
1257
  import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
1220
- import { jsx as jsx5 } from "react/jsx-runtime";
1258
+ import { jsx as jsx6 } from "react/jsx-runtime";
1221
1259
  function DropdownMenu(props) {
1222
- return /* @__PURE__ */ jsx5(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
1260
+ return /* @__PURE__ */ jsx6(DropdownMenuPrimitive.Root, { "data-slot": "dropdown-menu", ...props });
1223
1261
  }
1224
1262
  function DropdownMenuTrigger(props) {
1225
- return /* @__PURE__ */ jsx5(DropdownMenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
1263
+ return /* @__PURE__ */ jsx6(DropdownMenuPrimitive.Trigger, { "data-slot": "dropdown-menu-trigger", ...props });
1226
1264
  }
1227
1265
  function DropdownMenuContent({
1228
1266
  className,
1229
1267
  sideOffset = 4,
1230
1268
  ...props
1231
1269
  }) {
1232
- return /* @__PURE__ */ jsx5(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx5(
1270
+ return /* @__PURE__ */ jsx6(DropdownMenuPrimitive.Portal, { children: /* @__PURE__ */ jsx6(
1233
1271
  DropdownMenuPrimitive.Content,
1234
1272
  {
1235
1273
  "data-slot": "dropdown-menu-content",
@@ -1246,7 +1284,7 @@ function DropdownMenuItem({
1246
1284
  className,
1247
1285
  ...props
1248
1286
  }) {
1249
- return /* @__PURE__ */ jsx5(
1287
+ return /* @__PURE__ */ jsx6(
1250
1288
  DropdownMenuPrimitive.Item,
1251
1289
  {
1252
1290
  "data-slot": "dropdown-menu-item",
@@ -1262,7 +1300,7 @@ function DropdownMenuLabel({
1262
1300
  className,
1263
1301
  ...props
1264
1302
  }) {
1265
- return /* @__PURE__ */ jsx5(
1303
+ return /* @__PURE__ */ jsx6(
1266
1304
  DropdownMenuPrimitive.Label,
1267
1305
  {
1268
1306
  "data-slot": "dropdown-menu-label",
@@ -1273,7 +1311,7 @@ function DropdownMenuLabel({
1273
1311
  }
1274
1312
 
1275
1313
  // src/context-switcher.tsx
1276
- import { Fragment as Fragment3, jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
1314
+ import { Fragment as Fragment3, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1277
1315
  function groupByOrg(items) {
1278
1316
  return groupItemsByOrg(items, {
1279
1317
  orgId: (it) => it.orgId,
@@ -1304,29 +1342,29 @@ function ContextSwitcher({
1304
1342
  const active = items.find((it) => it.refId === activeRefId) ?? null;
1305
1343
  const groups = groupByOrg(items);
1306
1344
  const showOrgHeaders = groups.length > 1;
1307
- return /* @__PURE__ */ jsxs5(DropdownMenu, { children: [
1308
- /* @__PURE__ */ jsx6(DropdownMenuTrigger, { asChild: true, children: collapsed ? /* @__PURE__ */ jsx6(
1345
+ return /* @__PURE__ */ jsxs6(DropdownMenu, { children: [
1346
+ /* @__PURE__ */ jsx7(DropdownMenuTrigger, { asChild: true, children: collapsed ? /* @__PURE__ */ jsx7(
1309
1347
  "button",
1310
1348
  {
1311
1349
  type: "button",
1312
1350
  title: active?.name || placeholder,
1313
1351
  "aria-label": active?.name || placeholder,
1314
1352
  className: "flex h-10 w-10 items-center justify-center rounded-lg text-sidebar-foreground/70 transition-colors hover:bg-sidebar-foreground/5 hover:text-sidebar-foreground",
1315
- children: /* @__PURE__ */ jsx6(BrandGlyph, { brand: toBrand(active ?? { name: "" }), size: "lg" })
1353
+ children: /* @__PURE__ */ jsx7(BrandGlyph, { brand: toBrand(active ?? { name: "" }), size: "lg" })
1316
1354
  }
1317
- ) : /* @__PURE__ */ jsxs5(
1355
+ ) : /* @__PURE__ */ jsxs6(
1318
1356
  "button",
1319
1357
  {
1320
1358
  type: "button",
1321
1359
  className: "group flex items-center gap-2 rounded-md border border-sidebar-border bg-sidebar-accent/60 px-2.5 py-1.5 text-sm font-medium transition-colors hover:bg-sidebar",
1322
1360
  children: [
1323
- /* @__PURE__ */ jsx6(BrandGlyph, { brand: toBrand(active ?? { name: "" }) }),
1324
- /* @__PURE__ */ jsx6("span", { className: "max-w-[140px] truncate text-sidebar-accent-foreground", children: active?.name || placeholder }),
1325
- /* @__PURE__ */ jsx6(ChevronDown, { className: "h-3.5 w-3.5 text-sidebar-foreground/70 transition-transform group-data-[state=open]:rotate-180" })
1361
+ /* @__PURE__ */ jsx7(BrandGlyph, { brand: toBrand(active ?? { name: "" }) }),
1362
+ /* @__PURE__ */ jsx7("span", { className: "max-w-[140px] truncate text-sidebar-accent-foreground", children: active?.name || placeholder }),
1363
+ /* @__PURE__ */ jsx7(ChevronDown, { className: "h-3.5 w-3.5 text-sidebar-foreground/70 transition-transform group-data-[state=open]:rotate-180" })
1326
1364
  ]
1327
1365
  }
1328
1366
  ) }),
1329
- /* @__PURE__ */ jsxs5(
1367
+ /* @__PURE__ */ jsxs6(
1330
1368
  DropdownMenuContent,
1331
1369
  {
1332
1370
  side,
@@ -1335,31 +1373,31 @@ function ContextSwitcher({
1335
1373
  collisionPadding: 8,
1336
1374
  className: cn("w-60 overflow-hidden p-0", contentClassName),
1337
1375
  children: [
1338
- groups.map((group) => /* @__PURE__ */ jsxs5("div", { children: [
1339
- showOrgHeaders && /* @__PURE__ */ jsx6(DropdownMenuLabel, { className: "px-3 pb-1 pt-2 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: group.orgName ?? "Other" }),
1340
- /* @__PURE__ */ jsx6("div", { className: cn(showOrgHeaders && "ml-5 border-l border-border/60"), children: group.items.map((item) => {
1376
+ groups.map((group) => /* @__PURE__ */ jsxs6("div", { children: [
1377
+ showOrgHeaders && /* @__PURE__ */ jsx7(DropdownMenuLabel, { className: "px-3 pb-1 pt-2 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground", children: group.orgName ?? "Other" }),
1378
+ /* @__PURE__ */ jsx7("div", { className: cn(showOrgHeaders && "ml-5 border-l border-border/60"), children: group.items.map((item) => {
1341
1379
  const isActive = item.refId === activeRefId;
1342
- return /* @__PURE__ */ jsxs5(
1380
+ return /* @__PURE__ */ jsxs6(
1343
1381
  DropdownMenuItem,
1344
1382
  {
1345
1383
  "data-active": isActive || void 0,
1346
1384
  onSelect: () => onSelect(item),
1347
1385
  className: "flex w-full items-center gap-2.5 rounded-none px-3 py-2 text-sm",
1348
1386
  children: [
1349
- /* @__PURE__ */ jsx6(BrandGlyph, { brand: toBrand(item), subtle: true }),
1350
- /* @__PURE__ */ jsx6("span", { className: "flex-1 truncate text-left text-foreground/90", children: item.name }),
1351
- item.kindLabel && /* @__PURE__ */ jsxs5(Fragment3, { children: [
1387
+ /* @__PURE__ */ jsx7(BrandGlyph, { brand: toBrand(item), subtle: true }),
1388
+ /* @__PURE__ */ jsx7("span", { className: "flex-1 truncate text-left text-foreground/90", children: item.name }),
1389
+ item.kindLabel && /* @__PURE__ */ jsxs6(Fragment3, { children: [
1352
1390
  " ",
1353
- /* @__PURE__ */ jsx6("span", { className: "shrink-0 text-[11px] text-muted-foreground", children: item.kindLabel })
1391
+ /* @__PURE__ */ jsx7("span", { className: "shrink-0 text-[11px] text-muted-foreground", children: item.kindLabel })
1354
1392
  ] }),
1355
- isActive && /* @__PURE__ */ jsx6(Check, { className: "size-3.5 text-emerald-500" })
1393
+ isActive && /* @__PURE__ */ jsx7(Check, { className: "size-3.5 text-emerald-500" })
1356
1394
  ]
1357
1395
  },
1358
1396
  item.refId
1359
1397
  );
1360
1398
  }) })
1361
1399
  ] }, group.orgId ?? "unattributed")),
1362
- footer && /* @__PURE__ */ jsx6("div", { className: "sticky bottom-0 border-t border-border bg-popover", children: footer })
1400
+ footer && /* @__PURE__ */ jsx7("div", { className: "sticky bottom-0 border-t border-border bg-popover", children: footer })
1363
1401
  ]
1364
1402
  }
1365
1403
  )
@@ -1368,8 +1406,10 @@ function ContextSwitcher({
1368
1406
 
1369
1407
  // src/connector-picker.tsx
1370
1408
  import { useCallback as useCallback4, useEffect as useEffect6, useRef as useRef5, useState as useState7 } from "react";
1371
- import { Fragment as Fragment4, jsx as jsx7, jsxs as jsxs6 } from "react/jsx-runtime";
1409
+ import { Fragment as Fragment4, jsx as jsx8, jsxs as jsxs7 } from "react/jsx-runtime";
1372
1410
  var DEFAULT_CONNECT_ERROR = "Couldn't start the connection. Please try again.";
1411
+ var MAX_RECONNECT_REFOCUS_CHECKS = 3;
1412
+ var RECONNECT_UNCONFIRMED_ERROR = "Couldn't confirm the reconnect \u2014 the connection still reports unhealthy. Try again, or disconnect and reconnect.";
1373
1413
  var DEFAULT_DISCONNECT_ERROR = "Couldn't disconnect. Please try again.";
1374
1414
  var DEFAULT_LOAD_ERROR = "Couldn't load connections. Please try again.";
1375
1415
  var DEFAULT_GRANTS_LOAD_ERROR = "Couldn't load sharing. Please try again.";
@@ -1378,6 +1418,8 @@ var DEFAULT_REVOKE_ERROR = "Couldn't revoke access. Please try again.";
1378
1418
  var DEFAULT_ORG_DISABLED_REASON = "Org-wide connections aren't available to you.";
1379
1419
  var DEFAULT_CREDENTIAL_ERROR = "Couldn't save that credential. Please try again.";
1380
1420
  var DEFAULT_CREDENTIAL_TEST_ERROR = "Couldn't test that credential. Please try again.";
1421
+ var DEFAULT_RECONNECT_MESSAGE = "This connection needs to be reconnected to keep working.";
1422
+ var DISCONNECT_REVOKES_HINT = "Disconnecting revokes Reeve's access to this account.";
1381
1423
  var UNVERIFIABLE_CREDENTIAL_NOTE = "We can't verify this automatically \u2014 saving it is safe, but nothing has checked it yet.";
1382
1424
  var SKELETON_COUNT = 3;
1383
1425
  var UNGROUNDED_PLACEHOLDER = /\{\{[^}]*\}\}/;
@@ -1411,6 +1453,9 @@ function ownerLabel(entry) {
1411
1453
  function isSharedWithViewer(entry) {
1412
1454
  return entry.connection.status === "connected" && Boolean(entry.connection.shared_by) && !entry.connection.owned_by_viewer;
1413
1455
  }
1456
+ function isUnhealthy(entry) {
1457
+ return entry.connection.status === "connected" && entry.connection.health?.status === "unhealthy";
1458
+ }
1414
1459
  function ConnectorPicker({
1415
1460
  client,
1416
1461
  purpose,
@@ -1422,6 +1467,9 @@ function ConnectorPicker({
1422
1467
  const [entries, setEntries] = useState7(null);
1423
1468
  const [loadError, setLoadError] = useState7(null);
1424
1469
  const [uiState, setUiState] = useState7({});
1470
+ const reconnectingRef = useRef5(/* @__PURE__ */ new Set());
1471
+ const reconnectChecksRef = useRef5(/* @__PURE__ */ new Map());
1472
+ const refreshInFlightRef = useRef5(false);
1425
1473
  const grantsSupported = typeof client.listGrants === "function" && typeof client.grant === "function" && typeof client.revokeGrant === "function";
1426
1474
  const credentialsSupported = typeof client.submitCredentials === "function";
1427
1475
  const credentialTestSupported = typeof client.testCredentials === "function";
@@ -1450,20 +1498,45 @@ function ConnectorPicker({
1450
1498
  void load();
1451
1499
  }, [gated, load, purpose]);
1452
1500
  const refreshAfterReturn = useCallback4(async () => {
1453
- const list = await load();
1454
- if (!list) return;
1455
- setUiState((prev) => {
1456
- let changed = false;
1457
- const next = { ...prev };
1501
+ if (refreshInFlightRef.current) return;
1502
+ refreshInFlightRef.current = true;
1503
+ try {
1504
+ const list = await load();
1505
+ if (!list) return;
1506
+ const stillUnhealthyChecks = /* @__PURE__ */ new Map();
1458
1507
  for (const entry of list) {
1459
- if (next[entry.slug]?.kind === "connecting" && entry.connection.status === "connected") {
1460
- changed = true;
1461
- delete next[entry.slug];
1462
- onConnectedRef.current?.(entry);
1463
- }
1508
+ const stillUnhealthy = reconnectingRef.current.has(entry.slug) && entry.connection.health?.status === "unhealthy";
1509
+ if (!stillUnhealthy) continue;
1510
+ const checks = (reconnectChecksRef.current.get(entry.slug) ?? 0) + 1;
1511
+ reconnectChecksRef.current.set(entry.slug, checks);
1512
+ stillUnhealthyChecks.set(entry.slug, checks);
1464
1513
  }
1465
- return changed ? next : prev;
1466
- });
1514
+ setUiState((prev) => {
1515
+ let changed = false;
1516
+ const next = { ...prev };
1517
+ for (const entry of list) {
1518
+ if (next[entry.slug]?.kind !== "connecting" || entry.connection.status !== "connected") {
1519
+ continue;
1520
+ }
1521
+ const checks = stillUnhealthyChecks.get(entry.slug);
1522
+ if (checks !== void 0 && checks >= MAX_RECONNECT_REFOCUS_CHECKS) {
1523
+ changed = true;
1524
+ reconnectingRef.current.delete(entry.slug);
1525
+ reconnectChecksRef.current.delete(entry.slug);
1526
+ next[entry.slug] = { kind: "error", message: RECONNECT_UNCONFIRMED_ERROR };
1527
+ } else if (checks === void 0) {
1528
+ changed = true;
1529
+ delete next[entry.slug];
1530
+ reconnectingRef.current.delete(entry.slug);
1531
+ reconnectChecksRef.current.delete(entry.slug);
1532
+ onConnectedRef.current?.(entry);
1533
+ }
1534
+ }
1535
+ return changed ? next : prev;
1536
+ });
1537
+ } finally {
1538
+ refreshInFlightRef.current = false;
1539
+ }
1467
1540
  }, [load]);
1468
1541
  useEffect6(() => {
1469
1542
  if (gated) return;
@@ -1484,6 +1557,12 @@ function ConnectorPicker({
1484
1557
  }, [gated, refreshAfterReturn]);
1485
1558
  const handleConnect = useCallback4(
1486
1559
  async (entry, kind) => {
1560
+ if (isUnhealthy(entry)) {
1561
+ reconnectingRef.current.add(entry.slug);
1562
+ } else {
1563
+ reconnectingRef.current.delete(entry.slug);
1564
+ }
1565
+ reconnectChecksRef.current.delete(entry.slug);
1487
1566
  setUiState((prev) => ({ ...prev, [entry.slug]: { kind: "connecting" } }));
1488
1567
  try {
1489
1568
  const result = await clientRef.current.connect(entry, { kind });
@@ -1493,6 +1572,8 @@ function ConnectorPicker({
1493
1572
  }
1494
1573
  const list = await load();
1495
1574
  const updated = list?.find((e) => e.slug === entry.slug) ?? null;
1575
+ reconnectingRef.current.delete(entry.slug);
1576
+ reconnectChecksRef.current.delete(entry.slug);
1496
1577
  setUiState((prev) => {
1497
1578
  const next = { ...prev };
1498
1579
  delete next[entry.slug];
@@ -1502,6 +1583,8 @@ function ConnectorPicker({
1502
1583
  onConnectedRef.current?.(updated);
1503
1584
  }
1504
1585
  } catch (err) {
1586
+ reconnectingRef.current.delete(entry.slug);
1587
+ reconnectChecksRef.current.delete(entry.slug);
1505
1588
  const message = errorMessageFrom(err, DEFAULT_CONNECT_ERROR);
1506
1589
  setUiState((prev) => ({ ...prev, [entry.slug]: { kind: "error", message } }));
1507
1590
  }
@@ -1577,35 +1660,35 @@ function ConnectorPicker({
1577
1660
  );
1578
1661
  const ownEntries = entries?.filter((entry) => !isSharedWithViewer(entry)) ?? null;
1579
1662
  const sharedEntries = entries?.filter(isSharedWithViewer) ?? [];
1580
- return /* @__PURE__ */ jsxs6("div", { "data-testid": "connector-picker", "data-layout": layout, className: "flex flex-col gap-4", children: [
1581
- /* @__PURE__ */ jsxs6("div", { className: containerClassName, children: [
1582
- entries === null && !loadError && Array.from({ length: SKELETON_COUNT }).map((_, i) => /* @__PURE__ */ jsxs6(
1663
+ return /* @__PURE__ */ jsxs7("div", { "data-testid": "connector-picker", "data-layout": layout, className: "flex flex-col gap-4", children: [
1664
+ /* @__PURE__ */ jsxs7("div", { className: containerClassName, children: [
1665
+ entries === null && !loadError && Array.from({ length: SKELETON_COUNT }).map((_, i) => /* @__PURE__ */ jsxs7(
1583
1666
  "div",
1584
1667
  {
1585
1668
  "data-testid": "connector-picker-skeleton-item",
1586
1669
  "aria-hidden": "true",
1587
1670
  className: "flex items-center gap-3 rounded-lg border border-border p-3",
1588
1671
  children: [
1589
- /* @__PURE__ */ jsx7("span", { className: "h-8 w-8 shrink-0 animate-pulse rounded bg-foreground/10" }),
1590
- /* @__PURE__ */ jsx7("span", { className: "h-3 flex-1 animate-pulse rounded bg-foreground/10" })
1672
+ /* @__PURE__ */ jsx8("span", { className: "h-8 w-8 shrink-0 animate-pulse rounded bg-foreground/10" }),
1673
+ /* @__PURE__ */ jsx8("span", { className: "h-3 flex-1 animate-pulse rounded bg-foreground/10" })
1591
1674
  ]
1592
1675
  },
1593
1676
  i
1594
1677
  )),
1595
- loadError && /* @__PURE__ */ jsxs6(
1678
+ loadError && /* @__PURE__ */ jsxs7(
1596
1679
  "div",
1597
1680
  {
1598
1681
  role: "alert",
1599
1682
  "data-testid": "connector-picker-load-error",
1600
1683
  className: "flex items-center justify-between gap-3 rounded-lg border border-destructive/30 bg-destructive/5 p-3 text-sm text-destructive",
1601
1684
  children: [
1602
- /* @__PURE__ */ jsx7("span", { children: loadError }),
1603
- /* @__PURE__ */ jsx7("button", { type: "button", onClick: () => void load(), className: "shrink-0 underline", children: "Retry" })
1685
+ /* @__PURE__ */ jsx8("span", { children: loadError }),
1686
+ /* @__PURE__ */ jsx8("button", { type: "button", onClick: () => void load(), className: "shrink-0 underline", children: "Retry" })
1604
1687
  ]
1605
1688
  }
1606
1689
  ),
1607
- entries !== null && entries.length === 0 && !loadError && /* @__PURE__ */ jsx7("p", { "data-testid": "connector-picker-empty", className: "text-sm text-muted-foreground", children: "No connections available." }),
1608
- ownEntries?.map((entry) => /* @__PURE__ */ jsx7(
1690
+ entries !== null && entries.length === 0 && !loadError && /* @__PURE__ */ jsx8("p", { "data-testid": "connector-picker-empty", className: "text-sm text-muted-foreground", children: "No connections available." }),
1691
+ ownEntries?.map((entry) => /* @__PURE__ */ jsx8(
1609
1692
  ConnectorTile,
1610
1693
  {
1611
1694
  entry,
@@ -1625,9 +1708,9 @@ function ConnectorPicker({
1625
1708
  entry.slug
1626
1709
  ))
1627
1710
  ] }),
1628
- sharedEntries.length > 0 && /* @__PURE__ */ jsxs6("section", { "data-testid": "connector-picker-shared-with-me", className: "flex flex-col gap-2", children: [
1629
- /* @__PURE__ */ jsx7("h3", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: "Shared with me" }),
1630
- /* @__PURE__ */ jsx7("div", { className: containerClassName, children: sharedEntries.map((entry) => /* @__PURE__ */ jsx7(
1711
+ sharedEntries.length > 0 && /* @__PURE__ */ jsxs7("section", { "data-testid": "connector-picker-shared-with-me", className: "flex flex-col gap-2", children: [
1712
+ /* @__PURE__ */ jsx8("h3", { className: "text-xs font-medium uppercase tracking-wide text-muted-foreground", children: "Shared with me" }),
1713
+ /* @__PURE__ */ jsx8("div", { className: containerClassName, children: sharedEntries.map((entry) => /* @__PURE__ */ jsx8(
1631
1714
  ConnectorTile,
1632
1715
  {
1633
1716
  entry,
@@ -1670,6 +1753,7 @@ function ConnectorTile({
1670
1753
  const isConnecting = ui?.kind === "connecting";
1671
1754
  const isDisconnecting = ui?.kind === "disconnecting";
1672
1755
  const errorMessage = ui?.kind === "error" ? ui.message : null;
1756
+ const unhealthy = isUnhealthy(entry);
1673
1757
  const [kind, setKind] = useState7("personal");
1674
1758
  const [sharingOpen, setSharingOpen] = useState7(false);
1675
1759
  const [setupOpen, setSetupOpen] = useState7(false);
@@ -1682,7 +1766,7 @@ function ConnectorTile({
1682
1766
  const attribution = ownerLabel(entry);
1683
1767
  const canDisconnect = isConnected && !shared;
1684
1768
  const canManageSharing = isConnected && entry.connection.owned_by_viewer === true && grantsSupported;
1685
- return /* @__PURE__ */ jsxs6(
1769
+ return /* @__PURE__ */ jsxs7(
1686
1770
  "div",
1687
1771
  {
1688
1772
  "data-testid": `connector-tile-${entry.slug}`,
@@ -1690,12 +1774,12 @@ function ConnectorTile({
1690
1774
  "data-deprecated": entry.deprecated || void 0,
1691
1775
  className: cn("flex flex-col p-3", layout === "tiles" && "rounded-lg border border-border"),
1692
1776
  children: [
1693
- /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-3", children: [
1694
- /* @__PURE__ */ jsx7(BrandGlyph, { brand: { name: entry.name, logo: entry.logo }, size: "lg" }),
1695
- /* @__PURE__ */ jsxs6("div", { className: "min-w-0 flex-1", children: [
1696
- /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-2", children: [
1697
- /* @__PURE__ */ jsx7("p", { className: "truncate text-sm font-medium", children: entry.name }),
1698
- entry.deprecated && /* @__PURE__ */ jsx7(
1777
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-3", children: [
1778
+ /* @__PURE__ */ jsx8(BrandGlyph, { brand: { name: entry.name, logo: entry.logo }, size: "lg" }),
1779
+ /* @__PURE__ */ jsxs7("div", { className: "min-w-0 flex-1", children: [
1780
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-2", children: [
1781
+ /* @__PURE__ */ jsx8("p", { className: "truncate text-sm font-medium", children: entry.name }),
1782
+ entry.deprecated && /* @__PURE__ */ jsx8(
1699
1783
  "span",
1700
1784
  {
1701
1785
  "data-testid": `connector-deprecated-${entry.slug}`,
@@ -1704,14 +1788,14 @@ function ConnectorTile({
1704
1788
  }
1705
1789
  )
1706
1790
  ] }),
1707
- /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
1708
- /* @__PURE__ */ jsx7("span", { "data-testid": `connector-capability-${entry.slug}`, children: capabilityLabel(entry.capability) }),
1709
- entry.category && /* @__PURE__ */ jsxs6(Fragment4, { children: [
1710
- /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", children: "\xB7" }),
1711
- /* @__PURE__ */ jsx7("span", { className: "truncate", children: entry.category })
1791
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1.5 text-xs text-muted-foreground", children: [
1792
+ /* @__PURE__ */ jsx8("span", { "data-testid": `connector-capability-${entry.slug}`, children: capabilityLabel(entry.capability) }),
1793
+ entry.category && /* @__PURE__ */ jsxs7(Fragment4, { children: [
1794
+ /* @__PURE__ */ jsx8("span", { "aria-hidden": "true", children: "\xB7" }),
1795
+ /* @__PURE__ */ jsx8("span", { className: "truncate", children: entry.category })
1712
1796
  ] })
1713
1797
  ] }),
1714
- isConnected && /* @__PURE__ */ jsx7(
1798
+ isConnected && /* @__PURE__ */ jsx8(
1715
1799
  "p",
1716
1800
  {
1717
1801
  "data-testid": `connector-connected-since-${entry.slug}`,
@@ -1719,7 +1803,35 @@ function ConnectorTile({
1719
1803
  children: entry.connection.since ? `Connected since ${formatSince(entry.connection.since)}` : "Connected"
1720
1804
  }
1721
1805
  ),
1722
- attribution && /* @__PURE__ */ jsx7(
1806
+ isConnected && !shared && entry.connection.account_label && /* @__PURE__ */ jsxs7(
1807
+ "p",
1808
+ {
1809
+ "data-testid": `connector-account-${entry.slug}`,
1810
+ className: "text-xs text-muted-foreground",
1811
+ children: [
1812
+ "Connected as ",
1813
+ entry.connection.account_label
1814
+ ]
1815
+ }
1816
+ ),
1817
+ isConnected && entry.access_summary && /* @__PURE__ */ jsx8(
1818
+ "p",
1819
+ {
1820
+ "data-testid": `connector-access-summary-${entry.slug}`,
1821
+ className: "text-xs text-muted-foreground",
1822
+ children: entry.access_summary
1823
+ }
1824
+ ),
1825
+ unhealthy && /* @__PURE__ */ jsx8(
1826
+ "p",
1827
+ {
1828
+ role: "alert",
1829
+ "data-testid": `connector-unhealthy-${entry.slug}`,
1830
+ className: "text-xs font-medium text-destructive",
1831
+ children: DEFAULT_RECONNECT_MESSAGE
1832
+ }
1833
+ ),
1834
+ attribution && /* @__PURE__ */ jsx8(
1723
1835
  "p",
1724
1836
  {
1725
1837
  "data-testid": `connector-owner-${entry.slug}`,
@@ -1727,7 +1839,7 @@ function ConnectorTile({
1727
1839
  children: attribution
1728
1840
  }
1729
1841
  ),
1730
- !isConnected && /* @__PURE__ */ jsxs6(
1842
+ !isConnected && /* @__PURE__ */ jsxs7(
1731
1843
  "div",
1732
1844
  {
1733
1845
  "data-testid": `connector-kind-toggle-${entry.slug}`,
@@ -1735,7 +1847,7 @@ function ConnectorTile({
1735
1847
  "aria-label": "Connect as",
1736
1848
  className: "mt-1 flex items-center gap-1",
1737
1849
  children: [
1738
- /* @__PURE__ */ jsx7(
1850
+ /* @__PURE__ */ jsx8(
1739
1851
  "button",
1740
1852
  {
1741
1853
  type: "button",
@@ -1751,7 +1863,7 @@ function ConnectorTile({
1751
1863
  children: "Personal"
1752
1864
  }
1753
1865
  ),
1754
- /* @__PURE__ */ jsxs6(
1866
+ /* @__PURE__ */ jsxs7(
1755
1867
  "button",
1756
1868
  {
1757
1869
  type: "button",
@@ -1767,7 +1879,7 @@ function ConnectorTile({
1767
1879
  ),
1768
1880
  children: [
1769
1881
  "Org",
1770
- !orgPermitted && /* @__PURE__ */ jsxs6("span", { className: "sr-only", children: [
1882
+ !orgPermitted && /* @__PURE__ */ jsxs7("span", { className: "sr-only", children: [
1771
1883
  " (",
1772
1884
  orgDisabledReason,
1773
1885
  ")"
@@ -1778,21 +1890,50 @@ function ConnectorTile({
1778
1890
  ]
1779
1891
  }
1780
1892
  ),
1781
- errorMessage && /* @__PURE__ */ jsx7("p", { role: "alert", "data-testid": `connector-error-${entry.slug}`, className: "text-xs text-destructive", children: errorMessage })
1893
+ errorMessage && /* @__PURE__ */ jsx8("p", { role: "alert", "data-testid": `connector-error-${entry.slug}`, className: "text-xs text-destructive", children: errorMessage })
1782
1894
  ] }),
1783
- isConnected ? /* @__PURE__ */ jsxs6("div", { className: "flex shrink-0 flex-col items-end gap-1", children: [
1784
- canDisconnect && /* @__PURE__ */ jsx7(
1895
+ isConnected ? /* @__PURE__ */ jsxs7("div", { className: "flex shrink-0 flex-col items-end gap-1", children: [
1896
+ unhealthy && !shared && /* @__PURE__ */ jsx8(
1897
+ "button",
1898
+ {
1899
+ type: "button",
1900
+ "data-testid": `connector-reconnect-${entry.slug}`,
1901
+ onClick: () => onConnect(entry, entry.connection.kind ?? "personal"),
1902
+ disabled: isConnecting || isDisconnecting,
1903
+ className: "shrink-0 rounded-md bg-primary px-2.5 py-1 text-xs font-medium text-primary-foreground disabled:opacity-50",
1904
+ children: isConnecting ? "Reconnecting\u2026" : "Reconnect"
1905
+ }
1906
+ ),
1907
+ canDisconnect && /* @__PURE__ */ jsx8(
1785
1908
  "button",
1786
1909
  {
1787
1910
  type: "button",
1788
1911
  "data-testid": `connector-disconnect-${entry.slug}`,
1912
+ title: DISCONNECT_REVOKES_HINT,
1789
1913
  onClick: () => onDisconnect(entry),
1790
- disabled: isDisconnecting,
1914
+ disabled: isDisconnecting || isConnecting,
1791
1915
  className: "shrink-0 rounded-md px-2.5 py-1 text-xs font-medium text-destructive hover:bg-destructive/10 disabled:opacity-50",
1792
1916
  children: isDisconnecting ? "Disconnecting\u2026" : "Disconnect"
1793
1917
  }
1794
1918
  ),
1795
- canManageSharing && /* @__PURE__ */ jsx7(
1919
+ canDisconnect && // Outcome-eval finding (DEV-7873): with no width cap, this
1920
+ // paragraph's one long sentence forced the WHOLE shrink-0
1921
+ // button column to grow to its natural (unwrapped) width,
1922
+ // squeezing the sibling `min-w-0 flex-1` text column down to
1923
+ // one word per line at any realistic tile width. RTL's jsdom
1924
+ // tests never caught it — jsdom doesn't lay out real flexbox
1925
+ // sizing, so every textContent assertion still passed. A
1926
+ // narrow max-width forces the hint to wrap within the same
1927
+ // footprint as the button above it instead.
1928
+ /* @__PURE__ */ jsx8(
1929
+ "p",
1930
+ {
1931
+ "data-testid": `connector-disconnect-hint-${entry.slug}`,
1932
+ className: "max-w-28 text-right text-[11px] text-muted-foreground",
1933
+ children: DISCONNECT_REVOKES_HINT
1934
+ }
1935
+ ),
1936
+ canManageSharing && /* @__PURE__ */ jsx8(
1796
1937
  "button",
1797
1938
  {
1798
1939
  type: "button",
@@ -1803,8 +1944,8 @@ function ConnectorTile({
1803
1944
  children: sharingOpen ? "Hide sharing" : "Manage sharing"
1804
1945
  }
1805
1946
  )
1806
- ] }) : /* @__PURE__ */ jsxs6("div", { className: "flex shrink-0 flex-col items-end gap-1", children: [
1807
- /* @__PURE__ */ jsx7(
1947
+ ] }) : /* @__PURE__ */ jsxs7("div", { className: "flex shrink-0 flex-col items-end gap-1", children: [
1948
+ /* @__PURE__ */ jsx8(
1808
1949
  "button",
1809
1950
  {
1810
1951
  type: "button",
@@ -1815,7 +1956,7 @@ function ConnectorTile({
1815
1956
  children: isConnecting ? "Connecting\u2026" : "Connect"
1816
1957
  }
1817
1958
  ),
1818
- canSetUp && /* @__PURE__ */ jsx7(
1959
+ canSetUp && /* @__PURE__ */ jsx8(
1819
1960
  "button",
1820
1961
  {
1821
1962
  type: "button",
@@ -1829,15 +1970,15 @@ function ConnectorTile({
1829
1970
  )
1830
1971
  ] })
1831
1972
  ] }),
1832
- canSetUp && setupOpen && /* @__PURE__ */ jsxs6(
1973
+ canSetUp && setupOpen && /* @__PURE__ */ jsxs7(
1833
1974
  "div",
1834
1975
  {
1835
1976
  id: `connector-setup-panel-${entry.slug}`,
1836
1977
  "data-testid": `connector-setup-panel-${entry.slug}`,
1837
1978
  className: "mt-2 flex flex-col gap-3 rounded-md border border-border bg-foreground/5 p-2",
1838
1979
  children: [
1839
- guide && /* @__PURE__ */ jsx7(SetupGuidePanel, { entry, guide, showVerify: !pasteSupported }),
1840
- pasteSupported && /* @__PURE__ */ jsx7(
1980
+ guide && /* @__PURE__ */ jsx8(SetupGuidePanel, { entry, guide, showVerify: !pasteSupported }),
1981
+ pasteSupported && /* @__PURE__ */ jsx8(
1841
1982
  CredentialForm,
1842
1983
  {
1843
1984
  entry,
@@ -1852,7 +1993,7 @@ function ConnectorTile({
1852
1993
  ]
1853
1994
  }
1854
1995
  ),
1855
- canManageSharing && sharingOpen && /* @__PURE__ */ jsx7(
1996
+ canManageSharing && sharingOpen && /* @__PURE__ */ jsx8(
1856
1997
  ManageSharing,
1857
1998
  {
1858
1999
  entry,
@@ -1902,8 +2043,8 @@ function CopyableValue({ value, testId }) {
1902
2043
  setCopied(false);
1903
2044
  }
1904
2045
  }, [value]);
1905
- return /* @__PURE__ */ jsxs6("span", { className: "mt-1 flex items-center gap-1.5", children: [
1906
- /* @__PURE__ */ jsx7(
2046
+ return /* @__PURE__ */ jsxs7("span", { className: "mt-1 flex items-center gap-1.5", children: [
2047
+ /* @__PURE__ */ jsx8(
1907
2048
  "code",
1908
2049
  {
1909
2050
  "data-testid": `${testId}-value`,
@@ -1911,7 +2052,7 @@ function CopyableValue({ value, testId }) {
1911
2052
  children: value
1912
2053
  }
1913
2054
  ),
1914
- /* @__PURE__ */ jsx7(
2055
+ /* @__PURE__ */ jsx8(
1915
2056
  "button",
1916
2057
  {
1917
2058
  type: "button",
@@ -1937,8 +2078,8 @@ function SetupGuidePanel({
1937
2078
  ungrounded
1938
2079
  );
1939
2080
  }, [entry.slug, guide, leaked]);
1940
- return /* @__PURE__ */ jsxs6("div", { "data-testid": `connector-guide-${entry.slug}`, className: "flex flex-col gap-2", children: [
1941
- leaked && isDevEnvironment() && /* @__PURE__ */ jsxs6(
2081
+ return /* @__PURE__ */ jsxs7("div", { "data-testid": `connector-guide-${entry.slug}`, className: "flex flex-col gap-2", children: [
2082
+ leaked && isDevEnvironment() && /* @__PURE__ */ jsxs7(
1942
2083
  "p",
1943
2084
  {
1944
2085
  role: "alert",
@@ -1950,25 +2091,25 @@ function SetupGuidePanel({
1950
2091
  ]
1951
2092
  }
1952
2093
  ),
1953
- prerequisites.length > 0 && /* @__PURE__ */ jsxs6("div", { children: [
1954
- /* @__PURE__ */ jsx7("h4", { className: "text-xs font-medium", children: "Before you start" }),
1955
- /* @__PURE__ */ jsx7(
2094
+ prerequisites.length > 0 && /* @__PURE__ */ jsxs7("div", { children: [
2095
+ /* @__PURE__ */ jsx8("h4", { className: "text-xs font-medium", children: "Before you start" }),
2096
+ /* @__PURE__ */ jsx8(
1956
2097
  "ul",
1957
2098
  {
1958
2099
  "data-testid": `connector-guide-prerequisites-${entry.slug}`,
1959
2100
  className: "mt-1 list-disc pl-4 text-xs text-muted-foreground",
1960
- children: prerequisites.map((item) => /* @__PURE__ */ jsx7("li", { children: item }, item))
2101
+ children: prerequisites.map((item) => /* @__PURE__ */ jsx8("li", { children: item }, item))
1961
2102
  }
1962
2103
  )
1963
2104
  ] }),
1964
- steps.length > 0 && /* @__PURE__ */ jsx7(
2105
+ steps.length > 0 && /* @__PURE__ */ jsx8(
1965
2106
  "ol",
1966
2107
  {
1967
2108
  "data-testid": `connector-guide-steps-${entry.slug}`,
1968
2109
  className: "list-decimal pl-4 text-xs",
1969
- children: steps.map((step, index) => /* @__PURE__ */ jsxs6("li", { className: "mt-1 first:mt-0", children: [
1970
- /* @__PURE__ */ jsx7("span", { children: step.text }),
1971
- step.copyable && /* @__PURE__ */ jsx7(
2110
+ children: steps.map((step, index) => /* @__PURE__ */ jsxs7("li", { className: "mt-1 first:mt-0", children: [
2111
+ /* @__PURE__ */ jsx8("span", { children: step.text }),
2112
+ step.copyable && /* @__PURE__ */ jsx8(
1972
2113
  CopyableValue,
1973
2114
  {
1974
2115
  value: step.copyable,
@@ -1978,7 +2119,7 @@ function SetupGuidePanel({
1978
2119
  ] }, step.text))
1979
2120
  }
1980
2121
  ),
1981
- scopeNote && /* @__PURE__ */ jsx7(
2122
+ scopeNote && /* @__PURE__ */ jsx8(
1982
2123
  "p",
1983
2124
  {
1984
2125
  "data-testid": `connector-guide-scope-note-${entry.slug}`,
@@ -1986,7 +2127,7 @@ function SetupGuidePanel({
1986
2127
  children: scopeNote
1987
2128
  }
1988
2129
  ),
1989
- showVerify && verify && /* @__PURE__ */ jsx7(
2130
+ showVerify && verify && /* @__PURE__ */ jsx8(
1990
2131
  "p",
1991
2132
  {
1992
2133
  "data-testid": `connector-guide-verify-${entry.slug}`,
@@ -2050,7 +2191,7 @@ function CredentialForm({
2050
2191
  setBusy(false);
2051
2192
  }
2052
2193
  }, [kind, onSubmitCredentials, values]);
2053
- return /* @__PURE__ */ jsxs6(
2194
+ return /* @__PURE__ */ jsxs7(
2054
2195
  "form",
2055
2196
  {
2056
2197
  "data-testid": `connector-credential-form-${entry.slug}`,
@@ -2064,12 +2205,12 @@ function CredentialForm({
2064
2205
  fields.map((field) => {
2065
2206
  const inputId = `connector-credential-${entry.slug}-${field.key}`;
2066
2207
  const fieldError = fieldErrors?.[field.key] ?? null;
2067
- return /* @__PURE__ */ jsxs6("div", { className: "flex flex-col gap-1", children: [
2068
- /* @__PURE__ */ jsxs6("label", { htmlFor: inputId, className: "text-xs font-medium", children: [
2208
+ return /* @__PURE__ */ jsxs7("div", { className: "flex flex-col gap-1", children: [
2209
+ /* @__PURE__ */ jsxs7("label", { htmlFor: inputId, className: "text-xs font-medium", children: [
2069
2210
  field.label,
2070
- field.required !== false && /* @__PURE__ */ jsx7("span", { "aria-hidden": "true", className: "ml-0.5 text-destructive", children: "*" })
2211
+ field.required !== false && /* @__PURE__ */ jsx8("span", { "aria-hidden": "true", className: "ml-0.5 text-destructive", children: "*" })
2071
2212
  ] }),
2072
- /* @__PURE__ */ jsx7(
2213
+ /* @__PURE__ */ jsx8(
2073
2214
  "input",
2074
2215
  {
2075
2216
  id: inputId,
@@ -2089,7 +2230,7 @@ function CredentialForm({
2089
2230
  )
2090
2231
  }
2091
2232
  ),
2092
- fieldError && /* @__PURE__ */ jsx7(
2233
+ fieldError && /* @__PURE__ */ jsx8(
2093
2234
  "p",
2094
2235
  {
2095
2236
  id: `${inputId}-error`,
@@ -2100,7 +2241,7 @@ function CredentialForm({
2100
2241
  )
2101
2242
  ] }, field.key);
2102
2243
  }),
2103
- verify && /* @__PURE__ */ jsx7(
2244
+ verify && /* @__PURE__ */ jsx8(
2104
2245
  "p",
2105
2246
  {
2106
2247
  "data-testid": `connector-guide-verify-${entry.slug}`,
@@ -2108,8 +2249,8 @@ function CredentialForm({
2108
2249
  children: verify
2109
2250
  }
2110
2251
  ),
2111
- result && /* @__PURE__ */ jsx7(CredentialTestResult, { entry, result }),
2112
- error && /* @__PURE__ */ jsx7(
2252
+ result && /* @__PURE__ */ jsx8(CredentialTestResult, { entry, result }),
2253
+ error && /* @__PURE__ */ jsx8(
2113
2254
  "p",
2114
2255
  {
2115
2256
  role: "alert",
@@ -2118,8 +2259,8 @@ function CredentialForm({
2118
2259
  children: error
2119
2260
  }
2120
2261
  ),
2121
- /* @__PURE__ */ jsxs6("div", { className: "flex items-center justify-end gap-1.5", children: [
2122
- testSupported && /* @__PURE__ */ jsx7(
2262
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center justify-end gap-1.5", children: [
2263
+ testSupported && /* @__PURE__ */ jsx8(
2123
2264
  "button",
2124
2265
  {
2125
2266
  type: "button",
@@ -2130,7 +2271,7 @@ function CredentialForm({
2130
2271
  children: testing ? "Testing\u2026" : "Test connection"
2131
2272
  }
2132
2273
  ),
2133
- /* @__PURE__ */ jsx7(
2274
+ /* @__PURE__ */ jsx8(
2134
2275
  "button",
2135
2276
  {
2136
2277
  type: "submit",
@@ -2151,15 +2292,15 @@ function CredentialTestResult({
2151
2292
  result
2152
2293
  }) {
2153
2294
  if (result.valid === true) {
2154
- return /* @__PURE__ */ jsxs6(
2295
+ return /* @__PURE__ */ jsxs7(
2155
2296
  "div",
2156
2297
  {
2157
2298
  role: "status",
2158
2299
  "data-testid": `connector-credential-test-pass-${entry.slug}`,
2159
2300
  className: "rounded-md border border-primary/30 bg-primary/5 px-2 py-1 text-xs",
2160
2301
  children: [
2161
- /* @__PURE__ */ jsx7("p", { children: result.account_name ? `Verified \u2014 connected as ${result.account_name}.` : "Verified \u2014 these credentials work." }),
2162
- result.permissions_note && /* @__PURE__ */ jsx7(
2302
+ /* @__PURE__ */ jsx8("p", { children: result.account_name ? `Verified \u2014 connected as ${result.account_name}.` : "Verified \u2014 these credentials work." }),
2303
+ result.permissions_note && /* @__PURE__ */ jsx8(
2163
2304
  "p",
2164
2305
  {
2165
2306
  "data-testid": `connector-credential-permissions-${entry.slug}`,
@@ -2172,7 +2313,7 @@ function CredentialTestResult({
2172
2313
  );
2173
2314
  }
2174
2315
  if (result.valid === false) {
2175
- return /* @__PURE__ */ jsx7(
2316
+ return /* @__PURE__ */ jsx8(
2176
2317
  "p",
2177
2318
  {
2178
2319
  role: "alert",
@@ -2182,7 +2323,7 @@ function CredentialTestResult({
2182
2323
  }
2183
2324
  );
2184
2325
  }
2185
- return /* @__PURE__ */ jsx7(
2326
+ return /* @__PURE__ */ jsx8(
2186
2327
  "p",
2187
2328
  {
2188
2329
  role: "status",
@@ -2245,13 +2386,13 @@ function ManageSharing({
2245
2386
  },
2246
2387
  [load, revokeGrant]
2247
2388
  );
2248
- return /* @__PURE__ */ jsxs6(
2389
+ return /* @__PURE__ */ jsxs7(
2249
2390
  "div",
2250
2391
  {
2251
2392
  "data-testid": `connector-sharing-panel-${entry.slug}`,
2252
2393
  className: "mt-2 flex flex-col gap-2 rounded-md border border-border bg-foreground/5 p-2",
2253
2394
  children: [
2254
- grants === null && !error && /* @__PURE__ */ jsx7(
2395
+ grants === null && !error && /* @__PURE__ */ jsx8(
2255
2396
  "p",
2256
2397
  {
2257
2398
  "data-testid": `connector-grants-loading-${entry.slug}`,
@@ -2259,7 +2400,7 @@ function ManageSharing({
2259
2400
  children: "Loading sharing\u2026"
2260
2401
  }
2261
2402
  ),
2262
- error && /* @__PURE__ */ jsx7(
2403
+ error && /* @__PURE__ */ jsx8(
2263
2404
  "p",
2264
2405
  {
2265
2406
  role: "alert",
@@ -2268,7 +2409,7 @@ function ManageSharing({
2268
2409
  children: error
2269
2410
  }
2270
2411
  ),
2271
- grants !== null && grants.length === 0 && /* @__PURE__ */ jsx7(
2412
+ grants !== null && grants.length === 0 && /* @__PURE__ */ jsx8(
2272
2413
  "p",
2273
2414
  {
2274
2415
  "data-testid": `connector-grants-empty-${entry.slug}`,
@@ -2276,21 +2417,21 @@ function ManageSharing({
2276
2417
  children: "Not shared with anyone yet."
2277
2418
  }
2278
2419
  ),
2279
- grants?.map((grant) => /* @__PURE__ */ jsxs6(
2420
+ grants?.map((grant) => /* @__PURE__ */ jsxs7(
2280
2421
  "div",
2281
2422
  {
2282
2423
  "data-testid": `connector-grant-${entry.slug}-${grant.id}`,
2283
2424
  className: "flex items-center justify-between gap-2 text-xs",
2284
2425
  children: [
2285
- /* @__PURE__ */ jsxs6("span", { className: "truncate", children: [
2426
+ /* @__PURE__ */ jsxs7("span", { className: "truncate", children: [
2286
2427
  grant.grantee_name || grant.grantee_id,
2287
- /* @__PURE__ */ jsxs6("span", { className: "text-muted-foreground", children: [
2428
+ /* @__PURE__ */ jsxs7("span", { className: "text-muted-foreground", children: [
2288
2429
  " ",
2289
2430
  "\xB7 ",
2290
2431
  grant.grantee_type === "role" ? "Role" : "User"
2291
2432
  ] })
2292
2433
  ] }),
2293
- /* @__PURE__ */ jsx7(
2434
+ /* @__PURE__ */ jsx8(
2294
2435
  "button",
2295
2436
  {
2296
2437
  type: "button",
@@ -2305,8 +2446,8 @@ function ManageSharing({
2305
2446
  },
2306
2447
  grant.id
2307
2448
  )),
2308
- /* @__PURE__ */ jsxs6("div", { className: "flex items-center gap-1.5", children: [
2309
- /* @__PURE__ */ jsxs6(
2449
+ /* @__PURE__ */ jsxs7("div", { className: "flex items-center gap-1.5", children: [
2450
+ /* @__PURE__ */ jsxs7(
2310
2451
  "select",
2311
2452
  {
2312
2453
  "data-testid": `connector-grant-type-${entry.slug}`,
@@ -2319,12 +2460,12 @@ function ManageSharing({
2319
2460
  disabled: busy,
2320
2461
  className: "rounded-md border border-border bg-transparent px-1.5 py-1 text-xs disabled:opacity-50",
2321
2462
  children: [
2322
- /* @__PURE__ */ jsx7("option", { value: "user", children: "User" }),
2323
- /* @__PURE__ */ jsx7("option", { value: "role", children: "Role" })
2463
+ /* @__PURE__ */ jsx8("option", { value: "user", children: "User" }),
2464
+ /* @__PURE__ */ jsx8("option", { value: "role", children: "Role" })
2324
2465
  ]
2325
2466
  }
2326
2467
  ),
2327
- granteeType === "user" ? /* @__PURE__ */ jsx7(
2468
+ granteeType === "user" ? /* @__PURE__ */ jsx8(
2328
2469
  "input",
2329
2470
  {
2330
2471
  "data-testid": `connector-grant-grantee-${entry.slug}`,
@@ -2335,7 +2476,7 @@ function ManageSharing({
2335
2476
  disabled: busy,
2336
2477
  className: "min-w-0 flex-1 rounded-md border border-border bg-transparent px-1.5 py-1 text-xs disabled:opacity-50"
2337
2478
  }
2338
- ) : /* @__PURE__ */ jsxs6(
2479
+ ) : /* @__PURE__ */ jsxs7(
2339
2480
  "select",
2340
2481
  {
2341
2482
  "data-testid": `connector-grant-role-${entry.slug}`,
@@ -2345,12 +2486,12 @@ function ManageSharing({
2345
2486
  disabled: busy,
2346
2487
  className: "min-w-0 flex-1 rounded-md border border-border bg-transparent px-1.5 py-1 text-xs disabled:opacity-50",
2347
2488
  children: [
2348
- /* @__PURE__ */ jsx7("option", { value: "", children: "Select a role\u2026" }),
2349
- roleOptions.map((role) => /* @__PURE__ */ jsx7("option", { value: role.id, children: role.name }, role.id))
2489
+ /* @__PURE__ */ jsx8("option", { value: "", children: "Select a role\u2026" }),
2490
+ roleOptions.map((role) => /* @__PURE__ */ jsx8("option", { value: role.id, children: role.name }, role.id))
2350
2491
  ]
2351
2492
  }
2352
2493
  ),
2353
- /* @__PURE__ */ jsx7(
2494
+ /* @__PURE__ */ jsx8(
2354
2495
  "button",
2355
2496
  {
2356
2497
  type: "button",
@@ -2373,6 +2514,7 @@ export {
2373
2514
  ContextSwitcher,
2374
2515
  Flyout,
2375
2516
  GLYPH_CANVAS_FILL,
2517
+ InfoTip,
2376
2518
  LOCKUP_GAP,
2377
2519
  LOCKUP_ROW,
2378
2520
  MARK_CAP_RATIO,