sql-preview 0.6.4 → 0.6.6

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/mcp-app.html CHANGED
@@ -12677,7 +12677,15 @@ const useAppStore = create((set, get) => ({
12677
12677
  }),
12678
12678
  setActiveTab: (id) => set({ activeTabId: id }),
12679
12679
  updateTab: (id, updates) => set((state) => ({
12680
- tabs: state.tabs.map((tab) => tab.id === id ? { ...tab, ...updates } : tab)
12680
+ tabs: state.tabs.map((tab) => {
12681
+ if (tab.id !== id) return tab;
12682
+ const next = { ...tab, ...updates };
12683
+ if (updates.isLoading === true && !tab.isLoading) {
12684
+ next.loadingStartedAt = Date.now();
12685
+ next.cancelled = false;
12686
+ }
12687
+ return next;
12688
+ })
12681
12689
  })),
12682
12690
  getActiveTab: () => {
12683
12691
  const { tabs, activeTabId } = get();
@@ -74083,6 +74091,16 @@ const DataGrid = reactExports.forwardRef(function DataGrid2({
74083
74091
  },
74084
74092
  [onCellDoubleClick]
74085
74093
  );
74094
+ const onCellKeyDown = reactExports.useCallback(
74095
+ (e2) => {
74096
+ const keyboardEvent = e2.event;
74097
+ if (!keyboardEvent || keyboardEvent.key !== "Enter" || e2.column.getColId() === "_gutter" || !onCellDoubleClick) {
74098
+ return;
74099
+ }
74100
+ onCellDoubleClick(e2.colDef.headerName ?? e2.column.getColId(), e2.value);
74101
+ },
74102
+ [onCellDoubleClick]
74103
+ );
74086
74104
  if (!data || data.rows.length === 0) return null;
74087
74105
  const { row: rowHeight, header: headerHeight } = DENSITY_HEIGHTS[density];
74088
74106
  const resolvedTheme = nativeTheme ? agThemeUniversal : "legacy";
@@ -74156,7 +74174,8 @@ const DataGrid = reactExports.forwardRef(function DataGrid2({
74156
74174
  onCellMouseDown,
74157
74175
  onCellMouseOver,
74158
74176
  onCellClicked,
74159
- onCellDoubleClicked
74177
+ onCellDoubleClicked,
74178
+ onCellKeyDown
74160
74179
  }
74161
74180
  )
74162
74181
  }
@@ -74342,7 +74361,7 @@ const DynamicForm = ({
74342
74361
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-form-fields", children: [
74343
74362
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: fieldClass("name", "sp-conn-form-group"), children: [
74344
74363
  /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "sp-conn-form-label", children: [
74345
- "Connection Name ",
74364
+ "Connection name ",
74346
74365
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "required", children: "*" })
74347
74366
  ] }),
74348
74367
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -74393,7 +74412,7 @@ const DynamicForm = ({
74393
74412
  onClick: handleTest,
74394
74413
  disabled: isSubmitting,
74395
74414
  "aria-label": "Test connection",
74396
- children: "Test Connection"
74415
+ children: "Test connection"
74397
74416
  }
74398
74417
  ),
74399
74418
  submitFeedback && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-submit-feedback", role: "status", children: submitFeedback }),
@@ -74404,12 +74423,165 @@ const DynamicForm = ({
74404
74423
  className: "sp-btn sp-btn-primary",
74405
74424
  disabled: isSubmitting,
74406
74425
  "aria-label": "Save connection",
74407
- children: isSubmitting ? "Saving…" : submitFeedback ? "Saved" : "Save Connection"
74426
+ children: isSubmitting ? "Saving…" : submitFeedback ? "Saved" : "Save connection"
74408
74427
  }
74409
74428
  )
74410
74429
  ] })
74411
74430
  ] });
74412
74431
  };
