sql-preview 0.6.4 → 0.6.7

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
@@ -9,7 +9,7 @@
9
9
  body {
10
10
  margin: 0;
11
11
  padding: 0;
12
- font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
12
+ font-family: var(--vscode-editor-font-family, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif);
13
13
  background-color: transparent;
14
14
  }
15
15
 
@@ -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) {
@@ -74589,16 +74761,6 @@ const ConnectionsManager = () => {
74589
74761
  reactExports.useEffect(() => {
74590
74762
  fetchData();
74591
74763
  }, [fetchData]);
74592
- reactExports.useEffect(() => {
74593
- if (isFormOpen || connections.length === 0) {
74594
- return;
74595
- }
74596
- if (selectedConnectionId && connections.some((c) => c.id === selectedConnectionId)) {
74597
- return;
74598
- }
74599
- const nextSelection = connections.find((c) => supportsActiveConnection && c.id === activeConnectionId) ?? connections[0];
74600
- setSelectedConnectionId(nextSelection == null ? void 0 : nextSelection.id);
74601
- }, [activeConnectionId, connections, isFormOpen, selectedConnectionId, supportsActiveConnection]);
74602
74764
  reactExports.useEffect(() => {
74603
74765
  if (connections.length > 0) {
74604
74766
  connections.forEach((c) => {
@@ -74623,49 +74785,72 @@ const ConnectionsManager = () => {
74623
74785
  if (!isReady) {
74624
74786
  return false;
74625
74787
  }
74788
+ const requestId = (testRequestIds.current[connectionId] ?? 0) + 1;
74789
+ testRequestIds.current[connectionId] = requestId;
74790
+ const isStale = () => testRequestIds.current[connectionId] !== requestId;
74626
74791
  setStatuses((prev) => ({ ...prev, [connectionId]: "testing" }));
74627
74792
  setStatusMessages((prev) => ({ ...prev, [connectionId]: "" }));
74793
+ setTestStartedAt((prev) => ({ ...prev, [connectionId]: Date.now() }));
74628
74794
  try {
74629
- const result = await callServerTool("test_connection", {
74630
- connectionId
74631
- });
74795
+ const result = await withTestTimeout(
74796
+ callServerTool("test_connection", { connectionId }),
74797
+ CONNECTION_TEST_TIMEOUT_MS
74798
+ );
74799
+ if (isStale()) {
74800
+ return false;
74801
+ }
74632
74802
  const text = getToolText(result, ((_a3 = result.structuredContent) == null ? void 0 : _a3.message) ?? "No response");
74633
74803
  const isError = isErrorToolResult(result, text);
74634
74804
  setStatuses((prev) => ({ ...prev, [connectionId]: isError ? "error" : "ok" }));
74635
74805
  setStatusMessages((prev) => ({ ...prev, [connectionId]: text }));
74636
74806
  return !isError;
74637
74807
  } catch (e2) {
74808
+ if (isStale()) {
74809
+ return false;
74810
+ }
74638
74811
  setStatuses((prev) => ({ ...prev, [connectionId]: "error" }));
74639
- setStatusMessages((prev) => ({
74640
- ...prev,
74641
- [connectionId]: `Error: ${e2}`
74642
- }));
74812
+ setStatusMessages((prev) => ({ ...prev, [connectionId]: errorText(e2) }));
74643
74813
  return false;
74644
74814
  }
74645
74815
  };
74816
+ const handleCancelTest = (connectionId) => {
74817
+ testRequestIds.current[connectionId] = (testRequestIds.current[connectionId] ?? 0) + 1;
74818
+ setStatuses((prev) => ({ ...prev, [connectionId]: "unknown" }));
74819
+ setStatusMessages((prev) => ({ ...prev, [connectionId]: "Test cancelled." }));
74820
+ };
74646
74821
  const handleTestFormData = async (formData, connection) => {
74647
74822
  var _a3;
74648
74823
  const typeToTest = (connection == null ? void 0 : connection.type) ?? selectedType;
74649
74824
  if (!isReady || !typeToTest) {
74650
74825
  return;
74651
74826
  }
74827
+ const requestId = connection ? (testRequestIds.current[connection.id] ?? 0) + 1 : formTestIdRef.current += 1;
74828
+ const isStale = () => connection ? testRequestIds.current[connection.id] !== requestId : formTestIdRef.current !== requestId;
74652
74829
  if (connection) {
74830
+ testRequestIds.current[connection.id] = requestId;
74653
74831
  setToast(null);
74654
74832
  setStatuses((prev) => ({ ...prev, [connection.id]: "testing" }));
74655
74833
  setStatusMessages((prev) => ({ ...prev, [connection.id]: "" }));
74834
+ setTestStartedAt((prev) => ({ ...prev, [connection.id]: Date.now() }));
74656
74835
  } else {
74657
- setToast({ text: "Testing connection…", severity: "success" });
74836
+ setToast({ text: "Testing connection…", severity: "testing", startedAt: Date.now() });
74658
74837
  }
74659
74838
  try {
74660
74839
  const profileToTest = { ...formData, type: typeToTest };
74661
74840
  if (connection && profileToTest["password"] === "") {
74662
74841
  delete profileToTest["password"];
74663
74842
  }
74664
- const result = await callServerTool("test_connection", {
74665
- ...connection ? { connectionId: connection.id } : {},
74666
- type: typeToTest,
74667
- connectionProfile: profileToTest
74668
- });
74843
+ const result = await withTestTimeout(
74844
+ callServerTool("test_connection", {
74845
+ ...connection ? { connectionId: connection.id } : {},
74846
+ type: typeToTest,
74847
+ connectionProfile: profileToTest
74848
+ }),
74849
+ CONNECTION_TEST_TIMEOUT_MS
74850
+ );
74851
+ if (isStale()) {
74852
+ return;
74853
+ }
74669
74854
  const text = getToolText(result, ((_a3 = result.structuredContent) == null ? void 0 : _a3.message) ?? "No response");
74670
74855
  const isError = isErrorToolResult(result, text);
74671
74856
  if (connection) {
@@ -74675,7 +74860,10 @@ const ConnectionsManager = () => {
74675
74860
  setToast(buildConnectionTestToast(result.structuredContent, text));
74676
74861
  }
74677
74862
  } catch (e2) {
74678
- const message = `Error: ${e2}`;
74863
+ if (isStale()) {
74864
+ return;
74865
+ }
74866
+ const message = `Connection test failed: ${errorText(e2)}`;
74679
74867
  const advice = getOptionalDependencyAdvice(message);
74680
74868
  if (connection) {
74681
74869
  setStatuses((prev) => ({ ...prev, [connection.id]: "error" }));
@@ -74689,6 +74877,10 @@ const ConnectionsManager = () => {
74689
74877
  }
74690
74878
  }
74691
74879
  };
74880
+ const dismissToast = () => {
74881
+ formTestIdRef.current += 1;
74882
+ setToast(null);
74883
+ };
74692
74884
  const handleSaveConnection = async (formData, connection) => {
74693
74885
  const typeToSave = (connection == null ? void 0 : connection.type) ?? selectedType;
74694
74886
  if (!isReady || !typeToSave) {
@@ -74718,26 +74910,36 @@ const ConnectionsManager = () => {
74718
74910
  setToast({ text: `Connection '${profileToSave["name"]}' saved.`, severity: "success" });
74719
74911
  await fetchData();
74720
74912
  } catch (e2) {
74721
- setToast({ text: `Error saving: ${e2}`, severity: "error" });
74913
+ setToast({ text: `Couldn't save the connection: ${errorText(e2)}`, severity: "error" });
74722
74914
  } finally {
74723
74915
  setIsLoading(false);
74724
74916
  }
74725
74917
  };
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
- }
74918
+ const handleDeleteConnection = (id, name) => {
74919
+ if (!isReady) return;
74920
+ setPendingConfirm({
74921
+ title: "Delete connection",
74922
+ message: `Delete connection '${name}'? This can't be undone.`,
74923
+ confirmLabel: "Delete",
74924
+ onConfirm: () => {
74925
+ void (async () => {
74926
+ setIsLoading(true);
74927
+ try {
74928
+ await callServerTool("delete_connection", { connectionId: id });
74929
+ setSelectedConnectionId((prev) => prev === id ? void 0 : prev);
74930
+ setToast({ text: `Connection '${name}' deleted.`, severity: "success" });
74931
+ await fetchData();
74932
+ } catch (e2) {
74933
+ setToast({
74934
+ text: `Couldn't delete the connection: ${errorText(e2)}`,
74935
+ severity: "error"
74936
+ });
74937
+ } finally {
74938
+ setIsLoading(false);
74939
+ }
74940
+ })();
74941
+ }
74942
+ });
74741
74943
  };
74742
74944
  const handleSetActiveConnection = async (connection) => {
74743
74945
  if (!isReady || !supportsActiveConnection) {
@@ -74780,24 +74982,33 @@ const ConnectionsManager = () => {
74780
74982
  setToast({ text: `Error saving password: ${e2}`, severity: "error" });
74781
74983
  }
74782
74984
  };
74783
- const handleClearConnectionPassword = async (connection) => {
74784
- var _a3;
74985
+ const handleClearConnectionPassword = (connection) => {
74785
74986
  if (!isReady || !supportsActiveConnection || !connection.hasPassword) {
74786
74987
  return;
74787
74988
  }
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
- }
74989
+ setPendingConfirm({
74990
+ title: "Clear stored password",
74991
+ message: `Clear stored password for '${connection.name}'?`,
74992
+ confirmLabel: "Clear",
74993
+ onConfirm: () => {
74994
+ void (async () => {
74995
+ var _a3;
74996
+ try {
74997
+ const result = await callServerTool("clear_connection_password", {
74998
+ connectionId: connection.id
74999
+ });
75000
+ const text = getToolText(
75001
+ result,
75002
+ ((_a3 = result.structuredContent) == null ? void 0 : _a3.message) ?? "Password cleared."
75003
+ );
75004
+ setToast({ text, severity: "success" });
75005
+ await fetchData();
75006
+ } catch (e2) {
75007
+ setToast({ text: `Error clearing password: ${e2}`, severity: "error" });
75008
+ }
75009
+ })();
75010
+ }
75011
+ });
74801
75012
  };
74802
75013
  const handleInstallOptionalDependency = (advice) => {
74803
75014
  sendMessage("installOptionalDependency", {
@@ -74806,14 +75017,26 @@ const ConnectionsManager = () => {
74806
75017
  });
74807
75018
  };
74808
75019
  const openAddForm = () => {
75020
+ setSelectedConnectionId(void 0);
74809
75021
  setSelectedType("");
74810
75022
  setIsFormOpen(true);
74811
75023
  setToast(null);
74812
75024
  };
74813
- const closeForm = () => {
75025
+ const closeForm = reactExports.useCallback(() => {
74814
75026
  setIsFormOpen(false);
75027
+ setSelectedConnectionId(void 0);
74815
75028
  setSelectedType("");
74816
- };
75029
+ setToast(null);
75030
+ }, []);
75031
+ reactExports.useEffect(() => {
75032
+ function handleClickOutside(event) {
75033
+ if (isPopoverOpen && switcherWrapRef.current && !switcherWrapRef.current.contains(event.target)) {
75034
+ setIsPopoverOpen(false);
75035
+ }
75036
+ }
75037
+ document.addEventListener("mousedown", handleClickOutside);
75038
+ return () => document.removeEventListener("mousedown", handleClickOutside);
75039
+ }, [isPopoverOpen]);
74817
75040
  const activeSchemaDef = connectors.find((c) => c.id === selectedType);
74818
75041
  const selectedConnection = selectedConnectionId ? connections.find((c) => c.id === selectedConnectionId) : void 0;
74819
75042
  const activeFormSchema = (activeSchemaDef == null ? void 0 : activeSchemaDef.schema) ? schemaForConnectionMode(activeSchemaDef.schema, activeSchemaDef.id, mode) : void 0;
@@ -74833,7 +75056,10 @@ const ConnectionsManager = () => {
74833
75056
  role: toast.severity === "warning" || toast.severity === "error" ? "alert" : "status",
74834
75057
  tabIndex: -1,
74835
75058
  children: [
74836
- /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-toast-text", children: toast.text }),
75059
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "sp-conn-toast-text", children: [
75060
+ toast.text,
75061
+ toast.severity === "testing" && toast.startedAt !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(TestElapsed, { since: toast.startedAt })
75062
+ ] }),
74837
75063
  advice && /* @__PURE__ */ jsxRuntimeExports.jsxs(
74838
75064
  "button",
74839
75065
  {
@@ -74846,15 +75072,8 @@ const ConnectionsManager = () => {
74846
75072
  ]
74847
75073
  }
74848
75074
  ),
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
- )
75075
+ toast.severity === "testing" && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { type: "button", className: "sp-btn sp-conn-toast-action", onClick: dismissToast, children: "Cancel" }),
75076
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "sp-conn-toast-close", onClick: dismissToast, "aria-label": "Close message", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CloseIcon, { size: 14 }) })
74858
75077
  ]
74859
75078
  }
74860
75079
  );
@@ -74863,7 +75082,22 @@ const ConnectionsManager = () => {
74863
75082
  const status = statuses[connection.id] || "unknown";
74864
75083
  const statusMsg = statusMessages[connection.id] || "";
74865
75084
  if (status === "testing") {
74866
- return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-status-message", role: "status", children: "Testing connection…" });
75085
+ const startedAt = testStartedAt[connection.id];
75086
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-status-message sp-conn-status-message-testing", role: "status", children: [
75087
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
75088
+ "Testing connection…",
75089
+ startedAt !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(TestElapsed, { since: startedAt })
75090
+ ] }),
75091
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
75092
+ "button",
75093
+ {
75094
+ type: "button",
75095
+ className: "sp-btn sp-conn-status-action",
75096
+ onClick: () => handleCancelTest(connection.id),
75097
+ children: "Cancel"
75098
+ }
75099
+ )
75100
+ ] });
74867
75101
  }
