@comecaramelos/dsh-chrome-mcp 0.0.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -95
- package/assets/dsh-chrome-mcp-social.png +0 -0
- package/assets/icon.svg +71 -0
- package/assets/prelaunch-windows-chrome.html +277 -0
- package/lib/client.js +3005 -568
- package/lib/client.js.map +7 -0
- package/lib/host/apply.d.ts +40 -0
- package/lib/host/apply.d.ts.map +1 -0
- package/lib/host/apply.js +57 -0
- package/lib/host/apply.js.map +1 -0
- package/lib/host/bridge.d.ts +74 -0
- package/lib/host/bridge.d.ts.map +1 -0
- package/lib/host/bridge.js +168 -0
- package/lib/host/bridge.js.map +1 -0
- package/lib/host/catalog.d.ts +31 -0
- package/lib/host/catalog.d.ts.map +1 -0
- package/lib/host/catalog.js +92 -0
- package/lib/host/catalog.js.map +1 -0
- package/lib/host/commands/chrome-path.d.ts +4 -0
- package/lib/host/commands/chrome-path.d.ts.map +1 -0
- package/lib/host/commands/chrome-path.js +65 -0
- package/lib/host/commands/chrome-path.js.map +1 -0
- package/lib/host/commands/chrome-refresh.d.ts +17 -0
- package/lib/host/commands/chrome-refresh.d.ts.map +1 -0
- package/lib/host/commands/chrome-refresh.js +37 -0
- package/lib/host/commands/chrome-refresh.js.map +1 -0
- package/lib/host/commands/index.d.ts +26 -0
- package/lib/host/commands/index.d.ts.map +1 -0
- package/lib/host/commands/index.js +41 -0
- package/lib/host/commands/index.js.map +1 -0
- package/lib/host/constants.d.ts +306 -0
- package/lib/host/constants.d.ts.map +1 -0
- package/lib/host/constants.js +319 -0
- package/lib/host/constants.js.map +1 -0
- package/lib/host/controller/_trace.d.ts +3 -0
- package/lib/host/controller/_trace.d.ts.map +1 -0
- package/lib/host/controller/_trace.js +14 -0
- package/lib/host/controller/_trace.js.map +1 -0
- package/lib/host/controller/bridge-run.d.ts +40 -0
- package/lib/host/controller/bridge-run.d.ts.map +1 -0
- package/lib/host/controller/bridge-run.js +85 -0
- package/lib/host/controller/bridge-run.js.map +1 -0
- package/lib/host/controller/captures.d.ts +15 -0
- package/lib/host/controller/captures.d.ts.map +1 -0
- package/lib/host/controller/captures.js +85 -0
- package/lib/host/controller/captures.js.map +1 -0
- package/lib/host/controller/commits.d.ts +4 -0
- package/lib/host/controller/commits.d.ts.map +1 -0
- package/lib/host/controller/commits.js +131 -0
- package/lib/host/controller/commits.js.map +1 -0
- package/lib/host/controller/connections.d.ts +38 -0
- package/lib/host/controller/connections.d.ts.map +1 -0
- package/lib/host/controller/connections.js +71 -0
- package/lib/host/controller/connections.js.map +1 -0
- package/lib/host/controller/controller.d.ts +35 -0
- package/lib/host/controller/controller.d.ts.map +1 -0
- package/lib/host/controller/controller.js +234 -0
- package/lib/host/controller/controller.js.map +1 -0
- package/lib/host/controller/index.d.ts +30 -0
- package/lib/host/controller/index.d.ts.map +1 -0
- package/lib/host/controller/index.js +27 -0
- package/lib/host/controller/index.js.map +1 -0
- package/lib/host/controller/notes.d.ts +26 -0
- package/lib/host/controller/notes.d.ts.map +1 -0
- package/lib/host/controller/notes.js +44 -0
- package/lib/host/controller/notes.js.map +1 -0
- package/lib/host/controller/persist.d.ts +16 -0
- package/lib/host/controller/persist.d.ts.map +1 -0
- package/lib/host/controller/persist.js +98 -0
- package/lib/host/controller/persist.js.map +1 -0
- package/lib/host/controller/publish.d.ts +4 -0
- package/lib/host/controller/publish.d.ts.map +1 -0
- package/lib/host/controller/publish.js +56 -0
- package/lib/host/controller/publish.js.map +1 -0
- package/lib/host/controller/runs.d.ts +80 -0
- package/lib/host/controller/runs.d.ts.map +1 -0
- package/lib/host/controller/runs.js +394 -0
- package/lib/host/controller/runs.js.map +1 -0
- package/lib/host/controller/state.d.ts +172 -0
- package/lib/host/controller/state.d.ts.map +1 -0
- package/lib/host/controller/state.js +2 -0
- package/lib/host/controller/state.js.map +1 -0
- package/lib/host/controller/windows-run.d.ts +17 -0
- package/lib/host/controller/windows-run.d.ts.map +1 -0
- package/lib/host/controller/windows-run.js +109 -0
- package/lib/host/controller/windows-run.js.map +1 -0
- package/lib/host/discovery/candidates.d.ts +47 -0
- package/lib/host/discovery/candidates.d.ts.map +1 -0
- package/lib/host/discovery/candidates.js +68 -0
- package/lib/host/discovery/candidates.js.map +1 -0
- package/lib/host/discovery/index.d.ts +19 -0
- package/lib/host/discovery/index.d.ts.map +1 -0
- package/lib/host/discovery/index.js +19 -0
- package/lib/host/discovery/index.js.map +1 -0
- package/lib/host/discovery/probe.d.ts +29 -0
- package/lib/host/discovery/probe.d.ts.map +1 -0
- package/lib/host/discovery/probe.js +155 -0
- package/lib/host/discovery/probe.js.map +1 -0
- package/lib/host/discovery/scan.d.ts +72 -0
- package/lib/host/discovery/scan.d.ts.map +1 -0
- package/lib/host/discovery/scan.js +195 -0
- package/lib/host/discovery/scan.js.map +1 -0
- package/lib/host/flags.d.ts +65 -0
- package/lib/host/flags.d.ts.map +1 -0
- package/lib/host/flags.js +186 -0
- package/lib/host/flags.js.map +1 -0
- package/lib/host/kind.d.ts +45 -0
- package/lib/host/kind.d.ts.map +1 -0
- package/lib/host/kind.js +251 -0
- package/lib/host/kind.js.map +1 -0
- package/lib/host/manager.d.ts +21 -0
- package/lib/host/manager.d.ts.map +1 -0
- package/lib/host/manager.js +113 -0
- package/lib/host/manager.js.map +1 -0
- package/lib/host/migration.d.ts +26 -0
- package/lib/host/migration.d.ts.map +1 -0
- package/lib/host/migration.js +127 -0
- package/lib/host/migration.js.map +1 -0
- package/lib/host/platform.d.ts +38 -0
- package/lib/host/platform.d.ts.map +1 -0
- package/lib/host/platform.js +64 -0
- package/lib/host/platform.js.map +1 -0
- package/lib/host/plugin-meta.d.ts +21 -0
- package/lib/host/plugin-meta.d.ts.map +1 -0
- package/lib/host/plugin-meta.js +21 -0
- package/lib/host/plugin-meta.js.map +1 -0
- package/lib/host/schema.d.ts +361 -0
- package/lib/host/schema.d.ts.map +1 -0
- package/lib/host/schema.js +196 -0
- package/lib/host/schema.js.map +1 -0
- package/lib/host/settings.d.ts +28 -0
- package/lib/host/settings.d.ts.map +1 -0
- package/lib/host/settings.js +91 -0
- package/lib/host/settings.js.map +1 -0
- package/lib/host/status.d.ts +25 -0
- package/lib/host/status.d.ts.map +1 -0
- package/lib/host/status.js +45 -0
- package/lib/host/status.js.map +1 -0
- package/lib/host/tool.d.ts +65 -0
- package/lib/host/tool.d.ts.map +1 -0
- package/lib/host/tool.js +52 -0
- package/lib/host/tool.js.map +1 -0
- package/lib/host/types/config.d.ts +101 -0
- package/lib/host/types/config.d.ts.map +1 -0
- package/lib/host/types/config.js +2 -0
- package/lib/host/types/config.js.map +1 -0
- package/lib/host/types/executable.d.ts +35 -0
- package/lib/host/types/executable.d.ts.map +1 -0
- package/lib/host/types/executable.js +9 -0
- package/lib/host/types/executable.js.map +1 -0
- package/lib/host/types/index.d.ts +24 -0
- package/lib/host/types/index.d.ts.map +1 -0
- package/lib/host/types/index.js +2 -0
- package/lib/host/types/index.js.map +1 -0
- package/lib/host/types/plugin.d.ts +38 -0
- package/lib/host/types/plugin.d.ts.map +1 -0
- package/lib/host/types/plugin.js +10 -0
- package/lib/host/types/plugin.js.map +1 -0
- package/lib/host/types/services.d.ts +26 -0
- package/lib/host/types/services.d.ts.map +1 -0
- package/lib/host/types/services.js +9 -0
- package/lib/host/types/services.js.map +1 -0
- package/lib/host/types/settings.d.ts +180 -0
- package/lib/host/types/settings.d.ts.map +1 -0
- package/lib/host/types/settings.js +2 -0
- package/lib/host/types/settings.js.map +1 -0
- package/lib/host/types/stderr.d.ts +51 -0
- package/lib/host/types/stderr.d.ts.map +1 -0
- package/lib/host/types/stderr.js +9 -0
- package/lib/host/types/stderr.js.map +1 -0
- package/lib/host/types/windows.d.ts +39 -0
- package/lib/host/types/windows.d.ts.map +1 -0
- package/lib/host/types/windows.js +9 -0
- package/lib/host/types/windows.js.map +1 -0
- package/lib/host/values.d.ts +204 -0
- package/lib/host/values.d.ts.map +1 -0
- package/lib/host/values.js +404 -0
- package/lib/host/values.js.map +1 -0
- package/lib/host/windows/connect-flags.d.ts +27 -0
- package/lib/host/windows/connect-flags.d.ts.map +1 -0
- package/lib/host/windows/connect-flags.js +97 -0
- package/lib/host/windows/connect-flags.js.map +1 -0
- package/lib/host/windows/index.d.ts +31 -0
- package/lib/host/windows/index.d.ts.map +1 -0
- package/lib/host/windows/index.js +30 -0
- package/lib/host/windows/index.js.map +1 -0
- package/lib/host/windows/landing.d.ts +47 -0
- package/lib/host/windows/landing.d.ts.map +1 -0
- package/lib/host/windows/landing.js +174 -0
- package/lib/host/windows/landing.js.map +1 -0
- package/lib/host/windows/link.d.ts +11 -0
- package/lib/host/windows/link.d.ts.map +1 -0
- package/lib/host/windows/link.js +52 -0
- package/lib/host/windows/link.js.map +1 -0
- package/lib/host/windows/paths.d.ts +64 -0
- package/lib/host/windows/paths.d.ts.map +1 -0
- package/lib/host/windows/paths.js +148 -0
- package/lib/host/windows/paths.js.map +1 -0
- package/lib/host/windows/run.d.ts +74 -0
- package/lib/host/windows/run.d.ts.map +1 -0
- package/lib/host/windows/run.js +211 -0
- package/lib/host/windows/run.js.map +1 -0
- package/lib/host/windows/spawn.d.ts +22 -0
- package/lib/host/windows/spawn.d.ts.map +1 -0
- package/lib/host/windows/spawn.js +73 -0
- package/lib/host/windows/spawn.js.map +1 -0
- package/lib/index.d.ts +102 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +102 -636
- package/lib/index.js.map +1 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +57 -14
- package/cordis.patch.yml +0 -5
package/lib/client.js
CHANGED
|
@@ -4,582 +4,3019 @@ window.__ModuleLoader__.load({
|
|
|
4
4
|
var module = { exports: {} };
|
|
5
5
|
var exports = module.exports;
|
|
6
6
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
7
|
+
"use strict";
|
|
8
|
+
var __create = Object.create;
|
|
9
|
+
var __defProp = Object.defineProperty;
|
|
10
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
11
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
12
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
13
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
14
|
+
var __export = (target, all) => {
|
|
15
|
+
for (var name in all)
|
|
16
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
17
|
+
};
|
|
18
|
+
var __copyProps = (to, from, except, desc) => {
|
|
19
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
20
|
+
for (let key of __getOwnPropNames(from))
|
|
21
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
22
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
23
|
+
}
|
|
24
|
+
return to;
|
|
25
|
+
};
|
|
26
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
27
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
28
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
29
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
30
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
31
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
32
|
+
mod
|
|
33
|
+
));
|
|
34
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
7
35
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
36
|
+
// src/client/index.ts
|
|
37
|
+
var index_exports = {};
|
|
38
|
+
__export(index_exports, {
|
|
39
|
+
LIVE_KEYS: () => LIVE_KEYS,
|
|
40
|
+
RUN_SETTLE_TIMEOUT_MS: () => RUN_SETTLE_TIMEOUT_MS2,
|
|
41
|
+
apply: () => apply,
|
|
42
|
+
card: () => card,
|
|
43
|
+
cardActions: () => cardActions,
|
|
44
|
+
cardState: () => cardState,
|
|
45
|
+
inject: () => inject
|
|
46
|
+
});
|
|
47
|
+
module.exports = __toCommonJS(index_exports);
|
|
48
|
+
|
|
49
|
+
// node_modules/@comecaramelos/dsh-ancesters/lib/client.esm.js
|
|
50
|
+
var react4 = __toESM(require("react"), 1);
|
|
51
|
+
var import_jsx_runtime = require("react/jsx-runtime");
|
|
52
|
+
var react = __toESM(require("react"), 1);
|
|
53
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
54
|
+
var react2 = __toESM(require("react"), 1);
|
|
55
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
56
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
57
|
+
var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
58
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
59
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
60
|
+
var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
61
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
62
|
+
var react3 = __toESM(require("react"), 1);
|
|
63
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
64
|
+
var import_dsh_client_ui_primitives3 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
65
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
66
|
+
var import_dsh_client_ui_primitives4 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
67
|
+
var import_dsh_client_store = require("@deepseek-ai/dsh-client-store");
|
|
68
|
+
function rowConfigKey(pkgName, entryId) {
|
|
69
|
+
if (typeof pkgName !== "string" || pkgName === "") {
|
|
70
|
+
throw new Error("dsh-ancesters: rowConfigKey(pkg, entryId) requires a non-empty package name");
|
|
71
|
+
}
|
|
72
|
+
if (typeof entryId !== "string" || entryId === "") {
|
|
73
|
+
throw new Error("dsh-ancesters: rowConfigKey(pkg, entryId) requires a non-empty entry id");
|
|
74
|
+
}
|
|
75
|
+
return `${pkgName}#${entryId}`;
|
|
76
|
+
}
|
|
77
|
+
var cssText = '.qox3mn_body{flex-direction:column;gap:10px;display:flex}.qox3mn_field{align-items:flex-start;gap:4px;display:flex;flex-direction:column;width:100%}.qox3mn_fieldRow{align-items:center;gap:8px;display:flex;width:100%}.qox3mn_fieldTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px;flex:1;min-width:0}.qox3mn_fieldDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px;width:100%}.qox3mn_selector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.qox3mn_selector:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.qox3mn_selector:disabled{cursor:default}.qox3mn_selectorWrap{display:flex}.qox3mn_pillChevron{flex:none}.qox3mn_row{display:flex;gap:10px;align-items:center}.qox3mn_button{display:inline-flex;align-items:center;justify-content:center;gap:4px;border:.5px solid var(--dsw-alias-border-l3);border-radius:14px;cursor:pointer;font-size:12px;line-height:18px;color:var(--dsw-alias-label-primary);background:transparent;padding:0 10px;height:28px}.qox3mn_button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.qox3mn_button:disabled{cursor:not-allowed;opacity:.4}.qox3mn_button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.qox3mn_readOnly{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.qox3mn_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:1.5}.qox3mn_dot{box-sizing:border-box;corner-shape:round;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.qox3mn_dotError{background:var(--dsw-alias-state-error-primary)}.qox3mn_badge{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-1);border-radius:10px;padding:1px 8px;font-size:11px;line-height:16px;display:inline-flex;align-items:center;flex:none}.qox3mn_empty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.qox3mn_catalog{flex-direction:column;align-items:stretch;gap:10px;display:flex}.qox3mn_catalog+.qox3mn_catalog{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:12px}.qox3mn_catalog>.qox3mn_linkButton{align-self:flex-start}.qox3mn_catalog>.qox3mn_linkButtonRow{align-self:flex-start;display:flex;gap:8px;align-items:center}.qox3mn_linkButton{box-sizing:border-box;border:none;background:0 0;color:var(--dsw-alias-label-tertiary);cursor:pointer;border-radius:14px;align-items:center;height:28px;padding:0 10px;font:inherit;font-size:12px;line-height:18px;display:inline-flex}.qox3mn_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.qox3mn_linkButton:disabled{opacity:.4;cursor:default}.qox3mn_linkButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.qox3mn_rowList{flex-direction:column;align-items:stretch;gap:6px;display:flex}.qox3mn_rowList>button{align-self:flex-start}.qox3mn_catalogEntry{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-module-platform);border-radius:10px;padding:6px}.qox3mn_catalogRow{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) auto;align-items:center;gap:6px;display:grid}.qox3mn_catalogInput{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;height:28px;padding:0 10px;font:inherit;font-size:14px;line-height:22px;min-width:0;width:100%}.qox3mn_catalogInput::placeholder{color:var(--dsw-alias-label-dimmed)}.qox3mn_catalogInput:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.qox3mn_catalogInput:disabled{opacity:.6;cursor:default}.qox3mn_iconButton{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;display:inline-flex}.qox3mn_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.qox3mn_iconButton:disabled{opacity:.4;cursor:default}.qox3mn_iconButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.qox3mn_iconButtonDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.qox3mn_addButton{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:14px;align-self:flex-start;align-items:center;gap:4px;height:28px;padding:0 10px;font:inherit;font-size:12px;line-height:18px;display:inline-flex}.qox3mn_addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.qox3mn_addButton:disabled{opacity:.4;cursor:default}.qox3mn_disclosure{flex-direction:column;gap:10px;display:flex}.qox3mn_disclosureSummary{color:var(--dsw-alias-label-secondary);cursor:pointer;list-style:none;align-items:center;gap:6px;font-size:12px;line-height:18px;user-select:none;display:flex}.qox3mn_disclosureSummary::-webkit-details-marker{display:none}.qox3mn_disclosureSummary:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-radius:6px}.qox3mn_disclosureLabel:before{content:"\\25b8";display:inline-block;margin-right:6px;transition:transform .16s}.qox3mn_disclosure[open] .qox3mn_disclosureLabel:before{transform:rotate(90deg)}.qox3mn_disclosureCount{color:var(--dsw-alias-label-tertiary)}.qox3mn_disclosureBody{flex-direction:column;gap:10px;display:flex}.qox3mn_disclosureBody>.qox3mn_linkButton{align-self:flex-start}.qox3mn_disclosureBody>.qox3mn_linkButtonRow{align-self:flex-start;display:flex;gap:8px;align-items:center}.qox3mn_toggleLabel{align-items:center;display:inline-flex;flex:none}.qox3mn_fetchDialog{background:color-mix(in srgb,var(--dsw-alias-label-primary) 28%,transparent);align-items:center;justify-content:center;display:flex;position:fixed;inset:0;z-index:90}.qox3mn_dialogContent{background:var(--dsw-alias-bg-layer-3);border:.5px solid var(--dsw-alias-border-l3);border-radius:16px;flex-direction:column;gap:10px;width:min(520px,calc(100vw - 32px));max-height:min(620px,calc(100vh - 48px));display:flex;overflow:hidden}.qox3mn_dialogHeader{align-items:center;gap:8px;padding:14px 16px 0;display:flex}.qox3mn_dialogTitle{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:22px;flex:1;min-width:0;margin:0}.qox3mn_dialogClose{box-sizing:border-box;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;flex:none;width:28px;height:28px;display:inline-flex}.qox3mn_dialogClose:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.qox3mn_dialogClose:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.qox3mn_dialogDescription{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0;padding:0 16px}.qox3mn_dialogBody{flex-direction:column;flex:1;gap:8px;min-height:0;padding:0 16px;display:flex}.qox3mn_candidateToolbar{align-items:center;gap:8px;display:flex}.qox3mn_candidateSearch{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;height:32px;padding:0 10px;font:inherit;font-size:12px;line-height:20px;flex:1;min-width:0}.qox3mn_candidateSearch::placeholder{color:var(--dsw-alias-label-dimmed)}.qox3mn_candidateSearch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.qox3mn_candidateList{flex-direction:column;gap:2px;margin:0;padding:0 0 10px;list-style:none;overflow-y:auto;display:flex}.qox3mn_candidate{border-radius:8px;padding:4px 6px}.qox3mn_candidate:hover{background:var(--dsw-alias-interactive-bg-hover)}.qox3mn_candidateLabel{align-items:center;gap:8px;min-width:0;display:flex}.qox3mn_candidateLabel input[type=checkbox]{accent-color:var(--dsw-alias-brand-primary);flex:none;margin:0}.qox3mn_candidateId{color:var(--dsw-alias-label-primary);font-size:12px;line-height:18px;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.qox3mn_candidateNote{color:var(--dsw-alias-label-tertiary);flex:0 1 auto;min-width:0;overflow-wrap:anywhere;font-size:11px;line-height:16px}.qox3mn_dialogFooter{border-top:.5px solid var(--dsw-alias-border-l2);align-items:center;justify-content:flex-end;gap:8px;padding:12px 16px;display:flex}.qox3mn_dialogButton{display:inline-flex;align-items:center;justify-content:center;gap:4px;border:.5px solid var(--dsw-alias-border-l3);border-radius:16px;cursor:pointer;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary);background:transparent;padding:0 12px;height:32px}.qox3mn_dialogButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.qox3mn_dialogButton:disabled{cursor:not-allowed;opacity:.4}.qox3mn_dialogButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.qox3mn_dialogButtonPrimary{color:var(--dsw-alias-label-primary);font-weight:600}.qox3mn_selectorLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.qox3mn_result{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.qox3mn_resultValue{color:var(--dsw-alias-label-secondary);margin-left:4px}.qox3mn_resultAge{color:var(--dsw-alias-label-dimmed);margin-left:4px}.qox3mn_notice{flex-direction:column;gap:4px;display:flex;border:.5px solid var(--dsw-alias-border-l3);border-radius:10px;background:var(--dsw-alias-bg-layer-1);padding:8px 10px}.qox3mn_noticeTitle{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:600;line-height:18px}.qox3mn_noticeBody{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.qox3mn_docsLink{color:var(--dsw-alias-label-tertiary);align-items:center;gap:4px;display:inline-flex;text-decoration:none;font-size:12px;line-height:1.5}.qox3mn_docsLinkLabel{text-decoration:none}.qox3mn_docsLink:hover{color:var(--dsw-alias-brand-primary)}.qox3mn_docsLink:hover .qox3mn_docsLinkLabel{text-decoration:underline}.qox3mn_docsLink:hover .qox3mn_docsIcon{color:var(--dsw-alias-brand-primary)}.qox3mn_docsIcon{color:var(--dsw-alias-label-tertiary);flex:none}.qox3mn_docsLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-radius:4px}.qox3mn_catalogRowSingle{grid-template-columns:minmax(0,1fr) auto}.qox3mn_catalogInputMono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.qox3mn_footer{border-top:.5px solid var(--dsw-alias-border-l2);align-items:center;justify-content:flex-end;gap:8px;padding:12px 0 0;display:flex}.qox3mn_footerError{color:var(--dsw-alias-label-error);text-align:right;min-width:0;flex:1;margin:0;font-size:12px;line-height:1.5}.qox3mn_footerButton{border:.5px solid var(--dsw-alias-border-l3);border-radius:8px;cursor:pointer;color:var(--dsw-alias-label-secondary);background:transparent;padding:5px 14px;font-size:13px;line-height:1.5}.qox3mn_footerButton:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.qox3mn_footerButton:disabled{cursor:default;opacity:.4}.qox3mn_footerButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.qox3mn_footerButtonPrimary{color:var(--dsw-alias-bg-layer-3);font-weight:600;background:var(--dsw-alias-label-primary);border-color:transparent}.qox3mn_footerButtonPrimary:hover:not(:disabled){color:var(--dsw-alias-bg-layer-3);background:var(--dsw-alias-label-secondary);border-color:transparent}.qox3mn_liveLine{align-items:center;gap:8px;display:flex;padding:6px 10px;border:.5px solid var(--dsw-alias-border-l3);border-radius:8px;background:var(--dsw-alias-bg-layer-1)}.qox3mn_liveLine:hover{border-color:var(--dsw-alias-border-l4)}.qox3mn_liveText{flex:1;min-width:0;display:flex;align-items:center;gap:8px}.qox3mn_liveName{color:var(--dsw-alias-label-primary);font-size:14px;line-height:20px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.qox3mn_liveState{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.qox3mn_tools{flex:1 1 auto;min-width:0;display:flex;flex-wrap:wrap;gap:4px;color:var(--dsw-alias-label-tertiary);font-size:11px;line-height:16px}.qox3mn_tools span{padding:0 6px;border:.5px solid var(--dsw-alias-border-l3);border-radius:6px;background:var(--dsw-alias-bg-module-platform)}.qox3mn_control{box-sizing:border-box;width:100%;min-width:0;height:28px;padding:0 10px;border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;font-size:14px;line-height:22px}.qox3mn_control::placeholder{color:var(--dsw-alias-label-dimmed)}.qox3mn_control:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.qox3mn_control:disabled{opacity:.6;cursor:default}.qox3mn_textarea{box-sizing:border-box;width:100%;min-width:0;min-height:64px;padding:6px 10px;border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:18px;resize:vertical}.qox3mn_textarea:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.qox3mn_textarea:disabled{opacity:.6;cursor:default}.qox3mn_select{box-sizing:border-box;height:28px;min-width:0;padding:0 8px;border:.5px solid var(--dsw-alias-border-l4);border-radius:8px;background:var(--dsw-alias-bg-module-platform);color:var(--dsw-alias-label-primary);font:inherit;font-size:13px;line-height:22px}.qox3mn_select:disabled{opacity:.6;cursor:default}.qox3mn_checkbox{margin:0;accent-color:var(--dsw-alias-brand-primary)}.qox3mn_controlField{align-items:flex-start;gap:4px;display:flex;flex-direction:column;width:100%}.qox3mn_controlTitle{color:var(--dsw-alias-label-primary);font-size:12px;line-height:18px}.qox3mn_controlField .qox3mn_control,.qox3mn_controlField .qox3mn_textarea{margin-top:2px}.qox3mn_grid{display:grid;grid-template-columns:minmax(96px,20%) minmax(0,1fr);gap:6px 10px;align-items:center;width:100%}.qox3mn_grid>label{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.qox3mn_editor{gap:10px;display:flex;flex-direction:column;padding:10px;border:.5px solid var(--dsw-alias-border-l3);border-radius:10px;background:var(--dsw-alias-bg-layer-1)}.qox3mn_editorTitle{color:var(--dsw-alias-label-primary);font-size:14px;line-height:20px}.qox3mn_editorHint{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.qox3mn_editorActions{align-items:center;gap:8px;display:flex;justify-content:flex-end}.qox3mn_transport{color:var(--dsw-alias-label-tertiary);font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px;line-height:18px;word-break:break-all}.qox3mn_summary{color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px;display:flex;align-items:center;gap:6px}.qox3mn_summaryItem{color:var(--dsw-alias-label-primary);font-size:13px;line-height:20px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.qox3mn_summaryNone{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:20px}.qox3mn_summaryBroken{color:var(--dsw-alias-state-error-primary);font-size:13px;line-height:20px}.qox3mn_toastRoot{z-index:2147483000;flex-direction:column;gap:8px;display:flex;position:fixed;right:16px;bottom:16px;max-width:min(360px,50vw)}.qox3mn_toast{border:.5px solid var(--dsw-alias-border-l3);border-radius:10px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);padding:8px 10px;font-size:12px;line-height:18px;box-shadow:0 4px 12px #0000001f;overflow-wrap:anywhere}.qox3mn_toast[data-notice-kind=error]{border-color:var(--dsw-alias-state-error-primary);color:var(--dsw-alias-label-primary)}.qox3mn_toast[data-notice-kind=stall]{border-color:var(--dsw-alias-border-l4);color:var(--dsw-alias-label-tertiary)}.qox3mn_composerPills{display:inline-flex;gap:4px}.qox3mn_composerPillRoot{display:flex}.qox3mn_composerPill{min-width:0;max-width:220px;height:28px;font:inherit;font-size:13px;font-weight:500;line-height:20px;color:var(--dsw-alias-label-secondary);cursor:pointer;background:transparent;border:none;border-radius:24px;outline:none;align-items:center;gap:4px;padding:0 4px 0 8px;display:inline-flex}.qox3mn_composerPill:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.qox3mn_composerPill:disabled{cursor:default}.qox3mn_composerPillIcon{flex:none;display:inline-flex;color:var(--dsw-alias-label-secondary)}.qox3mn_composerPillLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.qox3mn_composerPillChevron{color:var(--dsw-alias-label-caption);flex:none;transition:transform .12s;display:inline-flex}.qox3mn_composerPillChevronOpen{transform:rotate(180deg)}\n';
|
|
78
|
+
var shared_default = { "body": "qox3mn_body", "field": "qox3mn_field", "fieldRow": "qox3mn_fieldRow", "fieldTitle": "qox3mn_fieldTitle", "fieldDesc": "qox3mn_fieldDesc", "selector": "qox3mn_selector", "selectorWrap": "qox3mn_selectorWrap", "pillChevron": "qox3mn_pillChevron", "row": "qox3mn_row", "button": "qox3mn_button", "readOnly": "qox3mn_readOnly", "error": "qox3mn_error", "dot": "qox3mn_dot", "dotError": "qox3mn_dotError", "badge": "qox3mn_badge", "empty": "qox3mn_empty", "catalog": "qox3mn_catalog", "linkButton": "qox3mn_linkButton", "linkButtonRow": "qox3mn_linkButtonRow", "rowList": "qox3mn_rowList", "catalogEntry": "qox3mn_catalogEntry", "catalogRow": "qox3mn_catalogRow", "catalogInput": "qox3mn_catalogInput", "iconButton": "qox3mn_iconButton", "iconButtonDanger": "qox3mn_iconButtonDanger", "addButton": "qox3mn_addButton", "disclosure": "qox3mn_disclosure", "disclosureSummary": "qox3mn_disclosureSummary", "disclosureLabel": "qox3mn_disclosureLabel", "disclosureCount": "qox3mn_disclosureCount", "disclosureBody": "qox3mn_disclosureBody", "toggleLabel": "qox3mn_toggleLabel", "fetchDialog": "qox3mn_fetchDialog", "dialogContent": "qox3mn_dialogContent", "dialogHeader": "qox3mn_dialogHeader", "dialogTitle": "qox3mn_dialogTitle", "dialogClose": "qox3mn_dialogClose", "dialogDescription": "qox3mn_dialogDescription", "dialogBody": "qox3mn_dialogBody", "candidateToolbar": "qox3mn_candidateToolbar", "candidateSearch": "qox3mn_candidateSearch", "candidateList": "qox3mn_candidateList", "candidate": "qox3mn_candidate", "candidateLabel": "qox3mn_candidateLabel", "candidateId": "qox3mn_candidateId", "candidateNote": "qox3mn_candidateNote", "dialogFooter": "qox3mn_dialogFooter", "dialogButton": "qox3mn_dialogButton", "dialogButtonPrimary": "qox3mn_dialogButtonPrimary", "selectorLabel": "qox3mn_selectorLabel", "result": "qox3mn_result", "resultValue": "qox3mn_resultValue", "resultAge": "qox3mn_resultAge", "notice": "qox3mn_notice", "noticeTitle": "qox3mn_noticeTitle", "noticeBody": "qox3mn_noticeBody", "docsLink": "qox3mn_docsLink", "docsLinkLabel": "qox3mn_docsLinkLabel", "docsIcon": "qox3mn_docsIcon", "catalogRowSingle": "qox3mn_catalogRowSingle", "catalogInputMono": "qox3mn_catalogInputMono", "footer": "qox3mn_footer", "footerError": "qox3mn_footerError", "footerButton": "qox3mn_footerButton", "footerButtonPrimary": "qox3mn_footerButtonPrimary", "liveLine": "qox3mn_liveLine", "liveText": "qox3mn_liveText", "liveName": "qox3mn_liveName", "liveState": "qox3mn_liveState", "tools": "qox3mn_tools", "control": "qox3mn_control", "textarea": "qox3mn_textarea", "select": "qox3mn_select", "checkbox": "qox3mn_checkbox", "controlField": "qox3mn_controlField", "controlTitle": "qox3mn_controlTitle", "grid": "qox3mn_grid", "editor": "qox3mn_editor", "editorTitle": "qox3mn_editorTitle", "editorHint": "qox3mn_editorHint", "editorActions": "qox3mn_editorActions", "transport": "qox3mn_transport", "summary": "qox3mn_summary", "summaryItem": "qox3mn_summaryItem", "summaryNone": "qox3mn_summaryNone", "summaryBroken": "qox3mn_summaryBroken", "toastRoot": "qox3mn_toastRoot", "toast": "qox3mn_toast", "composerPills": "qox3mn_composerPills", "composerPillRoot": "qox3mn_composerPillRoot", "composerPill": "qox3mn_composerPill", "composerPillIcon": "qox3mn_composerPillIcon", "composerPillLabel": "qox3mn_composerPillLabel", "composerPillChevron": "qox3mn_composerPillChevron", "composerPillChevronOpen": "qox3mn_composerPillChevronOpen" };
|
|
79
|
+
var CHEVRON_PATH = "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z";
|
|
80
|
+
var TRASH_PATH = "M2.5 4h11M6.5 4V2.5h3V4M4 4l.7 9a1 1 0 001 .9h4.6a1 1 0 001-.9L12 4M6.5 6.8v4.4M9.5 6.8v4.4";
|
|
81
|
+
var CLOSE_PATHS = [
|
|
82
|
+
"M14.1168 13.197L13.197 14.1167L1.8833 2.80303L2.80309 1.88324L14.1168 13.197Z",
|
|
83
|
+
"M13.197 1.88326L14.1168 2.80305L2.80309 14.1168L1.8833 13.197L13.197 1.88326Z"
|
|
84
|
+
];
|
|
85
|
+
var DOCS_PATHS = [
|
|
86
|
+
"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",
|
|
87
|
+
"M15 3h6v6",
|
|
88
|
+
"M10 14 21 3"
|
|
89
|
+
];
|
|
90
|
+
function RowsBlock(props) {
|
|
91
|
+
const served = Array.isArray(props.values) ? props.values : [];
|
|
92
|
+
const writable = props.writable === true;
|
|
93
|
+
const busy = props.busy === true;
|
|
94
|
+
const labels = Array.isArray(props.labels) ? props.labels : [];
|
|
95
|
+
const placeholders = Array.isArray(props.placeholders) ? props.placeholders : [];
|
|
96
|
+
const columns = Math.max(1, labels.length);
|
|
97
|
+
const blankRow = [];
|
|
98
|
+
for (let blank = 0; blank < columns; blank++) blankRow.push("");
|
|
99
|
+
const servedKey = JSON.stringify(served);
|
|
100
|
+
const draftState = react.useState({ key: "", rows: [] });
|
|
101
|
+
const draft = draftState[0];
|
|
102
|
+
const setDraft = draftState[1];
|
|
103
|
+
const rows = draft.key === servedKey ? draft.rows : served.map((row) => Array.from(row));
|
|
104
|
+
const write = (next) => {
|
|
105
|
+
const saved = props.save === void 0 ? void 0 : props.save(next);
|
|
106
|
+
return Promise.resolve(saved === void 0 ? void 0 : saved).then(
|
|
107
|
+
() => {
|
|
108
|
+
setDraft({ key: "", rows: [] });
|
|
109
|
+
},
|
|
110
|
+
(failure) => {
|
|
111
|
+
throw failure;
|
|
112
|
+
}
|
|
113
|
+
);
|
|
114
|
+
};
|
|
115
|
+
const setCell = (at, column, value) => {
|
|
116
|
+
const next = rows.map((row, index) => index === at ? row.map((cell, cellIndex) => cellIndex === column ? value : cell) : row.slice());
|
|
117
|
+
setDraft({ key: servedKey, rows: next });
|
|
118
|
+
};
|
|
119
|
+
const commit = () => {
|
|
120
|
+
const cleaned = [];
|
|
121
|
+
for (const row of rows) {
|
|
122
|
+
const cells = row.map((cell) => String(cell ?? "").trim());
|
|
123
|
+
if (cells.some((cell) => cell !== "")) cleaned.push(cells);
|
|
124
|
+
}
|
|
125
|
+
return write(cleaned);
|
|
126
|
+
};
|
|
127
|
+
const remove = (at) => {
|
|
128
|
+
return write(rows.filter((_row, index) => index !== at));
|
|
129
|
+
};
|
|
130
|
+
const add = () => {
|
|
131
|
+
setDraft({ key: servedKey, rows: rows.concat([blankRow.slice()]) });
|
|
132
|
+
};
|
|
133
|
+
const rowClass = props.rowClassName === void 0 || props.rowClassName === shared_default.catalogRow ? shared_default.catalogRow : shared_default.catalogRow + " " + props.rowClassName;
|
|
134
|
+
const inputClass = props.inputClassName === void 0 ? shared_default.catalogInput : props.inputClassName;
|
|
135
|
+
const list = (0, import_jsx_runtime2.jsxs)("div", {
|
|
136
|
+
className: shared_default.rowList,
|
|
137
|
+
children: [
|
|
138
|
+
served.length === 0 && props.emptyLabel !== void 0 ? (0, import_jsx_runtime2.jsx)("div", { className: shared_default.empty, children: props.emptyLabel }, "empty") : null,
|
|
139
|
+
rows.map(
|
|
140
|
+
(row, at) => (0, import_jsx_runtime2.jsx)("div", {
|
|
141
|
+
className: shared_default.catalogEntry,
|
|
142
|
+
children: (0, import_jsx_runtime2.jsxs)("div", {
|
|
143
|
+
className: rowClass,
|
|
144
|
+
children: [
|
|
145
|
+
row.map(
|
|
146
|
+
(cell, column) => (0, import_jsx_runtime2.jsx)("input", {
|
|
147
|
+
className: inputClass,
|
|
148
|
+
type: "text",
|
|
149
|
+
value: cell === void 0 ? "" : cell,
|
|
150
|
+
placeholder: placeholders[column] === void 0 ? "" : placeholders[column],
|
|
151
|
+
disabled: !writable || busy,
|
|
152
|
+
onChange: (event) => {
|
|
153
|
+
setCell(at, column, typeof event?.target?.value === "string" ? event.target.value : "");
|
|
154
|
+
},
|
|
155
|
+
onBlur: () => {
|
|
156
|
+
if (writable && !busy) void commit();
|
|
157
|
+
},
|
|
158
|
+
onKeyDown: (event) => {
|
|
159
|
+
if (event.key === "Enter") {
|
|
160
|
+
if (typeof event.preventDefault === "function") event.preventDefault();
|
|
161
|
+
if (writable && !busy) void commit();
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}, column)
|
|
165
|
+
),
|
|
166
|
+
(0, import_jsx_runtime2.jsx)("button", {
|
|
167
|
+
type: "button",
|
|
168
|
+
className: shared_default.iconButton + " " + shared_default.iconButtonDanger,
|
|
169
|
+
disabled: !writable || busy,
|
|
170
|
+
title: props.removeLabel === void 0 ? "" : props.removeLabel,
|
|
171
|
+
onClick: () => {
|
|
172
|
+
if (writable && !busy) void remove(at);
|
|
173
|
+
},
|
|
174
|
+
children: (0, import_jsx_runtime2.jsx)("svg", {
|
|
175
|
+
width: 14,
|
|
176
|
+
height: 14,
|
|
177
|
+
viewBox: "0 0 16 16",
|
|
178
|
+
fill: "none",
|
|
179
|
+
stroke: "currentColor",
|
|
180
|
+
children: (0, import_jsx_runtime2.jsx)("path", { d: TRASH_PATH })
|
|
181
|
+
})
|
|
182
|
+
}, "remove")
|
|
183
|
+
]
|
|
184
|
+
})
|
|
185
|
+
}, at)
|
|
186
|
+
),
|
|
187
|
+
(0, import_jsx_runtime2.jsx)("button", {
|
|
188
|
+
type: "button",
|
|
189
|
+
className: shared_default.linkButton,
|
|
190
|
+
disabled: !writable || busy,
|
|
191
|
+
title: props.addTitle === void 0 ? "" : props.addTitle,
|
|
192
|
+
onClick: () => {
|
|
193
|
+
if (!writable || busy) return;
|
|
194
|
+
add();
|
|
195
|
+
},
|
|
196
|
+
children: props.addLabel === void 0 ? "" : props.addLabel
|
|
197
|
+
}, "add"),
|
|
198
|
+
props.renderAction === void 0 ? null : props.renderAction(rows)
|
|
199
|
+
]
|
|
200
|
+
});
|
|
201
|
+
if (props.disclosure !== true) return list;
|
|
202
|
+
return (0, import_jsx_runtime2.jsxs)("details", {
|
|
203
|
+
className: shared_default.disclosure,
|
|
204
|
+
children: [
|
|
205
|
+
(0, import_jsx_runtime2.jsxs)("summary", {
|
|
206
|
+
className: shared_default.disclosureSummary,
|
|
207
|
+
children: [
|
|
208
|
+
(0, import_jsx_runtime2.jsx)("span", { className: shared_default.disclosureLabel, children: props.disclosureLabel === void 0 ? "" : props.disclosureLabel }),
|
|
209
|
+
(0, import_jsx_runtime2.jsx)("span", {
|
|
210
|
+
className: shared_default.disclosureCount,
|
|
211
|
+
children: (props.disclosureCountLabel === void 0 ? String(rows.length) : props.disclosureCountLabel).replace("{count}", String(rows.length))
|
|
212
|
+
})
|
|
213
|
+
]
|
|
214
|
+
}),
|
|
215
|
+
(0, import_jsx_runtime2.jsx)("div", { className: shared_default.disclosureBody, children: list })
|
|
216
|
+
]
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
function DialogBlock(props) {
|
|
220
|
+
var t = props.t;
|
|
221
|
+
var candidates = Array.from(props.candidates);
|
|
222
|
+
var savedIds = Array.from(props.savedIds);
|
|
223
|
+
var savedSet = new Set(savedIds);
|
|
224
|
+
var initialChecked = candidates.filter((candidate) => savedSet.has(candidate.id)).map((candidate) => candidate.id);
|
|
225
|
+
var servedKey = JSON.stringify(candidates) + "|" + JSON.stringify(savedIds);
|
|
226
|
+
var draftState = react2.useState({ key: "", query: "", checked: [] });
|
|
227
|
+
var draft = draftState[0];
|
|
228
|
+
var setDraft = draftState[1];
|
|
229
|
+
var dirty = draft.key !== servedKey;
|
|
230
|
+
var query = dirty ? "" : draft.query;
|
|
231
|
+
var checked = dirty ? initialChecked : draft.checked;
|
|
232
|
+
var checkedSet = new Set(checked);
|
|
233
|
+
var setQuery = (value) => {
|
|
234
|
+
setDraft({ key: servedKey, query: value, checked: Array.from(checkedSet) });
|
|
235
|
+
};
|
|
236
|
+
var setChecked = (make) => {
|
|
237
|
+
setDraft({ key: servedKey, query, checked: make(checked) });
|
|
238
|
+
};
|
|
239
|
+
var needle = query.trim().toLowerCase();
|
|
240
|
+
var shown = needle === "" ? candidates : candidates.filter((candidate) => candidate.id.toLowerCase().indexOf(needle) !== -1);
|
|
241
|
+
var addable = shown.filter((candidate) => !savedSet.has(candidate.id)).map((candidate) => candidate.id);
|
|
242
|
+
var allChecked = addable.length > 0 && addable.every((id) => checkedSet.has(id));
|
|
243
|
+
var toggle = (id, value) => {
|
|
244
|
+
setChecked((current) => value ? current.concat([id]) : current.filter((entry) => entry !== id));
|
|
245
|
+
};
|
|
246
|
+
return (0, import_jsx_runtime3.jsxs)("div", {
|
|
247
|
+
className: shared_default.fetchDialog,
|
|
248
|
+
role: "dialog",
|
|
249
|
+
"aria-modal": "true",
|
|
250
|
+
"aria-label": props.title,
|
|
251
|
+
children: [
|
|
252
|
+
(0, import_jsx_runtime3.jsxs)("div", {
|
|
253
|
+
className: shared_default.dialogContent,
|
|
254
|
+
children: [
|
|
255
|
+
(0, import_jsx_runtime3.jsxs)("div", {
|
|
256
|
+
className: shared_default.dialogHeader,
|
|
257
|
+
children: [
|
|
258
|
+
(0, import_jsx_runtime3.jsx)("h2", { className: shared_default.dialogTitle, children: props.title }),
|
|
259
|
+
(0, import_jsx_runtime3.jsx)("button", {
|
|
260
|
+
type: "button",
|
|
261
|
+
className: shared_default.dialogClose,
|
|
262
|
+
"aria-label": t("close"),
|
|
263
|
+
onClick: () => props.onClose(),
|
|
264
|
+
children: (0, import_jsx_runtime3.jsx)("svg", {
|
|
265
|
+
width: 14,
|
|
266
|
+
height: 14,
|
|
267
|
+
viewBox: "0 0 16 16",
|
|
268
|
+
fill: "none",
|
|
269
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
270
|
+
"aria-hidden": "true",
|
|
271
|
+
children: CLOSE_PATHS.map((d, at) => (0, import_jsx_runtime3.jsx)("path", { d, fill: "currentColor" }, at))
|
|
272
|
+
})
|
|
273
|
+
})
|
|
274
|
+
]
|
|
275
|
+
}),
|
|
276
|
+
(0, import_jsx_runtime3.jsx)("p", { className: shared_default.dialogDescription, children: props.description }),
|
|
277
|
+
(0, import_jsx_runtime3.jsxs)("div", {
|
|
278
|
+
className: shared_default.dialogBody,
|
|
279
|
+
children: [
|
|
280
|
+
(0, import_jsx_runtime3.jsxs)("div", {
|
|
281
|
+
className: shared_default.candidateToolbar,
|
|
282
|
+
children: [
|
|
283
|
+
(0, import_jsx_runtime3.jsx)("input", {
|
|
284
|
+
className: shared_default.candidateSearch,
|
|
285
|
+
type: "search",
|
|
286
|
+
placeholder: props.searchPlaceholder,
|
|
287
|
+
"aria-label": props.searchPlaceholder,
|
|
288
|
+
value: query,
|
|
289
|
+
onChange: (event) => {
|
|
290
|
+
setQuery(event && event.target ? String(event.target.value ?? "") : "");
|
|
291
|
+
}
|
|
292
|
+
}),
|
|
293
|
+
(0, import_jsx_runtime3.jsx)("button", {
|
|
294
|
+
type: "button",
|
|
295
|
+
className: shared_default.linkButton,
|
|
296
|
+
onClick: () => {
|
|
297
|
+
if (allChecked) setChecked(() => []);
|
|
298
|
+
else setChecked((current) => Array.from(new Set(current.concat(addable))));
|
|
299
|
+
},
|
|
300
|
+
children: t("selectAll")
|
|
301
|
+
})
|
|
302
|
+
]
|
|
303
|
+
}),
|
|
304
|
+
shown.length === 0 ? (0, import_jsx_runtime3.jsx)("p", { className: shared_default.empty, children: t("dialogEmpty") }) : (0, import_jsx_runtime3.jsx)("ul", {
|
|
305
|
+
className: shared_default.candidateList,
|
|
306
|
+
children: shown.map((candidate) => {
|
|
307
|
+
var isSaved = savedSet.has(candidate.id);
|
|
308
|
+
var note = candidate.note !== "" ? candidate.note : isSaved ? t("candidateSaved") : "";
|
|
309
|
+
return (0, import_jsx_runtime3.jsx)("li", {
|
|
310
|
+
className: shared_default.candidate,
|
|
311
|
+
children: (0, import_jsx_runtime3.jsxs)("label", {
|
|
312
|
+
className: shared_default.candidateLabel,
|
|
313
|
+
children: [
|
|
314
|
+
(0, import_jsx_runtime3.jsx)("input", {
|
|
315
|
+
type: "checkbox",
|
|
316
|
+
checked: isSaved ? true : checkedSet.has(candidate.id),
|
|
317
|
+
disabled: isSaved,
|
|
318
|
+
onChange: (event) => {
|
|
319
|
+
toggle(candidate.id, !!(event && event.target && event.target.checked));
|
|
320
|
+
}
|
|
321
|
+
}),
|
|
322
|
+
(0, import_jsx_runtime3.jsx)("span", { className: shared_default.candidateId, children: candidate.id }),
|
|
323
|
+
note === "" ? null : (0, import_jsx_runtime3.jsx)("span", { className: shared_default.candidateNote, children: note })
|
|
324
|
+
]
|
|
325
|
+
})
|
|
326
|
+
}, candidate.id);
|
|
327
|
+
})
|
|
328
|
+
})
|
|
329
|
+
]
|
|
330
|
+
}),
|
|
331
|
+
(0, import_jsx_runtime3.jsxs)("div", {
|
|
332
|
+
className: shared_default.dialogFooter,
|
|
333
|
+
children: [
|
|
334
|
+
(0, import_jsx_runtime3.jsx)("button", {
|
|
335
|
+
type: "button",
|
|
336
|
+
className: shared_default.dialogButton,
|
|
337
|
+
onClick: () => props.onClose(),
|
|
338
|
+
children: t("cancel")
|
|
339
|
+
}),
|
|
340
|
+
(0, import_jsx_runtime3.jsx)("button", {
|
|
341
|
+
type: "button",
|
|
342
|
+
className: shared_default.dialogButton + " " + shared_default.dialogButtonPrimary,
|
|
343
|
+
onClick: () => props.onAdd(Array.from(checkedSet)),
|
|
344
|
+
children: t("addSelected")
|
|
345
|
+
})
|
|
346
|
+
]
|
|
347
|
+
})
|
|
348
|
+
]
|
|
349
|
+
})
|
|
350
|
+
]
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
function PickerBlock(props) {
|
|
354
|
+
const entries = Array.isArray(props.entries) ? props.entries : [];
|
|
355
|
+
const options = Array.isArray(props.options) ? props.options : [];
|
|
356
|
+
const selectedId = props.selectedId === void 0 ? "" : props.selectedId;
|
|
357
|
+
const writable = props.writable === true;
|
|
358
|
+
const busy = props.busy === true;
|
|
359
|
+
const rows = entries.map((entry) => [entry.id, entry.name]);
|
|
360
|
+
const saveEntries = (next) => {
|
|
361
|
+
if (props.save === void 0) return Promise.resolve();
|
|
362
|
+
return Promise.resolve(props.save(next.map((row) => ({ id: row[0] ?? "", name: row[1] ?? "" }))));
|
|
363
|
+
};
|
|
364
|
+
const refreshAction = () => (0, import_jsx_runtime4.jsx)("button", {
|
|
365
|
+
type: "button",
|
|
366
|
+
className: shared_default.linkButton,
|
|
367
|
+
disabled: !writable || busy,
|
|
368
|
+
onClick: () => {
|
|
369
|
+
props.refresh();
|
|
370
|
+
},
|
|
371
|
+
children: busy && props.busyLabel !== void 0 ? props.busyLabel : props.refreshLabel
|
|
372
|
+
});
|
|
373
|
+
const extras = props.actions === void 0 ? [] : props.actions;
|
|
374
|
+
const renderActions = () => (0, import_jsx_runtime4.jsxs)("div", {
|
|
375
|
+
className: shared_default.linkButtonRow,
|
|
376
|
+
children: [
|
|
377
|
+
refreshAction(),
|
|
378
|
+
...extras.map(
|
|
379
|
+
(action, index) => (0, import_jsx_runtime4.jsx)("button", {
|
|
380
|
+
type: "button",
|
|
381
|
+
className: shared_default.linkButton,
|
|
382
|
+
disabled: !writable || busy || action.disabled === true,
|
|
383
|
+
title: action.title === void 0 ? "" : action.title,
|
|
384
|
+
onClick: () => {
|
|
385
|
+
action.onClick();
|
|
386
|
+
},
|
|
387
|
+
children: action.label
|
|
388
|
+
}, index)
|
|
389
|
+
)
|
|
390
|
+
]
|
|
391
|
+
});
|
|
392
|
+
return (0, import_jsx_runtime4.jsxs)("div", {
|
|
393
|
+
className: shared_default.catalog,
|
|
394
|
+
children: [
|
|
395
|
+
(0, import_jsx_runtime4.jsxs)("div", {
|
|
396
|
+
className: shared_default.field,
|
|
397
|
+
children: [
|
|
398
|
+
(0, import_jsx_runtime4.jsxs)("div", {
|
|
399
|
+
className: shared_default.fieldRow,
|
|
400
|
+
children: [
|
|
401
|
+
props.selectorLabel === void 0 || props.selectorLabel === "" ? null : (0, import_jsx_runtime4.jsx)("span", { className: shared_default.fieldTitle, children: props.selectorLabel }),
|
|
402
|
+
(0, import_jsx_runtime4.jsx)("span", {
|
|
403
|
+
className: shared_default.selectorWrap,
|
|
404
|
+
children: (0, import_jsx_runtime4.jsx)(import_dsh_client_ui_primitives.Menu, {
|
|
405
|
+
open: props.menuOpen === true,
|
|
406
|
+
onClose: () => {
|
|
407
|
+
props.setMenuOpen(false);
|
|
408
|
+
},
|
|
409
|
+
items: options.map((option) => ({ id: option.id, label: option.label })),
|
|
410
|
+
selectedId: options.some((option) => option.id === selectedId) ? selectedId : "",
|
|
411
|
+
onSelect: (id) => {
|
|
412
|
+
props.setMenuOpen(false);
|
|
413
|
+
props.select(id);
|
|
414
|
+
},
|
|
415
|
+
align: "end",
|
|
416
|
+
portal: true,
|
|
417
|
+
anchor: (0, import_jsx_runtime4.jsxs)("button", {
|
|
418
|
+
type: "button",
|
|
419
|
+
className: shared_default.selector,
|
|
420
|
+
"aria-haspopup": "menu",
|
|
421
|
+
"aria-expanded": props.menuOpen === true,
|
|
422
|
+
disabled: !writable || busy,
|
|
423
|
+
title: props.selectedTitle === void 0 ? "" : props.selectedTitle,
|
|
424
|
+
onClick: () => {
|
|
425
|
+
props.setMenuOpen(!(props.menuOpen === true));
|
|
426
|
+
},
|
|
427
|
+
children: [
|
|
428
|
+
// A bare label; a path needs its own
|
|
429
|
+
// truncating span.
|
|
430
|
+
(0, import_jsx_runtime4.jsx)("span", { className: shared_default.selectorLabel, children: props.selectedLabel }),
|
|
431
|
+
(0, import_jsx_runtime4.jsx)("svg", {
|
|
432
|
+
width: 14,
|
|
433
|
+
height: 14,
|
|
434
|
+
className: shared_default.pillChevron,
|
|
435
|
+
viewBox: "0 0 14 14",
|
|
436
|
+
fill: "none",
|
|
437
|
+
"aria-hidden": "true",
|
|
438
|
+
children: (0, import_jsx_runtime4.jsx)("path", { d: CHEVRON_PATH, fill: "currentColor" })
|
|
439
|
+
})
|
|
440
|
+
]
|
|
441
|
+
})
|
|
442
|
+
})
|
|
443
|
+
})
|
|
444
|
+
]
|
|
445
|
+
}),
|
|
446
|
+
props.hint === void 0 ? null : (0, import_jsx_runtime4.jsx)("div", { className: shared_default.fieldDesc, children: props.hint })
|
|
447
|
+
]
|
|
448
|
+
}),
|
|
449
|
+
RowsBlock({
|
|
450
|
+
values: rows,
|
|
451
|
+
save: saveEntries,
|
|
452
|
+
labels: [props.idLabel === void 0 ? "" : props.idLabel, props.nameLabel === void 0 ? "" : props.nameLabel],
|
|
453
|
+
placeholders: [props.idPlaceholder === void 0 ? "" : props.idPlaceholder, props.namePlaceholder === void 0 ? "" : props.namePlaceholder],
|
|
454
|
+
writable: props.writable,
|
|
455
|
+
busy,
|
|
456
|
+
emptyLabel: props.emptyText,
|
|
457
|
+
addLabel: props.addLabel,
|
|
458
|
+
removeLabel: props.removeLabel,
|
|
459
|
+
disclosureLabel: props.rowsLabel,
|
|
460
|
+
disclosure: true,
|
|
461
|
+
rowClassName: shared_default.catalogRow,
|
|
462
|
+
renderAction: renderActions
|
|
463
|
+
}),
|
|
464
|
+
props.statusLine === void 0 || props.statusLine === null ? null : props.statusLine
|
|
465
|
+
]
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
function FlagsBlock(props) {
|
|
469
|
+
const writable = props.writable === true;
|
|
470
|
+
const busy = props.busy === true;
|
|
471
|
+
const flags = Array.isArray(props.flags) ? props.flags : [];
|
|
472
|
+
const saveValues = (next) => {
|
|
473
|
+
const cleaned = next.map((row) => String(row === void 0 || row === null ? "" : row[0] ?? "").trim()).filter((flag) => flag !== "").filter((flag, index, all) => all.indexOf(flag) === index);
|
|
474
|
+
if (typeof props.save !== "function") return Promise.resolve();
|
|
475
|
+
return Promise.resolve(props.save(cleaned));
|
|
476
|
+
};
|
|
477
|
+
const actions = props.actions === void 0 ? [] : props.actions;
|
|
478
|
+
const renderAction = (visible) => (0, import_jsx_runtime5.jsxs)("div", {
|
|
479
|
+
className: shared_default.linkButtonRow,
|
|
480
|
+
children: actions.map(
|
|
481
|
+
(action, index) => (0, import_jsx_runtime5.jsx)(
|
|
482
|
+
"button",
|
|
483
|
+
{
|
|
484
|
+
type: "button",
|
|
485
|
+
className: shared_default.linkButton,
|
|
486
|
+
disabled: !writable || busy || action.disabled === true,
|
|
487
|
+
title: action.title === void 0 ? action.label : action.title,
|
|
488
|
+
onClick: () => {
|
|
489
|
+
if (!writable || busy) return;
|
|
490
|
+
const current = visible.map((row) => String(row[0] ?? "").trim()).filter((flag) => flag !== "");
|
|
491
|
+
const merged = Array.from(/* @__PURE__ */ new Set([...current, ...action.merged(current)]));
|
|
492
|
+
void saveValues(merged.map((flag) => [flag]));
|
|
493
|
+
},
|
|
494
|
+
children: action.label
|
|
495
|
+
},
|
|
496
|
+
index
|
|
497
|
+
)
|
|
498
|
+
)
|
|
499
|
+
}, "actions");
|
|
500
|
+
return (0, import_jsx_runtime5.jsxs)("div", {
|
|
501
|
+
className: shared_default.catalog,
|
|
502
|
+
children: [
|
|
503
|
+
(0, import_jsx_runtime5.jsxs)("div", {
|
|
504
|
+
className: shared_default.field,
|
|
505
|
+
children: [
|
|
506
|
+
(0, import_jsx_runtime5.jsxs)("div", {
|
|
507
|
+
className: shared_default.fieldRow,
|
|
508
|
+
children: [
|
|
509
|
+
(0, import_jsx_runtime5.jsx)("span", { className: shared_default.fieldTitle, children: props.title }),
|
|
510
|
+
props.link === void 0 || props.link.href === "" ? null : (0, import_jsx_runtime5.jsxs)("a", {
|
|
511
|
+
className: shared_default.docsLink,
|
|
512
|
+
href: props.link.href,
|
|
513
|
+
target: "_blank",
|
|
514
|
+
rel: "noopener noreferrer",
|
|
515
|
+
title: props.link.title === void 0 ? props.link.label : props.link.title,
|
|
516
|
+
children: [
|
|
517
|
+
(0, import_jsx_runtime5.jsx)("svg", {
|
|
518
|
+
className: shared_default.docsIcon,
|
|
519
|
+
width: 14,
|
|
520
|
+
height: 14,
|
|
521
|
+
viewBox: "0 0 24 24",
|
|
522
|
+
fill: "none",
|
|
523
|
+
stroke: "currentColor",
|
|
524
|
+
strokeWidth: 2,
|
|
525
|
+
strokeLinecap: "round",
|
|
526
|
+
strokeLinejoin: "round",
|
|
527
|
+
"aria-hidden": "true",
|
|
528
|
+
children: DOCS_PATHS.map((d, at) => (0, import_jsx_runtime5.jsx)("path", { d }, at))
|
|
529
|
+
}),
|
|
530
|
+
(0, import_jsx_runtime5.jsx)("span", { className: shared_default.docsLinkLabel, children: props.link.label })
|
|
531
|
+
]
|
|
532
|
+
})
|
|
533
|
+
]
|
|
534
|
+
}),
|
|
535
|
+
props.hint === void 0 ? null : (0, import_jsx_runtime5.jsx)("div", { className: shared_default.fieldDesc, children: props.hint })
|
|
536
|
+
]
|
|
537
|
+
}),
|
|
538
|
+
RowsBlock({
|
|
539
|
+
values: flags.map((flag) => [flag]),
|
|
540
|
+
save: saveValues,
|
|
541
|
+
labels: [props.rowLabel === void 0 ? "" : props.rowLabel],
|
|
542
|
+
placeholders: [props.rowPlaceholder === void 0 ? "" : props.rowPlaceholder],
|
|
543
|
+
writable: props.writable,
|
|
544
|
+
busy,
|
|
545
|
+
emptyLabel: props.emptyText,
|
|
546
|
+
addLabel: props.addLabel,
|
|
547
|
+
removeLabel: props.removeLabel,
|
|
548
|
+
disclosureLabel: props.disclosureLabel,
|
|
549
|
+
disclosure: props.disclosure === true,
|
|
550
|
+
rowClassName: shared_default.catalogRowSingle,
|
|
551
|
+
inputClassName: shared_default.catalogInput,
|
|
552
|
+
renderAction
|
|
553
|
+
})
|
|
554
|
+
]
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
function SwitchField(props) {
|
|
558
|
+
const control = (0, import_jsx_runtime6.jsx)(import_dsh_client_ui_primitives2.Switch, {
|
|
559
|
+
checked: props.checked === true,
|
|
560
|
+
label: props.label,
|
|
561
|
+
disabled: props.disabled === true || props.busy === true,
|
|
562
|
+
onChange: () => {
|
|
563
|
+
if (typeof props.onToggle === "function") props.onToggle();
|
|
564
|
+
}
|
|
565
|
+
});
|
|
566
|
+
if (props.variant === "row") {
|
|
567
|
+
return (0, import_jsx_runtime6.jsx)("span", {
|
|
568
|
+
className: shared_default.toggleLabel,
|
|
569
|
+
title: props.title === void 0 ? props.label : props.title,
|
|
570
|
+
"aria-label": props.label,
|
|
571
|
+
children: control
|
|
572
|
+
});
|
|
573
|
+
}
|
|
574
|
+
return (0, import_jsx_runtime6.jsxs)("div", {
|
|
575
|
+
className: shared_default.catalog,
|
|
576
|
+
children: [
|
|
577
|
+
(0, import_jsx_runtime6.jsxs)("div", {
|
|
578
|
+
className: shared_default.field,
|
|
579
|
+
children: [
|
|
580
|
+
(0, import_jsx_runtime6.jsxs)("div", {
|
|
581
|
+
className: shared_default.fieldRow,
|
|
582
|
+
children: [
|
|
583
|
+
(0, import_jsx_runtime6.jsx)("span", { className: shared_default.fieldTitle, children: props.label }),
|
|
584
|
+
(0, import_jsx_runtime6.jsx)("span", {
|
|
585
|
+
className: shared_default.toggleLabel,
|
|
586
|
+
title: props.title === void 0 ? props.label : props.title,
|
|
587
|
+
children: control
|
|
588
|
+
})
|
|
589
|
+
]
|
|
590
|
+
}),
|
|
591
|
+
props.hint === void 0 ? null : (0, import_jsx_runtime6.jsx)("div", { className: shared_default.fieldDesc, children: props.hint })
|
|
592
|
+
]
|
|
593
|
+
})
|
|
594
|
+
]
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
function LinkButtonRow(props) {
|
|
598
|
+
return (0, import_jsx_runtime7.jsxs)("div", { className: shared_default.linkButtonRow, children: props.children === void 0 ? [] : [props.children] });
|
|
599
|
+
}
|
|
600
|
+
function ErrorLine(props) {
|
|
601
|
+
const text2 = String(props.text ?? "");
|
|
602
|
+
if (text2 === "") return null;
|
|
603
|
+
return (0, import_jsx_runtime7.jsxs)("p", {
|
|
604
|
+
className: shared_default.error,
|
|
605
|
+
role: "status",
|
|
606
|
+
children: [
|
|
607
|
+
(0, import_jsx_runtime7.jsx)("span", { className: shared_default.dot + " " + shared_default.dotError, "aria-hidden": "true" }),
|
|
608
|
+
(0, import_jsx_runtime7.jsx)("span", { children: text2 })
|
|
609
|
+
]
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
function TextField(props) {
|
|
613
|
+
return field(props, (0, import_jsx_runtime8.jsx)("input", {
|
|
614
|
+
type: "text",
|
|
615
|
+
className: shared_default.control,
|
|
616
|
+
value: text(props.value),
|
|
617
|
+
placeholder: props.placeholder ?? "",
|
|
618
|
+
disabled: props.disabled === true,
|
|
619
|
+
"aria-label": props.label,
|
|
620
|
+
onChange: (event) => props.onChange(event.target.value)
|
|
621
|
+
}));
|
|
622
|
+
}
|
|
623
|
+
function LinesField(props) {
|
|
624
|
+
const box = useTypedBox(linesOf(props.value).join("\n"));
|
|
625
|
+
return field(props, (0, import_jsx_runtime8.jsx)("textarea", {
|
|
626
|
+
className: shared_default.textarea,
|
|
627
|
+
value: box.text,
|
|
628
|
+
placeholder: props.placeholder ?? "",
|
|
629
|
+
disabled: props.disabled === true,
|
|
630
|
+
"aria-label": props.label,
|
|
631
|
+
onChange: (event) => {
|
|
632
|
+
const typed = event.target.value;
|
|
633
|
+
box.stage(typed);
|
|
634
|
+
props.onChange(parseLines(typed));
|
|
635
|
+
}
|
|
636
|
+
}));
|
|
637
|
+
}
|
|
638
|
+
function MapField(props) {
|
|
639
|
+
const box = useTypedBox(serializeMap(props.value));
|
|
640
|
+
return field(props, (0, import_jsx_runtime8.jsx)("textarea", {
|
|
641
|
+
className: shared_default.textarea,
|
|
642
|
+
value: box.text,
|
|
643
|
+
placeholder: props.placeholder ?? "",
|
|
644
|
+
disabled: props.disabled === true,
|
|
645
|
+
"aria-label": props.label,
|
|
646
|
+
onChange: (event) => {
|
|
647
|
+
const typed = event.target.value;
|
|
648
|
+
box.stage(typed);
|
|
649
|
+
props.onChange(parseMap(typed));
|
|
650
|
+
}
|
|
651
|
+
}));
|
|
652
|
+
}
|
|
653
|
+
function SelectField(props) {
|
|
654
|
+
const options = selectOptions(props.value, props.options ?? [], props.placeholder);
|
|
655
|
+
return field(
|
|
656
|
+
props,
|
|
657
|
+
(0, import_jsx_runtime8.jsx)("select", {
|
|
658
|
+
className: shared_default.select,
|
|
659
|
+
value: text(props.value),
|
|
660
|
+
disabled: props.disabled === true,
|
|
661
|
+
"aria-label": props.label,
|
|
662
|
+
onChange: (event) => {
|
|
663
|
+
const picked = options.find((option) => text(option.value) === event.target.value);
|
|
664
|
+
props.onChange(picked === void 0 ? event.target.value : picked.value);
|
|
665
|
+
},
|
|
666
|
+
children: options.map(
|
|
667
|
+
(option) => (0, import_jsx_runtime8.jsx)("option", { value: text(option.value), children: option.label }, text(option.value))
|
|
668
|
+
)
|
|
669
|
+
})
|
|
670
|
+
);
|
|
671
|
+
}
|
|
672
|
+
function DropdownField(props) {
|
|
673
|
+
const openState = react3.useState(false);
|
|
674
|
+
const open = openState[0];
|
|
675
|
+
const setOpen = openState[1];
|
|
676
|
+
const disabled = props.disabled === true;
|
|
677
|
+
const options = selectOptions(props.value, props.options ?? [], props.placeholder);
|
|
678
|
+
const held = text(props.value);
|
|
679
|
+
const current = options.find((option) => text(option.value) === held);
|
|
680
|
+
return field(
|
|
681
|
+
props,
|
|
682
|
+
(0, import_jsx_runtime8.jsx)("span", {
|
|
683
|
+
className: shared_default.selectorWrap,
|
|
684
|
+
children: (0, import_jsx_runtime8.jsx)(import_dsh_client_ui_primitives3.Menu, {
|
|
685
|
+
open: open && !disabled,
|
|
686
|
+
onClose: () => setOpen(false),
|
|
687
|
+
items: options.map((option) => ({ id: text(option.value), label: option.label })),
|
|
688
|
+
selectedId: current === void 0 ? "" : held,
|
|
689
|
+
onSelect: (id) => {
|
|
690
|
+
setOpen(false);
|
|
691
|
+
if (id === held) return;
|
|
692
|
+
const picked = options.find((option) => text(option.value) === id);
|
|
693
|
+
props.onChange(picked === void 0 ? id : picked.value);
|
|
694
|
+
},
|
|
695
|
+
align: "start",
|
|
696
|
+
portal: true,
|
|
697
|
+
anchor: (0, import_jsx_runtime8.jsxs)("button", {
|
|
698
|
+
type: "button",
|
|
699
|
+
className: shared_default.selector,
|
|
700
|
+
"aria-haspopup": "menu",
|
|
701
|
+
"aria-expanded": open && !disabled,
|
|
702
|
+
"aria-label": props.label,
|
|
703
|
+
disabled,
|
|
704
|
+
onClick: () => setOpen(!open),
|
|
705
|
+
children: [
|
|
706
|
+
(0, import_jsx_runtime8.jsx)("span", { className: shared_default.selectorLabel, children: current === void 0 ? props.placeholder ?? "" : current.label }),
|
|
707
|
+
(0, import_jsx_runtime8.jsx)("svg", {
|
|
708
|
+
width: 14,
|
|
709
|
+
height: 14,
|
|
710
|
+
className: shared_default.pillChevron,
|
|
711
|
+
viewBox: "0 0 14 14",
|
|
712
|
+
fill: "none",
|
|
713
|
+
"aria-hidden": "true",
|
|
714
|
+
children: (0, import_jsx_runtime8.jsx)("path", { d: CHEVRON_PATH, fill: "currentColor" })
|
|
715
|
+
})
|
|
716
|
+
]
|
|
717
|
+
})
|
|
718
|
+
})
|
|
719
|
+
})
|
|
720
|
+
);
|
|
721
|
+
}
|
|
722
|
+
function ExtraField(props) {
|
|
723
|
+
const type = props.type === void 0 ? "string" : props.type;
|
|
724
|
+
if (type === "boolean") {
|
|
725
|
+
return field(
|
|
726
|
+
props,
|
|
727
|
+
(0, import_jsx_runtime8.jsx)("input", {
|
|
728
|
+
type: "checkbox",
|
|
729
|
+
className: shared_default.checkbox,
|
|
730
|
+
checked: props.value === true,
|
|
731
|
+
disabled: props.disabled === true,
|
|
732
|
+
"aria-label": props.label,
|
|
733
|
+
onChange: (event) => props.onChange(event.target.checked)
|
|
734
|
+
})
|
|
735
|
+
);
|
|
736
|
+
}
|
|
737
|
+
if (type === "lines") return (0, import_jsx_runtime8.jsx)(LinesField, props);
|
|
738
|
+
if (type === "select") return SelectField(props);
|
|
739
|
+
if (type === "secret") {
|
|
740
|
+
return field(
|
|
741
|
+
props,
|
|
742
|
+
(0, import_jsx_runtime8.jsx)("input", {
|
|
743
|
+
type: "password",
|
|
744
|
+
className: shared_default.control,
|
|
745
|
+
value: text(props.value),
|
|
746
|
+
placeholder: props.placeholder ?? "",
|
|
747
|
+
disabled: props.disabled === true,
|
|
748
|
+
"aria-label": props.label,
|
|
749
|
+
onChange: (event) => props.onChange(event.target.value)
|
|
750
|
+
})
|
|
751
|
+
);
|
|
752
|
+
}
|
|
753
|
+
if ((props.options ?? []).length > 0) return SelectField(props);
|
|
754
|
+
return TextField(props);
|
|
755
|
+
}
|
|
756
|
+
function selectOptions(value, served, placeholder) {
|
|
757
|
+
const out = [];
|
|
758
|
+
const seen = /* @__PURE__ */ new Set();
|
|
759
|
+
const held = text(value);
|
|
760
|
+
if (held === "" && placeholder !== void 0 && placeholder !== "" && !served.some((option) => text(option.value) === "")) {
|
|
761
|
+
out.push({ value: "", label: placeholder });
|
|
762
|
+
seen.add("");
|
|
763
|
+
}
|
|
764
|
+
for (const option of served) {
|
|
765
|
+
const key = text(option.value);
|
|
766
|
+
if (seen.has(key)) continue;
|
|
767
|
+
seen.add(key);
|
|
768
|
+
out.push(option);
|
|
769
|
+
}
|
|
770
|
+
if (held !== "" && !seen.has(held)) out.push({ value, label: held });
|
|
771
|
+
return out;
|
|
772
|
+
}
|
|
773
|
+
function linesOf(value) {
|
|
774
|
+
if (Array.isArray(value)) return value.map((item) => text(item)).filter((item) => item.trim() !== "");
|
|
775
|
+
if (typeof value === "string") return parseLines(value);
|
|
776
|
+
return [];
|
|
777
|
+
}
|
|
778
|
+
function useTypedBox(served) {
|
|
779
|
+
const typedState = react3.useState({ key: "", text: "" });
|
|
780
|
+
const typed = typedState[0];
|
|
781
|
+
const setTyped = typedState[1];
|
|
782
|
+
return {
|
|
783
|
+
text: typed.key === served ? typed.text : served,
|
|
784
|
+
stage: (text2) => setTyped({ key: served, text: text2 })
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
function text(value) {
|
|
788
|
+
if (value === void 0 || value === null) return "";
|
|
789
|
+
return typeof value === "string" ? value : String(value);
|
|
790
|
+
}
|
|
791
|
+
function parseLines(text2) {
|
|
792
|
+
return String(text2).split("\n").filter((line) => line.trim() !== "");
|
|
793
|
+
}
|
|
794
|
+
function parseMap(text2) {
|
|
795
|
+
const out = {};
|
|
796
|
+
for (const line of String(text2).split("\n")) {
|
|
797
|
+
if (line.trim() === "") continue;
|
|
798
|
+
const split = line.indexOf("=");
|
|
799
|
+
if (split <= 0) continue;
|
|
800
|
+
const key = line.slice(0, split);
|
|
801
|
+
if (key.trim() === "") continue;
|
|
802
|
+
out[key] = line.slice(split + 1);
|
|
803
|
+
}
|
|
804
|
+
return out;
|
|
805
|
+
}
|
|
806
|
+
function mapText(value) {
|
|
807
|
+
if (value === void 0 || value === null) return "";
|
|
808
|
+
if (typeof value === "string") return value;
|
|
809
|
+
if (Array.isArray(value)) return value.map((item) => text(item)).join(",");
|
|
810
|
+
if (typeof value === "object") return JSON.stringify(value);
|
|
811
|
+
return String(value);
|
|
812
|
+
}
|
|
813
|
+
function serializeMap(value) {
|
|
814
|
+
if (typeof value === "string") return value;
|
|
815
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return "";
|
|
816
|
+
return Object.entries(value).map(([key, item]) => `${key}=${mapText(item)}`).join("\n");
|
|
817
|
+
}
|
|
818
|
+
function field(props, control) {
|
|
819
|
+
return (0, import_jsx_runtime8.jsxs)("div", {
|
|
820
|
+
className: shared_default.controlField,
|
|
821
|
+
children: [
|
|
822
|
+
(0, import_jsx_runtime8.jsx)("div", { className: shared_default.controlTitle, children: props.label }),
|
|
823
|
+
control,
|
|
824
|
+
props.help === void 0 || props.help === "" ? null : (0, import_jsx_runtime8.jsx)("div", { className: shared_default.fieldDesc, children: props.help })
|
|
825
|
+
]
|
|
826
|
+
});
|
|
827
|
+
}
|
|
828
|
+
function ComposerPill(props) {
|
|
829
|
+
const disabled = props.disabled === true;
|
|
830
|
+
return (0, import_jsx_runtime9.jsx)("span", {
|
|
831
|
+
className: shared_default.composerPillRoot,
|
|
832
|
+
"data-pill": props.key,
|
|
833
|
+
children: (0, import_jsx_runtime9.jsx)(import_dsh_client_ui_primitives4.Menu, {
|
|
834
|
+
open: props.open && !disabled,
|
|
835
|
+
onClose: () => props.setOpen(false),
|
|
836
|
+
items: props.options,
|
|
837
|
+
selectedId: props.selectedId,
|
|
838
|
+
onSelect: (id) => {
|
|
839
|
+
props.setOpen(false);
|
|
840
|
+
if (id === props.selectedId) return;
|
|
841
|
+
Promise.resolve(props.onSelect(id)).catch(() => void 0);
|
|
842
|
+
},
|
|
843
|
+
align: "start",
|
|
844
|
+
side: "top",
|
|
845
|
+
portal: true,
|
|
846
|
+
anchor: (0, import_jsx_runtime9.jsxs)("button", {
|
|
847
|
+
type: "button",
|
|
848
|
+
className: shared_default.composerPill,
|
|
849
|
+
"aria-label": props.ariaLabel ?? (props.title === void 0 ? props.label : `${props.title}: ${props.label}`),
|
|
850
|
+
title: props.title ?? props.label,
|
|
851
|
+
"aria-haspopup": "menu",
|
|
852
|
+
"aria-expanded": props.open && !disabled,
|
|
853
|
+
disabled,
|
|
854
|
+
onClick: () => props.setOpen(!props.open),
|
|
855
|
+
children: [
|
|
856
|
+
props.icon === void 0 || props.icon.length === 0 ? null : (0, import_jsx_runtime9.jsx)("span", {
|
|
857
|
+
className: shared_default.composerPillIcon,
|
|
858
|
+
"aria-hidden": true,
|
|
859
|
+
children: (0, import_jsx_runtime9.jsx)("svg", {
|
|
860
|
+
width: 14,
|
|
861
|
+
height: 14,
|
|
862
|
+
viewBox: "0 0 24 24",
|
|
863
|
+
fill: "none",
|
|
864
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
865
|
+
children: props.icon.map(
|
|
866
|
+
(d, at) => (0, import_jsx_runtime9.jsx)("path", { d, stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round" }, at)
|
|
867
|
+
)
|
|
868
|
+
})
|
|
869
|
+
}),
|
|
870
|
+
(0, import_jsx_runtime9.jsx)("span", { className: shared_default.composerPillLabel, children: props.label }),
|
|
871
|
+
(0, import_jsx_runtime9.jsx)("span", {
|
|
872
|
+
className: shared_default.composerPillChevron + (props.open && !disabled ? " " + shared_default.composerPillChevronOpen : ""),
|
|
873
|
+
"aria-hidden": true,
|
|
874
|
+
children: (0, import_jsx_runtime9.jsx)("svg", {
|
|
875
|
+
width: 14,
|
|
876
|
+
height: 14,
|
|
877
|
+
viewBox: "0 0 14 14",
|
|
878
|
+
fill: "none",
|
|
879
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
880
|
+
children: (0, import_jsx_runtime9.jsx)("path", { d: CHEVRON_PATH, fill: "currentColor" })
|
|
881
|
+
})
|
|
882
|
+
})
|
|
883
|
+
]
|
|
884
|
+
})
|
|
885
|
+
})
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
var Blocks = {
|
|
889
|
+
RowsBlock,
|
|
890
|
+
DialogBlock,
|
|
891
|
+
PickerBlock,
|
|
892
|
+
FlagsBlock,
|
|
893
|
+
SwitchField,
|
|
894
|
+
LinkButtonRow,
|
|
895
|
+
ErrorLine,
|
|
896
|
+
TextField,
|
|
897
|
+
LinesField,
|
|
898
|
+
MapField,
|
|
899
|
+
SelectField,
|
|
900
|
+
DropdownField,
|
|
901
|
+
ExtraField,
|
|
902
|
+
ComposerPill
|
|
903
|
+
};
|
|
904
|
+
function tag(value) {
|
|
905
|
+
return Object.prototype.toString.call(value).slice(8, -1);
|
|
906
|
+
}
|
|
907
|
+
function isPlainObject(value) {
|
|
908
|
+
const prototype = Object.getPrototypeOf(value);
|
|
909
|
+
if (prototype === null) return true;
|
|
910
|
+
if (prototype === Object.prototype) return true;
|
|
911
|
+
return Object.getPrototypeOf(prototype) === null && tag(value) === "Object";
|
|
912
|
+
}
|
|
913
|
+
function canonicalCollection(value, kind) {
|
|
914
|
+
if (kind === "Set") {
|
|
915
|
+
return [...value].map(canonical).sort((left, right) => stableKey(left) < stableKey(right) ? -1 : 1);
|
|
916
|
+
}
|
|
917
|
+
return [...value].map(([key, item]) => [canonical(key), canonical(item)]).sort((left, right) => stableKey(left[0]) < stableKey(right[0]) ? -1 : 1);
|
|
918
|
+
}
|
|
919
|
+
function answersNothing(value) {
|
|
920
|
+
return value === void 0 || value === null;
|
|
921
|
+
}
|
|
922
|
+
function meaningfulKeys(value) {
|
|
923
|
+
return Object.keys(value).filter((key) => !answersNothing(value[key]));
|
|
924
|
+
}
|
|
925
|
+
function canonical(value) {
|
|
926
|
+
const kind = tag(value);
|
|
927
|
+
if (kind === "Set" || kind === "Map") return canonicalCollection(value, kind);
|
|
928
|
+
return value;
|
|
929
|
+
}
|
|
930
|
+
function stableKey(value) {
|
|
931
|
+
const text2 = JSON.stringify(value, (_key, item) => {
|
|
932
|
+
if (item !== null && typeof item === "object") {
|
|
933
|
+
const kind = tag(item);
|
|
934
|
+
if (kind === "Set" || kind === "Map") return canonicalCollection(item, kind);
|
|
935
|
+
}
|
|
936
|
+
if (item !== null && typeof item === "object" && !Array.isArray(item)) {
|
|
937
|
+
const sorted = {};
|
|
938
|
+
for (const name of Object.keys(item).sort()) {
|
|
939
|
+
const child = item[name];
|
|
940
|
+
if (!answersNothing(child)) sorted[name] = child;
|
|
941
|
+
}
|
|
942
|
+
return sorted;
|
|
943
|
+
}
|
|
944
|
+
return item === void 0 ? null : item;
|
|
945
|
+
});
|
|
946
|
+
return text2 === void 0 ? "null" : text2;
|
|
947
|
+
}
|
|
948
|
+
function sameValue(a, b) {
|
|
949
|
+
if (a === b) return true;
|
|
950
|
+
if (typeof a === "number" && typeof b === "number") return Number.isNaN(a) && Number.isNaN(b);
|
|
951
|
+
const leftMissing = answersNothing(a);
|
|
952
|
+
const rightMissing = answersNothing(b);
|
|
953
|
+
if (leftMissing || rightMissing) return leftMissing && rightMissing;
|
|
954
|
+
if (typeof a !== "object" || typeof b !== "object") return false;
|
|
955
|
+
if (Array.isArray(a) !== Array.isArray(b)) return false;
|
|
956
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
957
|
+
if (a.length !== b.length) return false;
|
|
958
|
+
return a.every((item, index) => sameValue(item, b[index]));
|
|
959
|
+
}
|
|
960
|
+
if (!isPlainObject(a) || !isPlainObject(b)) return sameOpaqueValue(a, b);
|
|
961
|
+
const left = meaningfulKeys(a);
|
|
962
|
+
const right = meaningfulKeys(b);
|
|
963
|
+
if (left.length !== right.length) return false;
|
|
964
|
+
return left.every(
|
|
965
|
+
(key) => Object.prototype.hasOwnProperty.call(b, key) && sameValue(a[key], b[key])
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
function sameOpaqueValue(a, b) {
|
|
969
|
+
const kind = tag(a);
|
|
970
|
+
if (kind !== tag(b)) return false;
|
|
971
|
+
if (kind === "Date") return sameValue(a.getTime(), b.getTime());
|
|
972
|
+
if (kind === "RegExp") {
|
|
973
|
+
return sameValue(a.source, b.source) && sameValue(a.flags, b.flags);
|
|
974
|
+
}
|
|
975
|
+
if (kind === "Map" || kind === "Set") {
|
|
976
|
+
return sameValue(canonical(a), canonical(b));
|
|
977
|
+
}
|
|
978
|
+
if (kind === "String" || kind === "Number" || kind === "Boolean") {
|
|
979
|
+
return sameValue(a.valueOf(), b.valueOf());
|
|
980
|
+
}
|
|
981
|
+
return false;
|
|
982
|
+
}
|
|
983
|
+
function nothingCardSnapshot() {
|
|
984
|
+
return {
|
|
985
|
+
available: false,
|
|
986
|
+
writable: false,
|
|
987
|
+
values: {},
|
|
988
|
+
overridden: [],
|
|
989
|
+
lastError: "",
|
|
990
|
+
dirty: false,
|
|
991
|
+
saving: false,
|
|
992
|
+
failed: false,
|
|
993
|
+
actionError: "",
|
|
994
|
+
notice: null
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
var RUN_SETTLE_TIMEOUT_MS = 9e4;
|
|
998
|
+
function settleOnRevision(host, settled, write, deadline = RUN_SETTLE_TIMEOUT_MS) {
|
|
999
|
+
if (host.disposed) return Promise.resolve();
|
|
1000
|
+
let satisfied = false;
|
|
1001
|
+
const armed = host.settleOn((snapshot) => {
|
|
1002
|
+
if (settled(snapshot) !== true) return false;
|
|
1003
|
+
satisfied = true;
|
|
1004
|
+
return true;
|
|
1005
|
+
});
|
|
1006
|
+
return new Promise((resolve) => {
|
|
1007
|
+
let done = false;
|
|
1008
|
+
const timer = setTimeout(() => finish(), deadline);
|
|
1009
|
+
host.settleTimer = timer;
|
|
1010
|
+
const finish = (refused = false) => {
|
|
1011
|
+
if (done) return;
|
|
1012
|
+
done = true;
|
|
1013
|
+
clearTimeout(timer);
|
|
1014
|
+
if (host.settleTimer === timer) host.settleTimer = null;
|
|
1015
|
+
armed.cancel();
|
|
1016
|
+
resolve();
|
|
1017
|
+
if (refused || satisfied || host.disposed) return;
|
|
1018
|
+
const state = host.getSnapshot();
|
|
1019
|
+
if (state.lastError !== "") host.noteNotice("error", state.lastError);
|
|
1020
|
+
else host.noteNotice("stall", "");
|
|
1021
|
+
};
|
|
1022
|
+
void armed.settle.then(() => finish());
|
|
1023
|
+
void Promise.resolve(write()).then(
|
|
1024
|
+
(accepted) => {
|
|
1025
|
+
if (accepted === false) {
|
|
1026
|
+
host.noteError("configuration write refused");
|
|
1027
|
+
finish(true);
|
|
1028
|
+
}
|
|
1029
|
+
},
|
|
1030
|
+
(error) => {
|
|
1031
|
+
host.noteError(error);
|
|
1032
|
+
finish(true);
|
|
1033
|
+
}
|
|
1034
|
+
);
|
|
1035
|
+
});
|
|
1036
|
+
}
|
|
1037
|
+
var MAX_WRITE_PASSES = 4;
|
|
1038
|
+
var CardController = class {
|
|
1039
|
+
/** Disposed — every late answer and timer bails on this flag first. */
|
|
1040
|
+
disposed = false;
|
|
1041
|
+
/** The armed stall-deadline timer (owned by ./wait.ts). */
|
|
1042
|
+
settleTimer = null;
|
|
1043
|
+
store;
|
|
1044
|
+
fields;
|
|
1045
|
+
errorField;
|
|
1046
|
+
settleDeadlineMs;
|
|
1047
|
+
settleField;
|
|
1048
|
+
/** The last pass of the write door, when the mount can issue it unfenced. */
|
|
1049
|
+
unfencedMutate;
|
|
1050
|
+
/** The form the entry's row page handed (`view: "page"`), if any. */
|
|
1051
|
+
pageForm;
|
|
1052
|
+
formRef;
|
|
1053
|
+
unsubscribe;
|
|
1054
|
+
/** Staged drafts: only fields that differ from what is served. */
|
|
1055
|
+
draft = {};
|
|
1056
|
+
/** The last served (undrafted) answers, recomputed on every push. */
|
|
1057
|
+
served = {};
|
|
1058
|
+
saving = false;
|
|
1059
|
+
failed = false;
|
|
1060
|
+
actionError = "";
|
|
1061
|
+
noticeQueue = null;
|
|
1062
|
+
noticeSeq = 0;
|
|
1063
|
+
/** Every armed settle; keyed against a published snapshot. */
|
|
1064
|
+
waits = [];
|
|
1065
|
+
constructor(form, spec = {}) {
|
|
1066
|
+
this.fields = spec.fields ?? {};
|
|
1067
|
+
this.errorField = spec.errorField ?? "lastError";
|
|
1068
|
+
this.settleDeadlineMs = spec.settleDeadlineMs;
|
|
1069
|
+
this.settleField = spec.settleField === void 0 || spec.settleField === "" ? void 0 : spec.settleField;
|
|
1070
|
+
this.unfencedMutate = spec.unfencedMutate;
|
|
1071
|
+
this.formRef = form;
|
|
1072
|
+
this.store = (0, import_dsh_client_store.createSnapshotStore)(nothingCardSnapshot());
|
|
1073
|
+
this.unsubscribe = form === void 0 ? void 0 : form.subscribe(() => {
|
|
1074
|
+
this.actionError = "";
|
|
1075
|
+
this.publish();
|
|
1076
|
+
});
|
|
1077
|
+
this.publish();
|
|
1078
|
+
}
|
|
1079
|
+
/** Adopt the form the row page hands with `view: "page"` (identity guarded:
|
|
1080
|
+
* an unchanged adopt is a no-op, keeping its publish out of the render). */
|
|
1081
|
+
adoptForm(form) {
|
|
1082
|
+
if (this.disposed) return;
|
|
1083
|
+
const next = form === void 0 ? void 0 : form;
|
|
1084
|
+
if (this.pageForm === next) return;
|
|
1085
|
+
this.pageForm = next;
|
|
1086
|
+
this.publish();
|
|
1087
|
+
}
|
|
1088
|
+
/** The card's store is what the card body renders. */
|
|
1089
|
+
getSnapshot() {
|
|
1090
|
+
return this.store.getSnapshot();
|
|
1091
|
+
}
|
|
1092
|
+
/** Whether anything serves this entry. */
|
|
1093
|
+
available() {
|
|
1094
|
+
return this.store.getSnapshot().available === true;
|
|
1095
|
+
}
|
|
1096
|
+
/** Read one field off the current snapshot (drafts overlaid). */
|
|
1097
|
+
value(field2) {
|
|
1098
|
+
return this.store.getSnapshot().values[field2];
|
|
1099
|
+
}
|
|
1100
|
+
/** One field as the Host serves it, drafts left out — what a staged edit
|
|
1101
|
+
* that lands back on it is compared against. */
|
|
1102
|
+
servedValue(field2) {
|
|
1103
|
+
return this.documentValue(field2);
|
|
1104
|
+
}
|
|
1105
|
+
/** One field as the served document answers it (what a wait arms against). */
|
|
1106
|
+
documentValue(field2) {
|
|
1107
|
+
const snapshot = this.readSnapshot();
|
|
1108
|
+
if (snapshot === void 0 || snapshot.status !== "ready" || snapshot.value === void 0) return void 0;
|
|
1109
|
+
return snapshot.value[field2];
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Staged edit: save one value as a draft. A draft equal to what is served
|
|
1113
|
+
* is not dirty — it stages nothing and dirties nothing.
|
|
1114
|
+
*/
|
|
1115
|
+
stage(field2, value) {
|
|
1116
|
+
if (this.disposed) return;
|
|
1117
|
+
const servedValue = this.served[field2];
|
|
1118
|
+
if (valuesEqual(servedValue, value)) {
|
|
1119
|
+
delete this.draft[field2];
|
|
1120
|
+
} else {
|
|
1121
|
+
this.draft[field2] = value;
|
|
1122
|
+
}
|
|
1123
|
+
this.publish();
|
|
1124
|
+
}
|
|
1125
|
+
/** Drop every staged draft: the card answers with what is served. */
|
|
1126
|
+
discard() {
|
|
1127
|
+
if (this.disposed) return;
|
|
1128
|
+
for (const key of Object.keys(this.draft)) delete this.draft[key];
|
|
1129
|
+
this.failed = false;
|
|
1130
|
+
this.publish();
|
|
1131
|
+
}
|
|
1132
|
+
/** Apply exactly the staged fields. Accepted: the drafts clear with the
|
|
1133
|
+
* Host's answers. Refused: the drafts stand, `failed` says so. */
|
|
1134
|
+
async applyStaged() {
|
|
1135
|
+
if (this.disposed) return false;
|
|
1136
|
+
const staged = Object.entries(this.draft);
|
|
1137
|
+
if (staged.length === 0) return true;
|
|
1138
|
+
this.saving = true;
|
|
1139
|
+
this.publish();
|
|
1140
|
+
const ops = staged.map(([field2, value]) => ({ op: "set", path: [field2], value }));
|
|
1141
|
+
const accepted = await this.writeDoor(() => ops);
|
|
1142
|
+
if (accepted) {
|
|
1143
|
+
for (const field2 of Object.keys(this.draft)) delete this.draft[field2];
|
|
1144
|
+
this.failed = false;
|
|
1145
|
+
} else {
|
|
1146
|
+
this.failed = true;
|
|
1147
|
+
this.actionError = "configuration write refused";
|
|
1148
|
+
}
|
|
1149
|
+
this.saving = false;
|
|
1150
|
+
this.publish();
|
|
1151
|
+
return accepted;
|
|
1152
|
+
}
|
|
1153
|
+
/** Immediate write of one field — rows, selections: written on the spot. */
|
|
1154
|
+
async writeField(field2, value) {
|
|
1155
|
+
if (this.disposed) return false;
|
|
1156
|
+
const accepted = await this.writeDoor(() => [{ op: "set", path: [field2], value }]);
|
|
1157
|
+
this.publish();
|
|
1158
|
+
return accepted;
|
|
1159
|
+
}
|
|
1160
|
+
/** Return one field to what the row's own configuration answers: the field
|
|
1161
|
+
* leaves the user layer (an `unset`), and any draft standing over it goes. */
|
|
1162
|
+
async resetField(field2) {
|
|
1163
|
+
if (this.disposed) return false;
|
|
1164
|
+
const accepted = await this.writeDoor(() => [{ op: "unset", path: [field2] }]);
|
|
1165
|
+
if (accepted) delete this.draft[field2];
|
|
1166
|
+
this.publish();
|
|
1167
|
+
return accepted;
|
|
1168
|
+
}
|
|
1169
|
+
/**
|
|
1170
|
+
* Trigger write — a nonce: the value is always a stamp that moved off what
|
|
1171
|
+
* stood before it (`nextStamp`), so a later commit always reads as a diff.
|
|
1172
|
+
* Returns as soon as the write lands; waiting for the Host *run* is the job
|
|
1173
|
+
* of `settle` — armed before this crosses the wire, so nothing can slip
|
|
1174
|
+
* between. A stamp that stands where it stood answers no run at all: two
|
|
1175
|
+
* actions inside one millisecond must not read as nothing happened.
|
|
1176
|
+
*/
|
|
1177
|
+
async writeTrigger(field2) {
|
|
1178
|
+
return this.writeDoor((document2) => [{ op: "set", path: [field2], value: nextStamp(document2[field2]) }]);
|
|
1179
|
+
}
|
|
1180
|
+
/** Write a trigger and wait for the mirror to satisfy `settled`. */
|
|
1181
|
+
settleAndTrigger(settled, field2) {
|
|
1182
|
+
return settleOnRevision(this, settled, () => this.writeTrigger(field2), this.settleDeadlineMs);
|
|
1183
|
+
}
|
|
1184
|
+
/** The immediate-write shape of `settleAndTrigger`: write one field on the
|
|
1185
|
+
* spot (a selection, a saved list) and wait for the Host run behind it to
|
|
1186
|
+
* satisfy `settled` — the wait armed before the write crosses the wire. */
|
|
1187
|
+
settleAndWrite(settled, field2, value) {
|
|
1188
|
+
return settleOnRevision(this, settled, () => this.writeField(field2, value), this.settleDeadlineMs);
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* Entry trigger — the keyed nonce (`entryActions` hole): stamps a moved
|
|
1192
|
+
* value **under `key`** inside the field's map, keeping every other row's
|
|
1193
|
+
* stamp, and writes the whole map through the door. The Host's trigger diff
|
|
1194
|
+
* answers per key (`host/adapter/form.ts`), so exactly the row that stamped
|
|
1195
|
+
* fires its run. The merge is composed inside the door (what the document
|
|
1196
|
+
* stands on now), never from what this half last rendered.
|
|
1197
|
+
*/
|
|
1198
|
+
async writeEntryTrigger(field2, key) {
|
|
1199
|
+
const wanted = String(key);
|
|
1200
|
+
return this.writeDoor((document2) => {
|
|
1201
|
+
const current = document2[field2];
|
|
1202
|
+
const stamps = current !== null && typeof current === "object" && !Array.isArray(current) ? { ...current } : {};
|
|
1203
|
+
stamps[wanted] = nextStamp(stamps[wanted]);
|
|
1204
|
+
return [{ op: "set", path: [field2], value: stamps }];
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
/** The keyed shape of `settleAndTrigger`: arm the wait, write the entry
|
|
1208
|
+
* nonce, settle when `settled` stands. */
|
|
1209
|
+
settleAndTriggerEntry(settled, field2, key) {
|
|
1210
|
+
return settleOnRevision(this, settled, () => this.writeEntryTrigger(field2, key), this.settleDeadlineMs);
|
|
1211
|
+
}
|
|
1212
|
+
/** Host-run settle on the `settleField` hole: write the trigger for
|
|
1213
|
+
* `triggerField`, settle once what `watchField` answers moves off the value
|
|
1214
|
+
* it stood at when the wait was armed — the diff is the answer, the wall
|
|
1215
|
+
* clock only the backstop. With no `watchField` declared anywhere, the
|
|
1216
|
+
* trigger field itself is what must move.
|
|
1217
|
+
*
|
|
1218
|
+
* Both sides read the **served document**: the store is what the body
|
|
1219
|
+
* renders, and at arm time it may not have answered the field at all (nothing
|
|
1220
|
+
* published yet) — armed against that, every answer reads as a move. */
|
|
1221
|
+
settleTrigger(triggerField, watchField) {
|
|
1222
|
+
const watched = watchField ?? this.settleField ?? triggerField;
|
|
1223
|
+
const armed = this.documentValue(watched);
|
|
1224
|
+
return settleOnRevision(
|
|
1225
|
+
this,
|
|
1226
|
+
() => !sameValue(this.documentValue(watched), armed),
|
|
1227
|
+
() => this.writeTrigger(triggerField),
|
|
1228
|
+
this.settleDeadlineMs
|
|
1229
|
+
);
|
|
1230
|
+
}
|
|
1231
|
+
/** The keyed shape of `settleTrigger`: the wait answers **per entry** — what
|
|
1232
|
+
* `watchField` answers for `key` moves off what it answered when armed. A
|
|
1233
|
+
* mirror shaped as a list of lines answers it by the line's own `id`/`key`,
|
|
1234
|
+
* which is the shape a live mirror really carries. */
|
|
1235
|
+
settleEntryTrigger(triggerField, key, watchField) {
|
|
1236
|
+
const watched = watchField ?? this.settleField ?? triggerField;
|
|
1237
|
+
const wanted = String(key);
|
|
1238
|
+
const armed = keyedAnswer(this.documentValue(watched), wanted);
|
|
1239
|
+
return settleOnRevision(
|
|
1240
|
+
this,
|
|
1241
|
+
() => !sameValue(keyedAnswer(this.documentValue(watched), wanted), armed),
|
|
1242
|
+
() => this.writeEntryTrigger(triggerField, key),
|
|
1243
|
+
this.settleDeadlineMs
|
|
1244
|
+
);
|
|
1245
|
+
}
|
|
1246
|
+
/** Arm one predicate against the next publish (the wait surface). */
|
|
1247
|
+
settleOn(settled) {
|
|
1248
|
+
let resolve = () => void 0;
|
|
1249
|
+
const settle = new Promise((done) => {
|
|
1250
|
+
resolve = done;
|
|
1251
|
+
});
|
|
1252
|
+
const wait = { settled, resolve };
|
|
1253
|
+
this.waits.push(wait);
|
|
1254
|
+
return {
|
|
1255
|
+
settle,
|
|
1256
|
+
cancel: () => {
|
|
1257
|
+
const index = this.waits.indexOf(wait);
|
|
1258
|
+
if (index >= 0) this.waits.splice(index, 1);
|
|
1259
|
+
resolve();
|
|
1260
|
+
}
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
/** Stage one failure notice for the body's toast host. */
|
|
1264
|
+
noteNotice(kind, text2) {
|
|
1265
|
+
this.noticeSeq += 1;
|
|
1266
|
+
this.noticeQueue = { seq: this.noticeSeq, kind, text: String(text2 ?? "") };
|
|
1267
|
+
this.publish();
|
|
1268
|
+
}
|
|
1269
|
+
/** Drop one announced notice (by `seq`). */
|
|
1270
|
+
clearNotice(seq) {
|
|
1271
|
+
if (this.noticeQueue !== null && this.noticeQueue.seq === seq) this.noticeQueue = null;
|
|
1272
|
+
this.publish();
|
|
1273
|
+
}
|
|
1274
|
+
/** Surface a refused or failed write as the card's own error line. */
|
|
1275
|
+
noteError(error) {
|
|
1276
|
+
this.actionError = String(error instanceof Error ? error.message : error);
|
|
1277
|
+
this.publish();
|
|
1278
|
+
}
|
|
1279
|
+
/** Release everything: subscriptions, settle, timers. */
|
|
1280
|
+
dispose() {
|
|
1281
|
+
this.disposed = true;
|
|
1282
|
+
this.unsubscribe?.();
|
|
1283
|
+
this.unsubscribe = void 0;
|
|
1284
|
+
this.pageForm = void 0;
|
|
1285
|
+
for (const wait of [...this.waits]) wait.resolve();
|
|
1286
|
+
this.waits.length = 0;
|
|
1287
|
+
if (this.settleTimer !== null && this.settleTimer !== void 0) {
|
|
1288
|
+
clearTimeout(this.settleTimer);
|
|
1289
|
+
this.settleTimer = null;
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
/** Everything a registered card body receives — the same object for every
|
|
1293
|
+
* render (identity stable), so a re-render cannot disturb the store. */
|
|
1294
|
+
inject() {
|
|
1295
|
+
return {
|
|
1296
|
+
store: this.store,
|
|
1297
|
+
controller: this,
|
|
1298
|
+
fields: this.fields
|
|
1299
|
+
};
|
|
1300
|
+
}
|
|
1301
|
+
/** Push the served answers, overlaid by drafts, into the store. */
|
|
1302
|
+
publish() {
|
|
1303
|
+
if (this.disposed) return;
|
|
1304
|
+
const previous = this.store.getSnapshot();
|
|
1305
|
+
const snapshot = this.readSnapshot();
|
|
1306
|
+
let values = {};
|
|
1307
|
+
let overridden = [];
|
|
1308
|
+
let available = false;
|
|
1309
|
+
let writable = false;
|
|
1310
|
+
if (snapshot !== void 0 && snapshot.status === "ready" && snapshot.value !== void 0) {
|
|
1311
|
+
available = true;
|
|
1312
|
+
writable = snapshot.writable !== false;
|
|
1313
|
+
values = { ...snapshot.value };
|
|
1314
|
+
const user = snapshot.user;
|
|
1315
|
+
if (user !== null && typeof user === "object") overridden = Object.keys(user);
|
|
1316
|
+
for (const [field2, value] of Object.entries(this.draft)) values[field2] = value;
|
|
1317
|
+
} else {
|
|
1318
|
+
for (const key of Object.keys(this.draft)) delete this.draft[key];
|
|
1319
|
+
this.releaseWaits();
|
|
1320
|
+
}
|
|
1321
|
+
this.served = snapshot !== void 0 && snapshot.status === "ready" && snapshot.value !== void 0 ? { ...snapshot.value } : {};
|
|
1322
|
+
this.store.set({
|
|
1323
|
+
available,
|
|
1324
|
+
writable,
|
|
1325
|
+
values,
|
|
1326
|
+
overridden,
|
|
1327
|
+
lastError: typeof values[this.errorField] === "string" ? String(values[this.errorField]) : "",
|
|
1328
|
+
dirty: Object.keys(this.draft).length > 0,
|
|
1329
|
+
saving: this.saving,
|
|
1330
|
+
failed: this.failed,
|
|
1331
|
+
actionError: this.actionError,
|
|
1332
|
+
notice: this.noticeQueue
|
|
1333
|
+
});
|
|
1334
|
+
const state = this.store.getSnapshot();
|
|
1335
|
+
for (const wait of [...this.waits]) {
|
|
1336
|
+
if (wait.settled(state) === true) {
|
|
1337
|
+
this.waits.splice(this.waits.indexOf(wait), 1);
|
|
1338
|
+
wait.resolve();
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
/** What every read stands on: the shared form's mirror, which subscribes
|
|
1343
|
+
* and so moves with every Host answer. The page's handed `state` is a
|
|
1344
|
+
* snapshot taken when the page rendered — only the fallback when no shared
|
|
1345
|
+
* form stands; the page form is adopted as the write **door**, not as the
|
|
1346
|
+
* source. */
|
|
1347
|
+
readSnapshot() {
|
|
1348
|
+
if (this.formRef !== void 0) {
|
|
1349
|
+
try {
|
|
1350
|
+
return this.formRef.getSnapshot();
|
|
1351
|
+
} catch {
|
|
1352
|
+
}
|
|
1353
|
+
}
|
|
1354
|
+
return this.pageForm?.state;
|
|
1355
|
+
}
|
|
1356
|
+
/**
|
|
1357
|
+
* The write door — a refused pass is re-issued against the re-read document
|
|
1358
|
+
* until the budget runs out, then the refusal is *reported*.
|
|
1359
|
+
*
|
|
1360
|
+
* The door takes what the ops are **made of**, not the ops themselves, for
|
|
1361
|
+
* one reason: anything that has to carry what the document already says (a
|
|
1362
|
+
* keyed trigger's stamp map, a stamp that must move) is composed against
|
|
1363
|
+
* what the document says *now*, on every pass. Composing it once from what
|
|
1364
|
+
* this half last rendered would re-issue a merge made against a document
|
|
1365
|
+
* that already moved — and drop the other row's stamp on the floor.
|
|
1366
|
+
*/
|
|
1367
|
+
async writeDoor(compose) {
|
|
1368
|
+
for (let pass = 0; pass < MAX_WRITE_PASSES; pass++) {
|
|
1369
|
+
const snapshot = this.readSnapshot();
|
|
1370
|
+
if (snapshot === void 0 || snapshot.status !== "ready") return false;
|
|
1371
|
+
const document2 = snapshot.value ?? {};
|
|
1372
|
+
const ops = withLiveCleared(compose(document2), this.fields.liveKeys);
|
|
1373
|
+
const pageForm = this.pageForm;
|
|
1374
|
+
const formRef = this.formRef;
|
|
1375
|
+
const door = pageForm !== void 0 ? (next) => pageForm.mutate(next) : formRef !== void 0 ? (next) => formRef.mutate(next) : void 0;
|
|
1376
|
+
if (door === void 0) return false;
|
|
1377
|
+
const last = pass === MAX_WRITE_PASSES - 1 && this.unfencedMutate !== void 0;
|
|
1378
|
+
try {
|
|
1379
|
+
const accepted = last ? await this.unfencedMutate(ops) : await door(ops);
|
|
1380
|
+
if (accepted === true) return true;
|
|
1381
|
+
} catch {
|
|
1382
|
+
}
|
|
1383
|
+
}
|
|
1384
|
+
return false;
|
|
1385
|
+
}
|
|
1386
|
+
/** Nothing serves: no wait can settle. */
|
|
1387
|
+
releaseWaits() {
|
|
1388
|
+
for (const wait of [...this.waits]) {
|
|
1389
|
+
this.waits.splice(this.waits.indexOf(wait), 1);
|
|
1390
|
+
wait.resolve();
|
|
1391
|
+
}
|
|
1392
|
+
}
|
|
1393
|
+
};
|
|
1394
|
+
function withLiveCleared(ops, liveKeys) {
|
|
1395
|
+
if (liveKeys === void 0 || liveKeys.length === 0) return ops;
|
|
1396
|
+
const written = new Set(ops.map((op) => op.path[0]));
|
|
1397
|
+
const clears = liveKeys.filter((key) => !written.has(key)).map((key) => ({ op: "unset", path: [key] }));
|
|
1398
|
+
return clears.length === 0 ? ops : [...ops, ...clears];
|
|
1399
|
+
}
|
|
1400
|
+
function valuesEqual(a, b) {
|
|
1401
|
+
return sameValue(a, b);
|
|
1402
|
+
}
|
|
1403
|
+
function keyedAnswer(value, key) {
|
|
1404
|
+
if (value === null || typeof value !== "object") return value;
|
|
1405
|
+
if (Array.isArray(value)) {
|
|
1406
|
+
const rows = value;
|
|
1407
|
+
const row = rows.find((item) => identityOf(item) === key);
|
|
1408
|
+
if (rows.some((item) => identityOf(item) !== void 0)) return row;
|
|
1409
|
+
return value;
|
|
1410
|
+
}
|
|
1411
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) return value[key];
|
|
1412
|
+
return value;
|
|
1413
|
+
}
|
|
1414
|
+
function identityOf(row) {
|
|
1415
|
+
if (row === null || typeof row !== "object") return void 0;
|
|
1416
|
+
const claimed = row.id ?? row.key;
|
|
1417
|
+
if (typeof claimed === "string") return claimed;
|
|
1418
|
+
if (typeof claimed === "number") return String(claimed);
|
|
1419
|
+
return void 0;
|
|
1420
|
+
}
|
|
1421
|
+
function nextStamp(previous) {
|
|
1422
|
+
const standing = typeof previous === "number" && Number.isFinite(previous) ? previous : 0;
|
|
1423
|
+
return Math.max(Date.now(), standing + 1);
|
|
1424
|
+
}
|
|
1425
|
+
var LOCALE_NAMESPACE = "dshAncesters";
|
|
1426
|
+
var DICTIONARIES = {
|
|
1427
|
+
en: {
|
|
1428
|
+
apply: "Apply",
|
|
1429
|
+
discard: "Discard",
|
|
1430
|
+
saving: "Saving\u2026",
|
|
1431
|
+
unsaved: "Unsaved changes",
|
|
1432
|
+
saveFailed: "Save failed",
|
|
1433
|
+
cancel: "Cancel",
|
|
1434
|
+
close: "Close",
|
|
1435
|
+
search: "Search",
|
|
1436
|
+
searchNoResults: "No matches",
|
|
1437
|
+
searchPlaceholder: "Search\u2026",
|
|
1438
|
+
addSelected: "Add selected",
|
|
1439
|
+
// The page-wide notices (`toasts`): a wait that ended with nothing
|
|
1440
|
+
// answered, and a failure the Host answered without a line of its own.
|
|
1441
|
+
toastStall: "The host did not answer the action \u2014 try it again.",
|
|
1442
|
+
toastError: "The host reported a failure."
|
|
1443
|
+
}
|
|
1444
|
+
};
|
|
1445
|
+
function mergeDictionaries(base = DICTIONARIES, override = {}) {
|
|
1446
|
+
const merged = {};
|
|
1447
|
+
for (const locale of [...Object.keys(base), ...Object.keys(override)]) {
|
|
1448
|
+
merged[locale] = { ...base[locale] === void 0 ? {} : base[locale], ...override[locale] === void 0 ? {} : override[locale] };
|
|
1449
|
+
}
|
|
1450
|
+
return merged;
|
|
1451
|
+
}
|
|
1452
|
+
var TOAST_ROOT_SELECTOR = "div[data-dsh-ancesters-toasts]";
|
|
1453
|
+
var TOAST_DISMISS_MS = 8e3;
|
|
1454
|
+
function noticeText(notice, t) {
|
|
1455
|
+
if (notice.kind === "stall") return t("toastStall");
|
|
1456
|
+
return notice.text !== "" ? notice.text : t("toastError");
|
|
1457
|
+
}
|
|
1458
|
+
function mountToastMirror(source, host, options = {}) {
|
|
1459
|
+
const doc = documentOf(host);
|
|
1460
|
+
if (doc === void 0) return () => void 0;
|
|
1461
|
+
const root = host === void 0 || host === null ? toastRoot(doc) : host;
|
|
1462
|
+
if (root === void 0 || typeof root.appendChild !== "function") return () => void 0;
|
|
1463
|
+
const t = typeof options.t === "function" ? options.t : (key) => key;
|
|
1464
|
+
const dismissMs = typeof options.dismissMs === "number" && options.dismissMs >= 0 ? options.dismissMs : TOAST_DISMISS_MS;
|
|
1465
|
+
let node = void 0;
|
|
1466
|
+
let shownSeq = -1;
|
|
1467
|
+
let timer = void 0;
|
|
1468
|
+
const dismiss = (seq) => {
|
|
1469
|
+
if (typeof source.clearNotice === "function") source.clearNotice(seq);
|
|
1470
|
+
};
|
|
1471
|
+
const stopTimer = () => {
|
|
1472
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
1473
|
+
timer = void 0;
|
|
1474
|
+
};
|
|
1475
|
+
const paint = () => {
|
|
1476
|
+
const snapshot = source.store.getSnapshot();
|
|
1477
|
+
const notice = snapshot.notice ?? null;
|
|
1478
|
+
if (notice === null) {
|
|
1479
|
+
stopTimer();
|
|
1480
|
+
shownSeq = -1;
|
|
1481
|
+
if (node !== void 0) {
|
|
1482
|
+
root.removeChild(node);
|
|
1483
|
+
node = void 0;
|
|
1484
|
+
}
|
|
1485
|
+
return;
|
|
1486
|
+
}
|
|
1487
|
+
if (node === void 0) {
|
|
1488
|
+
node = doc.createElement("div");
|
|
1489
|
+
node.className = shared_default.toast;
|
|
1490
|
+
root.appendChild(node);
|
|
1491
|
+
}
|
|
1492
|
+
node.dataset.dshAncestersToast = String(notice.seq);
|
|
1493
|
+
node.dataset.noticeKind = notice.kind;
|
|
1494
|
+
node.textContent = typeof options.text === "function" ? options.text(notice, snapshot, t) : noticeText(notice, t);
|
|
1495
|
+
const seq = notice.seq;
|
|
1496
|
+
node.onclick = () => dismiss(seq);
|
|
1497
|
+
if (seq !== shownSeq) {
|
|
1498
|
+
shownSeq = seq;
|
|
1499
|
+
stopTimer();
|
|
1500
|
+
if (dismissMs > 0 && typeof setTimeout === "function") timer = setTimeout(() => dismiss(seq), dismissMs);
|
|
1501
|
+
}
|
|
1502
|
+
};
|
|
1503
|
+
const unsubscribe = source.store.subscribe(() => paint());
|
|
1504
|
+
paint();
|
|
1505
|
+
return () => {
|
|
1506
|
+
unsubscribe();
|
|
1507
|
+
stopTimer();
|
|
1508
|
+
if (node !== void 0) {
|
|
1509
|
+
root.removeChild(node);
|
|
1510
|
+
node = void 0;
|
|
1511
|
+
}
|
|
1512
|
+
};
|
|
1513
|
+
}
|
|
1514
|
+
function documentOf(host) {
|
|
1515
|
+
const own = host !== void 0 && host !== null ? host.ownerDocument : void 0;
|
|
1516
|
+
if (own !== void 0 && own !== null) return own;
|
|
1517
|
+
return typeof document === "undefined" ? void 0 : document;
|
|
1518
|
+
}
|
|
1519
|
+
function toastRoot(doc) {
|
|
1520
|
+
const standing = doc.querySelectorAll(TOAST_ROOT_SELECTOR);
|
|
1521
|
+
if (standing.length > 0) return standing[0];
|
|
1522
|
+
const root = doc.createElement("div");
|
|
1523
|
+
root.className = shared_default.toastRoot;
|
|
1524
|
+
root.dataset.dshAncestersToasts = "1";
|
|
1525
|
+
const container = doc.body ?? doc.head;
|
|
1526
|
+
if (container === void 0) return void 0;
|
|
1527
|
+
container.appendChild(root);
|
|
1528
|
+
return root;
|
|
1529
|
+
}
|
|
1530
|
+
var SHEET_ID = "dsh-ancesters-" + hash(cssText);
|
|
1531
|
+
function sheetId(css) {
|
|
1532
|
+
return "dsh-ancesters-" + hash(css);
|
|
1533
|
+
}
|
|
1534
|
+
function injected(id) {
|
|
1535
|
+
return document.querySelectorAll('style[data-dsh-ancesters-css="' + id + '"]').length > 0;
|
|
1536
|
+
}
|
|
1537
|
+
function injectCardStyles(sheets) {
|
|
1538
|
+
if (typeof document === "undefined") return;
|
|
1539
|
+
const wanted = [cssText, ...sheets ?? []].filter((sheet) => typeof sheet === "string" && sheet !== "");
|
|
1540
|
+
for (const sheet of wanted) {
|
|
1541
|
+
const id = sheetId(sheet);
|
|
1542
|
+
if (injected(id)) continue;
|
|
1543
|
+
const styleTag = document.createElement("style");
|
|
1544
|
+
styleTag.dataset.dshAncestersCss = id;
|
|
1545
|
+
styleTag.textContent = sheet;
|
|
1546
|
+
document.head.appendChild(styleTag);
|
|
1547
|
+
}
|
|
1548
|
+
}
|
|
1549
|
+
function hash(text2) {
|
|
1550
|
+
let value = 2166136261 >>> 0;
|
|
1551
|
+
for (let index = 0; index < text2.length; index++) {
|
|
1552
|
+
value ^= text2.charCodeAt(index);
|
|
1553
|
+
value = Math.imul(value, 16777619) >>> 0;
|
|
1554
|
+
}
|
|
1555
|
+
return value.toString(36).padStart(6, "0").slice(0, 6) + "-" + text2.length.toString(36);
|
|
1556
|
+
}
|
|
1557
|
+
function unfencedSettingsWrite(ctx, ns) {
|
|
1558
|
+
const settings = ctx.remote?.settings;
|
|
1559
|
+
const mutate = settings?.mutate;
|
|
1560
|
+
if (settings === void 0 || typeof mutate !== "function") return void 0;
|
|
1561
|
+
return async (ops) => {
|
|
1562
|
+
try {
|
|
1563
|
+
const response = await mutate.call(settings, ns, ops, void 0);
|
|
1564
|
+
return response?.ok === true;
|
|
1565
|
+
} catch {
|
|
1566
|
+
return false;
|
|
1567
|
+
}
|
|
1568
|
+
};
|
|
1569
|
+
}
|
|
1570
|
+
function mountSettingsCard(spec) {
|
|
1571
|
+
if (spec === void 0 || typeof spec !== "object" || Array.isArray(spec)) {
|
|
1572
|
+
throw new TypeError("mountSettingsCard: requires a descriptor object ({ entryId, fields, blocks \u2026 })");
|
|
1573
|
+
}
|
|
1574
|
+
if (typeof spec.entryId !== "string" || spec.entryId === "") {
|
|
1575
|
+
throw new TypeError("mountSettingsCard: the descriptor requires a non-empty `entryId`");
|
|
1576
|
+
}
|
|
1577
|
+
if (spec.pluginId !== void 0 && (typeof spec.pluginId !== "string" || spec.pluginId === "")) {
|
|
1578
|
+
throw new TypeError("mountSettingsCard: the descriptor's `pluginId` must be a non-empty string (the row key needs the package identity)");
|
|
1579
|
+
}
|
|
1580
|
+
if (spec.bundleId !== void 0 && (typeof spec.bundleId !== "string" || spec.bundleId === "")) {
|
|
1581
|
+
throw new TypeError("mountSettingsCard: the descriptor's `bundleId` must be a non-empty string (it is the bundle package the row key is built from)");
|
|
1582
|
+
}
|
|
1583
|
+
if (spec.placement !== void 0 && spec.placement !== "row" && spec.placement !== "bundle") {
|
|
1584
|
+
throw new TypeError('mountSettingsCard: the descriptor\'s `placement` is "row" or "bundle"');
|
|
1585
|
+
}
|
|
1586
|
+
const namespace = spec.localeNamespace === void 0 || spec.localeNamespace === "" ? LOCALE_NAMESPACE : spec.localeNamespace;
|
|
1587
|
+
const bundle = spec.placement === "bundle";
|
|
1588
|
+
const slotName = bundle ? "plugins.bundle.config" : "plugins.row.config";
|
|
1589
|
+
return {
|
|
1590
|
+
inject: ["configForms", "slots", "locale", "remote", "remote.settings"],
|
|
1591
|
+
apply(ctx) {
|
|
1592
|
+
if (ctx === void 0 || typeof ctx !== "object" || ctx.slots === void 0 || typeof ctx.slots.inject !== "function") {
|
|
1593
|
+
throw new TypeError("mountSettingsCard.apply: needs the browser plugin context (the shell's `slots` service)");
|
|
1594
|
+
}
|
|
1595
|
+
injectCardStyles();
|
|
1596
|
+
const dicts = mergeDictionaries(DICTIONARIES, spec.locale ?? {});
|
|
1597
|
+
if (ctx.locale !== void 0 && typeof ctx.locale.register === "function") {
|
|
1598
|
+
ctx.effect(() => ctx.locale.register(namespace, dicts), `${spec.entryId}: dictionaries`);
|
|
1599
|
+
}
|
|
1600
|
+
const form = ctx.configForms === void 0 ? void 0 : ctx.configForms.get(spec.entryId);
|
|
1601
|
+
const controller = new CardController(form, {
|
|
1602
|
+
fields: spec.fields,
|
|
1603
|
+
errorField: spec.errorField,
|
|
1604
|
+
settleDeadlineMs: spec.settleDeadlineMs,
|
|
1605
|
+
settleField: spec.settleField,
|
|
1606
|
+
unfencedMutate: unfencedSettingsWrite(ctx, spec.entryId)
|
|
1607
|
+
});
|
|
1608
|
+
ctx.effect(() => () => controller.dispose(), `${spec.entryId}: card controller`);
|
|
1609
|
+
const translate = ctx.locale !== void 0 && typeof ctx.locale.bind === "function" ? ctx.locale.bind(namespace) : (key) => key;
|
|
1610
|
+
if (spec.toasts === true || spec.toasts !== void 0 && typeof spec.toasts === "object") {
|
|
1611
|
+
const toastHost = typeof spec.toasts === "object" ? spec.toasts.host : void 0;
|
|
1612
|
+
const dismissMs = typeof spec.toasts === "object" ? spec.toasts.dismissMs : void 0;
|
|
1613
|
+
const text2 = typeof spec.toasts === "object" ? spec.toasts.text : void 0;
|
|
1614
|
+
ctx.effect(
|
|
1615
|
+
() => mountToastMirror(controller, toastHost, { t: translate, dismissMs, text: text2 }),
|
|
1616
|
+
`${spec.entryId}: toast host`
|
|
1617
|
+
);
|
|
1618
|
+
}
|
|
1619
|
+
const body = (props) => {
|
|
1620
|
+
const view = String(props?.view) === "page" ? "page" : "summary";
|
|
1621
|
+
controller.adoptForm(props?.form === void 0 ? void 0 : props.form);
|
|
1622
|
+
const snapshot = controller.getSnapshot();
|
|
1623
|
+
if (view === "summary") {
|
|
1624
|
+
if (typeof spec.renderSummary !== "function") return null;
|
|
1625
|
+
return spec.renderSummary(snapshot, translate);
|
|
1626
|
+
}
|
|
1627
|
+
if (!snapshot.available && (spec.blocks ?? []).length === 0) return null;
|
|
1628
|
+
const renders = (spec.blocks ?? []).map(
|
|
1629
|
+
(block, index) => renderBlock(block, { snapshot, controller, view, t: translate })
|
|
1630
|
+
);
|
|
1631
|
+
const composed = renders.filter((rendered) => rendered !== null && rendered !== void 0);
|
|
1632
|
+
if (spec.errorLine === false) return composed;
|
|
1633
|
+
const error = snapshot.actionError !== "" ? snapshot.actionError : snapshot.lastError;
|
|
1634
|
+
const line = ErrorLine({ text: error === "" ? "" : error });
|
|
1635
|
+
return line === null ? composed : [...composed, line];
|
|
1636
|
+
};
|
|
1637
|
+
const pageKey = bundle ? bundleConfigKey(spec.bundleId ?? spec.pluginId) : rowConfigKey(spec.bundleId ?? spec.pluginId ?? "", spec.entryId);
|
|
1638
|
+
ctx.slots.inject(slotName, () => {
|
|
1639
|
+
ctx.slots.register(
|
|
1640
|
+
{
|
|
1641
|
+
name: slotName,
|
|
1642
|
+
key: pageKey,
|
|
1643
|
+
locale: namespace,
|
|
1644
|
+
inject: () => controller.inject()
|
|
1645
|
+
},
|
|
1646
|
+
body
|
|
1647
|
+
);
|
|
1648
|
+
});
|
|
1649
|
+
const composer = spec.composer;
|
|
1650
|
+
if (composer !== void 0) {
|
|
1651
|
+
if (typeof composer.id !== "string" || composer.id === "" || typeof composer.bind !== "function") {
|
|
1652
|
+
throw new TypeError("mountSettingsCard: `composer` needs a non-empty `id` and a `bind` function");
|
|
1653
|
+
}
|
|
1654
|
+
const pills = (props) => {
|
|
1655
|
+
const subscribe = props?.useAncestersComposer;
|
|
1656
|
+
const snapshot = typeof subscribe === "function" ? subscribe((state) => state) : controller.getSnapshot();
|
|
1657
|
+
const openState = react4.useState("");
|
|
1658
|
+
const open = openState[0];
|
|
1659
|
+
const setOpen = openState[1];
|
|
1660
|
+
if (snapshot?.available !== true) return null;
|
|
1661
|
+
const t = typeof props?.t === "function" ? props.t : translate;
|
|
1662
|
+
const declared = composer.bind(snapshot, controller, t) ?? [];
|
|
1663
|
+
if (declared.length === 0) return null;
|
|
1664
|
+
return (0, import_jsx_runtime.jsx)("span", {
|
|
1665
|
+
className: shared_default.composerPills,
|
|
1666
|
+
children: declared.map(
|
|
1667
|
+
(pill) => (0, import_jsx_runtime.jsx)(
|
|
1668
|
+
ComposerPill,
|
|
1669
|
+
{ ...pill, open: open === pill.key, setOpen: (next) => setOpen(next ? pill.key : "") },
|
|
1670
|
+
pill.key
|
|
1671
|
+
)
|
|
1672
|
+
)
|
|
1673
|
+
});
|
|
1674
|
+
};
|
|
1675
|
+
ctx.slots.inject("conversation.input.left", () => {
|
|
1676
|
+
ctx.slots.register(
|
|
1677
|
+
{
|
|
1678
|
+
name: "conversation.input.left",
|
|
1679
|
+
// The slot is kind `list`: entries are deduped and
|
|
1680
|
+
// placed by a stable `id`, not a keyed `key`.
|
|
1681
|
+
id: composer.id,
|
|
1682
|
+
locale: namespace,
|
|
1683
|
+
inject: () => ({ hooks: { ancestersComposer: controller.store }, controller })
|
|
1684
|
+
},
|
|
1685
|
+
pills
|
|
1686
|
+
);
|
|
1687
|
+
});
|
|
1688
|
+
}
|
|
1689
|
+
}
|
|
1690
|
+
};
|
|
1691
|
+
}
|
|
1692
|
+
function bundleConfigKey(pkgName) {
|
|
1693
|
+
if (typeof pkgName !== "string" || pkgName === "") {
|
|
1694
|
+
throw new TypeError('mountSettingsCard: `placement: "bundle"` needs `pluginId` or `bundleId` (the bundle page is keyed by its package name)');
|
|
1695
|
+
}
|
|
1696
|
+
return pkgName;
|
|
1697
|
+
}
|
|
1698
|
+
function renderBlock(block, props) {
|
|
1699
|
+
if (block.hideWhenUnavailable === true && props.snapshot.available !== true) return null;
|
|
1700
|
+
const compose = { ...block.props ?? {} };
|
|
1701
|
+
if (block.field !== void 0) {
|
|
1702
|
+
compose.value = props.snapshot.values[block.field];
|
|
1703
|
+
compose.field = block.field;
|
|
1704
|
+
}
|
|
1705
|
+
if (block.liveKeys !== void 0) {
|
|
1706
|
+
for (const liveKey of block.liveKeys) compose[liveKey] = props.snapshot.values[liveKey];
|
|
1707
|
+
}
|
|
1708
|
+
if (typeof block.bind === "function") Object.assign(compose, block.bind(props.snapshot, props.controller, props.t));
|
|
1709
|
+
if (block.action !== void 0) compose.action = composeAction(block.action, props.controller, block.field);
|
|
1710
|
+
const component = typeof block.block === "string" ? BlocksByName[block.block] : block.block;
|
|
1711
|
+
if (typeof component !== "function") return null;
|
|
1712
|
+
return component({ ...compose, t: props.t });
|
|
1713
|
+
}
|
|
1714
|
+
function composeAction(action, controller, field2) {
|
|
1715
|
+
if (typeof action === "function") return action(controller);
|
|
1716
|
+
if (action === "stage") return (value) => controller.stage(String(field2 ?? ""), value);
|
|
1717
|
+
if (action === "apply") return () => controller.applyStaged();
|
|
1718
|
+
if (action === "discard") return () => controller.discard();
|
|
1719
|
+
if (action === "write") return (value) => controller.writeField(String(field2 ?? ""), value);
|
|
1720
|
+
return (value) => value === void 0 ? controller.writeTrigger(String(field2 ?? "")) : controller.writeEntryTrigger(String(field2 ?? ""), value);
|
|
1721
|
+
}
|
|
1722
|
+
var BlocksByName = Blocks;
|
|
1723
|
+
function mountSettingsCard2(spec) {
|
|
1724
|
+
return mountSettingsCard(spec);
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1727
|
+
// src/client/catalog.ts
|
|
1728
|
+
var ID_MAX_LENGTH = 1024;
|
|
1729
|
+
var PATH_PATTERN = /^[^\x00-\x1f\x7f]{1,1024}$/u;
|
|
1730
|
+
var NAME_MAX_LENGTH = 200;
|
|
1731
|
+
var ENTRY_CAP = 50;
|
|
1732
|
+
function isValidEntryId(id) {
|
|
1733
|
+
if (id === "" || id.length > ID_MAX_LENGTH) return false;
|
|
1734
|
+
return PATH_PATTERN.test(id);
|
|
1735
|
+
}
|
|
1736
|
+
function entryLabel(entry) {
|
|
1737
|
+
const name = entry.name.trim();
|
|
1738
|
+
return name === "" ? entry.id : name;
|
|
1739
|
+
}
|
|
1740
|
+
function normalizeEntries(value) {
|
|
1741
|
+
if (!Array.isArray(value)) return [];
|
|
1742
|
+
const out = [];
|
|
1743
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1744
|
+
for (const item of value) {
|
|
1745
|
+
if (out.length === ENTRY_CAP) break;
|
|
1746
|
+
if (item === null || typeof item !== "object" || Array.isArray(item)) continue;
|
|
1747
|
+
const raw = item;
|
|
1748
|
+
const id = typeof raw.id === "string" ? raw.id.trim() : "";
|
|
1749
|
+
if (!isValidEntryId(id) || seen.has(id)) continue;
|
|
1750
|
+
seen.add(id);
|
|
1751
|
+
const name = typeof raw.name === "string" ? raw.name.trim() : "";
|
|
1752
|
+
out.push({ id, name: name.slice(0, NAME_MAX_LENGTH) });
|
|
1753
|
+
}
|
|
1754
|
+
return out;
|
|
1755
|
+
}
|
|
1756
|
+
|
|
1757
|
+
// src/client/card/index.ts
|
|
1758
|
+
var react8 = __toESM(require("react"), 1);
|
|
1759
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
1760
|
+
|
|
1761
|
+
// dsh-css:/home/roberto/dev/dsh/dsh-chrome-mcp/src/client/styles/ChromeMcpCard.module.css
|
|
1762
|
+
var cssText2 = '.e5pfpa_body{flex-direction:column;gap:10px;display:flex}.e5pfpa_field{align-items:flex-start;gap:4px;display:flex;flex-direction:column;width:100%}.e5pfpa_fieldRow{align-items:center;gap:8px;display:flex;width:100%}.e5pfpa_fieldTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:400;line-height:22px;flex:1;min-width:0}.e5pfpa_fieldDesc{color:var(--dsw-alias-label-tertiary);font-size:12px;font-weight:400;line-height:18px;width:100%}.e5pfpa_selector{background:var(--dsw-alias-bg-module-platform);height:36px;font:inherit;color:var(--dsw-alias-label-primary);cursor:pointer;border:none;border-radius:18px;align-items:center;gap:12px;padding:0 14px;font-size:14px;line-height:22px;display:inline-flex}.e5pfpa_selector:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_selector:disabled{cursor:default}.e5pfpa_selectorWrap{display:flex}.e5pfpa_pillChevron{flex:none}.e5pfpa_row{display:flex;gap:10px;align-items:center}.e5pfpa_button{display:inline-flex;align-items:center;justify-content:center;gap:4px;border:.5px solid var(--dsw-alias-border-l3);border-radius:14px;cursor:pointer;font-size:12px;line-height:18px;color:var(--dsw-alias-label-primary);background:transparent;padding:0 10px;height:28px}.e5pfpa_button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_button:disabled{cursor:not-allowed;opacity:.4}.e5pfpa_button:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_readOnly{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.e5pfpa_error{color:var(--dsw-alias-state-error-primary);margin:0;font-size:12px;line-height:1.5}.e5pfpa_dot{box-sizing:border-box;corner-shape:round;border-radius:50%;flex:none;width:8px;height:8px;display:inline-block}.e5pfpa_dotError{background:var(--dsw-alias-state-error-primary)}.e5pfpa_badge{color:var(--dsw-alias-label-tertiary);background:var(--dsw-alias-bg-layer-1);border-radius:10px;padding:1px 8px;font-size:11px;line-height:16px;display:inline-flex;align-items:center;flex:none}.e5pfpa_empty{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px}.e5pfpa_catalog{flex-direction:column;align-items:stretch;gap:10px;display:flex}.e5pfpa_catalog+.e5pfpa_catalog{border-top:.5px solid var(--dsw-alias-border-l2);padding-top:12px}.e5pfpa_catalog>.e5pfpa_linkButton{align-self:flex-start}.e5pfpa_catalog>.e5pfpa_linkButtonRow{align-self:flex-start;display:flex;gap:8px;align-items:center}.e5pfpa_linkButton{box-sizing:border-box;border:none;background:0 0;color:var(--dsw-alias-label-tertiary);cursor:pointer;border-radius:14px;align-items:center;height:28px;padding:0 10px;font:inherit;font-size:12px;line-height:18px;display:inline-flex}.e5pfpa_linkButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-secondary)}.e5pfpa_linkButton:disabled{opacity:.4;cursor:default}.e5pfpa_linkButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_catalogEntry{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-module-platform);border-radius:10px;padding:6px}.e5pfpa_catalogRow{grid-template-columns:minmax(0,1.4fr) minmax(0,1fr) auto;align-items:center;gap:6px;display:grid}.e5pfpa_catalogInput{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;height:28px;padding:0 10px;font:inherit;font-size:14px;line-height:22px;min-width:0;width:100%}.e5pfpa_catalogInput::placeholder{color:var(--dsw-alias-label-dimmed)}.e5pfpa_catalogInput:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.e5pfpa_catalogInput:disabled{opacity:.6;cursor:default}.e5pfpa_iconButton{box-sizing:border-box;width:28px;height:28px;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;display:inline-flex}.e5pfpa_iconButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.e5pfpa_iconButton:disabled{opacity:.4;cursor:default}.e5pfpa_iconButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_iconButtonDanger:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover-danger);color:var(--dsw-alias-state-error-primary)}.e5pfpa_addButton{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l3);color:var(--dsw-alias-label-primary);cursor:pointer;background:0 0;border-radius:14px;align-self:flex-start;align-items:center;gap:4px;height:28px;padding:0 10px;font:inherit;font-size:12px;line-height:18px;display:inline-flex}.e5pfpa_addButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_addButton:disabled{opacity:.4;cursor:default}.e5pfpa_disclosure{flex-direction:column;gap:10px;display:flex}.e5pfpa_disclosureSummary{color:var(--dsw-alias-label-secondary);cursor:pointer;list-style:none;align-items:center;gap:6px;font-size:12px;line-height:18px;user-select:none;display:flex}.e5pfpa_disclosureSummary::-webkit-details-marker{display:none}.e5pfpa_disclosureSummary:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-radius:6px}.e5pfpa_disclosureLabel:before{content:"\\25b8";display:inline-block;margin-right:6px;transition:transform .16s}.e5pfpa_disclosure[open] .e5pfpa_disclosureLabel:before{transform:rotate(90deg)}.e5pfpa_disclosureCount{color:var(--dsw-alias-label-tertiary)}.e5pfpa_disclosureBody{flex-direction:column;gap:10px;display:flex}.e5pfpa_disclosureBody>.e5pfpa_linkButton{align-self:flex-start}.e5pfpa_disclosureBody>.e5pfpa_linkButtonRow{align-self:flex-start;display:flex;gap:8px;align-items:center}.e5pfpa_toggleLabel{align-items:center;display:inline-flex;flex:none}.e5pfpa_fetchDialog{background:color-mix(in srgb,var(--dsw-alias-label-primary) 28%,transparent);align-items:center;justify-content:center;display:flex;position:fixed;inset:0;z-index:90}.e5pfpa_dialogContent{background:var(--dsw-alias-bg-layer-3);border:.5px solid var(--dsw-alias-border-l3);border-radius:16px;flex-direction:column;gap:10px;width:min(520px,calc(100vw - 32px));max-height:min(620px,calc(100vh - 48px));display:flex;overflow:hidden}.e5pfpa_dialogHeader{align-items:center;gap:8px;padding:14px 16px 0;display:flex}.e5pfpa_dialogTitle{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:22px;flex:1;min-width:0;margin:0}.e5pfpa_dialogClose{box-sizing:border-box;color:var(--dsw-alias-label-tertiary);cursor:pointer;background:0 0;border:none;border-radius:6px;justify-content:center;align-items:center;flex:none;width:28px;height:28px;display:inline-flex}.e5pfpa_dialogClose:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.e5pfpa_dialogClose:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_dialogDescription{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px;margin:0;padding:0 16px}.e5pfpa_dialogBody{flex-direction:column;flex:1;gap:8px;min-height:0;padding:0 16px;display:flex}.e5pfpa_candidateToolbar{align-items:center;gap:8px;display:flex}.e5pfpa_candidateSearch{box-sizing:border-box;border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);border-radius:8px;height:32px;padding:0 10px;font:inherit;font-size:12px;line-height:20px;flex:1;min-width:0}.e5pfpa_candidateSearch::placeholder{color:var(--dsw-alias-label-dimmed)}.e5pfpa_candidateSearch:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-1px}.e5pfpa_candidateList{flex-direction:column;gap:2px;margin:0;padding:0 0 10px;list-style:none;overflow-y:auto;display:flex}.e5pfpa_candidate{border-radius:8px;padding:4px 6px}.e5pfpa_candidate:hover{background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_candidateLabel{align-items:center;gap:8px;min-width:0;display:flex}.e5pfpa_candidateLabel input[type=checkbox]{accent-color:var(--dsw-alias-brand-primary);flex:none;margin:0}.e5pfpa_candidateId{color:var(--dsw-alias-label-primary);font-size:12px;line-height:18px;text-overflow:ellipsis;white-space:nowrap;flex:1;min-width:0;overflow:hidden}.e5pfpa_candidateNote{color:var(--dsw-alias-label-tertiary);flex:0 1 auto;min-width:0;overflow-wrap:anywhere;font-size:11px;line-height:16px}.e5pfpa_dialogFooter{border-top:.5px solid var(--dsw-alias-border-l2);align-items:center;justify-content:flex-end;gap:8px;padding:12px 16px;display:flex}.e5pfpa_dialogButton{display:inline-flex;align-items:center;justify-content:center;gap:4px;border:.5px solid var(--dsw-alias-border-l3);border-radius:16px;cursor:pointer;font-size:13px;line-height:20px;color:var(--dsw-alias-label-primary);background:transparent;padding:0 12px;height:32px}.e5pfpa_dialogButton:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.e5pfpa_dialogButton:disabled{cursor:not-allowed;opacity:.4}.e5pfpa_dialogButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_dialogButtonPrimary{color:var(--dsw-alias-label-primary);font-weight:600}.e5pfpa_selectorLabel{text-overflow:ellipsis;white-space:nowrap;min-width:0;overflow:hidden}.e5pfpa_result{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:18px}.e5pfpa_resultValue{color:var(--dsw-alias-label-secondary);margin-left:4px}.e5pfpa_resultAge{color:var(--dsw-alias-label-dimmed);margin-left:4px}.e5pfpa_notice{flex-direction:column;gap:4px;display:flex;border:.5px solid var(--dsw-alias-border-l3);border-radius:10px;background:var(--dsw-alias-bg-layer-1);padding:8px 10px}.e5pfpa_noticeTitle{color:var(--dsw-alias-label-primary);font-size:12px;font-weight:600;line-height:18px}.e5pfpa_noticeBody{color:var(--dsw-alias-label-tertiary);font-size:12px;line-height:18px}.e5pfpa_docsLink{color:var(--dsw-alias-label-tertiary);align-items:center;gap:4px;display:inline-flex;text-decoration:none;font-size:12px;line-height:1.5}.e5pfpa_docsLinkLabel{text-decoration:none}.e5pfpa_docsLink:hover{color:var(--dsw-alias-brand-primary)}.e5pfpa_docsLink:hover .e5pfpa_docsLinkLabel{text-decoration:underline}.e5pfpa_docsLink:hover .e5pfpa_docsIcon{color:var(--dsw-alias-brand-primary)}.e5pfpa_docsIcon{color:var(--dsw-alias-label-tertiary);flex:none}.e5pfpa_docsLink:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px;border-radius:4px}.e5pfpa_catalogRowSingle{grid-template-columns:minmax(0,1fr) auto}.e5pfpa_catalogInputMono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12px}.e5pfpa_footer{border-top:.5px solid var(--dsw-alias-border-l2);align-items:center;justify-content:flex-end;gap:8px;padding:12px 0 0;display:flex}.e5pfpa_footerError{color:var(--dsw-alias-label-error);text-align:right;min-width:0;flex:1;margin:0;font-size:12px;line-height:1.5}.e5pfpa_footerButton{border:.5px solid var(--dsw-alias-border-l3);border-radius:8px;cursor:pointer;color:var(--dsw-alias-label-secondary);background:transparent;padding:5px 14px;font-size:13px;line-height:1.5}.e5pfpa_footerButton:hover:not(:disabled){color:var(--dsw-alias-label-primary);border-color:var(--dsw-alias-label-dimmed)}.e5pfpa_footerButton:disabled{cursor:default;opacity:.4}.e5pfpa_footerButton:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:1px}.e5pfpa_footerButtonPrimary{color:var(--dsw-alias-bg-layer-3);font-weight:600;background:var(--dsw-alias-label-primary);border-color:transparent}.e5pfpa_footerButtonPrimary:hover:not(:disabled){color:var(--dsw-alias-bg-layer-3);background:var(--dsw-alias-label-secondary);border-color:transparent}\n';
|
|
1763
|
+
var ChromeMcpCard_default = { "body": "e5pfpa_body", "field": "e5pfpa_field", "fieldRow": "e5pfpa_fieldRow", "fieldTitle": "e5pfpa_fieldTitle", "fieldDesc": "e5pfpa_fieldDesc", "selector": "e5pfpa_selector", "selectorWrap": "e5pfpa_selectorWrap", "pillChevron": "e5pfpa_pillChevron", "row": "e5pfpa_row", "button": "e5pfpa_button", "readOnly": "e5pfpa_readOnly", "error": "e5pfpa_error", "dot": "e5pfpa_dot", "dotError": "e5pfpa_dotError", "badge": "e5pfpa_badge", "empty": "e5pfpa_empty", "catalog": "e5pfpa_catalog", "linkButton": "e5pfpa_linkButton", "linkButtonRow": "e5pfpa_linkButtonRow", "catalogEntry": "e5pfpa_catalogEntry", "catalogRow": "e5pfpa_catalogRow", "catalogInput": "e5pfpa_catalogInput", "iconButton": "e5pfpa_iconButton", "iconButtonDanger": "e5pfpa_iconButtonDanger", "addButton": "e5pfpa_addButton", "disclosure": "e5pfpa_disclosure", "disclosureSummary": "e5pfpa_disclosureSummary", "disclosureLabel": "e5pfpa_disclosureLabel", "disclosureCount": "e5pfpa_disclosureCount", "disclosureBody": "e5pfpa_disclosureBody", "toggleLabel": "e5pfpa_toggleLabel", "fetchDialog": "e5pfpa_fetchDialog", "dialogContent": "e5pfpa_dialogContent", "dialogHeader": "e5pfpa_dialogHeader", "dialogTitle": "e5pfpa_dialogTitle", "dialogClose": "e5pfpa_dialogClose", "dialogDescription": "e5pfpa_dialogDescription", "dialogBody": "e5pfpa_dialogBody", "candidateToolbar": "e5pfpa_candidateToolbar", "candidateSearch": "e5pfpa_candidateSearch", "candidateList": "e5pfpa_candidateList", "candidate": "e5pfpa_candidate", "candidateLabel": "e5pfpa_candidateLabel", "candidateId": "e5pfpa_candidateId", "candidateNote": "e5pfpa_candidateNote", "dialogFooter": "e5pfpa_dialogFooter", "dialogButton": "e5pfpa_dialogButton", "dialogButtonPrimary": "e5pfpa_dialogButtonPrimary", "selectorLabel": "e5pfpa_selectorLabel", "result": "e5pfpa_result", "resultValue": "e5pfpa_resultValue", "resultAge": "e5pfpa_resultAge", "notice": "e5pfpa_notice", "noticeTitle": "e5pfpa_noticeTitle", "noticeBody": "e5pfpa_noticeBody", "docsLink": "e5pfpa_docsLink", "docsLinkLabel": "e5pfpa_docsLinkLabel", "docsIcon": "e5pfpa_docsIcon", "catalogRowSingle": "e5pfpa_catalogRowSingle", "catalogInputMono": "e5pfpa_catalogInputMono", "footer": "e5pfpa_footer", "footerError": "e5pfpa_footerError", "footerButton": "e5pfpa_footerButton", "footerButtonPrimary": "e5pfpa_footerButtonPrimary" };
|
|
1764
|
+
|
|
1765
|
+
// src/client/card/flags.ts
|
|
1766
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
1767
|
+
|
|
1768
|
+
// src/client/plugin-meta.ts
|
|
1769
|
+
var ENTRY_ID = "mcp-chrome";
|
|
1770
|
+
var PLUGIN_ID = "@comecaramelos/dsh-chrome-mcp";
|
|
1771
|
+
var BUNDLE_ID = "@comecaramelos/dsh-mcp-manager-bundle";
|
|
1772
|
+
var ROW_CONFIG_KEY = `${BUNDLE_ID}#${ENTRY_ID}`;
|
|
1773
|
+
var LOCALE_NAMESPACE2 = "chromeMcp";
|
|
1774
|
+
var CONFIGURATION_URL = "https://github.com/ChromeDevTools/chrome-devtools-mcp/blob/main/docs/configuration.md";
|
|
1775
|
+
var RUN_SETTLE_TIMEOUT_MS2 = 9e4;
|
|
1776
|
+
var LIVE_KEYS = [
|
|
1777
|
+
"lastError",
|
|
1778
|
+
"chromeMissing",
|
|
1779
|
+
"executableDiscoveryRevision",
|
|
1780
|
+
"chromeVersion",
|
|
1781
|
+
"executableStatus",
|
|
1782
|
+
"effectiveChromePath",
|
|
1783
|
+
"effectiveSource",
|
|
1784
|
+
"stderrEffective",
|
|
1785
|
+
"defaultExtraFlags",
|
|
1786
|
+
"wslExtraFlags",
|
|
1787
|
+
"wslWindowsExecutable",
|
|
1788
|
+
"windowsChromeStatus",
|
|
1789
|
+
"carriesConnectionMode",
|
|
1790
|
+
"runningFlags",
|
|
1791
|
+
"runningNote"
|
|
1792
|
+
];
|
|
1793
|
+
|
|
1794
|
+
// src/client/card/icons.ts
|
|
1795
|
+
var CHEVRON_PATH2 = "M11.8486 5.5L11.4238 5.92383L8.69727 8.65137C8.44157 8.90706 8.21562 9.13382 8.01172 9.29785C7.79912 9.46883 7.55595 9.61756 7.25 9.66602C7.08435 9.69222 6.91565 9.69222 6.75 9.66602C6.44405 9.61756 6.20088 9.46883 5.98828 9.29785C5.78438 9.13382 5.55843 8.90706 5.30273 8.65137L2.57617 5.92383L2.15137 5.5L3 4.65137L3.42383 5.07617L6.15137 7.80273C6.42595 8.07732 6.59876 8.24849 6.74023 8.3623C6.87291 8.46904 6.92272 8.47813 6.9375 8.48047C6.97895 8.48703 7.02105 8.48703 7.0625 8.48047C7.07728 8.47813 7.12709 8.46904 7.25977 8.3623C7.40124 8.24849 7.57405 8.07732 7.84863 7.80273L10.5762 5.07617L11 4.65137L11.8486 5.5Z";
|
|
1796
|
+
var TRASH_PATH2 = "M2.5 4h11M6.5 4V2.5h3V4M4 4l.7 9a1 1 0 001 .9h4.6a1 1 0 001-.9L12 4M6.5 6.8v4.4M9.5 6.8v4.4";
|
|
1797
|
+
var CLOSE_PATHS2 = [
|
|
1798
|
+
"M14.1168 13.197L13.197 14.1167L1.8833 2.80303L2.80309 1.88324L14.1168 13.197Z",
|
|
1799
|
+
"M13.197 1.88326L14.1168 2.80305L2.80309 14.1168L1.8833 13.197L13.197 1.88326Z"
|
|
1800
|
+
];
|
|
1801
|
+
var DOCS_PATHS2 = [
|
|
1802
|
+
"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",
|
|
1803
|
+
"M15 3h6v6",
|
|
1804
|
+
"M10 14 21 3"
|
|
1805
|
+
];
|
|
14
1806
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
1807
|
+
// src/client/card/rows.ts
|
|
1808
|
+
var react5 = __toESM(require("react"), 1);
|
|
1809
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
1810
|
+
function RowList(props) {
|
|
1811
|
+
var served = Array.isArray(props.values) ? props.values : [];
|
|
1812
|
+
var writable = props.writable === true;
|
|
1813
|
+
var busy = props.busy === true;
|
|
1814
|
+
var labels = Array.isArray(props.labels) ? props.labels : [];
|
|
1815
|
+
var placeholders = Array.isArray(props.placeholders) ? props.placeholders : [];
|
|
1816
|
+
var columns = Math.max(1, labels.length);
|
|
1817
|
+
var blankRow = [];
|
|
1818
|
+
for (var blank = 0; blank < columns; blank++) blankRow.push("");
|
|
1819
|
+
var draftState = react5.useState(null);
|
|
1820
|
+
var draft = draftState[0];
|
|
1821
|
+
var setDraft = draftState[1];
|
|
1822
|
+
var focusedState = react5.useState(false);
|
|
1823
|
+
var focused = focusedState[0];
|
|
1824
|
+
var setFocused = focusedState[1];
|
|
1825
|
+
var servedKey = JSON.stringify(served);
|
|
1826
|
+
var syncState = react5.useState("");
|
|
1827
|
+
var servedSync = syncState[0];
|
|
1828
|
+
var setServedSync = syncState[1];
|
|
1829
|
+
if (servedKey !== servedSync) {
|
|
1830
|
+
setServedSync(servedKey);
|
|
1831
|
+
if (!focused) setDraft(null);
|
|
1832
|
+
}
|
|
1833
|
+
var rows = draft === null ? served : draft;
|
|
1834
|
+
var save = (next) => {
|
|
1835
|
+
if (typeof props.save !== "function") return Promise.resolve();
|
|
1836
|
+
setDraft(next);
|
|
1837
|
+
return Promise.resolve(props.save(next)).catch(() => {
|
|
1838
|
+
});
|
|
1839
|
+
};
|
|
1840
|
+
var withDraft = (make) => make(draft === null ? served : draft);
|
|
1841
|
+
var patchRow = (index2, column, value) => {
|
|
1842
|
+
setFocused(true);
|
|
1843
|
+
setDraft(
|
|
1844
|
+
withDraft(
|
|
1845
|
+
(current) => current.map(
|
|
1846
|
+
(row, at) => at === index2 ? row.map((cell, field2) => field2 === column ? value : cell) : row
|
|
1847
|
+
)
|
|
1848
|
+
)
|
|
1849
|
+
);
|
|
1850
|
+
};
|
|
1851
|
+
var removeRow = (index2) => {
|
|
1852
|
+
if (!writable || rows[index2] === void 0) return;
|
|
1853
|
+
save(rows.filter((_row, at) => at !== index2));
|
|
1854
|
+
};
|
|
1855
|
+
var addRow = () => {
|
|
1856
|
+
if (!writable) return;
|
|
1857
|
+
setDraft(withDraft((current) => current.concat([blankRow])));
|
|
1858
|
+
};
|
|
1859
|
+
var commit = () => {
|
|
1860
|
+
if (draft === null) return;
|
|
1861
|
+
save(rows);
|
|
1862
|
+
};
|
|
1863
|
+
var fieldNode = (row, index2, column) => (0, import_jsx_runtime10.jsx)("input", {
|
|
1864
|
+
className: props.inputClassName ? ChromeMcpCard_default.catalogInput + " " + props.inputClassName : ChromeMcpCard_default.catalogInput,
|
|
1865
|
+
type: "text",
|
|
1866
|
+
value: row[column] === void 0 ? "" : row[column],
|
|
1867
|
+
placeholder: placeholders[column],
|
|
1868
|
+
"aria-label": labels[column] + " " + (index2 + 1),
|
|
1869
|
+
title: column === 0 ? row[column] : void 0,
|
|
1870
|
+
disabled: !writable,
|
|
1871
|
+
spellCheck: false,
|
|
1872
|
+
autoComplete: "off",
|
|
1873
|
+
autocapitalize: "off",
|
|
1874
|
+
onChange: (event) => {
|
|
1875
|
+
patchRow(index2, column, event && event.target ? String(event.target.value ?? "") : "");
|
|
1876
|
+
},
|
|
1877
|
+
onFocus: () => setFocused(true),
|
|
1878
|
+
onBlur: () => {
|
|
1879
|
+
setFocused(false);
|
|
1880
|
+
commit();
|
|
1881
|
+
},
|
|
1882
|
+
onKeyDown: (event) => {
|
|
1883
|
+
if (event && event.key === "Enter") {
|
|
1884
|
+
setFocused(false);
|
|
1885
|
+
commit();
|
|
1886
|
+
}
|
|
1887
|
+
}
|
|
1888
|
+
}, column);
|
|
1889
|
+
var entryNode = (row, index2) => {
|
|
1890
|
+
var cells = [];
|
|
1891
|
+
var width = row.length === 0 ? columns : row.length;
|
|
1892
|
+
for (var column = 0; column < width; column++) cells.push(fieldNode(row, index2, column));
|
|
1893
|
+
cells.push(
|
|
1894
|
+
(0, import_jsx_runtime10.jsx)("button", {
|
|
1895
|
+
type: "button",
|
|
1896
|
+
className: ChromeMcpCard_default.iconButton + " " + ChromeMcpCard_default.iconButtonDanger,
|
|
1897
|
+
"aria-label": props.removeLabel + " " + (index2 + 1),
|
|
1898
|
+
title: props.removeLabel,
|
|
1899
|
+
disabled: !writable,
|
|
1900
|
+
onClick: () => {
|
|
1901
|
+
removeRow(index2);
|
|
1902
|
+
},
|
|
1903
|
+
children: (0, import_jsx_runtime10.jsx)("svg", {
|
|
1904
|
+
width: 14,
|
|
1905
|
+
height: 14,
|
|
1906
|
+
viewBox: "0 0 16 16",
|
|
1907
|
+
fill: "none",
|
|
1908
|
+
"aria-hidden": "true",
|
|
1909
|
+
children: (0, import_jsx_runtime10.jsx)("path", {
|
|
1910
|
+
d: TRASH_PATH2,
|
|
1911
|
+
stroke: "currentColor",
|
|
1912
|
+
strokeWidth: 1.3,
|
|
1913
|
+
strokeLinecap: "round",
|
|
1914
|
+
strokeLinejoin: "round"
|
|
1915
|
+
})
|
|
1916
|
+
})
|
|
1917
|
+
})
|
|
1918
|
+
);
|
|
1919
|
+
return (0, import_jsx_runtime10.jsx)("div", {
|
|
1920
|
+
className: ChromeMcpCard_default.catalogEntry,
|
|
1921
|
+
children: (0, import_jsx_runtime10.jsxs)("div", {
|
|
1922
|
+
className: props.rowClassName ? ChromeMcpCard_default.catalogRow + " " + props.rowClassName : ChromeMcpCard_default.catalogRow,
|
|
1923
|
+
children: cells
|
|
1924
|
+
})
|
|
1925
|
+
}, index2);
|
|
1926
|
+
};
|
|
1927
|
+
var body = [];
|
|
1928
|
+
if (typeof props.renderAction === "function") body.push(props.renderAction(rows, save));
|
|
1929
|
+
var visible = [];
|
|
1930
|
+
for (var index = 0; index < rows.length; index++) visible.push(entryNode(rows[index], index));
|
|
1931
|
+
body = body.concat(visible);
|
|
1932
|
+
body.push(
|
|
1933
|
+
(0, import_jsx_runtime10.jsx)("button", {
|
|
1934
|
+
type: "button",
|
|
1935
|
+
className: ChromeMcpCard_default.addButton,
|
|
1936
|
+
disabled: !writable || busy,
|
|
1937
|
+
onClick: addRow,
|
|
1938
|
+
children: props.addLabel
|
|
1939
|
+
})
|
|
1940
|
+
);
|
|
1941
|
+
var emptyLine = rows.length === 0 ? (0, import_jsx_runtime10.jsx)("p", { className: ChromeMcpCard_default.empty, children: props.emptyText }) : null;
|
|
1942
|
+
if (props.disclosure !== true) {
|
|
1943
|
+
return [emptyLine].concat(body);
|
|
1944
|
+
}
|
|
1945
|
+
return [
|
|
1946
|
+
emptyLine,
|
|
1947
|
+
(0, import_jsx_runtime10.jsxs)("details", {
|
|
1948
|
+
className: ChromeMcpCard_default.disclosure,
|
|
1949
|
+
children: [
|
|
1950
|
+
(0, import_jsx_runtime10.jsxs)("summary", {
|
|
1951
|
+
className: ChromeMcpCard_default.disclosureSummary,
|
|
1952
|
+
children: [
|
|
1953
|
+
(0, import_jsx_runtime10.jsx)("span", { className: ChromeMcpCard_default.disclosureLabel, children: props.rowsLabel }),
|
|
1954
|
+
(0, import_jsx_runtime10.jsx)("span", { className: ChromeMcpCard_default.disclosureCount, children: String(rows.length) })
|
|
1955
|
+
]
|
|
1956
|
+
}),
|
|
1957
|
+
(0, import_jsx_runtime10.jsx)("div", { className: ChromeMcpCard_default.disclosureBody, children: body })
|
|
1958
|
+
]
|
|
1959
|
+
})
|
|
1960
|
+
];
|
|
1961
|
+
}
|
|
43
1962
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
1963
|
+
// src/client/card/flags.ts
|
|
1964
|
+
function rowsOf(flags) {
|
|
1965
|
+
return flags.map((flag) => [flag]);
|
|
1966
|
+
}
|
|
1967
|
+
function flagsOf(rows) {
|
|
1968
|
+
var flags = [];
|
|
1969
|
+
for (const row of rows) {
|
|
1970
|
+
var flag = typeof row === "undefined" || row === null ? "" : String(row[0] ?? "").trim();
|
|
1971
|
+
if (flag === "") continue;
|
|
1972
|
+
if (flags.indexOf(flag) !== -1) continue;
|
|
1973
|
+
flags.push(flag);
|
|
1974
|
+
}
|
|
1975
|
+
return flags;
|
|
1976
|
+
}
|
|
1977
|
+
function ExtraFlagsEditor(props) {
|
|
1978
|
+
var t = props.t;
|
|
1979
|
+
var writable = props.writable;
|
|
1980
|
+
var flags = Array.isArray(props.flags) ? props.flags : [];
|
|
1981
|
+
var defaults = Array.isArray(props.defaultFlags) ? props.defaultFlags : [];
|
|
1982
|
+
var wsl = Array.isArray(props.wslFlags) ? props.wslFlags : [];
|
|
1983
|
+
var save = (next) => {
|
|
1984
|
+
if (typeof props.saveFlags !== "function") return Promise.resolve();
|
|
1985
|
+
return Promise.resolve(props.saveFlags(flagsOf(next)));
|
|
1986
|
+
};
|
|
1987
|
+
var restoreAction = (visible) => {
|
|
1988
|
+
var current = flagsOf(visible);
|
|
1989
|
+
var merged = current.concat(defaults.filter((flag) => current.indexOf(flag) === -1));
|
|
1990
|
+
return (0, import_jsx_runtime11.jsx)("button", {
|
|
1991
|
+
type: "button",
|
|
1992
|
+
className: ChromeMcpCard_default.linkButton,
|
|
1993
|
+
// The defaults list is host-served — with nothing to recover there
|
|
1994
|
+
// is nothing to do.
|
|
1995
|
+
disabled: !writable || defaults.length === 0,
|
|
1996
|
+
title: t("flagsRestoreTitle"),
|
|
1997
|
+
onClick: () => {
|
|
1998
|
+
if (!writable) return;
|
|
1999
|
+
save(merged.map((flag) => [flag]));
|
|
2000
|
+
},
|
|
2001
|
+
children: t("flagsRestore")
|
|
2002
|
+
});
|
|
2003
|
+
};
|
|
2004
|
+
var wslAction = (visible) => {
|
|
2005
|
+
var current = flagsOf(visible);
|
|
2006
|
+
var merged = current.concat(wsl.filter((flag) => current.indexOf(flag) === -1));
|
|
2007
|
+
return (0, import_jsx_runtime11.jsx)("button", {
|
|
2008
|
+
type: "button",
|
|
2009
|
+
className: ChromeMcpCard_default.linkButton,
|
|
2010
|
+
// The recommended list is host-served — with every one of them
|
|
2011
|
+
// already in the rows there is nothing left to add.
|
|
2012
|
+
disabled: !writable || wsl.length === 0,
|
|
2013
|
+
title: t("flagsWslTitle"),
|
|
2014
|
+
onClick: () => {
|
|
2015
|
+
if (!writable) return;
|
|
2016
|
+
save(merged.map((flag) => [flag]));
|
|
2017
|
+
},
|
|
2018
|
+
children: t("flagsWsl")
|
|
2019
|
+
});
|
|
2020
|
+
};
|
|
2021
|
+
var renderActions = (visible) => (0, import_jsx_runtime11.jsxs)("div", {
|
|
2022
|
+
className: ChromeMcpCard_default.linkButtonRow,
|
|
2023
|
+
children: [restoreAction(visible), wslAction(visible)]
|
|
2024
|
+
});
|
|
2025
|
+
return (0, import_jsx_runtime11.jsxs)("div", {
|
|
2026
|
+
className: ChromeMcpCard_default.catalog,
|
|
2027
|
+
children: [
|
|
2028
|
+
(0, import_jsx_runtime11.jsxs)("div", {
|
|
2029
|
+
className: ChromeMcpCard_default.field,
|
|
2030
|
+
children: [
|
|
2031
|
+
(0, import_jsx_runtime11.jsxs)("div", {
|
|
2032
|
+
className: ChromeMcpCard_default.fieldRow,
|
|
2033
|
+
children: [
|
|
2034
|
+
(0, import_jsx_runtime11.jsx)("span", { className: ChromeMcpCard_default.fieldTitle, children: t("flagsTitle") }),
|
|
2035
|
+
// The guide link rides the same field row the picker's
|
|
2036
|
+
// pill occupies.
|
|
2037
|
+
(0, import_jsx_runtime11.jsxs)("a", {
|
|
2038
|
+
className: ChromeMcpCard_default.docsLink,
|
|
2039
|
+
href: CONFIGURATION_URL,
|
|
2040
|
+
target: "_blank",
|
|
2041
|
+
rel: "noopener noreferrer",
|
|
2042
|
+
title: t("docsMessage"),
|
|
2043
|
+
children: [
|
|
2044
|
+
(0, import_jsx_runtime11.jsx)("svg", {
|
|
2045
|
+
className: ChromeMcpCard_default.docsIcon,
|
|
2046
|
+
width: 14,
|
|
2047
|
+
height: 14,
|
|
2048
|
+
viewBox: "0 0 24 24",
|
|
2049
|
+
fill: "none",
|
|
2050
|
+
stroke: "currentColor",
|
|
2051
|
+
strokeWidth: 2,
|
|
2052
|
+
strokeLinecap: "round",
|
|
2053
|
+
strokeLinejoin: "round",
|
|
2054
|
+
"aria-hidden": "true",
|
|
2055
|
+
children: DOCS_PATHS2.map((d, at) => (0, import_jsx_runtime11.jsx)("path", { d }, at))
|
|
2056
|
+
}),
|
|
2057
|
+
(0, import_jsx_runtime11.jsx)("span", { className: ChromeMcpCard_default.docsLinkLabel, children: t("docsLinkLabel") })
|
|
2058
|
+
]
|
|
2059
|
+
})
|
|
2060
|
+
]
|
|
2061
|
+
}),
|
|
2062
|
+
(0, import_jsx_runtime11.jsx)("div", { className: ChromeMcpCard_default.fieldDesc, children: t("flagsHint") })
|
|
2063
|
+
]
|
|
2064
|
+
}),
|
|
2065
|
+
// One row per saved flag: the single field is the flag itself, and
|
|
2066
|
+
// the two append controls — Restore defaults and Flags WSL — ride
|
|
2067
|
+
// the list's action line.
|
|
2068
|
+
(0, import_jsx_runtime11.jsx)(RowList, {
|
|
2069
|
+
values: rowsOf(flags),
|
|
2070
|
+
labels: [t("flagsValueLabel")],
|
|
2071
|
+
placeholders: [t("flagsValuePlaceholder")],
|
|
2072
|
+
writable,
|
|
2073
|
+
save,
|
|
2074
|
+
renderAction: renderActions,
|
|
2075
|
+
emptyText: t("flagsEmpty"),
|
|
2076
|
+
rowsLabel: t("flagsRows"),
|
|
2077
|
+
addLabel: t("addFlag"),
|
|
2078
|
+
removeLabel: t("removeFlag"),
|
|
2079
|
+
rowClassName: ChromeMcpCard_default.catalogRowSingle,
|
|
2080
|
+
inputClassName: ChromeMcpCard_default.catalogInputMono,
|
|
2081
|
+
disclosure: true
|
|
2082
|
+
})
|
|
2083
|
+
]
|
|
2084
|
+
});
|
|
2085
|
+
}
|
|
47
2086
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
2087
|
+
// src/client/card/picker.ts
|
|
2088
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2089
|
+
var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
2090
|
+
function CatalogPicker(props) {
|
|
2091
|
+
var entries = props.entries;
|
|
2092
|
+
var options = props.options;
|
|
2093
|
+
var selectedId = props.selectedId;
|
|
2094
|
+
var writable = props.writable;
|
|
2095
|
+
var busy = props.busy === true;
|
|
2096
|
+
var rows = entries.map((entry) => [entry.id, entry.name]);
|
|
2097
|
+
var saveEntries = (next) => {
|
|
2098
|
+
if (typeof props.saveEntries !== "function") return Promise.resolve();
|
|
2099
|
+
return Promise.resolve(props.saveEntries(next.map((row) => ({ id: row[0] ?? "", name: row[1] ?? "" }))));
|
|
2100
|
+
};
|
|
2101
|
+
var fetchAction = () => (0, import_jsx_runtime12.jsx)("button", {
|
|
2102
|
+
type: "button",
|
|
2103
|
+
className: ChromeMcpCard_default.linkButton,
|
|
2104
|
+
disabled: !writable || busy,
|
|
2105
|
+
onClick: () => {
|
|
2106
|
+
props.refresh();
|
|
2107
|
+
},
|
|
2108
|
+
children: busy ? props.busyLabel : props.refreshLabel
|
|
2109
|
+
});
|
|
2110
|
+
var windowsAction = () => (0, import_jsx_runtime12.jsx)("button", {
|
|
2111
|
+
type: "button",
|
|
2112
|
+
className: ChromeMcpCard_default.linkButton,
|
|
2113
|
+
disabled: props.windowsDisabled === true,
|
|
2114
|
+
title: props.windowsTitle,
|
|
2115
|
+
onClick: () => {
|
|
2116
|
+
if (typeof props.windowsOnOpen === "function") props.windowsOnOpen();
|
|
2117
|
+
},
|
|
2118
|
+
children: props.windowsLabel
|
|
2119
|
+
});
|
|
2120
|
+
var renderActions = () => (0, import_jsx_runtime12.jsxs)("div", {
|
|
2121
|
+
className: ChromeMcpCard_default.linkButtonRow,
|
|
2122
|
+
children: [fetchAction(), windowsAction()]
|
|
2123
|
+
});
|
|
2124
|
+
return (0, import_jsx_runtime12.jsxs)("div", {
|
|
2125
|
+
className: ChromeMcpCard_default.catalog,
|
|
2126
|
+
children: [
|
|
2127
|
+
(0, import_jsx_runtime12.jsxs)("div", {
|
|
2128
|
+
className: ChromeMcpCard_default.field,
|
|
2129
|
+
children: [
|
|
2130
|
+
(0, import_jsx_runtime12.jsxs)("div", {
|
|
2131
|
+
className: ChromeMcpCard_default.fieldRow,
|
|
2132
|
+
children: [
|
|
2133
|
+
(0, import_jsx_runtime12.jsx)("span", { className: ChromeMcpCard_default.fieldTitle, children: props.selectorLabel }),
|
|
2134
|
+
(0, import_jsx_runtime12.jsx)("span", {
|
|
2135
|
+
className: ChromeMcpCard_default.selectorWrap,
|
|
2136
|
+
children: (0, import_jsx_runtime12.jsx)(import_dsh_client_ui_primitives5.Menu, {
|
|
2137
|
+
open: props.menuOpen,
|
|
2138
|
+
onClose: () => {
|
|
2139
|
+
props.setMenuOpen(false);
|
|
2140
|
+
},
|
|
2141
|
+
items: options,
|
|
2142
|
+
selectedId: options.some((option) => option.id === selectedId) ? selectedId : "",
|
|
2143
|
+
onSelect: (id) => {
|
|
2144
|
+
props.setMenuOpen(false);
|
|
2145
|
+
props.select(id);
|
|
2146
|
+
},
|
|
2147
|
+
align: "end",
|
|
2148
|
+
portal: true,
|
|
2149
|
+
anchor: (0, import_jsx_runtime12.jsxs)("button", {
|
|
2150
|
+
type: "button",
|
|
2151
|
+
className: ChromeMcpCard_default.selector,
|
|
2152
|
+
"aria-haspopup": "menu",
|
|
2153
|
+
"aria-expanded": props.menuOpen,
|
|
2154
|
+
disabled: !writable || busy,
|
|
2155
|
+
title: props.selectedTitle,
|
|
2156
|
+
onClick: () => {
|
|
2157
|
+
props.setMenuOpen(!props.menuOpen);
|
|
2158
|
+
},
|
|
2159
|
+
children: [
|
|
2160
|
+
// The reference card hands the pill a bare label;
|
|
2161
|
+
// the path needs its own truncating span.
|
|
2162
|
+
(0, import_jsx_runtime12.jsx)("span", { className: ChromeMcpCard_default.selectorLabel, children: props.selectedLabel }),
|
|
2163
|
+
(0, import_jsx_runtime12.jsx)("svg", {
|
|
2164
|
+
width: 14,
|
|
2165
|
+
height: 14,
|
|
2166
|
+
className: ChromeMcpCard_default.pillChevron,
|
|
2167
|
+
viewBox: "0 0 14 14",
|
|
2168
|
+
fill: "none",
|
|
2169
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2170
|
+
children: (0, import_jsx_runtime12.jsx)("path", { d: CHEVRON_PATH2, fill: "currentColor" })
|
|
2171
|
+
})
|
|
2172
|
+
]
|
|
2173
|
+
})
|
|
2174
|
+
})
|
|
2175
|
+
})
|
|
2176
|
+
]
|
|
2177
|
+
}),
|
|
2178
|
+
(0, import_jsx_runtime12.jsx)("div", { className: ChromeMcpCard_default.fieldDesc, children: props.hint })
|
|
2179
|
+
]
|
|
2180
|
+
}),
|
|
2181
|
+
// The saved rows: two fields per row, folded behind the disclosure,
|
|
2182
|
+
// with the fetch action sitting inside the body.
|
|
2183
|
+
(0, import_jsx_runtime12.jsx)(RowList, {
|
|
2184
|
+
values: rows,
|
|
2185
|
+
labels: [props.idLabel, props.nameLabel],
|
|
2186
|
+
placeholders: [props.idPlaceholder, props.namePlaceholder],
|
|
2187
|
+
writable,
|
|
2188
|
+
busy,
|
|
2189
|
+
save: saveEntries,
|
|
2190
|
+
renderAction: renderActions,
|
|
2191
|
+
emptyText: props.emptyText,
|
|
2192
|
+
rowsLabel: props.rowsLabel,
|
|
2193
|
+
addLabel: props.addLabel,
|
|
2194
|
+
removeLabel: props.removeLabel,
|
|
2195
|
+
disclosure: true
|
|
2196
|
+
}),
|
|
2197
|
+
props.statusLine === void 0 || props.statusLine === null ? null : props.statusLine
|
|
2198
|
+
]
|
|
2199
|
+
});
|
|
2200
|
+
}
|
|
121
2201
|
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
// A new wait supersedes any pending one (the startup catch-up
|
|
260
|
-
// poll yielding to a manual re-check), so exactly one poll loop
|
|
261
|
-
// runs and the superseded wait settles instead of dangling.
|
|
262
|
-
var generation = ++controller.pollGeneration;
|
|
263
|
-
return new Promise((resolve) => {
|
|
264
|
-
var timer;
|
|
265
|
-
var settled = false;
|
|
266
|
-
var arm = (delay) => {
|
|
267
|
-
timer = setTimeout(tick, delay);
|
|
268
|
-
controller.pollTimer = timer;
|
|
269
|
-
};
|
|
270
|
-
var finish = () => {
|
|
271
|
-
if (settled) return;
|
|
272
|
-
settled = true;
|
|
273
|
-
clearTimeout(timer);
|
|
274
|
-
if (controller.pollTimer === timer) controller.pollTimer = null;
|
|
275
|
-
resolve();
|
|
276
|
-
};
|
|
277
|
-
var satisfied = () =>
|
|
278
|
-
controller.store.getSnapshot().checkRevision > baseline || Date.now() >= deadline;
|
|
279
|
-
var stale = () => controller.disposed || generation !== controller.pollGeneration;
|
|
280
|
-
var tick = () => {
|
|
281
|
-
if (stale() || satisfied()) {
|
|
282
|
-
finish();
|
|
283
|
-
return;
|
|
284
|
-
}
|
|
285
|
-
var loaded;
|
|
286
|
-
try {
|
|
287
|
-
loaded = controller.mirror.load();
|
|
288
|
-
} catch (error) {
|
|
289
|
-
loaded = void 0; // mirror read failure: the next tick retries
|
|
290
|
-
}
|
|
291
|
-
Promise.resolve(loaded)
|
|
292
|
-
.catch(() => {})
|
|
293
|
-
.then(() => {
|
|
294
|
-
if (stale() || satisfied()) {
|
|
295
|
-
finish();
|
|
296
|
-
return;
|
|
297
|
-
}
|
|
298
|
-
arm(CHECK_POLL_TICK_MS);
|
|
299
|
-
});
|
|
300
|
-
};
|
|
301
|
-
arm(CHECK_POLL_TICK_MS);
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
noteError(error) {
|
|
305
|
-
if (this.disposed) return;
|
|
306
|
-
var previous = this.store.getSnapshot();
|
|
307
|
-
this.store.set({
|
|
308
|
-
...previous,
|
|
309
|
-
actionError: error != null && typeof error.message === "string" ? error.message : String(error)
|
|
310
|
-
});
|
|
311
|
-
}
|
|
312
|
-
/** The face the card's slot registration injects. */
|
|
313
|
-
inject() {
|
|
314
|
-
return {
|
|
315
|
-
hooks: { chromeMcpCard: this.store },
|
|
316
|
-
saveFlags: (flags) => this.saveFlags(flags),
|
|
317
|
-
recheck: () => this.recheck(),
|
|
318
|
-
/** One mirror re-read (used when the card opens). */
|
|
319
|
-
refresh: () => this.refresh()
|
|
320
|
-
};
|
|
321
|
-
}
|
|
322
|
-
/**
|
|
323
|
-
* Re-read the shared describe mirror once so base-layer status
|
|
324
|
-
* captured asynchronously by the host (bridge connection errors)
|
|
325
|
-
* reaches an opened card without waiting for a write or a re-check.
|
|
326
|
-
*/
|
|
327
|
-
refresh() {
|
|
328
|
-
if (this.disposed) return Promise.resolve();
|
|
329
|
-
var load;
|
|
330
|
-
try {
|
|
331
|
-
load = this.mirror.load();
|
|
332
|
-
} catch (error) {
|
|
333
|
-
load = void 0;
|
|
334
|
-
}
|
|
335
|
-
return Promise.resolve(load).catch(() => {});
|
|
336
|
-
}
|
|
337
|
-
dispose() {
|
|
338
|
-
this.disposed = true;
|
|
339
|
-
if (this.pollTimer !== null) {
|
|
340
|
-
clearTimeout(this.pollTimer);
|
|
341
|
-
this.pollTimer = null;
|
|
342
|
-
}
|
|
343
|
-
this.unsubscribe();
|
|
344
|
-
}
|
|
345
|
-
};
|
|
2202
|
+
// src/client/card/dialog.ts
|
|
2203
|
+
var react6 = __toESM(require("react"), 1);
|
|
2204
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
2205
|
+
function CandidateDialog(props) {
|
|
2206
|
+
var t = props.t;
|
|
2207
|
+
var candidates = props.candidates;
|
|
2208
|
+
var savedIds = props.savedIds;
|
|
2209
|
+
var savedSet = new Set(savedIds);
|
|
2210
|
+
var initialChecked = candidates.filter((candidate) => savedSet.has(candidate.id)).map((candidate) => candidate.id);
|
|
2211
|
+
var servedKey = JSON.stringify(candidates) + "|" + JSON.stringify(savedIds);
|
|
2212
|
+
var draftState = react6.useState({ key: "", query: "", checked: [] });
|
|
2213
|
+
var draft = draftState[0];
|
|
2214
|
+
var setDraft = draftState[1];
|
|
2215
|
+
var dirty = draft.key !== servedKey;
|
|
2216
|
+
var query = dirty ? "" : draft.query;
|
|
2217
|
+
var checked = dirty ? initialChecked : draft.checked;
|
|
2218
|
+
var checkedSet = new Set(checked);
|
|
2219
|
+
var setQuery = (value) => {
|
|
2220
|
+
setDraft({ key: servedKey, query: value, checked: Array.from(checkedSet) });
|
|
2221
|
+
};
|
|
2222
|
+
var setChecked = (make) => {
|
|
2223
|
+
setDraft({ key: servedKey, query, checked: make(checked) });
|
|
2224
|
+
};
|
|
2225
|
+
var needle = query.trim().toLowerCase();
|
|
2226
|
+
var shown = needle === "" ? candidates : candidates.filter((candidate) => candidate.id.toLowerCase().indexOf(needle) !== -1);
|
|
2227
|
+
var addable = shown.filter((candidate) => !savedSet.has(candidate.id)).map((candidate) => candidate.id);
|
|
2228
|
+
var allChecked = addable.length > 0 && addable.every((id) => checkedSet.has(id));
|
|
2229
|
+
var toggle = (id, value) => {
|
|
2230
|
+
setChecked((current) => value ? current.concat([id]) : current.filter((entry) => entry !== id));
|
|
2231
|
+
};
|
|
2232
|
+
return (0, import_jsx_runtime13.jsxs)("div", {
|
|
2233
|
+
className: ChromeMcpCard_default.fetchDialog,
|
|
2234
|
+
role: "dialog",
|
|
2235
|
+
"aria-modal": "true",
|
|
2236
|
+
"aria-label": props.title,
|
|
2237
|
+
children: [
|
|
2238
|
+
(0, import_jsx_runtime13.jsxs)("div", {
|
|
2239
|
+
className: ChromeMcpCard_default.dialogContent,
|
|
2240
|
+
children: [
|
|
2241
|
+
(0, import_jsx_runtime13.jsxs)("div", {
|
|
2242
|
+
className: ChromeMcpCard_default.dialogHeader,
|
|
2243
|
+
children: [
|
|
2244
|
+
(0, import_jsx_runtime13.jsx)("h2", { className: ChromeMcpCard_default.dialogTitle, children: props.title }),
|
|
2245
|
+
(0, import_jsx_runtime13.jsx)("button", {
|
|
2246
|
+
type: "button",
|
|
2247
|
+
className: ChromeMcpCard_default.dialogClose,
|
|
2248
|
+
"aria-label": t("close"),
|
|
2249
|
+
onClick: () => props.onClose(),
|
|
2250
|
+
children: (0, import_jsx_runtime13.jsx)("svg", {
|
|
2251
|
+
width: 14,
|
|
2252
|
+
height: 14,
|
|
2253
|
+
viewBox: "0 0 16 16",
|
|
2254
|
+
fill: "none",
|
|
2255
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
2256
|
+
"aria-hidden": "true",
|
|
2257
|
+
children: CLOSE_PATHS2.map((d, at) => (0, import_jsx_runtime13.jsx)("path", { d, fill: "currentColor" }, at))
|
|
2258
|
+
})
|
|
2259
|
+
})
|
|
2260
|
+
]
|
|
2261
|
+
}),
|
|
2262
|
+
(0, import_jsx_runtime13.jsx)("p", { className: ChromeMcpCard_default.dialogDescription, children: props.description }),
|
|
2263
|
+
(0, import_jsx_runtime13.jsxs)("div", {
|
|
2264
|
+
className: ChromeMcpCard_default.dialogBody,
|
|
2265
|
+
children: [
|
|
2266
|
+
(0, import_jsx_runtime13.jsxs)("div", {
|
|
2267
|
+
className: ChromeMcpCard_default.candidateToolbar,
|
|
2268
|
+
children: [
|
|
2269
|
+
(0, import_jsx_runtime13.jsx)("input", {
|
|
2270
|
+
className: ChromeMcpCard_default.candidateSearch,
|
|
2271
|
+
type: "search",
|
|
2272
|
+
placeholder: props.searchPlaceholder,
|
|
2273
|
+
"aria-label": props.searchPlaceholder,
|
|
2274
|
+
value: query,
|
|
2275
|
+
onChange: (event) => {
|
|
2276
|
+
setQuery(event && event.target ? String(event.target.value ?? "") : "");
|
|
2277
|
+
}
|
|
2278
|
+
}),
|
|
2279
|
+
(0, import_jsx_runtime13.jsx)("button", {
|
|
2280
|
+
type: "button",
|
|
2281
|
+
className: ChromeMcpCard_default.linkButton,
|
|
2282
|
+
onClick: () => {
|
|
2283
|
+
if (allChecked) setChecked(() => []);
|
|
2284
|
+
else setChecked((current) => Array.from(new Set(current.concat(addable))));
|
|
2285
|
+
},
|
|
2286
|
+
children: t("selectAll")
|
|
2287
|
+
})
|
|
2288
|
+
]
|
|
2289
|
+
}),
|
|
2290
|
+
shown.length === 0 ? (0, import_jsx_runtime13.jsx)("p", { className: ChromeMcpCard_default.empty, children: t("dialogEmpty") }) : (0, import_jsx_runtime13.jsx)("ul", {
|
|
2291
|
+
className: ChromeMcpCard_default.candidateList,
|
|
2292
|
+
children: shown.map((candidate) => {
|
|
2293
|
+
var isSaved = savedSet.has(candidate.id);
|
|
2294
|
+
var note = candidate.note !== "" ? candidate.note : isSaved ? t("candidateSaved") : "";
|
|
2295
|
+
return (0, import_jsx_runtime13.jsx)("li", {
|
|
2296
|
+
className: ChromeMcpCard_default.candidate,
|
|
2297
|
+
children: (0, import_jsx_runtime13.jsxs)("label", {
|
|
2298
|
+
className: ChromeMcpCard_default.candidateLabel,
|
|
2299
|
+
children: [
|
|
2300
|
+
(0, import_jsx_runtime13.jsx)("input", {
|
|
2301
|
+
type: "checkbox",
|
|
2302
|
+
checked: isSaved ? true : checkedSet.has(candidate.id),
|
|
2303
|
+
disabled: isSaved,
|
|
2304
|
+
onChange: (event) => {
|
|
2305
|
+
toggle(candidate.id, !!(event && event.target && event.target.checked));
|
|
2306
|
+
}
|
|
2307
|
+
}),
|
|
2308
|
+
(0, import_jsx_runtime13.jsx)("span", { className: ChromeMcpCard_default.candidateId, children: candidate.id }),
|
|
2309
|
+
note === "" ? null : (0, import_jsx_runtime13.jsx)("span", { className: ChromeMcpCard_default.candidateNote, children: note })
|
|
2310
|
+
]
|
|
2311
|
+
})
|
|
2312
|
+
}, candidate.id);
|
|
2313
|
+
})
|
|
2314
|
+
})
|
|
2315
|
+
]
|
|
2316
|
+
}),
|
|
2317
|
+
(0, import_jsx_runtime13.jsxs)("div", {
|
|
2318
|
+
className: ChromeMcpCard_default.dialogFooter,
|
|
2319
|
+
children: [
|
|
2320
|
+
(0, import_jsx_runtime13.jsx)("button", {
|
|
2321
|
+
type: "button",
|
|
2322
|
+
className: ChromeMcpCard_default.dialogButton,
|
|
2323
|
+
onClick: () => props.onClose(),
|
|
2324
|
+
children: t("cancel")
|
|
2325
|
+
}),
|
|
2326
|
+
(0, import_jsx_runtime13.jsx)("button", {
|
|
2327
|
+
type: "button",
|
|
2328
|
+
className: ChromeMcpCard_default.dialogButton + " " + ChromeMcpCard_default.dialogButtonPrimary,
|
|
2329
|
+
onClick: () => props.onAdd(Array.from(checkedSet)),
|
|
2330
|
+
children: t("addSelected")
|
|
2331
|
+
})
|
|
2332
|
+
]
|
|
2333
|
+
})
|
|
2334
|
+
]
|
|
2335
|
+
})
|
|
2336
|
+
]
|
|
2337
|
+
});
|
|
2338
|
+
}
|
|
346
2339
|
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
2340
|
+
// src/client/card/run-actions.ts
|
|
2341
|
+
var react7 = __toESM(require("react"), 1);
|
|
2342
|
+
var PROBED_AGE_TICK_MS = 1e4;
|
|
2343
|
+
function useRunActions(deps) {
|
|
2344
|
+
const runningState = react7.useState(false);
|
|
2345
|
+
const isRunning = runningState[0];
|
|
2346
|
+
const setRunning = runningState[1];
|
|
2347
|
+
const windowsRunningState = react7.useState(false);
|
|
2348
|
+
const isWindowsRunning = windowsRunningState[0];
|
|
2349
|
+
const setWindowsRunning = windowsRunningState[1];
|
|
2350
|
+
const dialogRef = react7.useState(null);
|
|
2351
|
+
const dialog = dialogRef[0];
|
|
2352
|
+
const setDialog = dialogRef[1];
|
|
2353
|
+
const probedState = react7.useState(0);
|
|
2354
|
+
const lastProbedAt = probedState[0];
|
|
2355
|
+
const setLastProbedAt = probedState[1];
|
|
2356
|
+
const clockState = react7.useState(() => Date.now());
|
|
2357
|
+
const clock = clockState[0];
|
|
2358
|
+
const setClock = clockState[1];
|
|
2359
|
+
react7.useEffect(() => {
|
|
2360
|
+
const tick = setInterval(() => setClock(Date.now()), PROBED_AGE_TICK_MS);
|
|
2361
|
+
return () => clearInterval(tick);
|
|
2362
|
+
}, []);
|
|
2363
|
+
const runFetch = () => {
|
|
2364
|
+
setRunning(true);
|
|
2365
|
+
let promise;
|
|
2366
|
+
try {
|
|
2367
|
+
promise = deps.refreshExecutables();
|
|
2368
|
+
} catch (caught) {
|
|
2369
|
+
promise = Promise.reject(caught);
|
|
2370
|
+
}
|
|
2371
|
+
Promise.resolve(promise).then(
|
|
2372
|
+
async (statuses) => {
|
|
2373
|
+
setRunning(false);
|
|
2374
|
+
const settled = Date.now();
|
|
2375
|
+
setLastProbedAt(settled);
|
|
2376
|
+
setClock(settled);
|
|
2377
|
+
if (!Array.isArray(statuses) || statuses.length === 0) return;
|
|
2378
|
+
const candidates = statuses.map((status) => ({
|
|
2379
|
+
id: status.path,
|
|
2380
|
+
note: status.version !== "" ? status.version : status.error !== "" ? status.error : status.note,
|
|
2381
|
+
broken: status.version === "" && status.error !== ""
|
|
2382
|
+
}));
|
|
2383
|
+
setDialog({ candidates });
|
|
2384
|
+
},
|
|
2385
|
+
() => {
|
|
2386
|
+
setRunning(false);
|
|
2387
|
+
}
|
|
2388
|
+
);
|
|
2389
|
+
};
|
|
2390
|
+
const runWindowsChrome = () => {
|
|
2391
|
+
setWindowsRunning(true);
|
|
2392
|
+
let promise;
|
|
2393
|
+
try {
|
|
2394
|
+
promise = deps.openWindowsChrome();
|
|
2395
|
+
} catch (caught) {
|
|
2396
|
+
promise = Promise.reject(caught);
|
|
2397
|
+
}
|
|
2398
|
+
Promise.resolve(promise).then(
|
|
2399
|
+
() => {
|
|
2400
|
+
setWindowsRunning(false);
|
|
2401
|
+
},
|
|
2402
|
+
() => {
|
|
2403
|
+
setWindowsRunning(false);
|
|
2404
|
+
}
|
|
2405
|
+
);
|
|
2406
|
+
};
|
|
2407
|
+
const addFromDialog = (ids) => {
|
|
2408
|
+
setDialog(null);
|
|
2409
|
+
if (typeof deps.addExecutables === "function") Promise.resolve(deps.addExecutables(ids)).catch(() => {
|
|
2410
|
+
});
|
|
2411
|
+
};
|
|
2412
|
+
return {
|
|
2413
|
+
running: isRunning,
|
|
2414
|
+
windowsRunning: isWindowsRunning,
|
|
2415
|
+
dialog,
|
|
2416
|
+
runFetch,
|
|
2417
|
+
runWindowsChrome,
|
|
2418
|
+
addFromDialog,
|
|
2419
|
+
closeDialog: () => setDialog(null),
|
|
2420
|
+
lastProbedAt,
|
|
2421
|
+
clock
|
|
2422
|
+
};
|
|
2423
|
+
}
|
|
351
2424
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
onClick: () => {
|
|
388
|
-
setOpen(!open);
|
|
389
|
-
if (!open && typeof props.refresh === "function") props.refresh();
|
|
390
|
-
},
|
|
391
|
-
children: [
|
|
392
|
-
(0, reactJsx.jsxs)("span", {
|
|
393
|
-
className: CSS.headText,
|
|
394
|
-
children: [
|
|
395
|
-
(0, reactJsx.jsxs)("div", {
|
|
396
|
-
className: CSS.nameRow,
|
|
397
|
-
children: [
|
|
398
|
-
(0, reactJsx.jsx)("span", {
|
|
399
|
-
className: CSS.name,
|
|
400
|
-
children: t("title")
|
|
401
|
-
}),
|
|
402
|
-
tip !== ""
|
|
403
|
-
? (0, reactJsx.jsx)("span", {
|
|
404
|
-
className: CSS.dot + " " + CSS.dotError,
|
|
405
|
-
role: "img",
|
|
406
|
-
"aria-label": dotAria,
|
|
407
|
-
title: tip
|
|
408
|
-
})
|
|
409
|
-
: null
|
|
410
|
-
]
|
|
411
|
-
}),
|
|
412
|
-
(0, reactJsx.jsx)("span", { className: CSS.desc, children: t("description") })
|
|
413
|
-
]
|
|
414
|
-
}),
|
|
415
|
-
(0, reactJsx.jsx)("svg", {
|
|
416
|
-
width: 14,
|
|
417
|
-
height: 14,
|
|
418
|
-
className: CSS.chevron + (open ? " " + CSS.chevronOpen : ""),
|
|
419
|
-
viewBox: "0 0 14 14",
|
|
420
|
-
fill: "none",
|
|
421
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
422
|
-
children: (0, reactJsx.jsx)("path", { d: CHEVRON_PATH, fill: "currentColor" })
|
|
423
|
-
})
|
|
424
|
-
]
|
|
425
|
-
}),
|
|
426
|
-
open
|
|
427
|
-
? (0, reactJsx.jsxs)("div", {
|
|
428
|
-
id: bodyId,
|
|
429
|
-
className: CSS.body,
|
|
430
|
-
children: [
|
|
431
|
-
!state.writable
|
|
432
|
-
? (0, reactJsx.jsx)("p", { className: CSS.readOnly, role: "status", children: t("readOnly") })
|
|
433
|
-
: null,
|
|
434
|
-
(0, reactJsx.jsxs)("div", {
|
|
435
|
-
className: CSS.field,
|
|
436
|
-
children: [
|
|
437
|
-
(0, reactJsx.jsxs)("div", {
|
|
438
|
-
className: CSS.rowText,
|
|
439
|
-
children: [
|
|
440
|
-
(0, reactJsx.jsx)("div", { className: CSS.fieldTitle, children: t("flagsTitle") }),
|
|
441
|
-
(0, reactJsx.jsx)("div", { className: CSS.fieldDesc, children: t("flagsHint") })
|
|
442
|
-
]
|
|
443
|
-
})
|
|
444
|
-
]
|
|
445
|
-
}),
|
|
446
|
-
// Extra flags editor: one flag per line; the write goes
|
|
447
|
-
// through props.saveFlags (host validate + fiber.update).
|
|
448
|
-
// `key` re-mounts the textarea when the store value
|
|
449
|
-
// changes underneath the editor (e.g. a save from another
|
|
450
|
-
// window), so the shown value never drifts.
|
|
451
|
-
state.writable
|
|
452
|
-
? (0, reactJsx.jsxs)("div", {
|
|
453
|
-
className: CSS.editor,
|
|
454
|
-
children: [
|
|
455
|
-
(0, reactJsx.jsx)("textarea", {
|
|
456
|
-
className: CSS.text,
|
|
457
|
-
rows: Math.max(3, state.extraFlags.length),
|
|
458
|
-
placeholder: t("flagsPlaceholder"),
|
|
459
|
-
defaultValue: state.extraFlags.join("\n"),
|
|
460
|
-
key: state.extraFlags.join("\n"),
|
|
461
|
-
ref: flagsRef
|
|
462
|
-
}),
|
|
463
|
-
(0, reactJsx.jsx)("div", {
|
|
464
|
-
className: CSS.row,
|
|
465
|
-
children: (0, reactJsx.jsx)("button", {
|
|
466
|
-
type: "button",
|
|
467
|
-
className: CSS.button,
|
|
468
|
-
disabled: !state.writable,
|
|
469
|
-
onClick: () => {
|
|
470
|
-
var raw = flagsRef.current && typeof flagsRef.current.value === "string" ? flagsRef.current.value : "";
|
|
471
|
-
props.saveFlags(
|
|
472
|
-
raw
|
|
473
|
-
.split(/\r?\n/u)
|
|
474
|
-
.map((line) => line.trim())
|
|
475
|
-
.filter((line) => line !== "")
|
|
476
|
-
);
|
|
477
|
-
},
|
|
478
|
-
children: t("flagsSave")
|
|
479
|
-
})
|
|
480
|
-
})
|
|
481
|
-
]
|
|
482
|
-
})
|
|
483
|
-
: (0, reactJsx.jsx)("p", {
|
|
484
|
-
className: CSS.value,
|
|
485
|
-
children:
|
|
486
|
-
state.extraFlags.length > 0 ? state.extraFlags.join("\n") : t("flagsPlaceholder")
|
|
487
|
-
}),
|
|
488
|
-
(0, reactJsx.jsxs)("div", {
|
|
489
|
-
className: CSS.row,
|
|
490
|
-
children: [
|
|
491
|
-
(0, reactJsx.jsx)("button", {
|
|
492
|
-
type: "button",
|
|
493
|
-
className: CSS.button,
|
|
494
|
-
disabled: !state.writable || isChecking,
|
|
495
|
-
onClick: () => {
|
|
496
|
-
setChecking(true);
|
|
497
|
-
var checkPromise;
|
|
498
|
-
try {
|
|
499
|
-
checkPromise = props.recheck();
|
|
500
|
-
} catch (error) {
|
|
501
|
-
checkPromise = Promise.reject(error);
|
|
502
|
-
}
|
|
503
|
-
if (checkPromise == null || typeof checkPromise.finally !== "function") {
|
|
504
|
-
checkPromise = Promise.resolve(checkPromise);
|
|
505
|
-
}
|
|
506
|
-
checkPromise.finally(() => setChecking(false));
|
|
507
|
-
},
|
|
508
|
-
children: isChecking ? t("checking") : t("check")
|
|
509
|
-
})
|
|
510
|
-
]
|
|
511
|
-
}),
|
|
512
|
-
// Executable version discovered by the last check.
|
|
513
|
-
state.chromeVersion !== ""
|
|
514
|
-
? (0, reactJsx.jsxs)("div", {
|
|
515
|
-
className: CSS.field,
|
|
516
|
-
children: [
|
|
517
|
-
(0, reactJsx.jsxs)("div", {
|
|
518
|
-
className: CSS.rowText,
|
|
519
|
-
children: [
|
|
520
|
-
(0, reactJsx.jsx)("div", { className: CSS.fieldTitle, children: t("versionTitle") }),
|
|
521
|
-
(0, reactJsx.jsx)("p", {
|
|
522
|
-
className: CSS.value,
|
|
523
|
-
children: state.chromeVersion
|
|
524
|
-
})
|
|
525
|
-
]
|
|
526
|
-
})
|
|
527
|
-
]
|
|
528
|
-
})
|
|
529
|
-
: null,
|
|
530
|
-
// Product spec: the full configuration-guide message, with
|
|
531
|
-
// the upstream URL rendered as the external link.
|
|
532
|
-
(0, reactJsx.jsxs)("p", {
|
|
533
|
-
className: CSS.docs,
|
|
534
|
-
children: [
|
|
535
|
-
t("docsMessage") + " ",
|
|
536
|
-
(0, reactJsx.jsx)("a", {
|
|
537
|
-
className: CSS.link,
|
|
538
|
-
href: CONFIGURATION_URL,
|
|
539
|
-
target: "_blank",
|
|
540
|
-
rel: "noopener noreferrer",
|
|
541
|
-
children: CONFIGURATION_URL
|
|
542
|
-
})
|
|
543
|
-
]
|
|
544
|
-
})
|
|
545
|
-
]
|
|
546
|
-
})
|
|
547
|
-
: null
|
|
548
|
-
]
|
|
549
|
-
});
|
|
550
|
-
}
|
|
2425
|
+
// src/client/card/toggle.ts
|
|
2426
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2427
|
+
var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
2428
|
+
function LogOutputToggle(props) {
|
|
2429
|
+
var t = props.t;
|
|
2430
|
+
return (0, import_jsx_runtime14.jsxs)("div", {
|
|
2431
|
+
className: ChromeMcpCard_default.catalog,
|
|
2432
|
+
children: [
|
|
2433
|
+
(0, import_jsx_runtime14.jsxs)("div", {
|
|
2434
|
+
className: ChromeMcpCard_default.field,
|
|
2435
|
+
children: [
|
|
2436
|
+
(0, import_jsx_runtime14.jsxs)("div", {
|
|
2437
|
+
className: ChromeMcpCard_default.fieldRow,
|
|
2438
|
+
children: [
|
|
2439
|
+
(0, import_jsx_runtime14.jsx)("span", { className: ChromeMcpCard_default.fieldTitle, children: t("reduceLabel") }),
|
|
2440
|
+
(0, import_jsx_runtime14.jsx)("span", {
|
|
2441
|
+
className: ChromeMcpCard_default.toggleLabel,
|
|
2442
|
+
title: t("reduceTitle"),
|
|
2443
|
+
children: (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives6.Switch, {
|
|
2444
|
+
checked: props.checked,
|
|
2445
|
+
label: t("reduceLabel"),
|
|
2446
|
+
disabled: props.disabled,
|
|
2447
|
+
onChange: () => {
|
|
2448
|
+
if (typeof props.onToggle === "function") props.onToggle();
|
|
2449
|
+
}
|
|
2450
|
+
})
|
|
2451
|
+
})
|
|
2452
|
+
]
|
|
2453
|
+
}),
|
|
2454
|
+
(0, import_jsx_runtime14.jsx)("div", { className: ChromeMcpCard_default.fieldDesc, children: t("reduceHint") })
|
|
2455
|
+
]
|
|
2456
|
+
})
|
|
2457
|
+
]
|
|
2458
|
+
});
|
|
2459
|
+
}
|
|
551
2460
|
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
2461
|
+
// src/client/card/view.ts
|
|
2462
|
+
function labelOf(entries, id) {
|
|
2463
|
+
const row = entries.find((entry) => entry.id === id);
|
|
2464
|
+
return row === void 0 ? id : entryLabel(row);
|
|
2465
|
+
}
|
|
2466
|
+
function describeCard(state) {
|
|
2467
|
+
const error = state.lastError || state.actionError || "";
|
|
2468
|
+
const servedMode = typeof state.stderrMode === "string" ? state.stderrMode : "";
|
|
2469
|
+
const stderrEffective = servedMode !== "" ? servedMode : state.rowStderr === "console" ? "console" : "log";
|
|
2470
|
+
const executableEntries = normalizeEntries(state.executables);
|
|
2471
|
+
const statusList = Array.isArray(state.executableStatus) ? state.executableStatus : [];
|
|
2472
|
+
const optionIds = executableEntries.map((entry) => entry.id);
|
|
2473
|
+
const effectivePath = typeof state.effectiveChromePath === "string" ? state.effectiveChromePath : "";
|
|
2474
|
+
if (effectivePath !== "" && optionIds.indexOf(effectivePath) === -1) optionIds.push(effectivePath);
|
|
2475
|
+
const executableOptions = optionIds.map((id) => ({ id, label: labelOf(executableEntries, id) }));
|
|
2476
|
+
const brokenIds = statusList.filter((status) => status.version === "" && status.error !== "").map((status) => status.path);
|
|
2477
|
+
return {
|
|
2478
|
+
error,
|
|
2479
|
+
reduceChecked: stderrEffective === "log",
|
|
2480
|
+
executableEntries,
|
|
2481
|
+
executableOptions,
|
|
2482
|
+
brokenIds,
|
|
2483
|
+
effectivePath,
|
|
2484
|
+
version: typeof state.chromeVersion === "string" ? state.chromeVersion : "",
|
|
2485
|
+
missing: state.chromeMissing === true && error === "",
|
|
2486
|
+
dotIsError: error !== "",
|
|
2487
|
+
wslWindowsExecutable: state.wslWindowsExecutable === true,
|
|
2488
|
+
windowsChrome: readWindowsChrome(state.windowsChromeStatus),
|
|
2489
|
+
// Connect mode reads two ways. The mirror's answer is what the Host says
|
|
2490
|
+
// the bridge launches with — authoritative when it has been answered. And
|
|
2491
|
+
// the same question answered off the **saved flags**, which is what the
|
|
2492
|
+
// bridge launches with by the same precedence the flags rows edit: a flag
|
|
2493
|
+
// entry is a real config field a write-back never clears, so it keeps the
|
|
2494
|
+
// answer standing through the reset window every write pass leaves behind
|
|
2495
|
+
// (the same rule the pill's saved-path fallback follows). Either half
|
|
2496
|
+
// answering is enough; neither can contradict what the other states,
|
|
2497
|
+
// because both are asked of the same launch.
|
|
2498
|
+
connectMode: state.carriesConnectionMode === true || flagsCarryConnectionMode(state.extraFlags)
|
|
2499
|
+
};
|
|
2500
|
+
}
|
|
2501
|
+
var CONNECT_FLAG_PATTERN = /^--(?:browserUrl|wsEndpoint)(?:=|(?=\s)|$)/iu;
|
|
2502
|
+
function flagsCarryConnectionMode(flags) {
|
|
2503
|
+
return Array.isArray(flags) && flags.some((flag) => typeof flag === "string" && CONNECT_FLAG_PATTERN.test(flag));
|
|
2504
|
+
}
|
|
2505
|
+
function executableLabel(view, id) {
|
|
2506
|
+
return labelOf(view.executableEntries, id);
|
|
2507
|
+
}
|
|
2508
|
+
function readWindowsChrome(value) {
|
|
2509
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return { state: "off", port: 0, error: "" };
|
|
2510
|
+
const record = value;
|
|
2511
|
+
const known = ["off", "launching", "connected", "unreachable", "not-found", "launch-failed", "not-applicable"];
|
|
2512
|
+
const state = typeof record.state === "string" && known.indexOf(record.state) !== -1 ? record.state : "off";
|
|
2513
|
+
const port = typeof record.port === "number" && Number.isFinite(record.port) ? Math.trunc(record.port) : 0;
|
|
2514
|
+
const error = typeof record.error === "string" ? record.error : "";
|
|
2515
|
+
return { state, port, error };
|
|
2516
|
+
}
|
|
2517
|
+
function windowsChromeButton(view) {
|
|
2518
|
+
const status = view.windowsChrome;
|
|
2519
|
+
if (status.state === "launching") return { labelKey: "openWindowsChromeBusy", titleKey: "openWindowsChromeTitle", disabled: true, busy: true };
|
|
2520
|
+
if (status.state === "not-applicable") return { labelKey: "openWindowsChrome", titleKey: "windowsChromeNotWsl", disabled: true, busy: false };
|
|
2521
|
+
if (status.state === "not-found") return { labelKey: "openWindowsChrome", titleKey: "windowsChromeNotFound", disabled: false, busy: false };
|
|
2522
|
+
if (status.state === "unreachable") return { labelKey: "openWindowsChrome", titleKey: "windowsChromeUnreachable", disabled: false, busy: false };
|
|
2523
|
+
return { labelKey: "openWindowsChrome", titleKey: "openWindowsChromeTitle", disabled: false, busy: false };
|
|
2524
|
+
}
|
|
2525
|
+
function isBroken(view, id) {
|
|
2526
|
+
return view.brokenIds.indexOf(id) !== -1;
|
|
2527
|
+
}
|
|
2528
|
+
function probeAge(since, now, t) {
|
|
2529
|
+
const seconds = Math.max(0, Math.floor((now - since) / 1e3));
|
|
2530
|
+
if (seconds < 10) return t("probeJustNow");
|
|
2531
|
+
if (seconds < 60) return String(seconds) + " " + t("probeSecondsAgo");
|
|
2532
|
+
const minutes = Math.floor(seconds / 60);
|
|
2533
|
+
if (minutes < 60) return String(minutes) + " " + t("probeMinutesAgo");
|
|
2534
|
+
return String(Math.floor(minutes / 60)) + " " + t("probeHoursAgo");
|
|
2535
|
+
}
|
|
580
2536
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
2537
|
+
// src/client/card/index.ts
|
|
2538
|
+
function optionLabel(view, id, t) {
|
|
2539
|
+
const label = executableLabel(view, id);
|
|
2540
|
+
return isBroken(view, id) ? label + " (" + t("unavailableSuffix") + ")" : label;
|
|
2541
|
+
}
|
|
2542
|
+
function ChromeMcpCard(props) {
|
|
2543
|
+
const t = props.t;
|
|
2544
|
+
const state = props.useChromeMcpCard((snapshot) => snapshot);
|
|
2545
|
+
const menuState = react8.useState(false);
|
|
2546
|
+
const menuOpen = menuState[0];
|
|
2547
|
+
const setMenuOpen = menuState[1];
|
|
2548
|
+
const runs = useRunActions({
|
|
2549
|
+
refreshExecutables: props.refreshExecutables,
|
|
2550
|
+
openWindowsChrome: props.openWindowsChrome,
|
|
2551
|
+
addExecutables: props.addExecutables
|
|
2552
|
+
});
|
|
2553
|
+
if (props.view !== "page") return null;
|
|
2554
|
+
if (!state.available) return null;
|
|
2555
|
+
const view = describeCard(state);
|
|
2556
|
+
const rows = view.executableEntries;
|
|
2557
|
+
const savedIds = rows.map((entry) => entry.id);
|
|
2558
|
+
const options = view.executableOptions.map((option) => ({ id: option.id, label: optionLabel(view, option.id, t) }));
|
|
2559
|
+
const dotLabel = view.error !== "" ? view.error : t("chromeMissing");
|
|
2560
|
+
const dotAria = view.dotIsError || view.missing ? t("statusError") : t("statusOk");
|
|
2561
|
+
const statusDot = (0, import_jsx_runtime15.jsx)("span", {
|
|
2562
|
+
className: ChromeMcpCard_default.dot + " " + ChromeMcpCard_default.dotError,
|
|
2563
|
+
role: "img",
|
|
2564
|
+
"aria-label": dotAria,
|
|
2565
|
+
title: dotLabel
|
|
2566
|
+
});
|
|
2567
|
+
const windowsButton = windowsChromeButton(view);
|
|
2568
|
+
const windowsDisabled = windowsButton.disabled || runs.windowsRunning || !state.writable;
|
|
2569
|
+
const windowsBusy = windowsButton.busy || runs.windowsRunning;
|
|
2570
|
+
const connectLabel = view.windowsChrome.port > 0 ? t("connectModeLabel") + " (http://127.0.0.1:" + String(view.windowsChrome.port) + ")" : t("connectModeLabel");
|
|
2571
|
+
const selectedLabel = view.connectMode ? connectLabel : view.effectivePath === "" ? t("executableNone") : executableLabel(view, view.effectivePath);
|
|
2572
|
+
const statusLine = runs.running ? (0, import_jsx_runtime15.jsx)("p", { className: ChromeMcpCard_default.result, role: "status", children: t("probing") }) : view.version === "" ? null : (0, import_jsx_runtime15.jsxs)("p", {
|
|
2573
|
+
className: ChromeMcpCard_default.result,
|
|
2574
|
+
role: "status",
|
|
2575
|
+
children: [
|
|
2576
|
+
t("versionLabel"),
|
|
2577
|
+
(0, import_jsx_runtime15.jsx)("span", { className: ChromeMcpCard_default.resultValue, children: view.version }),
|
|
2578
|
+
runs.lastProbedAt === 0 ? null : (0, import_jsx_runtime15.jsx)("span", { className: ChromeMcpCard_default.resultAge, children: probeAge(runs.lastProbedAt, runs.clock, t) })
|
|
2579
|
+
]
|
|
2580
|
+
});
|
|
2581
|
+
const errorLine = view.error !== "" ? (0, import_jsx_runtime15.jsxs)("p", { className: ChromeMcpCard_default.error, role: "status", children: [statusDot, view.error] }) : view.missing ? (0, import_jsx_runtime15.jsxs)("p", { className: ChromeMcpCard_default.error, role: "status", children: [statusDot, t("chromeMissing")] }) : null;
|
|
2582
|
+
return (0, import_jsx_runtime15.jsxs)("div", {
|
|
2583
|
+
className: ChromeMcpCard_default.body,
|
|
2584
|
+
children: [
|
|
2585
|
+
// Nothing the page can write from here is writable: the row's
|
|
2586
|
+
// configuration is owned elsewhere (a home patch or the page's own
|
|
2587
|
+
// read-only state).
|
|
2588
|
+
!state.writable ? (0, import_jsx_runtime15.jsx)("p", { className: ChromeMcpCard_default.readOnly, role: "status", children: t("readOnly") }) : null,
|
|
2589
|
+
(0, import_jsx_runtime15.jsx)(CatalogPicker, {
|
|
2590
|
+
t,
|
|
2591
|
+
entries: rows,
|
|
2592
|
+
options,
|
|
2593
|
+
idPlaceholder: t("executableIdPlaceholder"),
|
|
2594
|
+
namePlaceholder: t("namePlaceholder"),
|
|
2595
|
+
selectedId: view.effectivePath,
|
|
2596
|
+
selectedLabel,
|
|
2597
|
+
selectedTitle: view.connectMode ? connectLabel : view.effectivePath !== "" ? view.effectivePath : selectedLabel,
|
|
2598
|
+
writable: state.writable,
|
|
2599
|
+
busy: runs.running,
|
|
2600
|
+
menuOpen,
|
|
2601
|
+
setMenuOpen,
|
|
2602
|
+
connectMode: view.connectMode,
|
|
2603
|
+
selectorLabel: t("executableLabel"),
|
|
2604
|
+
hint: view.connectMode ? t("connectModeHint") : t("executableHint"),
|
|
2605
|
+
windowsLabel: windowsBusy ? t("openWindowsChromeBusy") : t(windowsButton.labelKey),
|
|
2606
|
+
windowsTitle: t(windowsButton.titleKey),
|
|
2607
|
+
windowsDisabled,
|
|
2608
|
+
windowsOnOpen: runs.runWindowsChrome,
|
|
2609
|
+
rowsLabel: t("executableRows"),
|
|
2610
|
+
emptyText: t("executableEmpty"),
|
|
2611
|
+
idLabel: t("executableIdLabel"),
|
|
2612
|
+
nameLabel: t("executableNameLabel"),
|
|
2613
|
+
removeLabel: t("removeExecutable"),
|
|
2614
|
+
addLabel: t("addExecutable"),
|
|
2615
|
+
refreshLabel: t("fetchExecutables"),
|
|
2616
|
+
busyLabel: t("fetching"),
|
|
2617
|
+
select: (id) => {
|
|
2618
|
+
if (typeof props.selectExecutable === "function") void props.selectExecutable(id);
|
|
2619
|
+
},
|
|
2620
|
+
saveEntries: (entries) => props.saveExecutables(entries),
|
|
2621
|
+
refresh: runs.runFetch,
|
|
2622
|
+
statusLine
|
|
2623
|
+
}),
|
|
2624
|
+
// The one state no control of this form can express: the host runs
|
|
2625
|
+
// under WSL and what is selected is a Windows executable — which the
|
|
2626
|
+
// bridge cannot launch, however healthy its `--version` answer looks.
|
|
2627
|
+
// Nothing has failed yet, so this is a notice (static copy, shown only
|
|
2628
|
+
// while the host reports the state), not a third error surface: the
|
|
2629
|
+
// required configuration differs.
|
|
2630
|
+
view.wslWindowsExecutable ? (0, import_jsx_runtime15.jsxs)("div", {
|
|
2631
|
+
className: ChromeMcpCard_default.notice,
|
|
2632
|
+
role: "note",
|
|
2633
|
+
children: [
|
|
2634
|
+
(0, import_jsx_runtime15.jsx)("div", { className: ChromeMcpCard_default.noticeTitle, children: t("wslWindowsTitle") }),
|
|
2635
|
+
(0, import_jsx_runtime15.jsx)("div", { className: ChromeMcpCard_default.noticeBody, children: t("wslWindowsNote") })
|
|
2636
|
+
]
|
|
2637
|
+
}) : null,
|
|
2638
|
+
(0, import_jsx_runtime15.jsx)(ExtraFlagsEditor, {
|
|
2639
|
+
t,
|
|
2640
|
+
flags: Array.isArray(state.extraFlags) ? state.extraFlags : [],
|
|
2641
|
+
defaultFlags: Array.isArray(state.defaultExtraFlags) ? state.defaultExtraFlags : [],
|
|
2642
|
+
wslFlags: Array.isArray(state.wslExtraFlags) ? state.wslExtraFlags : [],
|
|
2643
|
+
writable: state.writable,
|
|
2644
|
+
saveFlags: props.saveFlags
|
|
2645
|
+
}),
|
|
2646
|
+
(0, import_jsx_runtime15.jsx)(LogOutputToggle, {
|
|
2647
|
+
t,
|
|
2648
|
+
checked: view.reduceChecked,
|
|
2649
|
+
disabled: !state.writable,
|
|
2650
|
+
onToggle: props.toggleStderr
|
|
2651
|
+
}),
|
|
2652
|
+
errorLine,
|
|
2653
|
+
runs.dialog !== null ? (0, import_jsx_runtime15.jsx)(CandidateDialog, {
|
|
2654
|
+
t,
|
|
2655
|
+
candidates: runs.dialog.candidates,
|
|
2656
|
+
savedIds,
|
|
2657
|
+
title: t("dialogExecutablesTitle"),
|
|
2658
|
+
description: t("dialogExecutablesDescription"),
|
|
2659
|
+
searchPlaceholder: t("searchExecutables"),
|
|
2660
|
+
onAdd: runs.addFromDialog,
|
|
2661
|
+
onClose: runs.closeDialog
|
|
2662
|
+
}) : null,
|
|
2663
|
+
// The form writes nothing as it is edited: every staged edit is
|
|
2664
|
+
// persisted only when **Apply** lands them, and **Discard** drops the
|
|
2665
|
+
// whole draft — reverting every staged value to what the host already
|
|
2666
|
+
// serves.
|
|
2667
|
+
(0, import_jsx_runtime15.jsxs)("div", {
|
|
2668
|
+
className: ChromeMcpCard_default.footer,
|
|
2669
|
+
children: [
|
|
2670
|
+
// A staged edit announces itself on the save line, since the
|
|
2671
|
+
// identity line the page draws says nothing about it.
|
|
2672
|
+
state.dirty ? (0, import_jsx_runtime15.jsx)("span", { className: ChromeMcpCard_default.badge, children: t("unsaved") }) : null,
|
|
2673
|
+
state.failed ? (0, import_jsx_runtime15.jsx)("p", { className: ChromeMcpCard_default.footerError, role: "status", children: t("saveFailed") }) : null,
|
|
2674
|
+
(0, import_jsx_runtime15.jsx)("button", {
|
|
2675
|
+
type: "button",
|
|
2676
|
+
className: ChromeMcpCard_default.footerButton,
|
|
2677
|
+
onClick: () => {
|
|
2678
|
+
if (typeof props.discard === "function") props.discard();
|
|
2679
|
+
},
|
|
2680
|
+
children: t("discard")
|
|
2681
|
+
}),
|
|
2682
|
+
(0, import_jsx_runtime15.jsx)("button", {
|
|
2683
|
+
type: "button",
|
|
2684
|
+
className: ChromeMcpCard_default.footerButton + " " + ChromeMcpCard_default.footerButtonPrimary,
|
|
2685
|
+
disabled: !state.dirty || state.saving || !state.writable,
|
|
2686
|
+
onClick: () => {
|
|
2687
|
+
if (typeof props.apply === "function") void props.apply();
|
|
2688
|
+
},
|
|
2689
|
+
children: state.saving ? t("saving") : t("apply")
|
|
2690
|
+
})
|
|
2691
|
+
]
|
|
2692
|
+
})
|
|
2693
|
+
]
|
|
2694
|
+
});
|
|
2695
|
+
}
|
|
2696
|
+
|
|
2697
|
+
// src/client/read.ts
|
|
2698
|
+
function sameEntries(a, b) {
|
|
2699
|
+
if (a === b) return true;
|
|
2700
|
+
if (a.length !== b.length) return false;
|
|
2701
|
+
for (let i = 0; i < a.length; i++) if (a[i].id !== b[i].id || a[i].name !== b[i].name) return false;
|
|
2702
|
+
return true;
|
|
2703
|
+
}
|
|
2704
|
+
function readFlags(value) {
|
|
2705
|
+
if (!Array.isArray(value)) return [];
|
|
2706
|
+
return value.filter((flag) => typeof flag === "string" && flag !== "");
|
|
2707
|
+
}
|
|
2708
|
+
function readNumber(value, fallback) {
|
|
2709
|
+
return typeof value === "number" ? value : fallback;
|
|
2710
|
+
}
|
|
2711
|
+
function readString(value, fallback) {
|
|
2712
|
+
return typeof value === "string" ? value : fallback;
|
|
2713
|
+
}
|
|
2714
|
+
function readWindowsChromeStatus(value) {
|
|
2715
|
+
const fallback = { state: "off", port: 0, error: "" };
|
|
2716
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return fallback;
|
|
2717
|
+
const status = value.state;
|
|
2718
|
+
const states = ["off", "launching", "connected", "unreachable", "not-found", "launch-failed", "not-applicable"];
|
|
2719
|
+
const port = value.port;
|
|
2720
|
+
const error = value.error;
|
|
2721
|
+
return {
|
|
2722
|
+
state: typeof status === "string" && states.indexOf(status) !== -1 ? status : "off",
|
|
2723
|
+
port: typeof port === "number" && Number.isFinite(port) ? Math.trunc(port) : 0,
|
|
2724
|
+
error: typeof error === "string" ? error : ""
|
|
2725
|
+
};
|
|
2726
|
+
}
|
|
2727
|
+
function readStatus(value) {
|
|
2728
|
+
if (!Array.isArray(value)) return [];
|
|
2729
|
+
const statuses = [];
|
|
2730
|
+
for (const item of value) {
|
|
2731
|
+
if (item === null || typeof item !== "object" || Array.isArray(item)) continue;
|
|
2732
|
+
const path = readString(item.path, "");
|
|
2733
|
+
if (path === "") continue;
|
|
2734
|
+
statuses.push({
|
|
2735
|
+
path,
|
|
2736
|
+
version: readString(item.version, ""),
|
|
2737
|
+
error: readString(item.error, ""),
|
|
2738
|
+
note: readString(item.note, "")
|
|
2739
|
+
});
|
|
2740
|
+
}
|
|
2741
|
+
return statuses;
|
|
2742
|
+
}
|
|
2743
|
+
|
|
2744
|
+
// src/client/project.ts
|
|
2745
|
+
function nothingProjected() {
|
|
2746
|
+
return {
|
|
2747
|
+
available: false,
|
|
2748
|
+
writable: false,
|
|
2749
|
+
extraFlags: [],
|
|
2750
|
+
lastError: "",
|
|
2751
|
+
chromeMissing: false,
|
|
2752
|
+
executableDiscoveryRevision: 0,
|
|
2753
|
+
chromeVersion: "",
|
|
2754
|
+
executables: [],
|
|
2755
|
+
executableStatus: [],
|
|
2756
|
+
chromePath: "",
|
|
2757
|
+
effectiveChromePath: "",
|
|
2758
|
+
effectiveSource: "",
|
|
2759
|
+
stderrMode: "",
|
|
2760
|
+
rowStderr: "log",
|
|
2761
|
+
defaultExtraFlags: [],
|
|
2762
|
+
wslExtraFlags: [],
|
|
2763
|
+
wslWindowsExecutable: false,
|
|
2764
|
+
windowsChromeStatus: { state: "off", port: 0, error: "" },
|
|
2765
|
+
carriesConnectionMode: false,
|
|
2766
|
+
actionError: "",
|
|
2767
|
+
dirty: false,
|
|
2768
|
+
saving: false,
|
|
2769
|
+
failed: false
|
|
2770
|
+
};
|
|
2771
|
+
}
|
|
2772
|
+
function projectCard(snapshot, heldWslNotice2) {
|
|
2773
|
+
if (snapshot.available !== true) return nothingProjected();
|
|
2774
|
+
const value = snapshot.values ?? {};
|
|
2775
|
+
const chromePath = readString(value.chromePath, "");
|
|
2776
|
+
const answeredEffective = readString(value.effectiveChromePath, "");
|
|
2777
|
+
const wslNotice = value.wslWindowsExecutable === true ? true : answeredEffective === "" && chromePath !== "" ? heldWslNotice2 : false;
|
|
2778
|
+
const effectiveChromePath = answeredEffective !== "" ? answeredEffective : value.wslWindowsExecutable === true ? "" : chromePath;
|
|
2779
|
+
const effectiveSource = value.effectiveSource === "selected" || value.effectiveSource === "row-config" ? value.effectiveSource : "";
|
|
2780
|
+
const stderrMode = value.stderrMode === "log" || value.stderrMode === "console" ? value.stderrMode : "";
|
|
2781
|
+
return {
|
|
2782
|
+
available: true,
|
|
2783
|
+
writable: snapshot.writable === true,
|
|
2784
|
+
extraFlags: readFlags(value.extraFlags),
|
|
2785
|
+
lastError: readString(value.lastError, ""),
|
|
2786
|
+
chromeMissing: value.chromeMissing === true,
|
|
2787
|
+
executableDiscoveryRevision: readNumber(value.executableDiscoveryRevision, 0),
|
|
2788
|
+
chromeVersion: readString(value.chromeVersion, ""),
|
|
2789
|
+
executables: normalizeEntries(value.executables),
|
|
2790
|
+
executableStatus: readStatus(value.executableStatus),
|
|
2791
|
+
chromePath,
|
|
2792
|
+
effectiveChromePath,
|
|
2793
|
+
effectiveSource,
|
|
2794
|
+
stderrMode,
|
|
2795
|
+
// The mode the bridge actually routes console output through, as the
|
|
2796
|
+
// Host resolves it — what the field states wins, the live answer fills
|
|
2797
|
+
// the gap.
|
|
2798
|
+
rowStderr: value.stderrEffective === "console" ? "console" : "log",
|
|
2799
|
+
defaultExtraFlags: readFlags(value.defaultExtraFlags),
|
|
2800
|
+
wslExtraFlags: readFlags(value.wslExtraFlags),
|
|
2801
|
+
wslWindowsExecutable: wslNotice,
|
|
2802
|
+
windowsChromeStatus: readWindowsChromeStatus(value.windowsChromeStatus),
|
|
2803
|
+
carriesConnectionMode: value.carriesConnectionMode === true,
|
|
2804
|
+
actionError: snapshot.actionError ?? "",
|
|
2805
|
+
dirty: snapshot.dirty === true,
|
|
2806
|
+
saving: snapshot.saving === true,
|
|
2807
|
+
failed: snapshot.failed === true
|
|
2808
|
+
};
|
|
2809
|
+
}
|
|
2810
|
+
|
|
2811
|
+
// src/client/block.ts
|
|
2812
|
+
var RUN_COUNTER = "executableDiscoveryRevision";
|
|
2813
|
+
var heldWslNotice = /* @__PURE__ */ new WeakMap();
|
|
2814
|
+
function runCounter(snapshot) {
|
|
2815
|
+
const value = snapshot.values?.[RUN_COUNTER];
|
|
2816
|
+
return typeof value === "number" ? value : 0;
|
|
2817
|
+
}
|
|
2818
|
+
function cardState(controller) {
|
|
2819
|
+
const state = projectCard(controller.getSnapshot(), heldWslNotice.get(controller) === true);
|
|
2820
|
+
heldWslNotice.set(controller, state.wslWindowsExecutable);
|
|
2821
|
+
return state;
|
|
2822
|
+
}
|
|
2823
|
+
function cardActions(controller) {
|
|
2824
|
+
const current = () => cardState(controller);
|
|
2825
|
+
const saveExecutables = (entries) => {
|
|
2826
|
+
const next = normalizeEntries(entries);
|
|
2827
|
+
if (sameEntries(next, current().executables)) return Promise.resolve();
|
|
2828
|
+
const baseline = runCounter(controller.getSnapshot());
|
|
2829
|
+
return controller.settleAndWrite((snapshot) => runCounter(snapshot) > baseline, "executables", next);
|
|
2830
|
+
};
|
|
2831
|
+
return {
|
|
2832
|
+
/** Stage the extra-flags list; a list equal to what is served is not
|
|
2833
|
+
* dirty (the controller drops that draft). */
|
|
2834
|
+
saveFlags: (flags) => {
|
|
2835
|
+
controller.stage("extraFlags", Array.isArray(flags) ? flags : []);
|
|
2836
|
+
return Promise.resolve();
|
|
2837
|
+
},
|
|
2838
|
+
/** Stage the flipped "Reduce log output" mode. A flip that lands back on
|
|
2839
|
+
* what is already effective drops the draft instead of staging a no-op:
|
|
2840
|
+
* it stages the served value itself, which the controller reads as clean. */
|
|
2841
|
+
toggleStderr: () => {
|
|
2842
|
+
const state = current();
|
|
2843
|
+
const held = state.stderrMode;
|
|
2844
|
+
const effective = held === "" ? state.rowStderr : held;
|
|
2845
|
+
const next = effective === "log" ? "console" : "log";
|
|
2846
|
+
const servedRaw = controller.servedValue("stderrMode");
|
|
2847
|
+
const served = servedRaw === "log" || servedRaw === "console" ? servedRaw : "";
|
|
2848
|
+
const servedEffective = served === "" ? state.rowStderr : served;
|
|
2849
|
+
controller.stage("stderrMode", next === servedEffective ? served : next);
|
|
2850
|
+
return Promise.resolve();
|
|
2851
|
+
},
|
|
2852
|
+
/** Select the executable the bridge launches with: written on the spot,
|
|
2853
|
+
* settled by the Host's own re-run. Picking what already runs writes
|
|
2854
|
+
* nothing. */
|
|
2855
|
+
selectExecutable: (id) => {
|
|
2856
|
+
const target = typeof id === "string" ? id.trim() : "";
|
|
2857
|
+
if (target === "" || target === current().effectiveChromePath) return Promise.resolve();
|
|
2858
|
+
const baseline = runCounter(controller.getSnapshot());
|
|
2859
|
+
return controller.settleAndWrite((snapshot) => runCounter(snapshot) > baseline, "chromePath", target);
|
|
2860
|
+
},
|
|
2861
|
+
saveExecutables,
|
|
2862
|
+
/** Merge the ids picked in the dialog into the saved rows. */
|
|
2863
|
+
addExecutables: (ids) => saveExecutables(current().executables.concat(
|
|
2864
|
+
(Array.isArray(ids) ? ids : []).filter((id) => typeof id === "string" && id.trim() !== "").map((id) => ({ id: id.trim(), name: "" }))
|
|
2865
|
+
)),
|
|
2866
|
+
/** Ask the Host to re-probe the saved rows; answers every path the run
|
|
2867
|
+
* answered for, read off the served mirror once it settles. */
|
|
2868
|
+
refreshExecutables: () => controller.settleTrigger("refreshExecutablesNonce", RUN_COUNTER).then(() => readStatus(controller.value("executableStatus"))),
|
|
2869
|
+
/** Ask the Host to drive a Windows-side Chrome in connect mode; what the
|
|
2870
|
+
* button reports is served through `windowsChromeStatus`. */
|
|
2871
|
+
openWindowsChrome: () => controller.settleTrigger("openWindowsChromeNonce", RUN_COUNTER),
|
|
2872
|
+
/** Persist every staged edit in one pass. */
|
|
2873
|
+
apply: async () => {
|
|
2874
|
+
await controller.applyStaged();
|
|
2875
|
+
},
|
|
2876
|
+
/** Drop every staged edit. */
|
|
2877
|
+
discard: () => controller.discard()
|
|
2878
|
+
};
|
|
2879
|
+
}
|
|
2880
|
+
function ChromeCardBlock(props) {
|
|
2881
|
+
const state = cardState(props.controller);
|
|
2882
|
+
return ChromeMcpCard({
|
|
2883
|
+
t: props.t,
|
|
2884
|
+
view: "page",
|
|
2885
|
+
useChromeMcpCard: (selector) => selector(state),
|
|
2886
|
+
...cardActions(props.controller)
|
|
2887
|
+
});
|
|
2888
|
+
}
|
|
2889
|
+
|
|
2890
|
+
// src/client/locales/en-US.ts
|
|
2891
|
+
var en = {
|
|
2892
|
+
executableLabel: "Chrome executable",
|
|
2893
|
+
executableHint: "The executable every connection launched from this row launches with, unless the connection picked its own. Changing it answers the live connections again.",
|
|
2894
|
+
executableNone: "No Chrome executable detected",
|
|
2895
|
+
executableRows: "Saved executables",
|
|
2896
|
+
executableIdLabel: "Executable path",
|
|
2897
|
+
executableIdPlaceholder: "Path to a Chrome executable",
|
|
2898
|
+
executableNameLabel: "Display name",
|
|
2899
|
+
namePlaceholder: "Display name",
|
|
2900
|
+
addExecutable: "Add executable",
|
|
2901
|
+
removeExecutable: "Delete executable",
|
|
2902
|
+
fetchExecutables: "Fetch executables",
|
|
2903
|
+
fetching: "Fetching\u2026",
|
|
2904
|
+
executableEmpty: "No executables saved. Use \u201CFetch executables\u201D, or add the Chrome path by hand.",
|
|
2905
|
+
dialogExecutablesTitle: "Choose executables to add",
|
|
2906
|
+
dialogExecutablesDescription: "These are the Chrome executables this host's last run answered for. Choose the ones to add.",
|
|
2907
|
+
dialogEmpty: "Nothing matches your search.",
|
|
2908
|
+
searchExecutables: "Search executables",
|
|
2909
|
+
selectAll: "Select all",
|
|
2910
|
+
addSelected: "Add selected",
|
|
2911
|
+
candidateSaved: "Saved",
|
|
2912
|
+
close: "Close",
|
|
2913
|
+
cancel: "Cancel",
|
|
2914
|
+
unavailableSuffix: "not runnable",
|
|
2915
|
+
wslWindowsTitle: "Windows executable under WSL",
|
|
2916
|
+
wslWindowsNote: "This host runs inside Windows Subsystem for Linux and the selected executable is the Windows Chrome, which no connection here can launch: the debug pipes it opens do not survive the WSL interop boundary, and its debugging port stays bound to the Windows loopback. It answers --version correctly, so the pill looks healthy until the first tool call fails. Drive it instead with the \u201CWindows Chrome (WSL debug port)\u201D connection, or with its run \u2014 Prelaunch Windows Chrome, the action the executable block carries next to Fetch executables, or the prelaunch_windows_chrome tool \u2014 which starts the Windows browser on a free debugging port. The run only reads whether Windows loopback reaches this WSL host (networkingMode=mirrored in %USERPROFILE%\\.wslconfig, then wsl --shutdown \u2014 a manual Windows-side setting it never edits). Chrome installed inside the Linux distro needs none of this.",
|
|
2917
|
+
probing: "Checking the executables\u2026",
|
|
2918
|
+
versionLabel: "Probed version:",
|
|
2919
|
+
probeJustNow: "just now",
|
|
2920
|
+
probeSecondsAgo: "seconds ago",
|
|
2921
|
+
probeMinutesAgo: "minutes ago",
|
|
2922
|
+
probeHoursAgo: "hours ago",
|
|
2923
|
+
flagsTitle: "Extra flags",
|
|
2924
|
+
flagsHint: "The extra flags every connection launched from this row launches with, unless the connection carries its own. One flag per row \u2014 applying them answers the live connections again.",
|
|
2925
|
+
flagsEmpty: "No extra flags saved. Add one by hand, or use \u201CRestore defaults\u201D.",
|
|
2926
|
+
flagsRows: "Saved flags",
|
|
2927
|
+
flagsValueLabel: "Extra flag",
|
|
2928
|
+
flagsValuePlaceholder: "e.g. --headless",
|
|
2929
|
+
addFlag: "Add flag",
|
|
2930
|
+
removeFlag: "Delete flag",
|
|
2931
|
+
flagsRestore: "Restore defaults",
|
|
2932
|
+
flagsRestoreTitle: "Keep every flag the rows carry and append the defaults that are still missing",
|
|
2933
|
+
flagsWsl: "Flags WSL",
|
|
2934
|
+
flagsWslTitle: "Append the recommended WSL<->Windows flags",
|
|
2935
|
+
openWindowsChrome: "Prelaunch Windows Chrome",
|
|
2936
|
+
openWindowsChromeTitle: "Start the Windows-side Chrome with --remote-debugging-port and refresh whatever Windows Chrome connections stand live",
|
|
2937
|
+
openWindowsChromeBusy: "Starting Windows Chrome\u2026",
|
|
2938
|
+
windowsChromeNotWsl: "Windows Chrome does not apply outside WSL.",
|
|
2939
|
+
windowsChromeNotFound: "No Windows Chrome was found (Program Files / Program Files (x86)) \u2014 run it again once one is installed.",
|
|
2940
|
+
windowsChromeUnreachable: "Needs networkingMode=mirrored in %USERPROFILE%\\.wslconfig, with wsl --shutdown: right now this WSL host cannot reach the Windows loopback.",
|
|
2941
|
+
connectModeLabel: "Connect mode",
|
|
2942
|
+
connectModeHint: "Connect mode: the connection launches no local Chrome (it connects with --browserUrl / --wsEndpoint); the local selection stays put.",
|
|
2943
|
+
reduceLabel: "Reduce log output",
|
|
2944
|
+
reduceTitle: "Capture the connection's stderr into the plugin's log file",
|
|
2945
|
+
reduceHint: "Captures stderr into the plugin's log file. Turn it off to debug the raw output; switching answers the live connections again.",
|
|
2946
|
+
// The staged form's own copy: nothing is written until **Apply** lands every
|
|
2947
|
+
// staged edit, so the card announces what a save would store and what it
|
|
2948
|
+
// could not land.
|
|
2949
|
+
apply: "Apply",
|
|
2950
|
+
discard: "Discard",
|
|
2951
|
+
saving: "Applying\u2026",
|
|
2952
|
+
unsaved: "Unsaved",
|
|
2953
|
+
saveFailed: "The last save was not accepted.",
|
|
2954
|
+
docsMessage: "Find the complete list of server parameters (e.g., --headless, --isolated, --slim) and how to configure WebSocket connections in the Configuration Guide.",
|
|
2955
|
+
docsLinkLabel: "Configuration Guide",
|
|
2956
|
+
statusError: "Error",
|
|
2957
|
+
statusOk: "OK",
|
|
2958
|
+
chromeMissing: "Chrome executable not found",
|
|
2959
|
+
// The body-mounted toast host's copy: it announces what the card's own error
|
|
2960
|
+
// line can only show while the row page is open. An error notice carries the
|
|
2961
|
+
// Host's captured line, so `toastError` only stands behind an empty one.
|
|
2962
|
+
toastStall: "The Chrome host did not answer the action \u2014 try it again.",
|
|
2963
|
+
toastError: "The Chrome host reported a failure.",
|
|
2964
|
+
readOnly: "Settings are read-only in this deployment."
|
|
2965
|
+
};
|
|
2966
|
+
|
|
2967
|
+
// src/client/locales/index.ts
|
|
2968
|
+
var DICTIONARIES2 = { en };
|
|
2969
|
+
|
|
2970
|
+
// src/client/styles/index.ts
|
|
2971
|
+
var CARD_CSS_ID = PLUGIN_ID + "/ChromeMcpCard.module.css";
|
|
2972
|
+
function injectCardStyles2() {
|
|
2973
|
+
if (typeof document === "undefined") return;
|
|
2974
|
+
if (document.querySelector('style[data-plugin-css="' + CARD_CSS_ID + '"]') !== null) return;
|
|
2975
|
+
const styleTag = document.createElement("style");
|
|
2976
|
+
styleTag.dataset.plugin = PLUGIN_ID;
|
|
2977
|
+
styleTag.dataset.pluginCss = CARD_CSS_ID;
|
|
2978
|
+
styleTag.textContent = cssText2;
|
|
2979
|
+
document.head.appendChild(styleTag);
|
|
2980
|
+
}
|
|
2981
|
+
|
|
2982
|
+
// src/client/index.ts
|
|
2983
|
+
var card = mountSettingsCard2({
|
|
2984
|
+
entryId: ENTRY_ID,
|
|
2985
|
+
pluginId: PLUGIN_ID,
|
|
2986
|
+
bundleId: BUNDLE_ID,
|
|
2987
|
+
localeNamespace: LOCALE_NAMESPACE2,
|
|
2988
|
+
locale: DICTIONARIES2,
|
|
2989
|
+
fields: {
|
|
2990
|
+
// The flags and the "Reduce log output" mode are edited as a draft:
|
|
2991
|
+
// nothing reaches the Host until Apply.
|
|
2992
|
+
staged: ["extraFlags", "stderrMode"],
|
|
2993
|
+
// The saved rows and the selection drive a Host run, so they land on
|
|
2994
|
+
// the click that asked for them.
|
|
2995
|
+
immediate: ["executables", "chromePath"],
|
|
2996
|
+
triggers: ["refreshExecutablesNonce", "openWindowsChromeNonce"],
|
|
2997
|
+
liveKeys: [...LIVE_KEYS]
|
|
2998
|
+
},
|
|
2999
|
+
blocks: [{ block: ChromeCardBlock, bind: (_snapshot, controller) => ({ controller }) }],
|
|
3000
|
+
// The body states the error itself (the dot and the line under the
|
|
3001
|
+
// toggle), so the shared second line stays off.
|
|
3002
|
+
errorLine: false,
|
|
3003
|
+
// A failure that lands while the person is elsewhere in the app is still
|
|
3004
|
+
// announced: the row page is closed most of the time a run is happening.
|
|
3005
|
+
// An error carries the Host's own line; a stall has no text of its own and
|
|
3006
|
+
// reads from the mirror — the known missing-executable answer when it
|
|
3007
|
+
// stands, the "the host did not answer" line otherwise.
|
|
3008
|
+
toasts: {
|
|
3009
|
+
text: (notice, snapshot, t) => notice.kind === "error" ? notice.text !== "" ? notice.text : t("toastError") : snapshot.values?.chromeMissing === true ? t("chromeMissing") : t("toastStall")
|
|
3010
|
+
},
|
|
3011
|
+
settleField: "executableDiscoveryRevision",
|
|
3012
|
+
settleDeadlineMs: RUN_SETTLE_TIMEOUT_MS2
|
|
3013
|
+
});
|
|
3014
|
+
var inject = card.inject;
|
|
3015
|
+
function apply(ctx) {
|
|
3016
|
+
injectCardStyles2();
|
|
3017
|
+
card.apply(ctx);
|
|
3018
|
+
}
|
|
3019
|
+
return module.exports;
|
|
584
3020
|
}
|
|
585
3021
|
});
|
|
3022
|
+
//# sourceMappingURL=client.js.map
|