74432
+ function ConfirmDialog({
74433
+ open,
74434
+ title,
74435
+ message,
74436
+ confirmLabel = "Confirm",
74437
+ onConfirm,
74438
+ onCancel
74439
+ }) {
74440
+ const dialogRef = reactExports.useRef(null);
74441
+ reactExports.useEffect(() => {
74442
+ const dialog = dialogRef.current;
74443
+ if (!dialog) return;
74444
+ if (open && !dialog.open) {
74445
+ dialog.showModal();
74446
+ } else if (!open && dialog.open) {
74447
+ dialog.close();
74448
+ }
74449
+ }, [open]);
74450
+ if (!open) return null;
74451
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
74452
+ "dialog",
74453
+ {
74454
+ ref: dialogRef,
74455
+ className: "sp-confirm-dialog",
74456
+ "aria-labelledby": "sp-confirm-dialog-title",
74457
+ onCancel: (e2) => {
74458
+ e2.preventDefault();
74459
+ onCancel();
74460
+ },
74461
+ children: [
74462
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { id: "sp-confirm-dialog-title", className: "sp-confirm-dialog-title", children: title }),
74463
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "sp-confirm-dialog-message", children: message }),
74464
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-confirm-dialog-actions", children: [
74465
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "sp-btn", onClick: onCancel, autoFocus: true, children: "Cancel" }),
74466
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "sp-btn sp-btn-danger", onClick: onConfirm, children: confirmLabel })
74467
+ ] })
74468
+ ]
74469
+ }
74470
+ );
74471
+ }
74472
+ const GLYPHS = {
74473
+ // Simple Icons (CC0)
74474
+ duckdb: {
74475
+ viewBox: "0 0 24 24",
74476
+ d: "M12 0C5.363 0 0 5.363 0 12s5.363 12 12 12 12-5.363 12-12S18.637 0 12 0zM9.502 7.03a4.974 4.974 0 0 1 4.97 4.97 4.974 4.974 0 0 1-4.97 4.97A4.974 4.974 0 0 1 4.532 12a4.974 4.974 0 0 1 4.97-4.97zm6.563 3.183h2.351c.98 0 1.787.782 1.787 1.762s-.807 1.789-1.787 1.789h-2.351v-3.551z",
74477
+ label: "DuckDB"
74478
+ },
74479
+ // Simple Icons (CC0)
74480
+ trino: {
74481
+ viewBox: "0 0 24 24",
74482
+ d: "M14.124 16.8529a.1615.1615 0 1 1 .1576.1614.1577.1577 0 0 1-.1576-.1614zm-5.607-.1576a.1614.1614 0 1 0 0 .3228.1614.1614 0 0 0 0-.3228zm10.1341-.6648v1.9869c-.031.5788-.524 1.0237-1.1029.9954h-.3843a5.0596 5.0596 0 0 1-1.1298 1.7178.3192.3192 0 0 0 0 .465l.2382.2191a.3036.3036 0 0 1 .0385.4304c-1.126 1.3835-2.9669 2.1521-5.0498 2.1521a6.575 6.575 0 0 1-4.8192-1.8985c-.0029-.0032-.0059-.0063-.0087-.0096a.6302.6302 0 0 1 .0548-.8896c.137-.1265.1371-.3462 0-.4727a4.944 4.944 0 0 1-1.126-1.714h-.3497c-.5797.0284-1.0737-.416-1.1068-.9954v-1.9869c.0351-.5779.5286-1.02 1.1068-.9915h.2728a5.7648 5.7648 0 0 1 2.0791-3.0936c-.4227-1.0991-1.1529-3.2551-1.226-5.0075C6.0229 4.4705 6.2189.078 7.8253.001c1.6064-.0768 1.3719 4.0275 1.0991 6.6946a32.732 32.732 0 0 0-.123 4.4503 6.994 6.994 0 0 1 2.4826-.4304 7.2414 7.2414 0 0 1 1.7371.2075c.2614-1.2682.8762-3.574 2.0292-5.1958 1.6717-2.352 3.4357-4.7808 4.6116-4.1006 1.176.6802-.3074 3.1398-1.3297 4.4272-1.0222 1.2874-2.7862 3.2089-3.3742 4.2274-.2114.3843-.4304.8032-.5956 1.1529a5.7375 5.7375 0 0 1 2.9169 3.6125h.073v-2.3058a.3075.3075 0 0 0-.1806-.2844.9148.9148 0 0 1-.5573-.8148 1.0184 1.0184 0 0 1 .9045-.9044c.5593-.0598 1.061.3452 1.1208.9044a.9187.9187 0 0 1-.5534.8148.3074.3074 0 0 0-.1691.2844v2.1522a.3113.3113 0 0 0 .1691.2805.9724.9724 0 0 1 .5648.857zm-1.0222-3.9737a.4345.4345 0 0 0 .4612-.4151.4151.4151 0 1 0-.4612.4151zm-.4227 3.4779c.0978.4794.148.9672.1498 1.4565v.3651h.4113a.3228.3228 0 0 0 .3228-.319v-1.0069c-.0111-.2967-.2733-.5256-.5688-.4957h-.3151zm-3.7278-4.481.611.2383a36.6046 36.6046 0 0 1 2.3828-3.8661c1.2874-1.7255 2.3365-3.5817 1.8715-3.8699-.465-.2883-1.6179 1.2297-2.7708 3.109a34.8978 34.8978 0 0 0-2.0945 4.3887zm-4.0544.6726.0154 1.3335c-.0039.2007.1881.3587.3843.3152a6.4317 6.4317 0 0 1 1.4565-.1653 5.995 5.995 0 0 1 1.4527.1729c.1956.0398.3853-.1153.3843-.3151v-1.3412a.319.319 0 0 0-.2421-.3113 6.664 6.664 0 0 0-1.6026-.1845 6.7093 6.7093 0 0 0-1.6025.1845.3188.3188 0 0 0-.246.3113zm1.7063 6.8637v.3843a.6878.6878 0 0 1-.4996.269c-.3074 0-.538-.4189-.538-.4189a.073.073 0 0 0-.1-.0307l-.0024.0013a.0693.0693 0 0 0-.0245.0947c.0115.0231.2806.4957.6649.4957a.7144.7144 0 0 0 .3843-.1268.3267.3267 0 0 1 .3612 0 .8332.8332 0 0 0 .4727.1345.957.957 0 0 0 .6572-.4803.0692.0692 0 0 0-.0269-.0961.0692.0692 0 0 0-.0999.0269c0 .0231-.2191.3843-.5419.4074a.8036.8036 0 0 1-.5765-.269v-.3843a.3154.3154 0 0 1 .1268-.2537c.196-.1499.415-.3958.415-.4919a.538.538 0 0 0-.5764-.4189c-.3766 0-.6533.2498-.6533.4573 0 .1345.2536.3382.4227.4612a.3226.3226 0 0 1 .1346.2383zM7.783 11.6455l.5765-.3074c-.0192-1.126-.0346-3.1436 0-4.5425.0538-2.0368.1537-4.5732-.5226-4.5463S6.6877 4.2285 6.949 7.007a33.0562 33.0562 0 0 0 .834 4.6385zm-3.305 5.3919a.319.319 0 0 0 .319.319h.3997a3.046 3.046 0 0 1 0-.3651 7.546 7.546 0 0 1 .1461-1.4565c-.0493.0002-.34.0005-.3866-.0021a.4881.4881 0 0 0-.4781.4979v1.0068zm.9184 1.4718a5.3254 5.3254 0 0 1-.123-.5573.3228.3228 0 0 0-.319-.2728h-.4957c.0007.0163-.0015.34.0009.355a.5188.5188 0 0 0 .5526.4827l.3842-.0076zm10.1265 2.917-.0884-.0807a.3229.3229 0 0 0-.3843-.0269 6.9823 6.9823 0 0 1-3.8046 1.0068 6.995 6.995 0 0 1-3.7932-1.0068.3228.3228 0 0 0-.3843.0269l-.0884.0807a.3154.3154 0 0 0 0 .4573 6.0305 6.0305 0 0 0 4.2927 1.5988 6.0453 6.0453 0 0 0 4.2889-1.5988.315.315 0 0 0-.0384-.4573zm1.4488-4.4158c0-2.4557-1.1529-4.3273-3.0245-5.2266-.2081-.1022-.4673.0594-.465.2921v1.3297a.3269.3269 0 0 0 .2037.296c1.7332.7109 2.9284 2.1866 2.9284 3.8776 0 2.2712-2.1559 3.8085-5.3419 3.8085-3.1859 0-5.3419-1.5411-5.3419-3.8085 0-1.691 1.1952-3.1667 2.9284-3.8776a.319.319 0 0 0 .2037-.296v-1.322c.0048-.2315-.2536-.3963-.4612-.2921-1.887.8839-3.0399 2.767-3.0399 5.2073 0 2.9899 2.2866 4.996 5.7108 4.996 3.4282.0001 5.6994-2.0098 5.6994-4.9844zm-8.6084-.538h-.0038a.5842.5842 0 1 0 .0038 0zm5.1614.5919c.0063.3226.2615.5789.584.5725a.5842.5842 0 1 0-.584-.5725zm4.5692.6225h-.4996a.3227.3227 0 0 0-.3151.2728c-.0346.173-.0768.3766-.1268.5573.0163.0007.3861-.0014.4012.0009a.5188.5188 0 0 0 .5366-.5004l.0037-.3306z",
74483
+ label: "Trino"
74484
+ },
74485
+ // Devicon postgresql-plain (MIT)
74486
+ postgres: {
74487
+ viewBox: "0 0 128 128",
74488
+ d: "M123.258 76.784c-.45-2.918-2.901-4.829-5.752-4.958-1.032-.047-2.08.061-3.109.192-1.243.158-2.471.438-3.711.623-.857.128-1.726.187-2.582.275l-.021-.111c1.598-3.018 3.263-6.003 4.775-9.064 1.159-2.348 2.151-4.781 3.176-7.194 1.696-3.998 3.051-8.12 4.173-12.309 1.075-4.011 1.995-8.066 2.284-12.227.116-1.662.196-3.331.187-4.995-.008-1.327-.151-2.656-.284-3.979-.15-1.516-.608-2.953-1.242-4.336-.836-1.822-2.132-3.317-3.496-4.737-1.092-1.137-2.293-2.173-3.484-3.208-1.698-1.477-3.607-2.656-5.59-3.703a32.18 32.18 0 00-7.09-2.75c-1.493-.381-3.02-.664-4.532-.966-.544-.11-1.089-.337-1.633-.337H85.086c-.37 0-.737.191-1.11.233-2.452.273-4.875.735-7.228 1.464-.88.273-1.684.101-2.52.024-.641-.059-1.271-.231-1.912-.263-2.442-.122-4.887-.301-7.328-.275-2.339.024-4.654.409-6.918 1.052-1.895.538-3.749 1.195-5.447 2.191-.727.426-1.303.346-2.055.129-2.527-.729-5.072-1.414-7.639-1.989-1.6-.358-3.245-.536-4.879-.707a57.214 57.214 0 00-4.718-.294c-1.538-.033-3.087-.032-4.618.104a30.16 30.16 0 00-7.158 1.513 23.813 23.813 0 00-7.086 3.865c-2.167 1.715-3.905 3.809-5.303 6.2-1.473 2.523-2.483 5.224-3.111 8.061-.34 1.537-.555 3.117-.788 4.678-.073.486.732.972-.268 1.456v6.794c1 .452.208.903.266 1.356.139 1.089.262 2.187.446 3.268.291 1.711.636 3.417.988 5.117a324.86 324.86 0 001.546 7.111c.396 1.72.847 3.43 1.319 5.131.721 2.598 1.431 5.201 2.246 7.77.757 2.387 1.624 4.74 2.484 7.093 1.191 3.255 2.617 6.405 4.327 9.424 1.479 2.614 3.169 5.062 5.436 7.076 1.494 1.327 3.157 2.347 5.093 2.857 1.521.4 3.067.448 4.624.129a10.979 10.979 0 004.824-2.311c.163-.134.342-.236.535.01.735.931 1.719 1.552 2.748 2.089 2.777 1.448 5.803 1.882 8.877 2.059.744.043 1.496-.064 2.246-.085 1.461-.04 2.881-.325 4.278-.729.732-.212 1.447-.481 2.192-.732.039.793.089 1.557.112 2.321l.104 4.166c.019.634.044 1.27.103 1.901.151 1.627.299 3.255.493 4.877.135 1.118.275 2.245.538 3.336a38.176 38.176 0 002.158 6.428 13.81 13.81 0 003.9 5.185c2.22 1.836 4.822 2.619 7.632 2.764 1.162.061 2.357.004 3.501-.204a49.01 49.01 0 005.387-1.275c3.591-1.084 6.695-2.956 9.014-5.981 1.32-1.724 2.404-3.589 3.1-5.648.574-1.701 1.115-3.419 1.545-5.16.34-1.372.508-2.787.715-4.188.137-.927.219-1.863.305-2.797.14-1.517.283-3.033.384-4.553.07-1.058.067-2.121.109-3.181.013-.323.065-.644.095-.966.028-.298.178-.401.482-.396 1.071.016 2.144.044 3.212-.004 1.197-.054 2.405-.105 3.583-.303a56.542 56.542 0 004.99-1.067c1.943-.508 3.725-1.418 5.44-2.455 1.998-1.207 3.819-2.623 5.297-4.447 1.285-1.591 1.894-3.43 1.584-5.438zm-3.412.982c-.066.915-.485 1.699-1.093 2.369-2.869 3.163-6.468 5.082-10.585 6.027-1.564.358-3.178.544-4.779.692a32.093 32.093 0 01-4.114.097c-1.006-.038-2.004-.268-3.032-.416-.103.94-.201 1.919-.32 2.896l-.479 3.745c-.145 1.187-.258 2.378-.407 3.564-.146 1.151-.328 2.298-.481 3.449-.143 1.072-.248 2.149-.407 3.219-.245 1.64-.479 3.284-.799 4.911-.384 1.945-.973 3.829-1.934 5.583-1.172 2.141-2.834 3.772-4.949 4.98-2.18 1.246-4.563 1.894-6.979 2.436-1.71.384-3.472.447-5.204.291-3.004-.272-5.568-1.557-7.506-3.886-1.85-2.223-3.102-4.771-3.55-7.655a63.102 63.102 0 01-.491-4.136 108.067 108.067 0 01-.299-4.62 250.203 250.203 0 01-.197-5.871c-.053-2.406-.07-4.812-.104-7.218l-.006-.092c-1.224.734-2.427 1.538-3.703 2.2a12.392 12.392 0 01-4.798 1.353c-1.318.1-2.653.191-3.965.086-2.151-.173-4.3-.51-6.226-1.569-.781-.43-1.596-.953-2.134-1.64-1.29-1.646-.672-3.726 1.273-4.727 1.344-.693 2.811-.982 4.268-1.319a44.368 44.368 0 003.761-1.029c1.222-.4 1.993-1.391 2.754-2.363l1.206-1.551c-.503-.053-.977-.107-1.451-.151-1.439-.136-2.812-.532-4.125-1.114-1.124-.497-1.141-.551-1.965.343-1.376 1.494-2.714 3.023-4.062 4.542-.992 1.117-1.978 2.241-2.965 3.361-.978 1.108-1.894 2.279-2.947 3.31-1.564 1.531-3.449 2.452-5.698 2.348-1.443-.066-2.764-.572-3.952-1.399-2.452-1.708-4.104-4.097-5.608-6.606-1.927-3.215-3.406-6.64-4.672-10.159-.876-2.432-1.756-4.866-2.521-7.333-.831-2.681-1.56-5.396-2.277-8.11a157.373 157.373 0 01-1.482-6.182 216.117 216.117 0 01-1.464-7.079c-.298-1.599-.471-3.221-.712-4.831-.325-2.17-.385-4.36-.267-6.539.105-1.963.387-3.921.667-5.871.388-2.698 1.277-5.244 2.556-7.648.783-1.473 1.755-2.812 2.879-4.056 1.845-2.042 4.078-3.518 6.562-4.626 1.736-.774 3.57-1.24 5.439-1.604 2.774-.54 5.573-.519 8.373-.461 1.224.025 2.443.248 3.666.369 2.633.262 5.214.816 7.762 1.5 1.857.498 3.676 1.143 5.518 1.703.185.056.456.051.607-.048 2.496-1.629 5.224-2.704 8.125-3.319 1.101-.233 2.237-.335 3.363-.407 1.369-.087 2.749-.167 4.115-.088 1.642.094 3.276.336 4.908.56.792.108 1.565.383 2.359.458.38.036.783-.242 1.185-.335 2.049-.473 4.089-1 6.156-1.374 1.539-.278 3.111-.409 4.676-.499 1.745-.1 3.503-.173 5.247-.089a36.66 36.66 0 016.555.923c2.677.623 5.245 1.528 7.686 2.784 1.824.938 3.558 2.026 5.119 3.364 1.023.878 2.07 1.745 2.994 2.723 1.14 1.206 2.303 2.413 3.018 3.958.538 1.165.922 2.371 1.028 3.647.132 1.586.292 3.178.277 4.766-.014 1.519-.221 3.037-.368 4.552-.334 3.454-1.085 6.833-1.997 10.167a116.972 116.972 0 01-2.589 8.17c-.879 2.481-1.893 4.917-2.918 7.343a80.07 80.07 0 01-2.458 5.303c-1.677 3.286-3.421 6.538-5.438 9.633-.348.535-.678 1.083-1.018 1.629.88.594 1.877.803 2.881.911.955.104 1.929.166 2.883.095 1.527-.113 3.049-.331 4.567-.544 1.504-.21 2.978-.638 4.522-.525 1.542.112 2.645 1.284 2.54 2.729zm-22.013-3.353c-.655-.846-1.323-1.682-1.964-2.538-1.006-1.344-1.729-2.845-2.455-4.353-.688-1.429-1.532-2.782-2.257-4.195-1.265-2.465-2.553-4.922-3.718-7.435-1.465-3.157-2.62-6.426-2.984-9.923-.154-1.48-.193-2.958.106-4.424.479-2.341 1.702-4.172 3.758-5.428 1.907-1.165 4.032-1.541 6.209-1.659 1.351-.073 2.708-.013 4.11-.013l-.047-.237c-.872-1.823-1.687-3.677-2.641-5.457-1.346-2.512-3.068-4.777-4.986-6.877-1.421-1.555-2.96-2.998-4.646-4.273-1.658-1.255-3.405-2.376-5.269-3.293-2.223-1.093-4.538-1.938-6.967-2.477-2.334-.518-4.683-.835-7.077-.861-2.042-.022-4.071.07-6.06.531-3.002.695-5.748 1.931-8.137 3.933a21.143 21.143 0 00-3.517 3.77c-1.196 1.643-2.161 3.417-2.986 5.277-1.132 2.552-1.909 5.208-2.44 7.938-.266 1.361-.474 2.734-.686 4.106-.074.48-.08.971-.123 1.521.369-.192.635-.34.907-.472l.885-.397c2.993-1.369 6.094-2.25 9.427-2.149 1.416.043 2.771.323 4.03.943 2.415 1.191 3.828 3.216 4.442 5.779.424 1.769.714 3.573.996 5.372.221 1.405.447 2.825.473 4.242.037 2.071-.068 4.146-.181 6.216a17.386 17.386 0 01-1.08 5.146c-1.12 2.993-2.368 5.937-3.534 8.913-.385.983-.681 2.001-1.045 3.082.562 0 1.018-.004 1.474.002.178.003.36.008.532.049 1.34.316 2.502.923 3.455 1.954 1.271 1.372 1.938 2.973 1.972 4.826.019 1.027-.089 2.057-.084 3.084.021 4.786.057 9.572.097 14.357.007.782.046 1.565.102 2.346.117 1.635.235 3.271.395 4.902.112 1.157.268 2.312.451 3.461.259 1.628 1 3.077 1.841 4.462.724 1.191 1.665 2.203 2.905 2.901 2.107 1.186 4.376 1.285 6.663.848 1.545-.295 3.062-.769 4.562-1.258a10.128 10.128 0 003.937-2.354c1.051-1.019 1.797-2.261 2.3-3.632.976-2.659 1.28-5.459 1.684-8.237.151-1.04.282-2.083.42-3.125.157-1.186.316-2.371.468-3.556.112-.883.214-1.768.322-2.651.154-1.268.317-2.535.464-3.804.113-.981.209-1.966.309-2.949.129-1.256.268-2.512.379-3.77.086-.955.051-1.927.22-2.864.311-1.718 1.123-3.18 2.646-4.125.637-.395 1.356-.655 2.063-.989l-.12-.186zm-57.597-7.052a17.526 17.526 0 01-1.354-5.622c-.128-1.825.089-3.643.276-5.46.182-1.76.333-3.528.386-5.296.088-2.906-.108-5.808-.247-8.712-.084-1.729.117-3.479.271-5.212.139-1.561.312-3.126.607-4.664.495-2.581 1.152-5.125 2.086-7.591.887-2.338 1.906-4.615 3.345-6.665.986-1.406 2.105-2.72 3.18-4.094l-.319-.113c-3.498-1.111-7.053-1.979-10.709-2.358-1.729-.179-3.464-.284-5.198-.387-.532-.032-1.072.04-1.606.091-1.322.126-2.66.176-3.961.424-2.214.421-4.338 1.129-6.305 2.282-1.766 1.035-3.249 2.373-4.491 3.978-1.372 1.772-2.295 3.776-2.958 5.913-.783 2.521-1.156 5.115-1.257 7.733-.088 2.295-.132 4.603.264 6.889.295 1.702.492 3.422.817 5.117.443 2.311.918 4.617 1.467 6.904.785 3.274 1.569 6.553 2.499 9.787.89 3.099 1.894 6.17 2.982 9.204.89 2.476 1.919 4.906 3.003 7.304.706 1.562 1.561 3.065 2.457 4.528.953 1.553 2.037 3.027 3.508 4.154 1.856 1.423 3.293 1.644 5.179.083.808-.669 1.491-1.495 2.194-2.282 1.117-1.25 2.195-2.534 3.307-3.788 1.416-1.598 2.85-3.179 4.273-4.769.301-.336.59-.682.883-1.022l-.484-.425a17.695 17.695 0 01-4.095-5.931zm53.688-47.569a61.488 61.488 0 013.309 4.204c2 2.809 3.598 5.842 4.775 9.087.521 1.43.937 2.874.751 4.439-.129 1.096-.118 2.208-.215 3.31-.081.917-.226 1.829-.345 2.743-.178 1.378-.436 2.752-.513 4.136-.073 1.317.003 2.648.086 3.968.084 1.341.265 2.676.388 4.015.139 1.518.326 3.036.369 4.557.035 1.249-.076 2.506-.185 3.753-.13 1.502-.511 2.956-1.079 4.351-.399.982-.876 1.934-1.327 2.917l.181.192.275.213.277-.496a93.621 93.621 0 006.222-11.493 186.333 186.333 0 003.287-7.766c1.624-4.064 2.909-8.242 3.903-12.503.446-1.913.787-3.855 1.09-5.797.236-1.518.433-3.054.477-4.586.047-1.625-.043-3.263-.193-4.884-.112-1.224-.414-2.456-1.181-3.451-1.233-1.602-2.564-3.134-4.201-4.346-1.378-1.021-2.751-2.068-4.23-2.927-2.345-1.36-4.883-2.266-7.535-2.883-2.588-.603-5.21-.863-7.849-.918-1.556-.033-3.119.134-4.672.28-1.407.132-2.805.357-4.222.543 1.52.855 3.019 1.615 4.433 2.511 2.973 1.883 5.637 4.149 7.924 6.831zM55.299 72.514c.961-3.073 2.27-6.007 3.538-8.959 1.028-2.394 1.59-4.916 1.777-7.506.093-1.277.067-2.57.004-3.851a44.628 44.628 0 00-.392-4.259c-.266-1.801-.569-3.603-.995-5.371-.462-1.913-1.627-3.245-3.623-3.736-1.216-.299-2.424-.287-3.653-.093-3.002.473-5.75 1.579-8.31 3.199-.515.326-.798.589-.709 1.328.188 1.565.229 3.155.222 4.735-.01 2.236-.105 4.472-.19 6.707-.028.728-.133 1.452-.211 2.177-.12 1.11-.351 2.219-.344 3.327.007 1.142.124 2.311.401 3.417.88 3.507 2.744 6.377 5.799 8.402 1.879 1.245 3.958 1.873 6.24 1.992.155-.524.293-1.019.446-1.509zm-3.586-30.087c-.402-.844-.172-1.543.76-1.867.227-.08.461-.165.697-.188.324-.032.654-.008.982-.008 1.182.006 2.319.171 3.295.923.626.482.794 1.122.389 1.779-.575.932-1.452 1.4-2.529 1.49-1.697.141-2.888-.65-3.594-2.129zm47.04-.308c.136-1.124.245-2.251.384-3.375.056-.452-.182-.574-.561-.585-1.192-.033-2.384-.075-3.576-.097-1.344-.024-2.652.192-3.896.703-1.38.568-2.431 1.478-2.86 2.98a9.042 9.042 0 00-.293 3.41 20.11 20.11 0 001.193 5.176c.834 2.221 1.707 4.441 2.75 6.569 1.413 2.881 3.012 5.67 4.513 8.507.401.757.738 1.547 1.156 2.431a13.783 13.783 0 001.351-5.622c.041-1.61-.088-3.227-.182-4.838-.059-.986-.198-1.966-.294-2.95-.134-1.371-.337-2.741-.368-4.115-.031-1.397.068-2.802.188-4.197.113-1.338.334-2.665.495-3.997zm-2.689-1.082c-.443 1.223-1.39 1.913-2.618 2.116-1.145.188-2.148-.235-2.894-1.148-.531-.65-.328-1.42.468-1.859.914-.506 1.919-.634 3.104-.711.322.059.807.108 1.268.24.669.189.916.692.672 1.362zm-35.422 37.66c-.655-.535-1.521-.566-2.144.021-.773.73-1.453 1.565-2.133 2.388-.785.951-1.521 1.94-2.534 2.677-1.474 1.071-3.192 1.515-4.919 1.935-1.373.334-2.752.644-4.129.965l-.017.178c.409.189.805.425 1.231.56 2.1.665 4.236.996 6.455.808 1.602-.136 3.128-.485 4.574-1.171 1.99-.943 3.521-2.437 4.823-4.175.218-.29.317-.719.343-1.093.089-1.321-.582-2.303-1.55-3.093zm51.751.526c-1.69.181-3.382.373-5.077.47-.818.047-1.648-.109-2.474-.176-1.385-.112-2.737-.42-3.908-1.16-.678-.427-1.241-.475-1.961-.233-1.028.346-1.867.872-2.115 1.986-.169.753-.23 1.533-.298 2.304-.013.136.157.386.287.42.793.209 1.59.456 2.401.529.996.09 2.01.061 3.013.011 1.083-.054 2.173-.124 3.24-.304 2.515-.422 4.948-1.11 7.109-2.536.779-.515 1.551-1.041 2.325-1.562l-.064-.11c-.826.123-1.648.273-2.478.361z",
74489
+ label: "PostgreSQL"
74490
+ },
74491
+ // Simple Icons (CC0)
74492
+ sqlite: {
74493
+ viewBox: "0 0 24 24",
74494
+ d: "M21.678.521c-1.032-.92-2.28-.55-3.513.544a8.71 8.71 0 0 0-.547.535c-2.109 2.237-4.066 6.38-4.674 9.544.237.48.422 1.093.544 1.561a13.044 13.044 0 0 1 .164.703s-.019-.071-.096-.296l-.05-.146a1.689 1.689 0 0 0-.033-.08c-.138-.32-.518-.995-.686-1.289-.143.423-.27.818-.376 1.176.484.884.778 2.4.778 2.4s-.025-.099-.147-.442c-.107-.303-.644-1.244-.772-1.464-.217.804-.304 1.346-.226 1.478.152.256.296.698.422 1.186.286 1.1.485 2.44.485 2.44l.017.224a22.41 22.41 0 0 0 .056 2.748c.095 1.146.273 2.13.5 2.657l.155-.084c-.334-1.038-.47-2.399-.41-3.967.09-2.398.642-5.29 1.661-8.304 1.723-4.55 4.113-8.201 6.3-9.945-1.993 1.8-4.692 7.63-5.5 9.788-.904 2.416-1.545 4.684-1.931 6.857.666-2.037 2.821-2.912 2.821-2.912s1.057-1.304 2.292-3.166c-.74.169-1.955.458-2.362.629-.6.251-.762.337-.762.337s1.945-1.184 3.613-1.72C21.695 7.9 24.195 2.767 21.678.521m-18.573.543A1.842 1.842 0 0 0 1.27 2.9v16.608a1.84 1.84 0 0 0 1.835 1.834h9.418a22.953 22.953 0 0 1-.052-2.707c-.006-.062-.011-.141-.016-.2a27.01 27.01 0 0 0-.473-2.378c-.121-.47-.275-.898-.369-1.057-.116-.197-.098-.31-.097-.432 0-.12.015-.245.037-.386a9.98 9.98 0 0 1 .234-1.045l.217-.028c-.017-.035-.014-.065-.031-.097l-.041-.381a32.8 32.8 0 0 1 .382-1.194l.2-.019c-.008-.016-.01-.038-.018-.053l-.043-.316c.63-3.28 2.587-7.443 4.8-9.791.066-.069.133-.128.198-.194Z",
74495
+ label: "SQLite"
74496
+ },
74497
+ // Material Design Icons dolphin (Apache-2.0)
74498
+ mysql: {
74499
+ viewBox: "0 0 24 24",
74500
+ d: "M20 7s0-4-5-4c-1.53 0-2.85.19-4 .5c-.5-.44-3.74-3.191-7 .07l2.56 2.56C2.5 10.53 4 18 4 18s-3 0-3 4l4-1l4 1c0-4-3-4-3-4s.85-5.76 7-6.82V14c2 0 2.68-1.81 2.89-3H18c4 0 5-1 5-2s-2-2-3-2m-2 1c-.55 0-1-.45-1-1s.45-1 1-1s1 .45 1 1s-.45 1-1 1",
74501
+ label: "MySQL"
74502
+ },
74503
+ // Simple Icons (CC0)
74504
+ snowflake: {
74505
+ viewBox: "0 0 24 24",
74506
+ d: "M24 3.459c0 .646-.418 1.18-1.141 1.18-.723 0-1.142-.534-1.142-1.18 0-.647.419-1.18 1.142-1.18.723 0 1.141.533 1.141 1.18zm-.228 0c0-.533-.38-.951-.913-.951s-.913.38-.913.95c0 .533.38.952.913.952.57 0 .913-.419.913-.951zm-1.37-.533h.495c.266 0 .456.152.456.38 0 .153-.076.229-.19.305l.19.266v.038h-.266l-.19-.266h-.229v.266h-.266zm.495.228h-.229v.267h.229c.114 0 .152-.038.152-.114.038-.077-.038-.153-.152-.153zM7.602 12.4c.038-.151.076-.304.076-.456 0-.114-.038-.228-.038-.342-.114-.343-.304-.647-.646-.838l-4.87-2.777c-.685-.38-1.56-.152-1.94.533-.381.685-.153 1.56.532 1.94l2.701 1.56-2.701 1.56c-.685.38-.913 1.256-.533 1.94.38.685 1.256.914 1.94.533l4.832-2.777c.343-.267.571-.533.647-.876zm1.332 2.626c-.266-.038-.57.038-.837.19l-4.832 2.777c-.685.38-.913 1.256-.532 1.94.38.686 1.255.914 1.94.533l2.701-1.56v3.12c0 .8.647 1.408 1.446 1.408.799 0 1.407-.647 1.407-1.408v-5.592c0-.761-.57-1.37-1.293-1.408zm4.946-6.088c.266.038.57-.038.837-.19l4.832-2.777c.685-.38.913-1.256.532-1.94-.38-.686-1.255-.914-1.94-.533l-2.701 1.56V1.975c0-.799-.647-1.408-1.446-1.408-.799 0-1.446.609-1.446 1.408V7.53c0 .76.609 1.37 1.332 1.407zM3.265 5.97l4.832 2.777c.266.152.533.19.837.19.723-.038 1.331-.684 1.331-1.407V1.975c0-.799-.646-1.408-1.407-1.408-.799 0-1.446.647-1.446 1.408v3.12l-2.701-1.56c-.685-.38-1.56-.152-1.94.533-.419.646-.19 1.521.494 1.902zm9.093 6.011a.412.412 0 00-.114-.266l-.57-.571a.346.346 0 00-.267-.114.412.412 0 00-.266.114l-.571.57a.411.411 0 00-.114.267c0 .076.038.19.114.267l.57.57a.345.345 0 00.267.114c.076 0 .19-.038.266-.114l.571-.57a.412.412 0 00.114-.267zm1.598.533L11.94 14.53c-.039.038-.153.114-.229.114h-.608a.411.411 0 01-.267-.114L8.82 12.514a.408.408 0 01-.076-.229v-.608c0-.076.038-.19.114-.267l2.016-2.016a.41.41 0 01.267-.114h.608a.41.41 0 01.267.114l2.016 2.016a.347.347 0 01.114.267v.608c-.076.077-.114.19-.19.229zm5.593 5.44l-4.832-2.777c-.266-.152-.57-.19-.837-.152-.723.038-1.332.684-1.332 1.408v5.554c0 .8.647 1.408 1.408 1.408.799 0 1.446-.647 1.446-1.408v-3.12l2.7 1.56c.686.38 1.561.152 1.941-.533.419-.646.19-1.521-.494-1.94zm2.549-7.533l-2.701 1.56 2.7 1.56c.686.38.914 1.256.533 1.94-.38.685-1.255.913-1.94.533l-4.832-2.778a1.644 1.644 0 01-.647-.798c-.037-.153-.076-.305-.076-.457 0-.114.039-.228.039-.342.114-.343.342-.647.646-.837l4.832-2.778c.685-.38 1.56-.152 1.94.533.457.609.19 1.484-.494 1.864",
74507
+ label: "Snowflake"
74508
+ },
74509
+ // Simple Icons (CC0)
74510
+ bigquery: {
74511
+ viewBox: "0 0 24 24",
74512
+ d: "M5.676 10.595h2.052v5.244a5.892 5.892 0 0 1-2.052-2.088v-3.156zm18.179 10.836a.504.504 0 0 1 0 .708l-1.716 1.716a.504.504 0 0 1-.708 0l-4.248-4.248a.206.206 0 0 1-.007-.007c-.02-.02-.028-.045-.043-.066a10.736 10.736 0 0 1-6.334 2.065C4.835 21.599 0 16.764 0 10.799S4.835 0 10.8 0s10.799 4.835 10.799 10.8c0 2.369-.772 4.553-2.066 6.333.025.017.052.028.074.05l4.248 4.248zm-5.028-10.632a8.015 8.015 0 1 0-8.028 8.028h.024a8.016 8.016 0 0 0 8.004-8.028zm-4.86 4.98a6.002 6.002 0 0 0 2.04-2.184v-1.764h-2.04v3.948zm-4.5.948c.442.057.887.08 1.332.072.4.025.8.025 1.2 0V7.692H9.468v9.035z",
74513
+ label: "BigQuery"
74514
+ },
74515
+ // In-house: database cylinder (no free monochrome SQL Server mark exists)
74516
+ mssql: {
74517
+ viewBox: "0 0 16 16",
74518
+ d: "M8 1.5c3.1 0 5.5 1 5.5 2.5v8c0 1.5-2.4 2.5-5.5 2.5s-5.5-1-5.5-2.5V4c0-1.5 2.4-2.5 5.5-2.5zM3.9 9.9V12c0 .5 1.6 1.2 4.1 1.2s4.1-.7 4.1-1.2V9.9c-1 .6-2.5.9-4.1.9s-3.1-.3-4.1-.9zm0-3.6v2.1C4 8.9 5.5 9.5 8 9.5s4-.6 4.1-1.1V6.3c-1 .6-2.5.9-4.1.9s-3.1-.3-4.1-.9zM8 2.8c-2.5 0-4.1.7-4.1 1.2S5.5 5.2 8 5.2 12.1 4.5 12.1 4 10.5 2.8 8 2.8z",
74519
+ label: "SQL Server"
74520
+ }
74521
+ };
74522
+ const FALLBACK = {
74523
+ viewBox: "0 0 16 16",
74524
+ d: "M5.5 1.5h1.4v3h2.2v-3h1.4v3h1a.5.5 0 01.5.5v2a4 4 0 01-3.3 3.94v1.06a1.5 1.5 0 01-3 0v-1.06A4 4 0 012.4 7V5a.5.5 0 01.5-.5h2.6v-3z"
74525
+ };
74526
+ function ConnectorGlyph({ type }) {
74527
+ const glyph = GLYPHS[type] ?? FALLBACK;
74528
+ return /* @__PURE__ */ jsxRuntimeExports.jsx(
74529
+ "svg",
74530
+ {
74531
+ viewBox: glyph.viewBox,
74532
+ fill: "currentColor",
74533
+ "aria-hidden": "true",
74534
+ focusable: "false",
74535
+ className: "sp-connector-glyph",
74536
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: glyph.d })
74537
+ }
74538
+ );
74539
+ }
74540
+ function getConnectorGroup(id) {
74541
+ return id === "duckdb" || id === "sqlite" ? "local" : "server";
74542
+ }
74543
+ function CloseIcon({ size = 10 }) {
74544
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { width: size, height: size, viewBox: "0 0 16 16", fill: "currentColor", "aria-hidden": "true", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M8 8.707l3.646 3.647.708-.707L8.707 8l3.647-3.646-.707-.708L8 7.293 4.354 3.646l-.708.708L7.293 8l-3.647 3.646.708.707L8 8.707z" }) });
74545
+ }
74546
+ function errorText(e2) {
74547
+ return e2 instanceof Error ? e2.message : String(e2);
74548
+ }
74549
+ const CONNECTION_TEST_TIMEOUT_MS = 15e3;
74550
+ function withTestTimeout(promise, ms) {
74551
+ return new Promise((resolve, reject) => {
74552
+ const timer = setTimeout(() => {
74553
+ reject(
74554
+ new Error(
74555
+ `Timed out after ${Math.round(ms / 1e3)}s — the connection may be unreachable. Check the host, port, and network.`
74556
+ )
74557
+ );
74558
+ }, ms);
74559
+ promise.then(
74560
+ (value) => {
74561
+ clearTimeout(timer);
74562
+ resolve(value);
74563
+ },
74564
+ (err) => {
74565
+ clearTimeout(timer);
74566
+ reject(err);
74567
+ }
74568
+ );
74569
+ });
74570
+ }
74571
+ function TestElapsed({ since }) {
74572
+ const [, setTick] = reactExports.useState(0);
74573
+ reactExports.useEffect(() => {
74574
+ const interval = setInterval(() => setTick((t) => t + 1), 500);
74575
+ return () => clearInterval(interval);
74576
+ }, []);
74577
+ const seconds = Math.max(0, Math.floor((Date.now() - since) / 1e3));
74578
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "sp-conn-test-elapsed", "aria-hidden": "true", children: [
74579
+ " ",
74580
+ "· ",
74581
+ seconds,
74582
+ "s"
74583
+ ] });
74584
+ }
74413
74585
  const OPTIONAL_DEPENDENCY_ADVICE = [
74414
74586
  {
74415
74587
  dependency: "@duckdb/node-api",
@@ -74424,15 +74596,9 @@ const OPTIONAL_DEPENDENCY_ADVICE = [
74424
74596
  guidance: "Snowflake connections require optional Snowflake SDK support, but the SDK is not available in this extension runtime."
74425
74597
  }
74426
74598
  ];
74427
- const CONNECTOR_ICONS = {
74428
- duckdb: "🦆",
74429
- trino: "",
74430
- postgres: "🐘",
74431
- sqlite: "📦",
74432
- mysql: "🐬",
74433
- mssql: "🗄️",
74434
- snowflake: "❄️",
74435
- bigquery: "📊"
74599
+ const CONNECTOR_GROUP_LABELS = {
74600
+ local: "Local files",
74601
+ server: "Servers & warehouses"
74436
74602
  };
74437
74603
  function getOptionalDependencyAdvice(message) {
74438
74604
  const lowerMessage = message.toLowerCase();
@@ -74542,10 +74708,16 @@ const ConnectionsManager = () => {
74542
74708
  const [lastSavedConnectionId, setLastSavedConnectionId] = reactExports.useState(void 0);
74543
74709
  const [statuses, setStatuses] = reactExports.useState({});
74544
74710
  const [statusMessages, setStatusMessages] = reactExports.useState({});
74711
+ const [testStartedAt, setTestStartedAt] = reactExports.useState({});
74712
+ const testRequestIds = reactExports.useRef({});
74713
+ const formTestIdRef = reactExports.useRef(0);
74545
74714
  const [toast, setToast] = reactExports.useState(null);
74715
+ const [pendingConfirm, setPendingConfirm] = reactExports.useState(null);
74546
74716
  const toastRef = reactExports.useRef(null);
74547
74717
  const [isFormOpen, setIsFormOpen] = reactExports.useState(false);
74548
74718
  const [selectedType, setSelectedType] = reactExports.useState("");
74719
+ const [isPopoverOpen, setIsPopoverOpen] = reactExports.useState(false);
74720
+ const switcherWrapRef = reactExports.useRef(null);
74549
74721
  const fetchData = reactExports.useCallback(async () => {
74550
74722
  var _a3, _b2, _c3, _d, _e2, _f;
74551
74723
  if (!isReady) {
@@ -74623,49 +74795,72 @@ const ConnectionsManager = () => {
74623
74795
  if (!isReady) {
74624
74796
  return false;
74625
74797
  }
74798
+ const requestId = (testRequestIds.current[connectionId] ?? 0) + 1;
74799
+ testRequestIds.current[connectionId] = requestId;
74800
+ const isStale = () => testRequestIds.current[connectionId] !== requestId;
74626
74801
  setStatuses((prev) => ({ ...prev, [connectionId]: "testing" }));
74627
74802
  setStatusMessages((prev) => ({ ...prev, [connectionId]: "" }));
74803
+ setTestStartedAt((prev) => ({ ...prev, [connectionId]: Date.now() }));
74628
74804
  try {
74629
- const result = await callServerTool("test_connection", {
74630
- connectionId
74631
- });
74805
+ const result = await withTestTimeout(
74806
+ callServerTool("test_connection", { connectionId }),
74807
+ CONNECTION_TEST_TIMEOUT_MS
74808
+ );
74809
+ if (isStale()) {
74810
+ return false;
74811
+ }
74632
74812
  const text = getToolText(result, ((_a3 = result.structuredContent) == null ? void 0 : _a3.message) ?? "No response");
74633
74813
  const isError = isErrorToolResult(result, text);
74634
74814
  setStatuses((prev) => ({ ...prev, [connectionId]: isError ? "error" : "ok" }));
74635
74815
  setStatusMessages((prev) => ({ ...prev, [connectionId]: text }));
74636
74816
  return !isError;
74637
74817
  } catch (e2) {
74818
+ if (isStale()) {
74819
+ return false;
74820
+ }
74638
74821
  setStatuses((prev) => ({ ...prev, [connectionId]: "error" }));
74639
- setStatusMessages((prev) => ({
74640
- ...prev,
74641
- [connectionId]: `Error: ${e2}`
74642
- }));
74822
+ setStatusMessages((prev) => ({ ...prev, [connectionId]: errorText(e2) }));
74643
74823
  return false;
74644
74824
  }
74645
74825
  };
74826
+ const handleCancelTest = (connectionId) => {
74827
+ testRequestIds.current[connectionId] = (testRequestIds.current[connectionId] ?? 0) + 1;
74828
+ setStatuses((prev) => ({ ...prev, [connectionId]: "unknown" }));
74829
+ setStatusMessages((prev) => ({ ...prev, [connectionId]: "Test cancelled." }));
74830
+ };
74646
74831
  const handleTestFormData = async (formData, connection) => {
74647
74832
  var _a3;
74648
74833
  const typeToTest = (connection == null ? void 0 : connection.type) ?? selectedType;
74649
74834
  if (!isReady || !typeToTest) {
74650
74835
  return;
74651
74836
  }
74837
+ const requestId = connection ? (testRequestIds.current[connection.id] ?? 0) + 1 : formTestIdRef.current += 1;
74838
+ const isStale = () => connection ? testRequestIds.current[connection.id] !== requestId : formTestIdRef.current !== requestId;
74652
74839
  if (connection) {
74840
+ testRequestIds.current[connection.id] = requestId;
74653
74841
  setToast(null);
74654
74842
  setStatuses((prev) => ({ ...prev, [connection.id]: "testing" }));
74655
74843
  setStatusMessages((prev) => ({ ...prev, [connection.id]: "" }));
74844
+ setTestStartedAt((prev) => ({ ...prev, [connection.id]: Date.now() }));
74656
74845
  } else {
74657
- setToast({ text: "Testing connection…", severity: "success" });
74846
+ setToast({ text: "Testing connection…", severity: "testing", startedAt: Date.now() });
74658
74847
  }
74659
74848
  try {
74660
74849
  const profileToTest = { ...formData, type: typeToTest };
74661
74850
  if (connection && profileToTest["password"] === "") {
74662
74851
  delete profileToTest["password"];
74663
74852
  }
74664
- const result = await callServerTool("test_connection", {
74665
- ...connection ? { connectionId: connection.id } : {},
74666
- type: typeToTest,
74667
- connectionProfile: profileToTest
74668
- });
74853
+ const result = await withTestTimeout(
74854
+ callServerTool("test_connection", {
74855
+ ...connection ? { connectionId: connection.id } : {},
74856
+ type: typeToTest,
74857
+ connectionProfile: profileToTest
74858
+ }),
74859
+ CONNECTION_TEST_TIMEOUT_MS
74860
+ );
74861
+ if (isStale()) {
74862
+ return;
74863
+ }
74669
74864
  const text = getToolText(result, ((_a3 = result.structuredContent) == null ? void 0 : _a3.message) ?? "No response");
74670
74865
  const isError = isErrorToolResult(result, text);
74671
74866
  if (connection) {
@@ -74675,7 +74870,10 @@ const ConnectionsManager = () => {
74675
74870
  setToast(buildConnectionTestToast(result.structuredContent, text));
74676
74871
  }
74677
74872
  } catch (e2) {
74678
- const message = `Error: ${e2}`;
74873
+ if (isStale()) {
74874
+ return;
74875
+ }
74876
+ const message = `Connection test failed: ${errorText(e2)}`;
74679
74877
  const advice = getOptionalDependencyAdvice(message);
74680
74878
  if (connection) {
74681
74879
  setStatuses((prev) => ({ ...prev, [connection.id]: "error" }));
@@ -74689,6 +74887,10 @@ const ConnectionsManager = () => {
74689
74887
  }
74690
74888
  }
74691
74889
  };
74890
+ const dismissToast = () => {
74891
+ formTestIdRef.current += 1;
74892
+ setToast(null);
74893
+ };
74692
74894
  const handleSaveConnection = async (formData, connection) => {
74693
74895
  const typeToSave = (connection == null ? void 0 : connection.type) ?? selectedType;
74694
74896
  if (!isReady || !typeToSave) {
@@ -74718,26 +74920,36 @@ const ConnectionsManager = () => {
74718
74920
  setToast({ text: `Connection '${profileToSave["name"]}' saved.`, severity: "success" });
74719
74921
  await fetchData();
74720
74922
  } catch (e2) {
74721
- setToast({ text: `Error saving: ${e2}`, severity: "error" });
74923
+ setToast({ text: `Couldn't save the connection: ${errorText(e2)}`, severity: "error" });
74722
74924
  } finally {
74723
74925
  setIsLoading(false);
74724
74926
  }
74725
74927
  };
74726
- const handleDeleteConnection = async (id, name) => {
74727
- if (!isReady || !window.confirm(`Delete connection '${name}'?`)) {
74728
- return;
74729
- }
74730
- setIsLoading(true);
74731
- try {
74732
- await callServerTool("delete_connection", { connectionId: id });
74733
- setSelectedConnectionId((prev) => prev === id ? void 0 : prev);
74734
- setToast({ text: `Connection '${name}' deleted.`, severity: "success" });
74735
- await fetchData();
74736
- } catch (e2) {
74737
- setToast({ text: `Error deleting: ${e2}`, severity: "error" });
74738
- } finally {
74739
- setIsLoading(false);
74740
- }
74928
+ const handleDeleteConnection = (id, name) => {
74929
+ if (!isReady) return;
74930
+ setPendingConfirm({
74931
+ title: "Delete connection",
74932
+ message: `Delete connection '${name}'? This can't be undone.`,
74933
+ confirmLabel: "Delete",
74934
+ onConfirm: () => {
74935
+ void (async () => {
74936
+ setIsLoading(true);
74937
+ try {
74938
+ await callServerTool("delete_connection", { connectionId: id });
74939
+ setSelectedConnectionId((prev) => prev === id ? void 0 : prev);
74940
+ setToast({ text: `Connection '${name}' deleted.`, severity: "success" });
74941
+ await fetchData();
74942
+ } catch (e2) {
74943
+ setToast({
74944
+ text: `Couldn't delete the connection: ${errorText(e2)}`,
74945
+ severity: "error"
74946
+ });
74947
+ } finally {
74948
+ setIsLoading(false);
74949
+ }
74950
+ })();
74951
+ }
74952
+ });
74741
74953
  };
74742
74954
  const handleSetActiveConnection = async (connection) => {
74743
74955
  if (!isReady || !supportsActiveConnection) {
@@ -74780,24 +74992,33 @@ const ConnectionsManager = () => {
74780
74992
  setToast({ text: `Error saving password: ${e2}`, severity: "error" });
74781
74993
  }
74782
74994
  };
74783
- const handleClearConnectionPassword = async (connection) => {
74784
- var _a3;
74995
+ const handleClearConnectionPassword = (connection) => {
74785
74996
  if (!isReady || !supportsActiveConnection || !connection.hasPassword) {
74786
74997
  return;
74787
74998
  }
74788
- if (!window.confirm(`Clear stored password for '${connection.name}'?`)) {
74789
- return;
74790
- }
74791
- try {
74792
- const result = await callServerTool("clear_connection_password", {
74793
- connectionId: connection.id
74794
- });
74795
- const text = getToolText(result, ((_a3 = result.structuredContent) == null ? void 0 : _a3.message) ?? "Password cleared.");
74796
- setToast({ text, severity: "success" });
74797
- await fetchData();
74798
- } catch (e2) {
74799
- setToast({ text: `Error clearing password: ${e2}`, severity: "error" });
74800
- }
74999
+ setPendingConfirm({
75000
+ title: "Clear stored password",
75001
+ message: `Clear stored password for '${connection.name}'?`,
75002
+ confirmLabel: "Clear",
75003
+ onConfirm: () => {
75004
+ void (async () => {
75005
+ var _a3;
75006
+ try {
75007
+ const result = await callServerTool("clear_connection_password", {
75008
+ connectionId: connection.id
75009
+ });
75010
+ const text = getToolText(
75011
+ result,
75012
+ ((_a3 = result.structuredContent) == null ? void 0 : _a3.message) ?? "Password cleared."
75013
+ );
75014
+ setToast({ text, severity: "success" });
75015
+ await fetchData();
75016
+ } catch (e2) {
75017
+ setToast({ text: `Error clearing password: ${e2}`, severity: "error" });
75018
+ }
75019
+ })();
75020
+ }
75021
+ });
74801
75022
  };
74802
75023
  const handleInstallOptionalDependency = (advice) => {
74803
75024
  sendMessage("installOptionalDependency", {
@@ -74810,10 +75031,20 @@ const ConnectionsManager = () => {
74810
75031
  setIsFormOpen(true);
74811
75032
  setToast(null);
74812
75033
  };
74813
- const closeForm = () => {
75034
+ const closeForm = reactExports.useCallback(() => {
74814
75035
  setIsFormOpen(false);
74815
75036
  setSelectedType("");
74816
- };
75037
+ setToast(null);
75038
+ }, []);
75039
+ reactExports.useEffect(() => {
75040
+ function handleClickOutside(event) {
75041
+ if (isPopoverOpen && switcherWrapRef.current && !switcherWrapRef.current.contains(event.target)) {
75042
+ setIsPopoverOpen(false);
75043
+ }
75044
+ }
75045
+ document.addEventListener("mousedown", handleClickOutside);
75046
+ return () => document.removeEventListener("mousedown", handleClickOutside);
75047
+ }, [isPopoverOpen]);
74817
75048
  const activeSchemaDef = connectors.find((c) => c.id === selectedType);
74818
75049
  const selectedConnection = selectedConnectionId ? connections.find((c) => c.id === selectedConnectionId) : void 0;
74819
75050
  const activeFormSchema = (activeSchemaDef == null ? void 0 : activeSchemaDef.schema) ? schemaForConnectionMode(activeSchemaDef.schema, activeSchemaDef.id, mode) : void 0;
@@ -74833,7 +75064,10 @@ const ConnectionsManager = () => {
74833
75064
  role: toast.severity === "warning" || toast.severity === "error" ? "alert" : "status",
74834
75065
  tabIndex: -1,
74835
75066
  children: [
74836
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-toast-text", children: toast.text }),
75067
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "sp-conn-toast-text", children: [
75068
+ toast.text,
75069
+ toast.severity === "testing" && toast.startedAt !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(TestElapsed, { since: toast.startedAt })
75070
+ ] }),
74837
75071
  advice && /* @__PURE__ */ jsxRuntimeExports.jsxs(
74838
75072
  "button",
74839
75073
  {
@@ -74846,15 +75080,8 @@ const ConnectionsManager = () => {
74846
75080
  ]
74847
75081
  }
74848
75082
  ),
74849
- /* @__PURE__ */ jsxRuntimeExports.jsx(
74850
- "button",
74851
- {
74852
- className: "sp-conn-toast-close",
74853
- onClick: () => setToast(null),
74854
- "aria-label": "Close message",
74855
- children: "✕"
74856
- }
74857
- )
75083
+ toast.severity === "testing" && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "sp-btn sp-conn-toast-action", onClick: dismissToast, children: "Cancel" }),
75084
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "sp-conn-toast-close", onClick: dismissToast, "aria-label": "Close message", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CloseIcon, { size: 14 }) })
74858
75085
  ]
74859
75086
  }
74860
75087
  );
@@ -74863,7 +75090,22 @@ const ConnectionsManager = () => {
74863
75090
  const status = statuses[connection.id] || "unknown";
74864
75091
  const statusMsg = statusMessages[connection.id] || "";
74865
75092
  if (status === "testing") {
74866
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-status-message", role: "status", children: "Testing connection…" });
75093
+ const startedAt = testStartedAt[connection.id];
75094
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-status-message sp-conn-status-message-testing", role: "status", children: [
75095
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
75096
+ "Testing connection…",
75097
+ startedAt !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(TestElapsed, { since: startedAt })
75098
+ ] }),
75099
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
75100
+ "button",
75101
+ {
75102
+ type: "button",
75103
+ className: "sp-btn sp-conn-status-action",
75104
+ onClick: () => handleCancelTest(connection.id),
75105
+ children: "Cancel"
75106
+ }
75107
+ )
75108
+ ] });
74867
75109
  }
74868
75110
  if (!statusMsg) {
74869
75111
  return null;
@@ -74901,30 +75143,46 @@ const ConnectionsManager = () => {
74901
75143
  }
74902
75144
  );
74903
75145
  };
74904
- const renderConnectionForm = () => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail", children: [
75146
+ const renderConnectionForm = () => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-detail", children: [
74905
75147
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail-header", children: [
74906
75148
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
74907
75149
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-detail-kicker", children: "Add connection" }),
74908
- /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "sp-conn-detail-title", children: "New Connection" })
75150
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "sp-conn-detail-title", children: "New connection" })
74909
75151
  ] }),