74868
75102
  if (!statusMsg) {
74869
75103
  return null;
@@ -74901,30 +75135,46 @@ const ConnectionsManager = () => {
74901
75135
  }
74902
75136
  );
74903
75137
  };
74904
- const renderConnectionForm = () => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail", children: [
75138
+ const renderConnectionForm = () => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-detail", children: [
74905
75139
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail-header", children: [
74906
75140
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
74907
75141
  /* @__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" })
75142
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "sp-conn-detail-title", children: "New connection" })
74909
75143
  ] }),
74910
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "sp-btn", onClick: closeForm, "aria-label": "Back to connection details", children: "Back" })
75144
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "sp-btn", onClick: closeForm, "aria-label": "Cancel", children: "Cancel" })
74911
75145
  ] }),
74912
75146
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail-body", children: [
74913
75147
  renderToast(),
74914
75148
  /* @__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
- )) }),
75149
+ ["local", "server"].map((group) => {
75150
+ const groupConnectors = connectors.filter((c) => getConnectorGroup(c.id) === group);
75151
+ if (groupConnectors.length === 0) return null;
75152
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(React$2.Fragment, { children: [
75153
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-type-group-label", id: `sp-conn-type-group-${group}`, children: CONNECTOR_GROUP_LABELS[group] }),
75154
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
75155
+ "div",
75156
+ {
75157
+ className: "sp-conn-type-grid",
75158
+ role: "group",
75159
+ "aria-labelledby": `sp-conn-type-group-${group}`,
75160
+ children: groupConnectors.map((c) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
75161
+ "button",
75162
+ {
75163
+ type: "button",
75164
+ className: `sp-conn-type-card${selectedType === c.id ? " selected" : ""}`,
75165
+ onClick: () => setSelectedType(c.id),
75166
+ "aria-pressed": selectedType === c.id,
75167
+ children: [
75168
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-type-card-icon", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ConnectorGlyph, { type: c.id }) }),
75169
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-type-card-name", children: c.displayName || c.id })
75170
+ ]
75171
+ },
75172
+ c.id
75173
+ ))
75174
+ }
75175
+ )
75176
+ ] }, group);
75177
+ }),
74928
75178
  activeSchemaDef && activeFormSchema ? /* @__PURE__ */ jsxRuntimeExports.jsx(
74929
75179
  DynamicForm,
74930
75180
  {
@@ -74940,7 +75190,7 @@ const ConnectionsManager = () => {
74940
75190
  ] });