74910
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "sp-btn", onClick: closeForm, "aria-label": "Back to connection details", children: "Back" })
75152
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "sp-btn", onClick: closeForm, "aria-label": "Cancel", children: "Cancel" })
74911
75153
  ] }),
74912
75154
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail-body", children: [
74913
75155
  renderToast(),
74914
75156
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-form-section", children: "Database Type" }),
74915
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-type-grid", children: connectors.map((c) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
74916
- "button",
74917
- {
74918
- type: "button",
74919
- className: `sp-conn-type-card${selectedType === c.id ? " selected" : ""}`,
74920
- onClick: () => setSelectedType(c.id),
74921
- children: [
74922
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-type-card-icon", children: CONNECTOR_ICONS[c.id] || "🔌" }),
74923
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-type-card-name", children: c.displayName || c.id })
74924
- ]
74925
- },
74926
- c.id
74927
- )) }),
75157
+ ["local", "server"].map((group) => {
75158
+ const groupConnectors = connectors.filter((c) => getConnectorGroup(c.id) === group);
75159
+ if (groupConnectors.length === 0) return null;
75160
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(React$2.Fragment, { children: [
75161
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-type-group-label", id: `sp-conn-type-group-${group}`, children: CONNECTOR_GROUP_LABELS[group] }),
75162
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
75163
+ "div",
75164
+ {
75165
+ className: "sp-conn-type-grid",
75166
+ role: "group",
75167
+ "aria-labelledby": `sp-conn-type-group-${group}`,
75168
+ children: groupConnectors.map((c) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
75169
+ "button",
75170
+ {
75171
+ type: "button",
75172
+ className: `sp-conn-type-card${selectedType === c.id ? " selected" : ""}`,
75173
+ onClick: () => setSelectedType(c.id),
75174
+ "aria-pressed": selectedType === c.id,
75175
+ children: [
75176
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-type-card-icon", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ConnectorGlyph, { type: c.id }) }),
75177
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-type-card-name", children: c.displayName || c.id })
75178
+ ]
75179
+ },
75180
+ c.id
75181
+ ))
75182
+ }
75183
+ )
75184
+ ] }, group);
75185
+ }),
74928
75186
  activeSchemaDef && activeFormSchema ? /* @__PURE__ */ jsxRuntimeExports.jsx(
74929
75187
  DynamicForm,
74930
75188
  {
@@ -74940,7 +75198,7 @@ const ConnectionsManager = () => {
74940
75198
  ] });
74941
75199
  const renderConnectionDetails = () => {
74942
75200
  if (!selectedConnection) {
74943
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-detail", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-empty sp-conn-empty-compact", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-empty-text", children: "Select a connection to view details, test it, or use it for queries." }) }) });
75201
+ return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-detail", children: /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-empty sp-conn-empty-compact", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-empty-text", children: "Select a connection to view details, test it, or use it for queries." }) }) });
74944
75202
  }
74945
75203
  const status = statuses[selectedConnection.id] || "unknown";
74946
75204
  const isActive = supportsActiveConnection && activeConnectionId === selectedConnection.id;
@@ -74987,7 +75245,7 @@ const ConnectionsManager = () => {
74987
75245
  ] })
74988
75246
  ] });
74989
75247
  };
74990
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail", children: [
75248
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-detail", children: [
74991
75249
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail-header", children: [
74992
75250
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
74993
75251
  /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-detail-kicker", children: "Connection settings" }),
@@ -75012,9 +75270,8 @@ const ConnectionsManager = () => {
75012
75270
  !selectedConnection.builtIn && /* @__PURE__ */ jsxRuntimeExports.jsx(
75013
75271
  "button",
75014
75272
  {
75015
- className: "sp-btn",
75273
+ className: "sp-btn sp-btn-ghost-danger",
75016
75274
  onClick: () => handleDeleteConnection(selectedConnection.id, selectedConnection.name),
75017
- style: { color: "var(--sp-error)" },
75018
75275
  "aria-label": `Delete connection ${selectedConnection.name}`,
75019
75276
  children: "Delete"
75020
75277
  }
@@ -75023,7 +75280,12 @@ const ConnectionsManager = () => {
75023
75280
  ] }),