74941
75191
  const renderConnectionDetails = () => {
74942
75192
  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." }) }) });
75193
+ 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
75194
  }
74945
75195
  const status = statuses[selectedConnection.id] || "unknown";
74946
75196
  const isActive = supportsActiveConnection && activeConnectionId === selectedConnection.id;
@@ -74987,18 +75237,17 @@ const ConnectionsManager = () => {
74987
75237
  ] })
74988
75238
  ] });
74989
75239
  };
74990
- return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail", children: [
74991
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail-header", children: [
74992
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
74993
- /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-detail-kicker", children: "Connection settings" }),
74994
- /* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "sp-conn-detail-title", children: selectedConnection.name }),
74995
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-item-meta", children: [
75240
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-detail", children: [
75241
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail-header", style: { display: "flex", justifyContent: "space-between", alignItems: "center", flexWrap: "wrap", gap: "16px", paddingBottom: "16px", borderBottom: "1px solid var(--sp-border)", marginBottom: "16px" }, children: [
75242
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "12px", flexWrap: "wrap" }, children: [
75243
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { fontWeight: 600, fontSize: "14px", color: "var(--sp-fg)" }, children: selectedConnection ? "Edit Connection" : "New Connection" }),
75244
+ selectedConnection && /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
74996
75245
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-type-badge", children: selectedConnection.type }),
74997
- isActive && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-active-badge", children: "Active for queries" }),
75246
+ isActive && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-active-badge", children: "Active" }),
74998
75247
  selectedConnection.builtIn && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-conn-built-in-label", children: "Built-in" })
74999
75248
  ] })
75000
75249
  ] }),
75001
- /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail-actions", children: [
75250
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail-actions", style: { display: "flex", gap: "8px", flexWrap: "wrap" }, children: [
75002
75251
  supportsActiveConnection && /* @__PURE__ */ jsxRuntimeExports.jsx(
75003
75252
  "button",
75004
75253
  {
@@ -75006,15 +75255,14 @@ const ConnectionsManager = () => {
75006
75255
  onClick: () => handleSetActiveConnection(selectedConnection),
75007
75256
  disabled: isActive || status === "testing",
75008
75257
  "aria-label": `Set ${selectedConnection.name} as the active connection for queries`,
75009
- children: isActive ? "Active for queries" : "Set active for queries"
75258
+ children: isActive ? "Active" : "Set active"
75010
75259
  }
75011
75260
  ),
75012
75261
  !selectedConnection.builtIn && /* @__PURE__ */ jsxRuntimeExports.jsx(
75013
75262
  "button",
75014
75263
  {
75015
- className: "sp-btn",
75264
+ className: "sp-btn sp-btn-ghost-danger",
75016
75265
  onClick: () => handleDeleteConnection(selectedConnection.id, selectedConnection.name),
75017
- style: { color: "var(--sp-error)" },
75018
75266
  "aria-label": `Delete connection ${selectedConnection.name}`,
75019
75267
  children: "Delete"
75020
75268
  }
@@ -75023,7 +75271,6 @@ const ConnectionsManager = () => {
75023
75271
  ] }),
75024
75272
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-detail-body", children: [
75025
75273
  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." }),
75027
75274
  modeAwareEditSchema ? /* @__PURE__ */ jsxRuntimeExports.jsx(
75028
75275
  DynamicForm,
75029
75276
  {
@@ -75040,86 +75287,90 @@ const ConnectionsManager = () => {
75040
75287
  ] })
75041
75288
  ] });
75042
75289
  };
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: [
75048
- /* @__PURE__ */ jsxRuntimeExports.jsx(
75049
- "button",
75050
- {
75051
- className: "sp-btn",
75052
- onClick: fetchData,
75053
- disabled: isLoading,
75054
- "aria-label": "Refresh connections",
75055
- children: "Refresh"
75056
- }
75057
- ),
75058
- /* @__PURE__ */ jsxRuntimeExports.jsx(
75059
- "button",
75060
- {
75061
- className: "sp-btn sp-btn-primary",
75062
- onClick: openAddForm,
75063
- "aria-label": "Add new connection",
75064
- children: "Add"
75065
- }
75066
- )
75067
- ] })
75068
- ] }),
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." }),
75290
+ const renderGrid = () => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-grid-view", children: [
75291
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-head", style: { marginBottom: 16 }, children: [
75292
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h2", { children: "DB Connections" }),
75293
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-head-actions", children: [
75294
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
75295
+ "button",
75296
+ {
75297
+ className: "sp-btn",
75298
+ onClick: fetchData,
75299
+ disabled: isLoading,
75300
+ "aria-label": "Refresh connections",
75301
+ title: "Refresh",
75302
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx("svg", { width: "14", height: "14", viewBox: "0 0 16 16", xmlns: "http://www.w3.org/2000/svg", fill: "currentColor", children: /* @__PURE__ */ jsxRuntimeExports.jsx("path", { fillRule: "evenodd", clipRule: "evenodd", d: "M4.681 3H2V2h3.5l.5.5V6H5V4a5 5 0 1 0 4.53-.761l.302-.953A6 6 0 1 1 4.681 3z" }) })
75303
+ }
75304
+ ),
75074
75305
  /* @__PURE__ */ jsxRuntimeExports.jsx(
75075
75306
  "button",
75076
75307
  {
75077
75308
  className: "sp-btn sp-btn-primary",
75078
75309
  onClick: openAddForm,
75079
75310
  "aria-label": "Add new connection",
75080
- children: "Add your first connection"
75311
+ children: "+ New Connection"
75081
75312
  }
75082
75313
  )
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(
75089
- "button",
75090
- {
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,
75099
- children: [
75100
- /* @__PURE__ */ jsxRuntimeExports.jsx(
75101
- "div",
75102
- {
75103
- className: `sp-conn-status sp-conn-status-${status}`,
75104
- title: statusMsg || (status === "unknown" ? "Not tested" : status)
75105
- }
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
- ] })
75115
- ]
75116
- },
75117
- c.id
75118
- );
75119
- }) })
75314
+ ] })
75120
75315
  ] }),