75024
75281
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail-body", children: [
75025
75282
  renderToast(),
75026
- isActive && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-active-callout", role: "status", children: "Queries from SQL Preview and MCP will use this connection unless a query overrides it." }),
75283
+ isActive && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-callout", role: "status", children: [
75284
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-dot sp-dot-ok" }),
75285
+ "Queries from SQL Preview and MCP use ",
75286
+ /* @__PURE__ */ jsxRuntimeExports.jsx("b", { children: selectedConnection.name }),
75287
+ " unless a query overrides it."
75288
+ ] }),
75027
75289
  modeAwareEditSchema ? /* @__PURE__ */ jsxRuntimeExports.jsx(
75028
75290
  DynamicForm,
75029
75291
  {
@@ -75040,11 +75302,11 @@ const ConnectionsManager = () => {
75040
75302
  ] })
75041
75303
  ] });
75042
75304
  };
75043
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-page", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-workspace", children: [
75044
- /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "sp-conn-sidebar", "aria-label": "Connections list", children: [
75045
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-header", children: [
75046
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-title", children: "Connections" }),
75047
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", gap: 4 }, children: [
75305
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-page", children: [
75306
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn", children: [
75307
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-head", children: [
75308
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { children: "Connections" }),
75309
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-head-actions", children: [
75048
75310
  /* @__PURE__ */ jsxRuntimeExports.jsx(
75049
75311
  "button",
75050
75312
  {
@@ -75052,7 +75314,26 @@ const ConnectionsManager = () => {
75052
75314
  onClick: fetchData,
75053
75315
  disabled: isLoading,
75054
75316
  "aria-label": "Refresh connections",
75055
- children: "Refresh"
75317
+ title: "Refresh",
75318
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
75319
+ "svg",
75320
+ {
75321
+ width: "12",
75322
+ height: "12",
75323
+ viewBox: "0 0 16 16",
75324
+ fill: "none",
75325
+ xmlns: "http://www.w3.org/2000/svg",
75326
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
75327
+ "path",
75328
+ {
75329
+ fillRule: "evenodd",
75330
+ clipRule: "evenodd",
75331
+ d: "M13.627 7.25H15C14.7347 4.09068 12.1963 1.55227 9.03698 1.28698V2.66579C11.4398 2.9238 13.3638 4.84777 13.6218 7.25055L13.627 7.25ZM8.0004 0C3.58212 0 0.000396729 3.58172 0.000396729 8C0.000396729 12.4183 3.58212 16 8.0004 16C12.1643 16 15.5843 12.8124 15.9682 8.75H14.4532C14.0792 11.9772 11.3323 14.5 8.0004 14.5C4.41054 14.5 1.5004 11.5899 1.5004 8C1.5004 4.41015 4.41054 1.5 8.0004 1.5C9.72825 1.5 11.2982 2.17415 12.4578 3.27218L10.0004 5.75H15.5004V0.25L13.5186 2.23179C12.1158 0.849658 10.158 0 8.0004 0ZM2.37344 8.75C2.63873 11.9093 5.17714 14.4477 8.33644 14.713V13.3342C5.93366 13.0762 4.00969 11.1522 3.75168 8.74945L3.74646 8.75H2.37344Z",
75332
+ fill: "currentColor"
75333
+ }
75334
+ )
75335
+ }
75336
+ )
75056
75337
  }
75057
75338
  ),