75121
- /* @__PURE__ */ jsxRuntimeExports.jsx("section", { "aria-label": "Connection details", children: isFormOpen ? renderConnectionForm() : renderConnectionDetails() })
75122
- ] }) });
75316
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-grid", style: { display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(260px, 1fr))", gap: "12px" }, children: connections.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn-empty", style: { gridColumn: "1 / -1" }, children: "No connections configured." }) : connections.map((c) => {
75317
+ const status = statuses[c.id] || "unknown";
75318
+ const isActive = supportsActiveConnection && activeConnectionId === c.id;
75319
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
75320
+ "div",
75321
+ {
75322
+ className: "sp-conn-card",
75323
+ style: {
75324
+ border: "1px solid var(--sp-border)",
75325
+ borderRadius: "6px",
75326
+ padding: "12px",
75327
+ background: "var(--sp-header-bg)",
75328
+ cursor: "pointer",
75329
+ display: "flex",
75330
+ flexDirection: "column",
75331
+ gap: "8px"
75332
+ },
75333
+ onClick: () => {
75334
+ setSelectedConnectionId(c.id);
75335
+ setIsFormOpen(false);
75336
+ },
75337
+ children: [
75338
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "8px", fontWeight: 600 }, children: [
75339
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { display: "flex", width: 16, height: 16, alignItems: "center", justifyContent: "center", color: "var(--sp-btn-bg)" }, children: /* @__PURE__ */ jsxRuntimeExports.jsx(ConnectorGlyph, { type: c.type }) }),
75340
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: c.name })
75341
+ ] }) }),
75342
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { style: { fontSize: "12px", color: "var(--sp-muted-fg)" }, children: c.type.toUpperCase() }),
75343
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { style: { display: "flex", alignItems: "center", gap: "6px", fontSize: "11px", marginTop: "4px" }, children: [
75344
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: `sp-dot sp-dot-${status}` }),
75345
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--sp-muted-fg)" }, children: status === "ok" ? "Connected" : status === "error" ? "Error" : status === "testing" ? "Testing..." : "Disconnected" }),
75346
+ isActive && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "sp-pill", style: { marginLeft: "auto" }, children: "Active" })
75347
+ ] })
75348
+ ]
75349
+ },
75350
+ c.id
75351
+ );
75352
+ }) })
75353
+ ] });
75354
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-conn-page", children: [
75355
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "sp-conn", children: !isFormOpen && !selectedConnectionId ? renderGrid() : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
75356
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "sp-btn", onClick: closeForm, style: { marginBottom: 12, alignSelf: "flex-start" }, children: "← Back to connections" }),
75357
+ /* @__PURE__ */ jsxRuntimeExports.jsx("section", { "aria-label": "Connection details", style: { background: "var(--sp-bg)", border: "1px solid var(--sp-border)", borderRadius: 6 }, children: isFormOpen ? renderConnectionForm() : renderConnectionDetails() })
75358
+ ] }) }),
75359
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
75360
+ ConfirmDialog,
75361
+ {
75362
+ open: pendingConfirm !== null,
75363
+ title: (pendingConfirm == null ? void 0 : pendingConfirm.title) ?? "Confirm",
75364
+ message: (pendingConfirm == null ? void 0 : pendingConfirm.message) ?? "",
75365
+ confirmLabel: (pendingConfirm == null ? void 0 : pendingConfirm.confirmLabel) ?? "Confirm",
75366
+ onConfirm: () => {
75367
+ pendingConfirm == null ? void 0 : pendingConfirm.onConfirm();
75368
+ setPendingConfirm(null);
75369
+ },
75370
+ onCancel: () => setPendingConfirm(null)
75371
+ }
75372
+ )
75373
+ ] });
75123
75374
  };
75124
75375
  function extractQueryResult(rawData) {
75125
75376
  if (!rawData || typeof rawData !== "object") return null;
@@ -75355,7 +75606,7 @@ function App() {
75355
75606
  },
75356
75607
  title: "Close tab",
75357
75608
  "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" }) })
75609
+ children: /* @__PURE__ */ jsxRuntimeExports.jsx(CloseIcon, { size: 10 })
75359
75610
  }
75360
75611
  )
75361
75612
  ]
@@ -75365,7 +75616,7 @@ function App() {
75365
75616
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-content", children: [
75366
75617
  error && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-error-bar", children: [
75367
75618
  /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: error }),
75368
- /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => updateTab(activeTab.id, { error: null }), "aria-label": "Close error message", children: "✕" })
75619
+ /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: () => updateTab(activeTab.id, { error: null }), "aria-label": "Close error message", children: /* @__PURE__ */ jsxRuntimeExports.jsx(CloseIcon, { size: 14 }) })
75369
75620
  ] }),
75370
75621
  activeView === "query" ? /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
75371
75622
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "sp-result-header", children: [
@@ -96795,6 +97046,20 @@ body.light-theme .ag-theme-quartz {
96795
97046
  }
96796
97047
  /* src/ui/core/tokens.css — design tokens + shared component styles */
96797
97048
 
97049
+ /* ── Accessibility utilities ─────────────────────────────────── */
97050
+ /* Standard visually-hidden pattern: present to assistive tech, invisible on screen. */
97051
+ .sp-visually-hidden {
97052
+ position: absolute;
97053
+ width: 1px;
97054
+ height: 1px;
97055
+ padding: 0;
97056
+ margin: -1px;
97057
+ overflow: hidden;
97058
+ clip: rect(0, 0, 0, 0);
97059
+ white-space: nowrap;
97060
+ border: 0;
97061
+ }
97062
+
96798
97063
  /* ── Tokens ────────────────────────────────────────────────── */
96799
97064
  :root {
96800
97065
  --sp-bg: var(--vscode-editor-background, #ffffff);
@@ -96828,8 +97093,15 @@ body.light-theme .ag-theme-quartz {
96828
97093
  --sp-selection-bg: var(--vscode-editor-selectionBackground, rgba(38, 79, 120, 0.7));
96829
97094
  --sp-hover-bg: var(--vscode-list-hoverBackground, rgba(255, 255, 255, 0.07));
96830
97095
 
97096
+ /* Modal backdrop scrim — only for elements that truly float above the page (native <dialog>). */
97097
+ --sp-backdrop: rgba(0, 0, 0, 0.5);
97098
+
96831
97099
  --sp-focus-border: var(--vscode-focusBorder, #007acc);
96832
97100
  --sp-error: var(--vscode-errorForeground, #a1260d);
97101
+ /* Solid destructive fill — dark enough in both themes to carry the button foreground,
97102
+ unlike --sp-error whose dark value (salmon) is a text color, not a fill. */
97103
+ --sp-btn-danger-bg: var(--vscode-statusBarItem-errorBackground, #a1260d);
97104
+ --sp-btn-danger-fg: var(--vscode-statusBarItem-errorForeground, #ffffff);
96833
97105
  --sp-success: var(--vscode-charts-green, #107c10);
96834
97106
  --sp-warning: var(--vscode-charts-yellow, #ca8a04);
96835
97107
 
@@ -96848,6 +97120,7 @@ body.light-theme .ag-theme-quartz {
96848
97120
  --sp-space-lg: 24px;
96849
97121
 
96850
97122
  --sp-radius: 3px;
97123
+ --sp-shadow-floating: 0 6px 18px rgba(0, 0, 0, 0.3), 0 1px 4px rgba(0, 0, 0, 0.15);
96851
97124
  }
96852
97125
 
96853
97126
  .vscode-dark,
@@ -96934,6 +97207,7 @@ body {
96934
97207
  padding: 0 6px;
96935
97208
  flex-shrink: 0;
96936
97209
  border-left: 1px solid var(--sp-border);
97210
+ gap: 6px;
96937
97211
  }
96938
97212
 
96939
97213
  .sp-active-file-indicator {
@@ -97001,6 +97275,10 @@ body {
97001
97275
  border-bottom-color: var(--sp-tab-border);
97002
97276
  background: var(--sp-tab-active-bg, var(--sp-bg));
97003
97277
  }
97278
+ .sp-tab:focus-visible {
97279
+ outline: 2px solid var(--sp-focus-border);
97280
+ outline-offset: -2px;
97281
+ }
97004
97282
 
97005
97283
  .sp-tab-label {
97006
97284
  font-size: 12px;
@@ -97029,6 +97307,11 @@ body {
97029
97307
  .sp-tab.active .sp-tab-close {
97030
97308
  opacity: 0.6;
97031
97309
  }
97310
+ .sp-tab-close:focus-visible {
97311
+ opacity: 1;
97312
+ outline: 2px solid var(--sp-focus-border);
97313
+ outline-offset: 1px;
97314
+ }
97032
97315
  .sp-tab-close:hover {
97033
97316
  opacity: 1 !important;
97034
97317
  background: var(--sp-hover-bg);
@@ -97049,7 +97332,7 @@ body {
97049
97332
  align-items: center;
97050
97333
  justify-content: space-between;
97051
97334
  padding: 6px 12px;
97052
- background: rgba(161, 38, 13, 0.1);
97335
+ background: color-mix(in srgb, var(--sp-error) 10%, transparent);
97053
97336
  border-bottom: 1px solid var(--sp-error);
97054
97337
  color: var(--sp-error);
97055
97338
  font-size: 12px;
@@ -97085,7 +97368,7 @@ body {
97085
97368
  align-items: flex-start;
97086
97369
  gap: 10px;
97087
97370
  padding: 10px 12px;
97088
- background: rgba(202, 138, 4, 0.12);
97371
+ background: color-mix(in srgb, var(--sp-warning) 12%, transparent);
97089
97372
  border-bottom: 1px solid var(--sp-warning);
97090
97373
  color: var(--sp-warning);
97091
97374
  flex-shrink: 0;
@@ -97106,6 +97389,33 @@ body {
97106
97389
  opacity: 1;
97107
97390
  }
97108
97391
 
97392
+ /* Cancelled notice — user-initiated outcome, so neutral surface tones, not status color. */
97393
+ .sp-cancelled-bar {
97394
+ display: flex;
97395
+ align-items: center;
97396
+ justify-content: space-between;
97397
+ padding: 6px 12px;
97398
+ background: var(--sp-header-bg);
97399
+ border-bottom: 1px solid var(--sp-border);
97400
+ color: var(--sp-muted-fg);
97401
+ font-size: 12px;
97402
+ flex-shrink: 0;
97403
+ gap: 8px;
97404
+ }
97405
+ .sp-cancelled-bar button {
97406
+ background: none;
97407
+ border: none;
97408
+ cursor: pointer;
97409
+ color: currentColor;
97410
+ font-size: 14px;
97411
+ flex-shrink: 0;
97412
+ padding: 0 2px;
97413
+ opacity: 0.8;
97414
+ }
97415
+ .sp-cancelled-bar button:hover {
97416
+ opacity: 1;
97417
+ }
97418
+
97109
97419
  /* ── Result header ─────────────────────────────────────────── */
97110
97420
  .sp-result-header {
97111
97421
  display: flex;
@@ -97165,14 +97475,14 @@ body {
97165
97475
  cursor: pointer;
97166
97476
  border: none;
97167
97477
  border-radius: var(--sp-radius);
97168
- background: var(--sp-btn-sec-bg, #3a3d41);
97169
- color: var(--sp-btn-sec-fg, #cccccc);
97478
+ background: var(--sp-btn-sec-bg);
97479
+ color: var(--sp-btn-sec-fg);
97170
97480
  white-space: nowrap;
97171
97481
  transition: background 0.1s;
97172
97482
  line-height: 1.4;
97173
97483
  }
97174
97484
  .sp-btn:hover:not(:disabled) {
97175
- background: var(--sp-btn-sec-hover, #45494e);
97485
+ background: var(--sp-btn-sec-hover);
97176
97486
  }
97177
97487
  .sp-btn:disabled {
97178
97488
  opacity: 0.4;
@@ -97188,6 +97498,54 @@ body {
97188
97498
  background: var(--sp-btn-hover);
97189
97499
  }
97190
97500
 
97501
+ .sp-btn-danger {
97502
+ background: var(--sp-btn-danger-bg);
97503
+ color: var(--sp-btn-danger-fg);
97504
+ font-weight: 500;
97505
+ }
97506
+ .sp-btn-danger:hover:not(:disabled) {
97507
+ background: color-mix(in srgb, var(--sp-btn-danger-bg) 85%, black);
97508
+ }
97509
+ /* Quiet destructive action outside confirm moments: derived error tints, no solid fill. */
97510
+ .sp-btn-ghost-danger {
97511
+ background: color-mix(in srgb, var(--sp-error) 10%, transparent);
97512
+ border: 1px solid color-mix(in srgb, var(--sp-error) 55%, transparent);
97513
+ color: var(--sp-error);
97514
+ }
97515
+ .sp-btn-ghost-danger:hover:not(:disabled) {
97516
+ background: color-mix(in srgb, var(--sp-error) 18%, transparent);
97517
+ }
97518
+
97519
+ /* ── Confirm dialog (themed replacement for window.confirm) ─── */
97520
+ .sp-confirm-dialog {
97521
+ width: min(90vw, 26rem);
97522
+ padding: 16px;
97523
+ border: 1px solid var(--sp-border);
97524
+ border-radius: var(--sp-radius);
97525
+ background: var(--sp-header-bg, var(--sp-bg));
97526
+ color: var(--sp-fg);
97527
+ font-family: var(--sp-font);
97528
+ }
97529
+ .sp-confirm-dialog::backdrop {
97530
+ background: var(--sp-backdrop);
97531
+ }
97532
+ .sp-confirm-dialog-title {
97533
+ margin: 0 0 6px;
97534
+ font-size: 13px;
97535
+ font-weight: 600;
97536
+ }
97537
+ .sp-confirm-dialog-message {
97538
+ margin: 0 0 16px;
97539
+ color: var(--sp-muted-fg);
97540
+ font-size: 12px;
97541
+ line-height: 1.5;
97542
+ }
97543
+ .sp-confirm-dialog-actions {
97544
+ display: flex;
97545
+ justify-content: flex-end;
97546
+ gap: 8px;
97547
+ }
97548
+
97191
97549
  /* ── Icon-only button (shared by density, side panel, etc.) ── */
97192
97550
  .sp-icon-btn {
97193
97551
  display: inline-flex;
@@ -97213,8 +97571,10 @@ body {
97213
97571
  }
97214
97572
  .sp-icon-btn.active {
97215
97573
  color: var(--sp-btn-bg);
97216
- border-color: var(--sp-btn-bg);
97217
97574
  background: var(--sp-hover-bg);
97575
+ border-color: transparent !important;
97576
+ outline: none !important;
97577
+ box-shadow: none !important;
97218
97578
  }
97219
97579
 
97220
97580
  /* ── Grid container ────────────────────────────────────────── */
@@ -97241,6 +97601,11 @@ body {
97241
97601
  .sp-loading p {
97242
97602
  margin: 0;
97243
97603
  }
97604
+ /* Live elapsed readout; tabular digits so the count-up doesn't jitter horizontally. */
97605
+ .sp-loading-elapsed {
97606
+ margin-left: 6px;
97607
+ font-variant-numeric: tabular-nums;
97608
+ }
97244
97609
 
97245
97610
  /* ── Empty state ───────────────────────────────────────────── */
97246
97611
  .sp-empty {
@@ -97364,7 +97729,7 @@ body {
97364
97729
  min-height: 22px;
97365
97730
  padding: 3px 7px;
97366
97731
  border: 1px solid var(--sp-border);
97367
- border-radius: 4px;
97732
+ border-radius: var(--sp-radius);
97368
97733
  background: color-mix(in srgb, var(--sp-header-bg) 82%, transparent);
97369
97734
  box-sizing: border-box;
97370
97735
  color: var(--sp-muted-fg);
@@ -97714,6 +98079,46 @@ body.vscode-high-contrast .ag-theme-quartz {
97714
98079
  opacity: 0.9;
97715
98080
  }
97716
98081
 
98082
+ /* ── Tab provenance badge (client type, shown in "All Sessions" view) ──── */
98083
+ .sp-tab-provenance {
98084
+ font-size: 10px;
98085
+ font-weight: 600;
98086
+ letter-spacing: 0.02em;
98087
+ text-transform: uppercase;
98088
+ color: var(--sp-muted-fg);
98089
+ background: var(--sp-badge-bg);
98090
+ border-radius: 3px;
98091
+ padding: 1px 5px;
98092
+ white-space: nowrap;
98093
+ cursor: default;
98094
+ }
98095
+
98096
+ /* ── MCP trust indicator ──────────────────────────────────── */
98097
+ .sp-trust-badge {
98098
+ font-size: 11px;
98099
+ font-weight: 600;
98100
+ border: 1px solid transparent;
98101
+ border-radius: var(--sp-radius);
98102
+ height: 24px;
98103
+ display: inline-flex;
98104
+ align-items: center;
98105
+ justify-content: center;
98106
+ padding: 0 8px;
98107
+ box-sizing: border-box;
98108
+ white-space: nowrap;
98109
+ cursor: default;
98110
+ }
98111
+ .sp-trust-badge.safe {
98112
+ background: var(--sp-hover-bg);
98113
+ color: var(--sp-fg);
98114
+ border-color: var(--sp-border);
98115
+ }
98116
+ .sp-trust-badge.unrestricted {
98117
+ background: var(--sp-hover-bg);
98118
+ color: var(--sp-warning);
98119
+ border-color: var(--sp-border);
98120
+ }
98121
+
97717
98122
  /* ── Tab context menu ──────────────────────────────────────── */
97718
98123
  .sp-ctx-menu {
97719
98124
  position: fixed;
@@ -98024,6 +98429,11 @@ body.vscode-high-contrast .ag-theme-quartz {
98024
98429
  grid-template-columns: minmax(360px, 520px) 1fr;
98025
98430
  align-items: start;
98026
98431
  gap: 22px;
98432
+ /* The preview column's own content caps out well short of 1fr (see PREVIEW_MAX_WIDTH in
98433
+ SettingsPanel.tsx) — without a matching cap here, a wide standalone browser tab stretches
98434
+ this grid edge-to-edge and leaves a dead gap beside the preview instead of using that width. */
98435
+ max-width: 1080px;
98436
+ margin-inline: auto;
98027
98437
  }
98028
98438
 
98029
98439
  .sp-settings-main {
@@ -98305,6 +98715,11 @@ body.vscode-high-contrast .ag-theme-quartz {
98305
98715
  color: var(--sp-warning);
98306
98716
  }
98307
98717
 
98718
+ /* In-progress MCP test — amber, matching the testing vocabulary elsewhere. */
98719
+ .sp-settings-status.testing {
98720
+ color: var(--sp-warning);
98721
+ }
98722
+
98308
98723
  .sp-settings-status.error {
98309
98724
  color: var(--sp-error);
98310
98725
  }
@@ -98336,6 +98751,15 @@ body.vscode-high-contrast .ag-theme-quartz {
98336
98751
  border-bottom: 1px solid var(--sp-border);
98337
98752
  }
98338
98753
 
98754
+ /* Label + copy affordance for snippets the user pastes into an external client. */
98755
+ .sp-settings-guide-section-header {
98756
+ display: flex;
98757
+ align-items: center;
98758
+ justify-content: space-between;
98759
+ gap: 8px;
98760
+ margin-bottom: 4px;
98761
+ }
98762
+
98339
98763
  .sp-settings-guide-section:last-child {
98340
98764
  border-bottom: none;
98341
98765
  }
@@ -98473,7 +98897,10 @@ body.vscode-high-contrast .ag-theme-quartz {
98473
98897
  display: flex;
98474
98898
  flex-direction: column;
98475
98899
  gap: 12px;
98476
- max-width: none;
98900
+ /* Same cap as .sp-settings-layout — otherwise the connection form stretches edge-to-edge
98901
+ of a wide standalone browser tab instead of staying a dense, disciplined width. */
98902
+ max-width: 1080px;
98903
+ margin-inline: auto;
98477
98904
  min-height: 0;
98478
98905
  }
98479
98906
 
@@ -98499,36 +98926,247 @@ body.vscode-high-contrast .ag-theme-quartz {
98499
98926
  overflow: hidden;
98500
98927
  }
98501
98928
 
98502
- .sp-conn-detail-header {
98929
+ .sp-conn-head {
98503
98930
  display: flex;
98504
- align-items: flex-start;
98931
+ align-items: center;
98505
98932
  justify-content: space-between;
98506
- gap: 12px;
98507
- padding: 14px;
98933
+ gap: 10px;
98934
+ }
98935
+
98936
+ .sp-conn-head h2 {
98937
+ margin: 0;
98938
+ font-size: 13px;
98939
+ font-weight: 600;
98940
+ }
98941
+
98942
+ .sp-head-actions {
98943
+ display: flex;
98944
+ align-items: center;
98945
+ gap: 6px;
98946
+ }
98947
+
98948
+ .sp-switcher-wrap {
98949
+ position: relative;
98950
+ }
98951
+
98952
+ .sp-switcher {
98953
+ width: 100%;
98954
+ display: flex;
98955
+ align-items: center;
98956
+ gap: 10px;
98957
+ padding: 10px 12px;
98508
98958
  background: var(--sp-header-bg);
98509
- border-bottom: 1px solid var(--sp-border);
98959
+ border: 1px solid var(--sp-border);
98960
+ border-radius: var(--sp-radius);
98961
+ color: var(--sp-fg);
98962
+ font: inherit;
98963
+ cursor: pointer;
98964
+ text-align: left;
98965
+ transition: border-color 0.1s ease, background 0.1s ease;
98510
98966
  }
98511
98967
 
98512
- .sp-conn-detail-kicker {
98968
+ .sp-switcher:hover {
98969
+ border-color: var(--sp-muted-fg);
98970
+ }
98971
+
98972
+ .sp-switcher[aria-expanded="true"] {
98973
+ border-color: var(--sp-focus-border);
98974
+ }
98975
+
98976
+ .sp-switcher .sp-sw-name {
98977
+ font-weight: 600;
98978
+ font-size: 13px;
98979
+ }
98980
+
98981
+ .sp-switcher .sp-grow {
98982
+ flex: 1;
98983
+ min-width: 0;
98984
+ display: flex;
98985
+ align-items: center;
98986
+ gap: 8px;
98987
+ overflow: hidden;
98988
+ }
98989
+
98990
+ .sp-switcher .sp-chev {
98513
98991
  color: var(--sp-muted-fg);
98992
+ transition: transform 0.15s ease;
98993
+ flex-shrink: 0;
98994
+ }
98995
+
98996
+ .sp-switcher[aria-expanded="true"] .sp-chev {
98997
+ transform: rotate(180deg);
98998
+ }
98999
+
99000
+ .sp-dot {
99001
+ width: 8px;
99002
+ height: 8px;
99003
+ border-radius: 50%;
99004
+ flex-shrink: 0;
99005
+ }
99006
+
99007
+ .sp-dot-ok {
99008
+ background: var(--sp-success);
99009
+ }
99010
+
99011
+ .sp-dot-error {
99012
+ background: var(--sp-error);
99013
+ }
99014
+
99015
+ .sp-dot-unknown,
99016
+ .sp-dot-testing {
99017
+ background: var(--sp-border);
99018
+ box-shadow: inset 0 0 0 1px var(--sp-muted-fg);
99019
+ }
99020
+
99021
+ .sp-dot-testing {
99022
+ animation: pulse-border 1.5s infinite;
99023
+ }
99024
+
99025
+ .sp-badge {
99026
+ font-size: 10px;
99027
+ font-weight: 600;
99028
+ letter-spacing: 0.04em;
99029
+ padding: 1px 6px;
99030
+ border-radius: 2px;
99031
+ background: var(--sp-bg);
99032
+ border: 1px solid var(--sp-border);
99033
+ color: var(--sp-muted-fg);
99034
+ white-space: nowrap;
99035
+ flex-shrink: 0;
99036
+ }
99037
+
99038
+ .sp-pill {
98514
99039
  font-size: 10px;
98515
99040
  font-weight: 700;
98516
- letter-spacing: 0.06em;
98517
- text-transform: uppercase;
99041
+ padding: 1px 7px;
99042
+ border-radius: 999px;
99043
+ background: var(--sp-hover-bg);
99044
+ color: var(--sp-fg);
99045
+ border: 1px solid var(--sp-border);
99046
+ white-space: nowrap;
99047
+ flex-shrink: 0;
99048
+ }
99049
+
99050
+ .sp-tag-builtin {
99051
+ font-size: 10px;
99052
+ color: var(--sp-muted-fg);
99053
+ font-weight: 500;
99054
+ white-space: nowrap;
98518
99055
  }
98519
99056
 
98520
- .sp-conn-detail-title {
98521
- margin: 3px 0 6px;
99057
+ .sp-popover {
99058
+ position: absolute;
99059
+ top: calc(100% + 4px);
99060
+ left: 0;
99061
+ width: 100%;
99062
+ z-index: 50;
99063
+ background: var(--sp-bg);
99064
+ border: 1px solid var(--sp-border);
99065
+ border-radius: var(--sp-radius);
99066
+ box-shadow: var(--sp-shadow-floating);
99067
+ padding: 4px;
99068
+ display: none;
99069
+ transform-origin: top center;
99070
+ }
99071
+
99072
+ .sp-popover.open {
99073
+ display: block;
99074
+ animation: pop 0.12s ease-out;
99075
+ }
99076
+
99077
+ @keyframes pop {
99078
+ from { opacity: 0; transform: translateY(-4px) scale(0.99); }
99079
+ to { opacity: 1; transform: none; }
99080
+ }
99081
+
99082
+ .sp-pop-row {
99083
+ width: 100%;
99084
+ display: flex;
99085
+ align-items: center;
99086
+ gap: 10px;
99087
+ padding: 8px 10px;
99088
+ background: transparent;
99089
+ border: none;
99090
+ border-radius: 2px;
98522
99091
  color: var(--sp-fg);
98523
- font-size: 15px;
98524
- line-height: 1.3;
99092
+ font: inherit;
99093
+ text-align: left;
99094
+ cursor: pointer;
99095
+ }
99096
+
99097
+ .sp-pop-row:hover {
99098
+ background: var(--sp-hover-bg);
99099
+ }
99100
+
99101
+ .sp-pop-row[aria-current="true"] {
99102
+ background: var(--sp-selection-bg);
98525
99103
  }
98526
99104
 
98527
- .sp-conn-detail-actions {
99105
+ .sp-pop-row .sp-grow {
99106
+ flex: 1;
99107
+ min-width: 0;
98528
99108
  display: flex;
98529
- flex-wrap: wrap;
98530
- justify-content: flex-end;
98531
- gap: 6px;
99109
+ align-items: center;
99110
+ gap: 8px;
99111
+ overflow: hidden;
99112
+ }
99113
+
99114
+ .sp-pop-row .sp-nm {
99115
+ font-weight: 600;
99116
+ overflow: hidden;
99117
+ text-overflow: ellipsis;
99118
+ white-space: nowrap;
99119
+ }
99120
+
99121
+ .sp-pop-check {
99122
+ color: var(--sp-focus-border);
99123
+ font-size: 12px;
99124
+ flex-shrink: 0;
99125
+ }
99126
+
99127
+ .sp-pop-sep {
99128
+ height: 1px;
99129
+ background: var(--sp-border);
99130
+ margin: 4px 2px;
99131
+ }
99132
+
99133
+ .sp-pop-add {
99134
+ color: var(--sp-focus-border);
99135
+ font-weight: 600;
99136
+ }
99137
+
99138
+ .sp-pop-add .sp-plus {
99139
+ font-size: 14px;
99140
+ }
99141
+
99142
+ .sp-callout {
99143
+ display: flex;
99144
+ align-items: center;
99145
+ gap: 9px;
99146
+ padding: 9px 12px;
99147
+ border: 1px solid color-mix(in srgb, var(--sp-success) 30%, var(--sp-border));
99148
+ border-radius: var(--sp-radius);
99149
+ color: var(--sp-fg);
99150
+ background: color-mix(in srgb, var(--sp-success) 8%, transparent);
99151
+ font-size: 12px;
99152
+ line-height: 1.4;
99153
+ }
99154
+
99155
+ .sp-callout b {
99156
+ font-weight: 600;
99157
+ }
99158
+
99159
+ .sp-detail {
99160
+ display: flex;
99161
+ flex-direction: column;
99162
+ gap: 16px;
99163
+ }
99164
+
99165
+ .sp-detail .sp-conn-detail-header {
99166
+ display: flex;
99167
+ align-items: flex-start;
99168
+ justify-content: space-between;
99169
+ gap: 12px;
98532
99170
  }
98533
99171
 
98534
99172
  .sp-conn-detail-body {
@@ -98585,18 +99223,13 @@ body.vscode-high-contrast .ag-theme-quartz {
98585
99223
  outline: 1px solid var(--sp-focus-border);
98586
99224
  outline-offset: -1px;
98587
99225
  }
99226
+ /* Active-for-queries: tonal selection background; the green "Active" badge carries the state. */
98588
99227
  .sp-conn-item-active {
98589
99228
  background: var(--sp-selection-bg);
98590
- box-shadow: inset 4px 0 0 var(--sp-success);
98591
99229
  }
99230
+ /* Currently viewed: full selection ring (DESIGN.md ring vocabulary), not an edge stripe. */
98592
99231
  .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);
99232
+ box-shadow: inset 0 0 0 1px var(--sp-btn-bg);
98600
99233
  }
98601
99234
 
98602
99235
  .sp-conn-item-info {
@@ -98681,9 +99314,11 @@ body.vscode-high-contrast .ag-theme-quartz {
98681
99314
  align-self: flex-start;
98682
99315
  }
98683
99316
 
99317
+ /* Neutral provenance descriptor, not a status — muted keeps success-green meaning
99318
+ "connection OK / active" only (DESIGN.md: status color is semantic, never decorative). */
98684
99319
  .sp-conn-built-in-label {
98685
99320
  font-size: 10px;
98686
- color: var(--sp-success);
99321
+ color: var(--sp-muted-fg);
98687
99322
  font-weight: 500;
98688
99323
  white-space: nowrap;
98689
99324
  }
@@ -98695,8 +99330,9 @@ body.vscode-high-contrast .ag-theme-quartz {
98695
99330
  font-weight: 700;
98696
99331
  padding: 1px 6px;
98697
99332
  border-radius: 999px;
98698
- color: var(--sp-bg);
98699
- background: var(--sp-success);
99333
+ color: var(--sp-fg);
99334
+ background: var(--sp-hover-bg);
99335
+ border: 1px solid var(--sp-border);
98700
99336
  white-space: nowrap;
98701
99337
  }
98702
99338
 
@@ -98741,7 +99377,21 @@ body.vscode-high-contrast .ag-theme-quartz {
98741
99377
  gap: 10px;
98742
99378
  color: var(--sp-warning);
98743
99379
  border-color: var(--sp-warning);
98744
- background: rgba(202, 138, 4, 0.12);
99380
+ background: color-mix(in srgb, var(--sp-warning) 12%, transparent);
99381
+ }
99382
+
99383
+ .sp-conn-status-message-testing {
99384
+ display: flex;
99385
+ align-items: center;
99386
+ justify-content: space-between;
99387
+ gap: 10px;
99388
+ }
99389
+
99390
+ /* Tabular digits so the count-up doesn't jitter horizontally. */
99391
+ .sp-conn-test-elapsed {
99392
+ margin-left: 4px;
99393
+ font-variant-numeric: tabular-nums;
99394
+ color: var(--sp-muted-fg);
98745
99395
  }
98746
99396
 
98747
99397
  .sp-conn-warning-content {
@@ -98844,6 +99494,27 @@ body.vscode-high-contrast .ag-theme-quartz {
98844
99494
  .sp-conn-type-card-icon {
98845
99495
  font-size: 22px;
98846
99496
  line-height: 1;
99497
+ color: var(--sp-muted-fg);
99498
+ }
99499
+ /* Glyphs inherit the icon slot's font-size so the whole picker rescales with the editor font. */
99500
+ .sp-conn-type-card-icon .sp-connector-glyph {
99501
+ display: block;
99502
+ width: 1em;
99503
+ height: 1em;
99504
+ }
99505
+ .sp-conn-type-card:hover .sp-conn-type-card-icon,
99506
+ .sp-conn-type-card.selected .sp-conn-type-card-icon {
99507
+ color: var(--sp-fg);
99508
+ }
99509
+
99510
+ .sp-conn-type-group-label {
99511
+ font-size: 11px;
99512
+ font-weight: 600;
99513
+ color: var(--sp-muted-fg);
99514
+ margin: 10px 0 6px;
99515
+ }
99516
+ .sp-conn-type-group-label:first-of-type {
99517
+ margin-top: 0;
98847
99518
  }
98848
99519
 
98849
99520
  /* ── Connection form ─────────────────────────────────────── */
@@ -98861,7 +99532,7 @@ body.vscode-high-contrast .ag-theme-quartz {
98861
99532
  }
98862
99533
 
98863
99534
  .sp-conn-form-field {
98864
- grid-column: span 6;
99535
+ grid-column: 1 / -1;
98865
99536
  min-width: 0;
98866
99537
  }
98867
99538
 
@@ -98871,6 +99542,12 @@ body.vscode-high-contrast .ag-theme-quartz {
98871
99542
  grid-column: 1 / -1;
98872
99543
  }
98873
99544
 
99545
+ .sp-conn-form-field-catalog,
99546
+ .sp-conn-form-field-schema,
99547
+ .sp-conn-form-field-source {
99548
+ grid-column: span 6;
99549
+ }
99550
+
98874
99551
  .sp-conn-form-field-host {
98875
99552
  grid-column: span 8;
98876
99553
  }
@@ -99010,7 +99687,7 @@ body.vscode-high-contrast .ag-theme-quartz {
99010
99687
  justify-content: flex-end;
99011
99688
  gap: 6px;
99012
99689
  margin-top: 8px;
99013
- padding-top: 10px;
99690
+ padding: 10px 0;
99014
99691
  border-top: 1px solid var(--sp-border);
99015
99692
  }
99016
99693
 
@@ -99041,20 +99718,26 @@ body.vscode-high-contrast .ag-theme-quartz {
99041
99718
  border: 1px solid transparent;
99042
99719
  }
99043
99720
  .sp-conn-toast-success {
99044
- background: rgba(16, 124, 16, 0.08);
99721
+ background: color-mix(in srgb, var(--sp-success) 8%, transparent);
99045
99722
  border-color: var(--sp-success);
99046
99723
  color: var(--sp-success);
99047
99724
  }
99048
99725
  .sp-conn-toast-error {
99049
- background: rgba(161, 38, 13, 0.08);
99726
+ background: color-mix(in srgb, var(--sp-error) 8%, transparent);
99050
99727
  border-color: var(--sp-error);
99051
99728
  color: var(--sp-error);
99052
99729
  }
99053
99730
  .sp-conn-toast-warning {
99054
- background: rgba(202, 138, 4, 0.12);
99731
+ background: color-mix(in srgb, var(--sp-warning) 12%, transparent);
99055
99732
  border-color: var(--sp-warning);
99056
99733
  color: var(--sp-warning);
99057
99734
  }
99735
+ /* In-progress test — amber like the connection list's testing dots, distinct from a warning outcome. */
99736
+ .sp-conn-toast-testing {
99737
+ background: color-mix(in srgb, var(--sp-warning) 8%, transparent);
99738
+ border-color: color-mix(in srgb, var(--sp-warning) 55%, transparent);
99739
+ color: var(--sp-warning);
99740
+ }
99058
99741
  .sp-conn-toast-text {
99059
99742
  flex: 1;
99060
99743
  min-width: 0;
@@ -99081,6 +99764,8 @@ body.vscode-high-contrast .ag-theme-quartz {
99081
99764
  opacity: 1;
99082
99765
  }
99083
99766
 
99767
+
99768
+
99084
99769
  /* Keep the user-selected type size flowing through shared UI primitives. */
99085
99770
  .sp-app,
99086
99771
  .sp-app :where(button, input, select, textarea, code, pre),
@@ -99203,6 +99888,24 @@ body.vscode-high-contrast .ag-theme-quartz {
99203
99888
  .sp-conn-credential-actions {
99204
99889
  justify-content: flex-start;
99205
99890
  }
99891
+ }
99892
+
99893
+ /* ── Reduced motion ────────────────────────────────────────── */
99894
+ /* Looping animations (spin/pulse) are disabled outright rather than slowed, since a static
99895
+ indicator still communicates loading/testing state via its accompanying text or color. Short
99896
+ hover/focus transitions (opacity, color, background) are left alone — they're not the kind of
99897
+ sustained or large-amplitude motion prefers-reduced-motion targets. */
99898
+ @media (prefers-reduced-motion: reduce) {
99899
+ .sp-spinner,
99900
+ .sp-conn-status-testing {
99901
+ animation: none;
99902
+ }
99903
+ .sp-spinner {
99904
+ opacity: 0.7;
99905
+ }
99906
+ .sp-conn-status-testing {
99907
+ opacity: 0.7;
99908
+ }
99206
99909
  }</style>
99207
99910
  </head>
99208
99911