75058
75339
  /* @__PURE__ */ jsxRuntimeExports.jsx(
@@ -75066,60 +75347,119 @@ const ConnectionsManager = () => {
75066
75347
  )
75067
75348
  ] })
75068
75349
  ] }),
75069
- isLoading && connections.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-loading", style: { padding: 32 }, children: [
75070
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-spinner sp-spinner-lg" }),
75071
- /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "Loading connections…" })
75072
- ] }) : connections.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-empty", children: [
75073
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-empty-text", children: "No connections configured yet." }),
75074
- /* @__PURE__ */ jsxRuntimeExports.jsx(
75075
- "button",
75076
- {
75077
- className: "sp-btn sp-btn-primary",
75078
- onClick: openAddForm,
75079
- "aria-label": "Add new connection",
75080
- children: "Add your first connection"
75081
- }
75082
- )
75083
- ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-list", children: connections.map((c) => {
75084
- const status = statuses[c.id] || "unknown";
75085
- const statusMsg = statusMessages[c.id] || "";
75086
- const isActive = supportsActiveConnection && activeConnectionId === c.id;
75087
- const isSelected = selectedConnectionId === c.id && !isFormOpen;
75088
- return /* @__PURE__ */ jsxRuntimeExports.jsxs(
75350
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-switcher-wrap", ref: switcherWrapRef, children: [
75351
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
75089
75352
  "button",
75090
75353
  {
75091
- type: "button",
75092
- className: `sp-conn-item${isActive ? " sp-conn-item-active" : ""}${isSelected ? " sp-conn-item-selected" : ""}`,
75093
- onClick: () => {
75094
- setSelectedConnectionId(c.id);
75095
- closeForm();
75096
- setToast(null);
75097
- },
75098
- "aria-pressed": isSelected,
75354
+ className: "sp-switcher",
75355
+ "aria-expanded": isPopoverOpen,
75356
+ onClick: () => setIsPopoverOpen((v) => !v),
75099
75357
  children: [
75358
+ selectedConnection ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
75359
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
75360
+ "div",
75361
+ {
75362
+ className: `sp-dot ${statuses[selectedConnection.id] === "ok" ? "sp-dot-ok" : statuses[selectedConnection.id] === "error" ? "sp-dot-error" : statuses[selectedConnection.id] === "testing" ? "sp-dot-testing" : "sp-dot-unknown"}`
75363
+ }
75364
+ ),
75365
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-grow", children: [
75366
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-sw-name", children: selectedConnection.name }),
75367
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-badge", children: selectedConnection.type.toUpperCase() }),
75368
+ supportsActiveConnection && activeConnectionId === selectedConnection.id && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-pill", children: "Active for queries" })
75369
+ ] })
75370
+ ] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-grow", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-sw-name", children: "No connection selected" }) }),
75100
75371
  /* @__PURE__ */ jsxRuntimeExports.jsx(
75101
- "div",
75372
+ "svg",
75102
75373
  {
75103
- className: `sp-conn-status sp-conn-status-${status}`,
75104
- title: statusMsg || (status === "unknown" ? "Not tested" : status)
75374
+ className: "sp-chev",
75375
+ width: "16",
75376
+ height: "16",
75377
+ viewBox: "0 0 16 16",
75378
+ fill: "none",
75379
+ xmlns: "http://www.w3.org/2000/svg",
75380
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(
75381
+ "path",
75382
+ {
75383
+ d: "M4.29303 5.29289C4.68355 4.90237 5.31672 4.90237 5.70724 5.29289L8.00014 7.58579L10.293 5.29289C10.6836 4.90237 11.3167 4.90237 11.7072 5.29289C12.0978 5.68342 12.0978 6.31658 11.7072 6.70711L8.70724 9.70711C8.31672 10.0976 7.68355 10.0976 7.29303 9.70711L4.29303 6.70711C3.90251 6.31658 3.90251 5.68342 4.29303 5.29289Z",
75384
+ fill: "currentColor"
75385
+ }
75386
+ )
75105
75387
  }
75106
- ),
75107
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-item-info", children: [
75108
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-item-name", children: c.name }),
75109
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-item-meta", children: [
75110
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-type-badge", children: c.type }),
75111
- isActive && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-active-badge", children: "Active for queries" }),
75112
- c.builtIn && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-built-in-label", children: "Built-in" })
75113
- ] })
75114
- ] })
75388
+ )
75115
75389
  ]
75116
- },
75117
- c.id
75118
- );
75119
- }) })
75390
+ }
75391
+ ),
75392
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `sp-popover ${isPopoverOpen ? "open" : ""}`, children: [
75393
+ connections.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { padding: "8px 10px", color: "var(--sp-muted-fg)" }, children: "No connections configured." }) : connections.map((c) => {
75394
+ const status = statuses[c.id] || "unknown";
75395
+ const isActive = supportsActiveConnection && activeConnectionId === c.id;
75396
+ const isSelected = selectedConnectionId === c.id && !isFormOpen;
75397
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
75398
+ "button",
75399
+ {
75400
+ type: "button",
75401
+ className: "sp-pop-row",
75402
+ "aria-current": isSelected,
75403
+ onClick: () => {
75404
+ setSelectedConnectionId(c.id);
75405
+ closeForm();
75406
+ setIsPopoverOpen(false);
75407
+ setToast(null);
75408
+ },
75409
+ children: [
75410
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
75411
+ "div",
75412
+ {
75413
+ className: `sp-dot ${status === "ok" ? "sp-dot-ok" : status === "error" ? "sp-dot-error" : status === "testing" ? "sp-dot-testing" : "sp-dot-unknown"}`
75414
+ }
75415
+ ),
75416
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-grow", children: [
75417
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-nm", children: c.name }),
75418
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-badge", children: c.type.toUpperCase() }),
75419
+ isActive && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-pill", children: "Active" }),
75420
+ c.builtIn && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-tag-builtin", children: "Built-in" })
75421
+ ] }),
75422
+ isSelected && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-pop-check", children: "✓" })
75423
+ ]
75424
+ },
75425
+ c.id
75426
+ );
75427
+ }),
75428
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-pop-sep" }),
75429
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
75430
+ "button",
75431
+ {
75432
+ type: "button",
75433
+ className: "sp-pop-row sp-pop-add",
75434
+ onClick: () => {
75435
+ openAddForm();
75436
+ setIsPopoverOpen(false);
75437
+ },
75438
+ children: [
75439
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-plus", children: "+" }),
75440
+ " Add connection"
75441
+ ]
75442
+ }
75443
+ )
75444
+ ] })
75445
+ ] }),
75446
+ /* @__PURE__ */ jsxRuntimeExports.jsx("section", { "aria-label": "Connection details", children: isFormOpen ? renderConnectionForm() : renderConnectionDetails() })
75120
75447
  ] }),
75121
- /* @__PURE__ */ jsxRuntimeExports.jsx("section", { "aria-label": "Connection details", children: isFormOpen ? renderConnectionForm() : renderConnectionDetails() })
75122
- ] }) });
75448
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
75449
+ ConfirmDialog,
75450
+ {
75451
+ open: pendingConfirm !== null,
75452
+ title: (pendingConfirm == null ? void 0 : pendingConfirm.title) ?? "Confirm",
75453
+ message: (pendingConfirm == null ? void 0 : pendingConfirm.message) ?? "",
75454
+ confirmLabel: (pendingConfirm == null ? void 0 : pendingConfirm.confirmLabel) ?? "Confirm",
75455
+ onConfirm: () => {
75456
+ pendingConfirm == null ? void 0 : pendingConfirm.onConfirm();
75457
+ setPendingConfirm(null);
75458
+ },
75459
+ onCancel: () => setPendingConfirm(null)
75460
+ }
75461
+ )
75462
+ ] });
75123
75463
  };
75124
75464
  function extractQueryResult(rawData) {
75125
75465
  if (!rawData || typeof rawData !== "object") return null;
@@ -75355,7 +75695,7 @@ function App() {
75355
75695
  },
75356
75696
  title: "Close tab",
75357
75697
  "aria-label": "Close tab",
75358
- children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { width: "10", height: "10", viewBox: "0 0 16 16", fill: "currentColor", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M8 8.707l3.646 3.647.708-.707L8.707 8l3.647-3.646-.707-.708L8 7.293 4.354 3.646l-.708.708L7.293 8l-3.647 3.646.708.707L8 8.707z" }) })
75698
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(CloseIcon, { size: 10 })
75359
75699
  }
75360
75700
  )
75361
75701
  ]
@@ -75365,7 +75705,7 @@ function App() {
75365
75705
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-content", children: [
75366
75706
  error && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-error-bar", children: [
75367
75707
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: error }),
75368
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => updateTab(activeTab.id, { error: null }), "aria-label": "Close error message", children: "✕" })
75708
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => updateTab(activeTab.id, { error: null }), "aria-label": "Close error message", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CloseIcon, { size: 14 }) })
75369
75709
  ] }),
75370
75710
  activeView === "query" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
75371
75711
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-result-header", children: [
@@ -96795,6 +97135,20 @@ body.light-theme .ag-theme-quartz {
96795
97135
  }
96796
97136
  /* src/ui/core/tokens.css — design tokens + shared component styles */
96797
97137
 
97138
+ /* ── Accessibility utilities ─────────────────────────────────── */
97139
+ /* Standard visually-hidden pattern: present to assistive tech, invisible on screen. */
97140
+ .sp-visually-hidden {
97141
+ position: absolute;
97142
+ width: 1px;
97143
+ height: 1px;
97144
+ padding: 0;
97145
+ margin: -1px;
97146
+ overflow: hidden;
97147
+ clip: rect(0, 0, 0, 0);
97148
+ white-space: nowrap;
97149
+ border: 0;
97150
+ }
97151
+
96798
97152
  /* ── Tokens ────────────────────────────────────────────────── */
96799
97153
  :root {
96800
97154
  --sp-bg: var(--vscode-editor-background, #ffffff);
@@ -96828,8 +97182,15 @@ body.light-theme .ag-theme-quartz {
96828
97182
  --sp-selection-bg: var(--vscode-editor-selectionBackground, rgba(38, 79, 120, 0.7));
96829
97183
  --sp-hover-bg: var(--vscode-list-hoverBackground, rgba(255, 255, 255, 0.07));
96830
97184
 
97185
+ /* Modal backdrop scrim — only for elements that truly float above the page (native <dialog>). */
97186
+ --sp-backdrop: rgba(0, 0, 0, 0.5);
97187
+
96831
97188
  --sp-focus-border: var(--vscode-focusBorder, #007acc);
96832
97189
  --sp-error: var(--vscode-errorForeground, #a1260d);
97190
+ /* Solid destructive fill — dark enough in both themes to carry the button foreground,
97191
+ unlike --sp-error whose dark value (salmon) is a text color, not a fill. */
97192
+ --sp-btn-danger-bg: var(--vscode-statusBarItem-errorBackground, #a1260d);
97193
+ --sp-btn-danger-fg: var(--vscode-statusBarItem-errorForeground, #ffffff);
96833
97194
  --sp-success: var(--vscode-charts-green, #107c10);
96834
97195
  --sp-warning: var(--vscode-charts-yellow, #ca8a04);
96835
97196
 
@@ -97001,6 +97362,10 @@ body {
97001
97362
  border-bottom-color: var(--sp-tab-border);
97002
97363
  background: var(--sp-tab-active-bg, var(--sp-bg));
97003
97364
  }
97365
+ .sp-tab:focus-visible {
97366
+ outline: 2px solid var(--sp-focus-border);
97367
+ outline-offset: -2px;
97368
+ }
97004
97369
 
97005
97370
  .sp-tab-label {
97006
97371
  font-size: 12px;
@@ -97029,6 +97394,11 @@ body {
97029
97394
  .sp-tab.active .sp-tab-close {
97030
97395
  opacity: 0.6;
97031
97396
  }
97397
+ .sp-tab-close:focus-visible {
97398
+ opacity: 1;
97399
+ outline: 2px solid var(--sp-focus-border);
97400
+ outline-offset: 1px;
97401
+ }
97032
97402
  .sp-tab-close:hover {
97033
97403
  opacity: 1 !important;
97034
97404
  background: var(--sp-hover-bg);
@@ -97049,7 +97419,7 @@ body {
97049
97419
  align-items: center;
97050
97420
  justify-content: space-between;
97051
97421
  padding: 6px 12px;
97052
- background: rgba(161, 38, 13, 0.1);
97422
+ background: color-mix(in srgb, var(--sp-error) 10%, transparent);
97053
97423
  border-bottom: 1px solid var(--sp-error);
97054
97424
  color: var(--sp-error);
97055
97425
  font-size: 12px;
@@ -97085,7 +97455,7 @@ body {
97085
97455
  align-items: flex-start;
97086
97456
  gap: 10px;
97087
97457
  padding: 10px 12px;
97088
- background: rgba(202, 138, 4, 0.12);
97458
+ background: color-mix(in srgb, var(--sp-warning) 12%, transparent);
97089
97459
  border-bottom: 1px solid var(--sp-warning);
97090
97460
  color: var(--sp-warning);
97091
97461
  flex-shrink: 0;
@@ -97106,6 +97476,33 @@ body {
97106
97476
  opacity: 1;
97107
97477
  }
97108
97478
 
97479
+ /* Cancelled notice — user-initiated outcome, so neutral surface tones, not status color. */
97480
+ .sp-cancelled-bar {
97481
+ display: flex;
97482
+ align-items: center;
97483
+ justify-content: space-between;
97484
+ padding: 6px 12px;
97485
+ background: var(--sp-header-bg);
97486
+ border-bottom: 1px solid var(--sp-border);
97487
+ color: var(--sp-muted-fg);
97488
+ font-size: 12px;
97489
+ flex-shrink: 0;
97490
+ gap: 8px;
97491
+ }
97492
+ .sp-cancelled-bar button {
97493
+ background: none;
97494
+ border: none;
97495
+ cursor: pointer;
97496
+ color: currentColor;
97497
+ font-size: 14px;
97498
+ flex-shrink: 0;
97499
+ padding: 0 2px;
97500
+ opacity: 0.8;
97501
+ }
97502
+ .sp-cancelled-bar button:hover {
97503
+ opacity: 1;
97504
+ }
97505
+
97109
97506
  /* ── Result header ─────────────────────────────────────────── */
97110
97507
  .sp-result-header {
97111
97508
  display: flex;
@@ -97165,14 +97562,14 @@ body {
97165
97562
  cursor: pointer;
97166
97563
  border: none;
97167
97564
  border-radius: var(--sp-radius);
97168
- background: var(--sp-btn-sec-bg, #3a3d41);
97169
- color: var(--sp-btn-sec-fg, #cccccc);
97565
+ background: var(--sp-btn-sec-bg);
97566
+ color: var(--sp-btn-sec-fg);
97170
97567
  white-space: nowrap;
97171
97568
  transition: background 0.1s;
97172
97569
  line-height: 1.4;
97173
97570
  }
97174
97571
  .sp-btn:hover:not(:disabled) {
97175
- background: var(--sp-btn-sec-hover, #45494e);
97572
+ background: var(--sp-btn-sec-hover);
97176
97573
  }
97177
97574
  .sp-btn:disabled {
97178
97575
  opacity: 0.4;
@@ -97188,6 +97585,54 @@ body {
97188
97585
  background: var(--sp-btn-hover);
97189
97586
  }
97190
97587
 
97588
+ .sp-btn-danger {
97589
+ background: var(--sp-btn-danger-bg);
97590
+ color: var(--sp-btn-danger-fg);
97591
+ font-weight: 500;
97592
+ }
97593
+ .sp-btn-danger:hover:not(:disabled) {
97594
+ background: color-mix(in srgb, var(--sp-btn-danger-bg) 85%, black);
97595
+ }
97596
+ /* Quiet destructive action outside confirm moments: derived error tints, no solid fill. */
97597
+ .sp-btn-ghost-danger {
97598
+ background: color-mix(in srgb, var(--sp-error) 10%, transparent);
97599
+ border: 1px solid color-mix(in srgb, var(--sp-error) 55%, transparent);
97600
+ color: var(--sp-error);
97601
+ }
97602
+ .sp-btn-ghost-danger:hover:not(:disabled) {
97603
+ background: color-mix(in srgb, var(--sp-error) 18%, transparent);
97604
+ }
97605
+
97606
+ /* ── Confirm dialog (themed replacement for window.confirm) ─── */
97607
+ .sp-confirm-dialog {
97608
+ width: min(90vw, 26rem);
97609
+ padding: 16px;
97610
+ border: 1px solid var(--sp-border);
97611
+ border-radius: var(--sp-radius);
97612
+ background: var(--sp-header-bg, var(--sp-bg));
97613
+ color: var(--sp-fg);
97614
+ font-family: var(--sp-font);
97615
+ }
97616
+ .sp-confirm-dialog::backdrop {
97617
+ background: var(--sp-backdrop);
97618
+ }
97619
+ .sp-confirm-dialog-title {
97620
+ margin: 0 0 6px;
97621
+ font-size: 13px;
97622
+ font-weight: 600;
97623
+ }
97624
+ .sp-confirm-dialog-message {
97625
+ margin: 0 0 16px;
97626
+ color: var(--sp-muted-fg);
97627
+ font-size: 12px;
97628
+ line-height: 1.5;
97629
+ }
97630
+ .sp-confirm-dialog-actions {
97631
+ display: flex;
97632
+ justify-content: flex-end;
97633
+ gap: 8px;
97634
+ }
97635
+
97191
97636
  /* ── Icon-only button (shared by density, side panel, etc.) ── */
97192
97637
  .sp-icon-btn {
97193
97638
  display: inline-flex;
@@ -97241,6 +97686,11 @@ body {
97241
97686
  .sp-loading p {
97242
97687
  margin: 0;
97243
97688
  }
97689
+ /* Live elapsed readout; tabular digits so the count-up doesn't jitter horizontally. */
97690
+ .sp-loading-elapsed {
97691
+ margin-left: 6px;
97692
+ font-variant-numeric: tabular-nums;
97693
+ }
97244
97694
 
97245
97695
  /* ── Empty state ───────────────────────────────────────────── */
97246
97696
  .sp-empty {
@@ -97364,7 +97814,7 @@ body {
97364
97814
  min-height: 22px;
97365
97815
  padding: 3px 7px;
97366
97816
  border: 1px solid var(--sp-border);
97367
- border-radius: 4px;
97817
+ border-radius: var(--sp-radius);
97368
97818
  background: color-mix(in srgb, var(--sp-header-bg) 82%, transparent);
97369
97819
  box-sizing: border-box;
97370
97820
  color: var(--sp-muted-fg);
@@ -97714,6 +98164,37 @@ body.vscode-high-contrast .ag-theme-quartz {
97714
98164
  opacity: 0.9;
97715
98165
  }
97716
98166
 
98167
+ /* ── Tab provenance badge (client type, shown in "All Sessions" view) ──── */
98168
+ .sp-tab-provenance {
98169
+ font-size: 10px;
98170
+ font-weight: 600;
98171
+ letter-spacing: 0.02em;
98172
+ text-transform: uppercase;
98173
+ color: var(--sp-muted-fg);
98174
+ background: var(--sp-badge-bg);
98175
+ border-radius: 3px;
98176
+ padding: 1px 5px;
98177
+ white-space: nowrap;
98178
+ cursor: default;
98179
+ }
98180
+
98181
+ /* ── MCP trust indicator ──────────────────────────────────── */
98182
+ .sp-trust-badge {
98183
+ font-size: 11px;
98184
+ font-weight: 600;
98185
+ border: 1px solid currentColor;
98186
+ border-radius: var(--sp-radius);
98187
+ padding: 2px 8px;
98188
+ white-space: nowrap;
98189
+ cursor: default;
98190
+ }
98191
+ .sp-trust-badge.safe {
98192
+ color: var(--sp-success);
98193
+ }
98194
+ .sp-trust-badge.unrestricted {
98195
+ color: var(--sp-warning);
98196
+ }
98197
+
97717
98198
  /* ── Tab context menu ──────────────────────────────────────── */
97718
98199
  .sp-ctx-menu {
97719
98200
  position: fixed;
@@ -98024,6 +98505,11 @@ body.vscode-high-contrast .ag-theme-quartz {
98024
98505
  grid-template-columns: minmax(360px, 520px) 1fr;
98025
98506
  align-items: start;
98026
98507
  gap: 22px;
98508
+ /* The preview column's own content caps out well short of 1fr (see PREVIEW_MAX_WIDTH in
98509
+ SettingsPanel.tsx) — without a matching cap here, a wide standalone browser tab stretches
98510
+ this grid edge-to-edge and leaves a dead gap beside the preview instead of using that width. */
98511
+ max-width: 1080px;
98512
+ margin-inline: auto;
98027
98513
  }
98028
98514
 
98029
98515
  .sp-settings-main {
@@ -98305,6 +98791,11 @@ body.vscode-high-contrast .ag-theme-quartz {
98305
98791
  color: var(--sp-warning);
98306
98792
  }
98307
98793
 
98794
+ /* In-progress MCP test — amber, matching the testing vocabulary elsewhere. */
98795
+ .sp-settings-status.testing {
98796
+ color: var(--sp-warning);
98797
+ }
98798
+
98308
98799
  .sp-settings-status.error {
98309
98800
  color: var(--sp-error);
98310
98801
  }
@@ -98336,6 +98827,15 @@ body.vscode-high-contrast .ag-theme-quartz {
98336
98827
  border-bottom: 1px solid var(--sp-border);
98337
98828
  }
98338
98829
 
98830
+ /* Label + copy affordance for snippets the user pastes into an external client. */
98831
+ .sp-settings-guide-section-header {
98832
+ display: flex;
98833
+ align-items: center;
98834
+ justify-content: space-between;
98835
+ gap: 8px;
98836
+ margin-bottom: 4px;
98837
+ }
98838
+
98339
98839
  .sp-settings-guide-section:last-child {
98340
98840
  border-bottom: none;
98341
98841
  }
@@ -98473,7 +98973,10 @@ body.vscode-high-contrast .ag-theme-quartz {
98473
98973
  display: flex;
98474
98974
  flex-direction: column;
98475
98975
  gap: 12px;
98476
- max-width: none;
98976
+ /* Same cap as .sp-settings-layout — otherwise the connection form stretches edge-to-edge
98977
+ of a wide standalone browser tab instead of staying a dense, disciplined width. */
98978
+ max-width: 1080px;
98979
+ margin-inline: auto;
98477
98980
  min-height: 0;
98478
98981
  }
98479
98982
 
@@ -98499,36 +99002,250 @@ body.vscode-high-contrast .ag-theme-quartz {
98499
99002
  overflow: hidden;
98500
99003
  }
98501
99004
 
98502
- .sp-conn-detail-header {
99005
+ .sp-conn-head {
98503
99006
  display: flex;
98504
- align-items: flex-start;
99007
+ align-items: center;
98505
99008
  justify-content: space-between;
98506
- gap: 12px;
98507
- padding: 14px;
99009
+ gap: 10px;
99010
+ }
99011
+
99012
+ .sp-conn-head h2 {
99013
+ margin: 0;
99014
+ font-size: 13px;
99015
+ font-weight: 600;
99016
+ }
99017
+
99018
+ .sp-head-actions {
99019
+ display: flex;
99020
+ align-items: center;
99021
+ gap: 6px;
99022
+ }
99023
+
99024
+ .sp-switcher-wrap {
99025
+ position: relative;
99026
+ }
99027
+
99028
+ .sp-switcher {
99029
+ width: 100%;
99030
+ display: flex;
99031
+ align-items: center;
99032
+ gap: 10px;
99033
+ padding: 10px 12px;
98508
99034
  background: var(--sp-header-bg);
98509
- border-bottom: 1px solid var(--sp-border);
99035
+ border: 1px solid var(--sp-border);
99036
+ border-radius: var(--sp-radius);
99037
+ color: var(--sp-fg);
99038
+ font: inherit;
99039
+ cursor: pointer;
99040
+ text-align: left;
99041
+ transition: border-color 0.1s ease, background 0.1s ease;
99042
+ }
99043
+
99044
+ .sp-switcher:hover {
99045
+ border-color: var(--sp-muted-fg);
99046
+ }
99047
+
99048
+ .sp-switcher[aria-expanded="true"] {
99049
+ border-color: var(--sp-focus-border);
99050
+ }
99051
+
99052
+ .sp-switcher .sp-sw-name {
99053
+ font-weight: 600;
99054
+ font-size: 13px;
99055
+ }
99056
+
99057
+ .sp-switcher .sp-grow {
99058
+ flex: 1;
99059
+ min-width: 0;
99060
+ display: flex;
99061
+ align-items: center;
99062
+ gap: 8px;
99063
+ overflow: hidden;
99064
+ }
99065
+
99066
+ .sp-switcher .sp-chev {
99067
+ color: var(--sp-muted-fg);
99068
+ transition: transform 0.15s ease;
99069
+ flex-shrink: 0;
99070
+ }
99071
+
99072
+ .sp-switcher[aria-expanded="true"] .sp-chev {
99073
+ transform: rotate(180deg);
99074
+ }
99075
+
99076
+ .sp-dot {
99077
+ width: 8px;
99078
+ height: 8px;
99079
+ border-radius: 50%;
99080
+ flex-shrink: 0;
99081
+ }
99082
+
99083
+ .sp-dot-ok {
99084
+ background: var(--sp-success);
99085
+ }
99086
+
99087
+ .sp-dot-error {
99088
+ background: var(--sp-error);
99089
+ }
99090
+
99091
+ .sp-dot-unknown,
99092
+ .sp-dot-testing {
99093
+ background: var(--sp-border);
99094
+ box-shadow: inset 0 0 0 1px var(--sp-muted-fg);
99095
+ }
99096
+
99097
+ .sp-dot-testing {
99098
+ animation: pulse-border 1.5s infinite;
98510
99099
  }
98511
99100
 
98512
- .sp-conn-detail-kicker {
99101
+ .sp-badge {
99102
+ font-size: 10px;
99103
+ font-weight: 600;
99104
+ letter-spacing: 0.04em;
99105
+ padding: 1px 6px;
99106
+ border-radius: 2px;
99107
+ background: var(--sp-bg);
99108
+ border: 1px solid var(--sp-border);
98513
99109
  color: var(--sp-muted-fg);
99110
+ white-space: nowrap;
99111
+ flex-shrink: 0;
99112
+ }
99113
+
99114
+ .sp-pill {
98514
99115
  font-size: 10px;
98515
99116
  font-weight: 700;
98516
- letter-spacing: 0.06em;
98517
- text-transform: uppercase;
99117
+ padding: 1px 7px;
99118
+ border-radius: 999px;
99119
+ background: var(--sp-success);
99120
+ color: var(--sp-bg);
99121
+ white-space: nowrap;
99122
+ flex-shrink: 0;
99123
+ }
99124
+
99125
+ .sp-tag-builtin {
99126
+ font-size: 10px;
99127
+ color: var(--sp-muted-fg);
99128
+ font-weight: 500;
99129
+ white-space: nowrap;
99130
+ }
99131
+
99132
+ .sp-popover {
99133
+ position: absolute;
99134
+ top: calc(100% + 4px);
99135
+ left: 0;
99136
+ width: 100%;
99137
+ z-index: 50;
99138
+ background: var(--sp-bg);
99139
+ border: 1px solid var(--sp-border);
99140
+ border-radius: var(--sp-radius);
99141
+ box-shadow: var(--sp-shadow, 0 6px 18px rgba(0, 0, 0, 0.18), 0 1px 4px rgba(0, 0, 0, 0.10));
99142
+ padding: 4px;
99143
+ display: none;
99144
+ transform-origin: top center;
99145
+ }
99146
+
99147
+ .vscode-dark .sp-popover {
99148
+ box-shadow: var(--sp-shadow, 0 6px 18px rgba(0, 0, 0, 0.45), 0 1px 4px rgba(0, 0, 0, 0.30));
98518
99149
  }
98519
99150
 
98520
- .sp-conn-detail-title {
98521
- margin: 3px 0 6px;
99151
+ .sp-popover.open {
99152
+ display: block;
99153
+ animation: pop 0.12s ease-out;
99154
+ }
99155
+
99156
+ @keyframes pop {
99157
+ from { opacity: 0; transform: translateY(-4px) scale(0.99); }
99158
+ to { opacity: 1; transform: none; }
99159
+ }
99160
+
99161
+ .sp-pop-row {
99162
+ width: 100%;
99163
+ display: flex;
99164
+ align-items: center;
99165
+ gap: 10px;
99166
+ padding: 8px 10px;
99167
+ background: transparent;
99168
+ border: none;
99169
+ border-radius: 2px;
98522
99170
  color: var(--sp-fg);
98523
- font-size: 15px;
98524
- line-height: 1.3;
99171
+ font: inherit;
99172
+ text-align: left;
99173
+ cursor: pointer;
98525
99174
  }
98526
99175
 
98527
- .sp-conn-detail-actions {
99176
+ .sp-pop-row:hover {
99177
+ background: var(--sp-hover-bg);
99178
+ }
99179
+
99180
+ .sp-pop-row[aria-current="true"] {
99181
+ background: var(--sp-selection-bg);
99182
+ }
99183
+
99184
+ .sp-pop-row .sp-grow {
99185
+ flex: 1;
99186
+ min-width: 0;
98528
99187
  display: flex;
98529
- flex-wrap: wrap;
98530
- justify-content: flex-end;
98531
- gap: 6px;
99188
+ align-items: center;
99189
+ gap: 8px;
99190
+ overflow: hidden;
99191
+ }
99192
+
99193
+ .sp-pop-row .sp-nm {
99194
+ font-weight: 600;
99195
+ overflow: hidden;
99196
+ text-overflow: ellipsis;
99197
+ white-space: nowrap;
99198
+ }
99199
+
99200
+ .sp-pop-check {
99201
+ color: var(--sp-focus-border);
99202
+ font-size: 12px;
99203
+ flex-shrink: 0;
99204
+ }
99205
+
99206
+ .sp-pop-sep {
99207
+ height: 1px;
99208
+ background: var(--sp-border);
99209
+ margin: 4px 2px;
99210
+ }
99211
+
99212
+ .sp-pop-add {
99213
+ color: var(--sp-focus-border);
99214
+ font-weight: 600;
99215
+ }
99216
+
99217
+ .sp-pop-add .sp-plus {
99218
+ font-size: 14px;
99219
+ }
99220
+
99221
+ .sp-callout {
99222
+ display: flex;
99223
+ align-items: center;
99224
+ gap: 9px;
99225
+ padding: 9px 12px;
99226
+ border: 1px solid color-mix(in srgb, var(--sp-success) 30%, var(--sp-border));
99227
+ border-radius: var(--sp-radius);
99228
+ color: var(--sp-fg);
99229
+ background: color-mix(in srgb, var(--sp-success) 8%, transparent);
99230
+ font-size: 12px;
99231
+ line-height: 1.4;
99232
+ }
99233
+
99234
+ .sp-callout b {
99235
+ font-weight: 600;
99236
+ }
99237
+
99238
+ .sp-detail {
99239
+ display: flex;
99240
+ flex-direction: column;
99241
+ gap: 16px;
99242
+ }
99243
+
99244
+ .sp-detail .sp-conn-detail-header {
99245
+ display: flex;
99246
+ align-items: flex-start;
99247
+ justify-content: space-between;
99248
+ gap: 12px;
98532
99249
  }
98533
99250
 
98534
99251
  .sp-conn-detail-body {
@@ -98585,18 +99302,13 @@ body.vscode-high-contrast .ag-theme-quartz {
98585
99302
  outline: 1px solid var(--sp-focus-border);
98586
99303
  outline-offset: -1px;
98587
99304
  }
99305
+ /* Active-for-queries: tonal selection background; the green "Active" badge carries the state. */
98588
99306
  .sp-conn-item-active {
98589
99307
  background: var(--sp-selection-bg);
98590
- box-shadow: inset 4px 0 0 var(--sp-success);
98591
99308
  }
99309
+ /* Currently viewed: full selection ring (DESIGN.md ring vocabulary), not an edge stripe. */
98592
99310
  .sp-conn-item-selected {
98593
- box-shadow: inset 2px 0 0 var(--sp-btn-bg);
98594
- }
98595
-
98596
- .sp-conn-item-active.sp-conn-item-selected {
98597
- box-shadow:
98598
- inset 4px 0 0 var(--sp-success),
98599
- inset 0 0 0 1px var(--sp-btn-bg);
99311
+ box-shadow: inset 0 0 0 1px var(--sp-btn-bg);
98600
99312
  }
98601
99313
 
98602
99314
  .sp-conn-item-info {
@@ -98681,9 +99393,11 @@ body.vscode-high-contrast .ag-theme-quartz {
98681
99393
  align-self: flex-start;
98682
99394
  }
98683
99395
 
99396
+ /* Neutral provenance descriptor, not a status — muted keeps success-green meaning
99397
+ "connection OK / active" only (DESIGN.md: status color is semantic, never decorative). */
98684
99398
  .sp-conn-built-in-label {
98685
99399
  font-size: 10px;
98686
- color: var(--sp-success);
99400
+ color: var(--sp-muted-fg);
98687
99401
  font-weight: 500;
98688
99402
  white-space: nowrap;
98689
99403
  }
@@ -98741,7 +99455,21 @@ body.vscode-high-contrast .ag-theme-quartz {
98741
99455
  gap: 10px;
98742
99456
  color: var(--sp-warning);
98743
99457
  border-color: var(--sp-warning);
98744
- background: rgba(202, 138, 4, 0.12);
99458
+ background: color-mix(in srgb, var(--sp-warning) 12%, transparent);
99459
+ }
99460
+
99461
+ .sp-conn-status-message-testing {
99462
+ display: flex;
99463
+ align-items: center;
99464
+ justify-content: space-between;
99465
+ gap: 10px;
99466
+ }
99467
+
99468
+ /* Tabular digits so the count-up doesn't jitter horizontally. */
99469
+ .sp-conn-test-elapsed {
99470
+ margin-left: 4px;
99471
+ font-variant-numeric: tabular-nums;
99472
+ color: var(--sp-muted-fg);
98745
99473
  }
98746
99474
 
98747
99475
  .sp-conn-warning-content {
@@ -98844,6 +99572,27 @@ body.vscode-high-contrast .ag-theme-quartz {
98844
99572
  .sp-conn-type-card-icon {
98845
99573
  font-size: 22px;
98846
99574
  line-height: 1;
99575
+ color: var(--sp-muted-fg);
99576
+ }
99577
+ /* Glyphs inherit the icon slot's font-size so the whole picker rescales with the editor font. */
99578
+ .sp-conn-type-card-icon .sp-connector-glyph {
99579
+ display: block;
99580
+ width: 1em;
99581
+ height: 1em;
99582
+ }
99583
+ .sp-conn-type-card:hover .sp-conn-type-card-icon,
99584
+ .sp-conn-type-card.selected .sp-conn-type-card-icon {
99585
+ color: var(--sp-fg);
99586
+ }
99587
+
99588
+ .sp-conn-type-group-label {
99589
+ font-size: 11px;
99590
+ font-weight: 600;
99591
+ color: var(--sp-muted-fg);
99592
+ margin: 10px 0 6px;
99593
+ }
99594
+ .sp-conn-type-group-label:first-of-type {
99595
+ margin-top: 0;
98847
99596
  }
98848
99597
 
98849
99598
  /* ── Connection form ─────────────────────────────────────── */
@@ -98861,7 +99610,7 @@ body.vscode-high-contrast .ag-theme-quartz {
98861
99610
  }
98862
99611
 
98863
99612
  .sp-conn-form-field {
98864
- grid-column: span 6;
99613
+ grid-column: 1 / -1;
98865
99614
  min-width: 0;
98866
99615
  }
98867
99616
 
@@ -98871,6 +99620,12 @@ body.vscode-high-contrast .ag-theme-quartz {
98871
99620
  grid-column: 1 / -1;
98872
99621
  }
98873
99622
 
99623
+ .sp-conn-form-field-catalog,
99624
+ .sp-conn-form-field-schema,
99625
+ .sp-conn-form-field-source {
99626
+ grid-column: span 6;
99627
+ }
99628
+
98874
99629
  .sp-conn-form-field-host {
98875
99630
  grid-column: span 8;
98876
99631
  }
@@ -99041,20 +99796,26 @@ body.vscode-high-contrast .ag-theme-quartz {
99041
99796
  border: 1px solid transparent;
99042
99797
  }
99043
99798
  .sp-conn-toast-success {
99044
- background: rgba(16, 124, 16, 0.08);
99799
+ background: color-mix(in srgb, var(--sp-success) 8%, transparent);
99045
99800
  border-color: var(--sp-success);
99046
99801
  color: var(--sp-success);
99047
99802
  }
99048
99803
  .sp-conn-toast-error {
99049
- background: rgba(161, 38, 13, 0.08);
99804
+ background: color-mix(in srgb, var(--sp-error) 8%, transparent);
99050
99805
  border-color: var(--sp-error);
99051
99806
  color: var(--sp-error);
99052
99807
  }
99053
99808
  .sp-conn-toast-warning {
99054
- background: rgba(202, 138, 4, 0.12);
99809
+ background: color-mix(in srgb, var(--sp-warning) 12%, transparent);
99055
99810
  border-color: var(--sp-warning);
99056
99811
  color: var(--sp-warning);
99057
99812
  }
99813
+ /* In-progress test — amber like the connection list's testing dots, distinct from a warning outcome. */
99814
+ .sp-conn-toast-testing {
99815
+ background: color-mix(in srgb, var(--sp-warning) 8%, transparent);
99816
+ border-color: color-mix(in srgb, var(--sp-warning) 55%, transparent);
99817
+ color: var(--sp-warning);
99818
+ }
99058
99819
  .sp-conn-toast-text {
99059
99820
  flex: 1;
99060
99821
  min-width: 0;
@@ -99081,6 +99842,28 @@ body.vscode-high-contrast .ag-theme-quartz {
99081
99842
  opacity: 1;
99082
99843
  }
99083
99844
 
99845
+ /* Undo toasts float above the document flow, so the Floating shadow vocabulary applies (DESIGN.md #4). */
99846
+ .sp-tab-undo-stack {
99847
+ position: fixed;
99848
+ bottom: 16px;
99849
+ left: 50%;
99850
+ z-index: 100;
99851
+ display: flex;
99852
+ flex-direction: column;
99853
+ gap: 6px;
99854
+ transform: translateX(-50%);
99855
+ /* Closing many tabs in quick succession shouldn't grow this stack to cover the viewport. */
99856
+ max-height: min(60vh, 320px);
99857
+ overflow-y: auto;
99858
+ overscroll-behavior: contain;
99859
+ }
99860
+
99861
+ .sp-tab-undo-toast {
99862
+ box-shadow:
99863
+ 0 6px 18px rgba(0, 0, 0, 0.3),
99864
+ 0 1px 4px rgba(0, 0, 0, 0.15);
99865
+ }
99866
+
99084
99867
  /* Keep the user-selected type size flowing through shared UI primitives. */
99085
99868
  .sp-app,
99086
99869
  .sp-app :where(button, input, select, textarea, code, pre),
@@ -99203,6 +99986,24 @@ body.vscode-high-contrast .ag-theme-quartz {
99203
99986
  .sp-conn-credential-actions {
99204
99987
  justify-content: flex-start;
99205
99988
  }
99989
+ }
99990
+
99991
+ /* ── Reduced motion ────────────────────────────────────────── */
99992
+ /* Looping animations (spin/pulse) are disabled outright rather than slowed, since a static
99993
+ indicator still communicates loading/testing state via its accompanying text or color. Short
99994
+ hover/focus transitions (opacity, color, background) are left alone — they're not the kind of
99995
+ sustained or large-amplitude motion prefers-reduced-motion targets. */
99996
+ @media (prefers-reduced-motion: reduce) {
99997
+ .sp-spinner,
99998
+ .sp-conn-status-testing {
99999
+ animation: none;
100000
+ }
100001
+ .sp-spinner {
100002
+ opacity: 0.7;
100003
+ }
100004
+ .sp-conn-status-testing {
100005
+ opacity: 0.7;
100006
+ }
99206
100007
  }</style>
99207
100008
  </head>
99208
100009