@comecaramelos/dsh-chrome-mcp 1.0.0 → 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 -39
- package/lib/client.js +2186 -614
- package/lib/client.js.map +4 -4
- package/lib/host/apply.d.ts +38 -1
- package/lib/host/apply.d.ts.map +1 -1
- package/lib/host/apply.js +43 -17
- package/lib/host/apply.js.map +1 -1
- package/lib/host/bridge.d.ts +28 -19
- package/lib/host/bridge.d.ts.map +1 -1
- package/lib/host/bridge.js +71 -79
- package/lib/host/bridge.js.map +1 -1
- package/lib/host/catalog.d.ts +2 -2
- package/lib/host/catalog.js +2 -2
- 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 +107 -30
- package/lib/host/constants.d.ts.map +1 -1
- package/lib/host/constants.js +107 -30
- package/lib/host/constants.js.map +1 -1
- 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 +4 -2
- package/lib/host/controller/bridge-run.d.ts.map +1 -1
- package/lib/host/controller/bridge-run.js +24 -8
- package/lib/host/controller/bridge-run.js.map +1 -1
- package/lib/host/controller/captures.d.ts +9 -16
- package/lib/host/controller/captures.d.ts.map +1 -1
- package/lib/host/controller/captures.js +73 -48
- package/lib/host/controller/captures.js.map +1 -1
- package/lib/host/controller/commits.d.ts +2 -2
- package/lib/host/controller/commits.d.ts.map +1 -1
- package/lib/host/controller/commits.js +97 -41
- package/lib/host/controller/commits.js.map +1 -1
- 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 +19 -24
- package/lib/host/controller/controller.d.ts.map +1 -1
- package/lib/host/controller/controller.js +181 -114
- package/lib/host/controller/controller.js.map +1 -1
- package/lib/host/controller/index.d.ts +18 -14
- package/lib/host/controller/index.d.ts.map +1 -1
- package/lib/host/controller/index.js +16 -14
- package/lib/host/controller/index.js.map +1 -1
- package/lib/host/controller/notes.d.ts +9 -9
- package/lib/host/controller/notes.d.ts.map +1 -1
- package/lib/host/controller/notes.js +16 -21
- package/lib/host/controller/notes.js.map +1 -1
- package/lib/host/controller/persist.d.ts +10 -3
- package/lib/host/controller/persist.d.ts.map +1 -1
- package/lib/host/controller/persist.js +89 -42
- package/lib/host/controller/persist.js.map +1 -1
- 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 +34 -10
- package/lib/host/controller/runs.d.ts.map +1 -1
- package/lib/host/controller/runs.js +241 -58
- package/lib/host/controller/runs.js.map +1 -1
- package/lib/host/controller/state.d.ts +122 -20
- package/lib/host/controller/state.d.ts.map +1 -1
- package/lib/host/controller/windows-run.d.ts +10 -2
- package/lib/host/controller/windows-run.d.ts.map +1 -1
- package/lib/host/controller/windows-run.js +66 -35
- package/lib/host/controller/windows-run.js.map +1 -1
- package/lib/host/discovery/candidates.d.ts +23 -13
- package/lib/host/discovery/candidates.d.ts.map +1 -1
- package/lib/host/discovery/candidates.js +20 -8
- package/lib/host/discovery/candidates.js.map +1 -1
- package/lib/host/discovery/index.d.ts +1 -0
- package/lib/host/discovery/index.d.ts.map +1 -1
- package/lib/host/discovery/index.js +1 -0
- package/lib/host/discovery/index.js.map +1 -1
- package/lib/host/discovery/probe.d.ts +16 -5
- package/lib/host/discovery/probe.d.ts.map +1 -1
- package/lib/host/discovery/probe.js +68 -10
- package/lib/host/discovery/probe.js.map +1 -1
- package/lib/host/discovery/scan.d.ts +14 -9
- package/lib/host/discovery/scan.d.ts.map +1 -1
- package/lib/host/discovery/scan.js +56 -30
- package/lib/host/discovery/scan.js.map +1 -1
- package/lib/host/flags.d.ts +28 -5
- package/lib/host/flags.d.ts.map +1 -1
- package/lib/host/flags.js +75 -7
- package/lib/host/flags.js.map +1 -1
- 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/plugin-meta.d.ts +12 -3
- package/lib/host/plugin-meta.d.ts.map +1 -1
- package/lib/host/plugin-meta.js +13 -4
- package/lib/host/plugin-meta.js.map +1 -1
- package/lib/host/schema.d.ts +301 -247
- package/lib/host/schema.d.ts.map +1 -1
- package/lib/host/schema.js +145 -120
- package/lib/host/schema.js.map +1 -1
- package/lib/host/settings.d.ts +22 -3
- package/lib/host/settings.d.ts.map +1 -1
- package/lib/host/settings.js +81 -60
- package/lib/host/settings.js.map +1 -1
- package/lib/host/status.d.ts +7 -10
- package/lib/host/status.d.ts.map +1 -1
- package/lib/host/status.js +8 -23
- package/lib/host/status.js.map +1 -1
- package/lib/host/tool.d.ts +13 -7
- package/lib/host/tool.d.ts.map +1 -1
- package/lib/host/tool.js +4 -3
- package/lib/host/tool.js.map +1 -1
- package/lib/host/types/config.d.ts +66 -12
- package/lib/host/types/config.d.ts.map +1 -1
- package/lib/host/types/executable.d.ts +8 -3
- package/lib/host/types/executable.d.ts.map +1 -1
- package/lib/host/types/index.d.ts +5 -4
- package/lib/host/types/index.d.ts.map +1 -1
- 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 +118 -65
- package/lib/host/types/settings.d.ts.map +1 -1
- package/lib/host/types/stderr.d.ts +3 -5
- package/lib/host/types/stderr.d.ts.map +1 -1
- package/lib/host/values.d.ts +152 -37
- package/lib/host/values.d.ts.map +1 -1
- package/lib/host/values.js +304 -112
- package/lib/host/values.js.map +1 -1
- package/lib/host/windows/connect-flags.d.ts +19 -8
- package/lib/host/windows/connect-flags.d.ts.map +1 -1
- package/lib/host/windows/connect-flags.js +50 -20
- package/lib/host/windows/connect-flags.js.map +1 -1
- package/lib/host/windows/index.d.ts +1 -1
- package/lib/host/windows/index.d.ts.map +1 -1
- package/lib/host/windows/index.js +1 -1
- package/lib/host/windows/index.js.map +1 -1
- package/lib/host/windows/paths.d.ts +27 -6
- package/lib/host/windows/paths.d.ts.map +1 -1
- package/lib/host/windows/paths.js +40 -13
- package/lib/host/windows/paths.js.map +1 -1
- package/lib/host/windows/run.d.ts.map +1 -1
- package/lib/host/windows/run.js +3 -2
- package/lib/host/windows/run.js.map +1 -1
- package/lib/index.d.ts +72 -56
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +74 -55
- package/lib/index.js.map +1 -1
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +35 -14
- package/cordis.patch.yml +0 -5
package/lib/client.js
CHANGED
|
@@ -36,47 +36,1777 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
36
36
|
// src/client/index.ts
|
|
37
37
|
var index_exports = {};
|
|
38
38
|
__export(index_exports, {
|
|
39
|
-
|
|
40
|
-
|
|
39
|
+
LIVE_KEYS: () => LIVE_KEYS,
|
|
40
|
+
RUN_SETTLE_TIMEOUT_MS: () => RUN_SETTLE_TIMEOUT_MS2,
|
|
41
41
|
apply: () => apply,
|
|
42
|
+
card: () => card,
|
|
43
|
+
cardActions: () => cardActions,
|
|
44
|
+
cardState: () => cardState,
|
|
42
45
|
inject: () => inject
|
|
43
46
|
});
|
|
44
47
|
module.exports = __toCommonJS(index_exports);
|
|
45
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
|
+
|
|
46
1757
|
// src/client/card/index.ts
|
|
47
|
-
var
|
|
48
|
-
var
|
|
1758
|
+
var react8 = __toESM(require("react"), 1);
|
|
1759
|
+
var import_jsx_runtime15 = require("react/jsx-runtime");
|
|
49
1760
|
|
|
50
1761
|
// dsh-css:/home/roberto/dev/dsh/dsh-chrome-mcp/src/client/styles/ChromeMcpCard.module.css
|
|
51
|
-
var cssText = '.e5pfpa_card{border:.5px solid var(--dsw-alias-border-l4);background:var(--dsw-alias-bg-layer-3);border-radius:16px;list-style:none;transition:border-color .16s,background .16s}.e5pfpa_card:hover{border-color:var(--dsw-alias-label-dimmed)}.e5pfpa_cardOpen{background:var(--dsw-alias-bg-layer-2);border-color:var(--dsw-alias-label-dimmed)}.e5pfpa_header{appearance:none;width:100%;font:inherit;color:inherit;text-align:left;cursor:pointer;background:0 0;border:0;border-radius:12px;align-items:center;gap:12px;padding:14px 16px;display:flex}.e5pfpa_header:focus-visible{outline:2px solid var(--dsw-alias-brand-primary);outline-offset:-2px}.e5pfpa_headText{flex-direction:column;flex:1;gap:4px;min-width:0;display:flex}.e5pfpa_nameRow{align-items:center;gap:8px;min-width:0;display:flex}.e5pfpa_name{color:var(--dsw-alias-label-primary);font-size:15px;font-weight:600;line-height:1.4}.e5pfpa_desc{color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}.e5pfpa_chevron{color:var(--dsw-alias-label-tertiary);flex:none;transition:transform .16s}.e5pfpa_chevronOpen{transform:rotate(180deg)}.e5pfpa_body{border-top:.5px solid var(--dsw-alias-border-l2);display:flex;flex-direction:column;gap:10px;margin:0 16px;padding:12px 0}.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_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:none;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}\n';
|
|
52
|
-
var ChromeMcpCard_default = { "
|
|
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" };
|
|
53
1764
|
|
|
54
1765
|
// src/client/card/flags.ts
|
|
55
|
-
var
|
|
1766
|
+
var import_jsx_runtime11 = require("react/jsx-runtime");
|
|
56
1767
|
|
|
57
1768
|
// src/client/plugin-meta.ts
|
|
58
|
-
var
|
|
59
|
-
var LOCALE_NAMESPACE = "chromeMcp";
|
|
1769
|
+
var ENTRY_ID = "mcp-chrome";
|
|
60
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";
|
|
61
1774
|
var CONFIGURATION_URL = "https://github.com/ChromeDevTools/chrome-devtools-mcp/blob/main/docs/configuration.md";
|
|
62
|
-
var
|
|
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
|
+
];
|
|
63
1793
|
|
|
64
1794
|
// src/client/card/icons.ts
|
|
65
|
-
var
|
|
66
|
-
var
|
|
67
|
-
var
|
|
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 = [
|
|
68
1798
|
"M14.1168 13.197L13.197 14.1167L1.8833 2.80303L2.80309 1.88324L14.1168 13.197Z",
|
|
69
1799
|
"M13.197 1.88326L14.1168 2.80305L2.80309 14.1168L1.8833 13.197L13.197 1.88326Z"
|
|
70
1800
|
];
|
|
71
|
-
var
|
|
1801
|
+
var DOCS_PATHS2 = [
|
|
72
1802
|
"M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6",
|
|
73
1803
|
"M15 3h6v6",
|
|
74
1804
|
"M10 14 21 3"
|
|
75
1805
|
];
|
|
76
1806
|
|
|
77
1807
|
// src/client/card/rows.ts
|
|
78
|
-
var
|
|
79
|
-
var
|
|
1808
|
+
var react5 = __toESM(require("react"), 1);
|
|
1809
|
+
var import_jsx_runtime10 = require("react/jsx-runtime");
|
|
80
1810
|
function RowList(props) {
|
|
81
1811
|
var served = Array.isArray(props.values) ? props.values : [];
|
|
82
1812
|
var writable = props.writable === true;
|
|
@@ -86,14 +1816,14 @@ function RowList(props) {
|
|
|
86
1816
|
var columns = Math.max(1, labels.length);
|
|
87
1817
|
var blankRow = [];
|
|
88
1818
|
for (var blank = 0; blank < columns; blank++) blankRow.push("");
|
|
89
|
-
var draftState =
|
|
1819
|
+
var draftState = react5.useState(null);
|
|
90
1820
|
var draft = draftState[0];
|
|
91
1821
|
var setDraft = draftState[1];
|
|
92
|
-
var focusedState =
|
|
1822
|
+
var focusedState = react5.useState(false);
|
|
93
1823
|
var focused = focusedState[0];
|
|
94
1824
|
var setFocused = focusedState[1];
|
|
95
1825
|
var servedKey = JSON.stringify(served);
|
|
96
|
-
var syncState =
|
|
1826
|
+
var syncState = react5.useState("");
|
|
97
1827
|
var servedSync = syncState[0];
|
|
98
1828
|
var setServedSync = syncState[1];
|
|
99
1829
|
if (servedKey !== servedSync) {
|
|
@@ -113,7 +1843,7 @@ function RowList(props) {
|
|
|
113
1843
|
setDraft(
|
|
114
1844
|
withDraft(
|
|
115
1845
|
(current) => current.map(
|
|
116
|
-
(row, at) => at === index2 ? row.map((cell,
|
|
1846
|
+
(row, at) => at === index2 ? row.map((cell, field2) => field2 === column ? value : cell) : row
|
|
117
1847
|
)
|
|
118
1848
|
)
|
|
119
1849
|
);
|
|
@@ -130,7 +1860,7 @@ function RowList(props) {
|
|
|
130
1860
|
if (draft === null) return;
|
|
131
1861
|
save(rows);
|
|
132
1862
|
};
|
|
133
|
-
var fieldNode = (row, index2, column) => (0,
|
|
1863
|
+
var fieldNode = (row, index2, column) => (0, import_jsx_runtime10.jsx)("input", {
|
|
134
1864
|
className: props.inputClassName ? ChromeMcpCard_default.catalogInput + " " + props.inputClassName : ChromeMcpCard_default.catalogInput,
|
|
135
1865
|
type: "text",
|
|
136
1866
|
value: row[column] === void 0 ? "" : row[column],
|
|
@@ -161,7 +1891,7 @@ function RowList(props) {
|
|
|
161
1891
|
var width = row.length === 0 ? columns : row.length;
|
|
162
1892
|
for (var column = 0; column < width; column++) cells.push(fieldNode(row, index2, column));
|
|
163
1893
|
cells.push(
|
|
164
|
-
(0,
|
|
1894
|
+
(0, import_jsx_runtime10.jsx)("button", {
|
|
165
1895
|
type: "button",
|
|
166
1896
|
className: ChromeMcpCard_default.iconButton + " " + ChromeMcpCard_default.iconButtonDanger,
|
|
167
1897
|
"aria-label": props.removeLabel + " " + (index2 + 1),
|
|
@@ -170,14 +1900,14 @@ function RowList(props) {
|
|
|
170
1900
|
onClick: () => {
|
|
171
1901
|
removeRow(index2);
|
|
172
1902
|
},
|
|
173
|
-
children: (0,
|
|
1903
|
+
children: (0, import_jsx_runtime10.jsx)("svg", {
|
|
174
1904
|
width: 14,
|
|
175
1905
|
height: 14,
|
|
176
1906
|
viewBox: "0 0 16 16",
|
|
177
1907
|
fill: "none",
|
|
178
1908
|
"aria-hidden": "true",
|
|
179
|
-
children: (0,
|
|
180
|
-
d:
|
|
1909
|
+
children: (0, import_jsx_runtime10.jsx)("path", {
|
|
1910
|
+
d: TRASH_PATH2,
|
|
181
1911
|
stroke: "currentColor",
|
|
182
1912
|
strokeWidth: 1.3,
|
|
183
1913
|
strokeLinecap: "round",
|
|
@@ -186,9 +1916,9 @@ function RowList(props) {
|
|
|
186
1916
|
})
|
|
187
1917
|
})
|
|
188
1918
|
);
|
|
189
|
-
return (0,
|
|
1919
|
+
return (0, import_jsx_runtime10.jsx)("div", {
|
|
190
1920
|
className: ChromeMcpCard_default.catalogEntry,
|
|
191
|
-
children: (0,
|
|
1921
|
+
children: (0, import_jsx_runtime10.jsxs)("div", {
|
|
192
1922
|
className: props.rowClassName ? ChromeMcpCard_default.catalogRow + " " + props.rowClassName : ChromeMcpCard_default.catalogRow,
|
|
193
1923
|
children: cells
|
|
194
1924
|
})
|
|
@@ -200,7 +1930,7 @@ function RowList(props) {
|
|
|
200
1930
|
for (var index = 0; index < rows.length; index++) visible.push(entryNode(rows[index], index));
|
|
201
1931
|
body = body.concat(visible);
|
|
202
1932
|
body.push(
|
|
203
|
-
(0,
|
|
1933
|
+
(0, import_jsx_runtime10.jsx)("button", {
|
|
204
1934
|
type: "button",
|
|
205
1935
|
className: ChromeMcpCard_default.addButton,
|
|
206
1936
|
disabled: !writable || busy,
|
|
@@ -208,23 +1938,23 @@ function RowList(props) {
|
|
|
208
1938
|
children: props.addLabel
|
|
209
1939
|
})
|
|
210
1940
|
);
|
|
211
|
-
var emptyLine = rows.length === 0 ? (0,
|
|
1941
|
+
var emptyLine = rows.length === 0 ? (0, import_jsx_runtime10.jsx)("p", { className: ChromeMcpCard_default.empty, children: props.emptyText }) : null;
|
|
212
1942
|
if (props.disclosure !== true) {
|
|
213
1943
|
return [emptyLine].concat(body);
|
|
214
1944
|
}
|
|
215
1945
|
return [
|
|
216
1946
|
emptyLine,
|
|
217
|
-
(0,
|
|
1947
|
+
(0, import_jsx_runtime10.jsxs)("details", {
|
|
218
1948
|
className: ChromeMcpCard_default.disclosure,
|
|
219
1949
|
children: [
|
|
220
|
-
(0,
|
|
1950
|
+
(0, import_jsx_runtime10.jsxs)("summary", {
|
|
221
1951
|
className: ChromeMcpCard_default.disclosureSummary,
|
|
222
1952
|
children: [
|
|
223
|
-
(0,
|
|
224
|
-
(0,
|
|
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) })
|
|
225
1955
|
]
|
|
226
1956
|
}),
|
|
227
|
-
(0,
|
|
1957
|
+
(0, import_jsx_runtime10.jsx)("div", { className: ChromeMcpCard_default.disclosureBody, children: body })
|
|
228
1958
|
]
|
|
229
1959
|
})
|
|
230
1960
|
];
|
|
@@ -257,7 +1987,7 @@ function ExtraFlagsEditor(props) {
|
|
|
257
1987
|
var restoreAction = (visible) => {
|
|
258
1988
|
var current = flagsOf(visible);
|
|
259
1989
|
var merged = current.concat(defaults.filter((flag) => current.indexOf(flag) === -1));
|
|
260
|
-
return (0,
|
|
1990
|
+
return (0, import_jsx_runtime11.jsx)("button", {
|
|
261
1991
|
type: "button",
|
|
262
1992
|
className: ChromeMcpCard_default.linkButton,
|
|
263
1993
|
// The defaults list is host-served — with nothing to recover there
|
|
@@ -274,7 +2004,7 @@ function ExtraFlagsEditor(props) {
|
|
|
274
2004
|
var wslAction = (visible) => {
|
|
275
2005
|
var current = flagsOf(visible);
|
|
276
2006
|
var merged = current.concat(wsl.filter((flag) => current.indexOf(flag) === -1));
|
|
277
|
-
return (0,
|
|
2007
|
+
return (0, import_jsx_runtime11.jsx)("button", {
|
|
278
2008
|
type: "button",
|
|
279
2009
|
className: ChromeMcpCard_default.linkButton,
|
|
280
2010
|
// The recommended list is host-served — with every one of them
|
|
@@ -288,30 +2018,30 @@ function ExtraFlagsEditor(props) {
|
|
|
288
2018
|
children: t("flagsWsl")
|
|
289
2019
|
});
|
|
290
2020
|
};
|
|
291
|
-
var renderActions = (visible) => (0,
|
|
2021
|
+
var renderActions = (visible) => (0, import_jsx_runtime11.jsxs)("div", {
|
|
292
2022
|
className: ChromeMcpCard_default.linkButtonRow,
|
|
293
2023
|
children: [restoreAction(visible), wslAction(visible)]
|
|
294
2024
|
});
|
|
295
|
-
return (0,
|
|
2025
|
+
return (0, import_jsx_runtime11.jsxs)("div", {
|
|
296
2026
|
className: ChromeMcpCard_default.catalog,
|
|
297
2027
|
children: [
|
|
298
|
-
(0,
|
|
2028
|
+
(0, import_jsx_runtime11.jsxs)("div", {
|
|
299
2029
|
className: ChromeMcpCard_default.field,
|
|
300
2030
|
children: [
|
|
301
|
-
(0,
|
|
2031
|
+
(0, import_jsx_runtime11.jsxs)("div", {
|
|
302
2032
|
className: ChromeMcpCard_default.fieldRow,
|
|
303
2033
|
children: [
|
|
304
|
-
(0,
|
|
2034
|
+
(0, import_jsx_runtime11.jsx)("span", { className: ChromeMcpCard_default.fieldTitle, children: t("flagsTitle") }),
|
|
305
2035
|
// The guide link rides the same field row the picker's
|
|
306
2036
|
// pill occupies.
|
|
307
|
-
(0,
|
|
2037
|
+
(0, import_jsx_runtime11.jsxs)("a", {
|
|
308
2038
|
className: ChromeMcpCard_default.docsLink,
|
|
309
2039
|
href: CONFIGURATION_URL,
|
|
310
2040
|
target: "_blank",
|
|
311
2041
|
rel: "noopener noreferrer",
|
|
312
2042
|
title: t("docsMessage"),
|
|
313
2043
|
children: [
|
|
314
|
-
(0,
|
|
2044
|
+
(0, import_jsx_runtime11.jsx)("svg", {
|
|
315
2045
|
className: ChromeMcpCard_default.docsIcon,
|
|
316
2046
|
width: 14,
|
|
317
2047
|
height: 14,
|
|
@@ -322,20 +2052,20 @@ function ExtraFlagsEditor(props) {
|
|
|
322
2052
|
strokeLinecap: "round",
|
|
323
2053
|
strokeLinejoin: "round",
|
|
324
2054
|
"aria-hidden": "true",
|
|
325
|
-
children:
|
|
2055
|
+
children: DOCS_PATHS2.map((d, at) => (0, import_jsx_runtime11.jsx)("path", { d }, at))
|
|
326
2056
|
}),
|
|
327
|
-
(0,
|
|
2057
|
+
(0, import_jsx_runtime11.jsx)("span", { className: ChromeMcpCard_default.docsLinkLabel, children: t("docsLinkLabel") })
|
|
328
2058
|
]
|
|
329
2059
|
})
|
|
330
2060
|
]
|
|
331
2061
|
}),
|
|
332
|
-
(0,
|
|
2062
|
+
(0, import_jsx_runtime11.jsx)("div", { className: ChromeMcpCard_default.fieldDesc, children: t("flagsHint") })
|
|
333
2063
|
]
|
|
334
2064
|
}),
|
|
335
2065
|
// One row per saved flag: the single field is the flag itself, and
|
|
336
2066
|
// the two append controls — Restore defaults and Flags WSL — ride
|
|
337
2067
|
// the list's action line.
|
|
338
|
-
(0,
|
|
2068
|
+
(0, import_jsx_runtime11.jsx)(RowList, {
|
|
339
2069
|
values: rowsOf(flags),
|
|
340
2070
|
labels: [t("flagsValueLabel")],
|
|
341
2071
|
placeholders: [t("flagsValuePlaceholder")],
|
|
@@ -355,8 +2085,8 @@ function ExtraFlagsEditor(props) {
|
|
|
355
2085
|
}
|
|
356
2086
|
|
|
357
2087
|
// src/client/card/picker.ts
|
|
358
|
-
var
|
|
359
|
-
var
|
|
2088
|
+
var import_jsx_runtime12 = require("react/jsx-runtime");
|
|
2089
|
+
var import_dsh_client_ui_primitives5 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
360
2090
|
function CatalogPicker(props) {
|
|
361
2091
|
var entries = props.entries;
|
|
362
2092
|
var options = props.options;
|
|
@@ -368,7 +2098,7 @@ function CatalogPicker(props) {
|
|
|
368
2098
|
if (typeof props.saveEntries !== "function") return Promise.resolve();
|
|
369
2099
|
return Promise.resolve(props.saveEntries(next.map((row) => ({ id: row[0] ?? "", name: row[1] ?? "" }))));
|
|
370
2100
|
};
|
|
371
|
-
var fetchAction = () => (0,
|
|
2101
|
+
var fetchAction = () => (0, import_jsx_runtime12.jsx)("button", {
|
|
372
2102
|
type: "button",
|
|
373
2103
|
className: ChromeMcpCard_default.linkButton,
|
|
374
2104
|
disabled: !writable || busy,
|
|
@@ -377,7 +2107,7 @@ function CatalogPicker(props) {
|
|
|
377
2107
|
},
|
|
378
2108
|
children: busy ? props.busyLabel : props.refreshLabel
|
|
379
2109
|
});
|
|
380
|
-
var windowsAction = () => (0,
|
|
2110
|
+
var windowsAction = () => (0, import_jsx_runtime12.jsx)("button", {
|
|
381
2111
|
type: "button",
|
|
382
2112
|
className: ChromeMcpCard_default.linkButton,
|
|
383
2113
|
disabled: props.windowsDisabled === true,
|
|
@@ -387,23 +2117,23 @@ function CatalogPicker(props) {
|
|
|
387
2117
|
},
|
|
388
2118
|
children: props.windowsLabel
|
|
389
2119
|
});
|
|
390
|
-
var renderActions = () => (0,
|
|
2120
|
+
var renderActions = () => (0, import_jsx_runtime12.jsxs)("div", {
|
|
391
2121
|
className: ChromeMcpCard_default.linkButtonRow,
|
|
392
2122
|
children: [fetchAction(), windowsAction()]
|
|
393
2123
|
});
|
|
394
|
-
return (0,
|
|
2124
|
+
return (0, import_jsx_runtime12.jsxs)("div", {
|
|
395
2125
|
className: ChromeMcpCard_default.catalog,
|
|
396
2126
|
children: [
|
|
397
|
-
(0,
|
|
2127
|
+
(0, import_jsx_runtime12.jsxs)("div", {
|
|
398
2128
|
className: ChromeMcpCard_default.field,
|
|
399
2129
|
children: [
|
|
400
|
-
(0,
|
|
2130
|
+
(0, import_jsx_runtime12.jsxs)("div", {
|
|
401
2131
|
className: ChromeMcpCard_default.fieldRow,
|
|
402
2132
|
children: [
|
|
403
|
-
(0,
|
|
404
|
-
(0,
|
|
2133
|
+
(0, import_jsx_runtime12.jsx)("span", { className: ChromeMcpCard_default.fieldTitle, children: props.selectorLabel }),
|
|
2134
|
+
(0, import_jsx_runtime12.jsx)("span", {
|
|
405
2135
|
className: ChromeMcpCard_default.selectorWrap,
|
|
406
|
-
children: (0,
|
|
2136
|
+
children: (0, import_jsx_runtime12.jsx)(import_dsh_client_ui_primitives5.Menu, {
|
|
407
2137
|
open: props.menuOpen,
|
|
408
2138
|
onClose: () => {
|
|
409
2139
|
props.setMenuOpen(false);
|
|
@@ -416,7 +2146,7 @@ function CatalogPicker(props) {
|
|
|
416
2146
|
},
|
|
417
2147
|
align: "end",
|
|
418
2148
|
portal: true,
|
|
419
|
-
anchor: (0,
|
|
2149
|
+
anchor: (0, import_jsx_runtime12.jsxs)("button", {
|
|
420
2150
|
type: "button",
|
|
421
2151
|
className: ChromeMcpCard_default.selector,
|
|
422
2152
|
"aria-haspopup": "menu",
|
|
@@ -429,15 +2159,15 @@ function CatalogPicker(props) {
|
|
|
429
2159
|
children: [
|
|
430
2160
|
// The reference card hands the pill a bare label;
|
|
431
2161
|
// the path needs its own truncating span.
|
|
432
|
-
(0,
|
|
433
|
-
(0,
|
|
2162
|
+
(0, import_jsx_runtime12.jsx)("span", { className: ChromeMcpCard_default.selectorLabel, children: props.selectedLabel }),
|
|
2163
|
+
(0, import_jsx_runtime12.jsx)("svg", {
|
|
434
2164
|
width: 14,
|
|
435
2165
|
height: 14,
|
|
436
2166
|
className: ChromeMcpCard_default.pillChevron,
|
|
437
2167
|
viewBox: "0 0 14 14",
|
|
438
2168
|
fill: "none",
|
|
439
2169
|
xmlns: "http://www.w3.org/2000/svg",
|
|
440
|
-
children: (0,
|
|
2170
|
+
children: (0, import_jsx_runtime12.jsx)("path", { d: CHEVRON_PATH2, fill: "currentColor" })
|
|
441
2171
|
})
|
|
442
2172
|
]
|
|
443
2173
|
})
|
|
@@ -445,12 +2175,12 @@ function CatalogPicker(props) {
|
|
|
445
2175
|
})
|
|
446
2176
|
]
|
|
447
2177
|
}),
|
|
448
|
-
(0,
|
|
2178
|
+
(0, import_jsx_runtime12.jsx)("div", { className: ChromeMcpCard_default.fieldDesc, children: props.hint })
|
|
449
2179
|
]
|
|
450
2180
|
}),
|
|
451
2181
|
// The saved rows: two fields per row, folded behind the disclosure,
|
|
452
2182
|
// with the fetch action sitting inside the body.
|
|
453
|
-
(0,
|
|
2183
|
+
(0, import_jsx_runtime12.jsx)(RowList, {
|
|
454
2184
|
values: rows,
|
|
455
2185
|
labels: [props.idLabel, props.nameLabel],
|
|
456
2186
|
placeholders: [props.idPlaceholder, props.namePlaceholder],
|
|
@@ -470,8 +2200,8 @@ function CatalogPicker(props) {
|
|
|
470
2200
|
}
|
|
471
2201
|
|
|
472
2202
|
// src/client/card/dialog.ts
|
|
473
|
-
var
|
|
474
|
-
var
|
|
2203
|
+
var react6 = __toESM(require("react"), 1);
|
|
2204
|
+
var import_jsx_runtime13 = require("react/jsx-runtime");
|
|
475
2205
|
function CandidateDialog(props) {
|
|
476
2206
|
var t = props.t;
|
|
477
2207
|
var candidates = props.candidates;
|
|
@@ -479,7 +2209,7 @@ function CandidateDialog(props) {
|
|
|
479
2209
|
var savedSet = new Set(savedIds);
|
|
480
2210
|
var initialChecked = candidates.filter((candidate) => savedSet.has(candidate.id)).map((candidate) => candidate.id);
|
|
481
2211
|
var servedKey = JSON.stringify(candidates) + "|" + JSON.stringify(savedIds);
|
|
482
|
-
var draftState =
|
|
2212
|
+
var draftState = react6.useState({ key: "", query: "", checked: [] });
|
|
483
2213
|
var draft = draftState[0];
|
|
484
2214
|
var setDraft = draftState[1];
|
|
485
2215
|
var dirty = draft.key !== servedKey;
|
|
@@ -499,44 +2229,44 @@ function CandidateDialog(props) {
|
|
|
499
2229
|
var toggle = (id, value) => {
|
|
500
2230
|
setChecked((current) => value ? current.concat([id]) : current.filter((entry) => entry !== id));
|
|
501
2231
|
};
|
|
502
|
-
return (0,
|
|
2232
|
+
return (0, import_jsx_runtime13.jsxs)("div", {
|
|
503
2233
|
className: ChromeMcpCard_default.fetchDialog,
|
|
504
2234
|
role: "dialog",
|
|
505
2235
|
"aria-modal": "true",
|
|
506
2236
|
"aria-label": props.title,
|
|
507
2237
|
children: [
|
|
508
|
-
(0,
|
|
2238
|
+
(0, import_jsx_runtime13.jsxs)("div", {
|
|
509
2239
|
className: ChromeMcpCard_default.dialogContent,
|
|
510
2240
|
children: [
|
|
511
|
-
(0,
|
|
2241
|
+
(0, import_jsx_runtime13.jsxs)("div", {
|
|
512
2242
|
className: ChromeMcpCard_default.dialogHeader,
|
|
513
2243
|
children: [
|
|
514
|
-
(0,
|
|
515
|
-
(0,
|
|
2244
|
+
(0, import_jsx_runtime13.jsx)("h2", { className: ChromeMcpCard_default.dialogTitle, children: props.title }),
|
|
2245
|
+
(0, import_jsx_runtime13.jsx)("button", {
|
|
516
2246
|
type: "button",
|
|
517
2247
|
className: ChromeMcpCard_default.dialogClose,
|
|
518
2248
|
"aria-label": t("close"),
|
|
519
2249
|
onClick: () => props.onClose(),
|
|
520
|
-
children: (0,
|
|
2250
|
+
children: (0, import_jsx_runtime13.jsx)("svg", {
|
|
521
2251
|
width: 14,
|
|
522
2252
|
height: 14,
|
|
523
2253
|
viewBox: "0 0 16 16",
|
|
524
2254
|
fill: "none",
|
|
525
2255
|
xmlns: "http://www.w3.org/2000/svg",
|
|
526
2256
|
"aria-hidden": "true",
|
|
527
|
-
children:
|
|
2257
|
+
children: CLOSE_PATHS2.map((d, at) => (0, import_jsx_runtime13.jsx)("path", { d, fill: "currentColor" }, at))
|
|
528
2258
|
})
|
|
529
2259
|
})
|
|
530
2260
|
]
|
|
531
2261
|
}),
|
|
532
|
-
(0,
|
|
533
|
-
(0,
|
|
2262
|
+
(0, import_jsx_runtime13.jsx)("p", { className: ChromeMcpCard_default.dialogDescription, children: props.description }),
|
|
2263
|
+
(0, import_jsx_runtime13.jsxs)("div", {
|
|
534
2264
|
className: ChromeMcpCard_default.dialogBody,
|
|
535
2265
|
children: [
|
|
536
|
-
(0,
|
|
2266
|
+
(0, import_jsx_runtime13.jsxs)("div", {
|
|
537
2267
|
className: ChromeMcpCard_default.candidateToolbar,
|
|
538
2268
|
children: [
|
|
539
|
-
(0,
|
|
2269
|
+
(0, import_jsx_runtime13.jsx)("input", {
|
|
540
2270
|
className: ChromeMcpCard_default.candidateSearch,
|
|
541
2271
|
type: "search",
|
|
542
2272
|
placeholder: props.searchPlaceholder,
|
|
@@ -546,7 +2276,7 @@ function CandidateDialog(props) {
|
|
|
546
2276
|
setQuery(event && event.target ? String(event.target.value ?? "") : "");
|
|
547
2277
|
}
|
|
548
2278
|
}),
|
|
549
|
-
(0,
|
|
2279
|
+
(0, import_jsx_runtime13.jsx)("button", {
|
|
550
2280
|
type: "button",
|
|
551
2281
|
className: ChromeMcpCard_default.linkButton,
|
|
552
2282
|
onClick: () => {
|
|
@@ -557,17 +2287,17 @@ function CandidateDialog(props) {
|
|
|
557
2287
|
})
|
|
558
2288
|
]
|
|
559
2289
|
}),
|
|
560
|
-
shown.length === 0 ? (0,
|
|
2290
|
+
shown.length === 0 ? (0, import_jsx_runtime13.jsx)("p", { className: ChromeMcpCard_default.empty, children: t("dialogEmpty") }) : (0, import_jsx_runtime13.jsx)("ul", {
|
|
561
2291
|
className: ChromeMcpCard_default.candidateList,
|
|
562
2292
|
children: shown.map((candidate) => {
|
|
563
2293
|
var isSaved = savedSet.has(candidate.id);
|
|
564
2294
|
var note = candidate.note !== "" ? candidate.note : isSaved ? t("candidateSaved") : "";
|
|
565
|
-
return (0,
|
|
2295
|
+
return (0, import_jsx_runtime13.jsx)("li", {
|
|
566
2296
|
className: ChromeMcpCard_default.candidate,
|
|
567
|
-
children: (0,
|
|
2297
|
+
children: (0, import_jsx_runtime13.jsxs)("label", {
|
|
568
2298
|
className: ChromeMcpCard_default.candidateLabel,
|
|
569
2299
|
children: [
|
|
570
|
-
(0,
|
|
2300
|
+
(0, import_jsx_runtime13.jsx)("input", {
|
|
571
2301
|
type: "checkbox",
|
|
572
2302
|
checked: isSaved ? true : checkedSet.has(candidate.id),
|
|
573
2303
|
disabled: isSaved,
|
|
@@ -575,8 +2305,8 @@ function CandidateDialog(props) {
|
|
|
575
2305
|
toggle(candidate.id, !!(event && event.target && event.target.checked));
|
|
576
2306
|
}
|
|
577
2307
|
}),
|
|
578
|
-
(0,
|
|
579
|
-
note === "" ? null : (0,
|
|
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 })
|
|
580
2310
|
]
|
|
581
2311
|
})
|
|
582
2312
|
}, candidate.id);
|
|
@@ -584,16 +2314,16 @@ function CandidateDialog(props) {
|
|
|
584
2314
|
})
|
|
585
2315
|
]
|
|
586
2316
|
}),
|
|
587
|
-
(0,
|
|
2317
|
+
(0, import_jsx_runtime13.jsxs)("div", {
|
|
588
2318
|
className: ChromeMcpCard_default.dialogFooter,
|
|
589
2319
|
children: [
|
|
590
|
-
(0,
|
|
2320
|
+
(0, import_jsx_runtime13.jsx)("button", {
|
|
591
2321
|
type: "button",
|
|
592
2322
|
className: ChromeMcpCard_default.dialogButton,
|
|
593
2323
|
onClick: () => props.onClose(),
|
|
594
2324
|
children: t("cancel")
|
|
595
2325
|
}),
|
|
596
|
-
(0,
|
|
2326
|
+
(0, import_jsx_runtime13.jsx)("button", {
|
|
597
2327
|
type: "button",
|
|
598
2328
|
className: ChromeMcpCard_default.dialogButton + " " + ChromeMcpCard_default.dialogButtonPrimary,
|
|
599
2329
|
onClick: () => props.onAdd(Array.from(checkedSet)),
|
|
@@ -608,25 +2338,25 @@ function CandidateDialog(props) {
|
|
|
608
2338
|
}
|
|
609
2339
|
|
|
610
2340
|
// src/client/card/run-actions.ts
|
|
611
|
-
var
|
|
2341
|
+
var react7 = __toESM(require("react"), 1);
|
|
612
2342
|
var PROBED_AGE_TICK_MS = 1e4;
|
|
613
2343
|
function useRunActions(deps) {
|
|
614
|
-
const runningState =
|
|
2344
|
+
const runningState = react7.useState(false);
|
|
615
2345
|
const isRunning = runningState[0];
|
|
616
2346
|
const setRunning = runningState[1];
|
|
617
|
-
const windowsRunningState =
|
|
2347
|
+
const windowsRunningState = react7.useState(false);
|
|
618
2348
|
const isWindowsRunning = windowsRunningState[0];
|
|
619
2349
|
const setWindowsRunning = windowsRunningState[1];
|
|
620
|
-
const dialogRef =
|
|
2350
|
+
const dialogRef = react7.useState(null);
|
|
621
2351
|
const dialog = dialogRef[0];
|
|
622
2352
|
const setDialog = dialogRef[1];
|
|
623
|
-
const probedState =
|
|
2353
|
+
const probedState = react7.useState(0);
|
|
624
2354
|
const lastProbedAt = probedState[0];
|
|
625
2355
|
const setLastProbedAt = probedState[1];
|
|
626
|
-
const clockState =
|
|
2356
|
+
const clockState = react7.useState(() => Date.now());
|
|
627
2357
|
const clock = clockState[0];
|
|
628
2358
|
const setClock = clockState[1];
|
|
629
|
-
|
|
2359
|
+
react7.useEffect(() => {
|
|
630
2360
|
const tick = setInterval(() => setClock(Date.now()), PROBED_AGE_TICK_MS);
|
|
631
2361
|
return () => clearInterval(tick);
|
|
632
2362
|
}, []);
|
|
@@ -647,7 +2377,7 @@ function useRunActions(deps) {
|
|
|
647
2377
|
if (!Array.isArray(statuses) || statuses.length === 0) return;
|
|
648
2378
|
const candidates = statuses.map((status) => ({
|
|
649
2379
|
id: status.path,
|
|
650
|
-
note: status.version !== "" ? status.version : status.error,
|
|
2380
|
+
note: status.version !== "" ? status.version : status.error !== "" ? status.error : status.note,
|
|
651
2381
|
broken: status.version === "" && status.error !== ""
|
|
652
2382
|
}));
|
|
653
2383
|
setDialog({ candidates });
|
|
@@ -693,24 +2423,24 @@ function useRunActions(deps) {
|
|
|
693
2423
|
}
|
|
694
2424
|
|
|
695
2425
|
// src/client/card/toggle.ts
|
|
696
|
-
var
|
|
697
|
-
var
|
|
2426
|
+
var import_jsx_runtime14 = require("react/jsx-runtime");
|
|
2427
|
+
var import_dsh_client_ui_primitives6 = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
698
2428
|
function LogOutputToggle(props) {
|
|
699
2429
|
var t = props.t;
|
|
700
|
-
return (0,
|
|
2430
|
+
return (0, import_jsx_runtime14.jsxs)("div", {
|
|
701
2431
|
className: ChromeMcpCard_default.catalog,
|
|
702
2432
|
children: [
|
|
703
|
-
(0,
|
|
2433
|
+
(0, import_jsx_runtime14.jsxs)("div", {
|
|
704
2434
|
className: ChromeMcpCard_default.field,
|
|
705
2435
|
children: [
|
|
706
|
-
(0,
|
|
2436
|
+
(0, import_jsx_runtime14.jsxs)("div", {
|
|
707
2437
|
className: ChromeMcpCard_default.fieldRow,
|
|
708
2438
|
children: [
|
|
709
|
-
(0,
|
|
710
|
-
(0,
|
|
2439
|
+
(0, import_jsx_runtime14.jsx)("span", { className: ChromeMcpCard_default.fieldTitle, children: t("reduceLabel") }),
|
|
2440
|
+
(0, import_jsx_runtime14.jsx)("span", {
|
|
711
2441
|
className: ChromeMcpCard_default.toggleLabel,
|
|
712
2442
|
title: t("reduceTitle"),
|
|
713
|
-
children: (0,
|
|
2443
|
+
children: (0, import_jsx_runtime14.jsx)(import_dsh_client_ui_primitives6.Switch, {
|
|
714
2444
|
checked: props.checked,
|
|
715
2445
|
label: t("reduceLabel"),
|
|
716
2446
|
disabled: props.disabled,
|
|
@@ -721,43 +2451,13 @@ function LogOutputToggle(props) {
|
|
|
721
2451
|
})
|
|
722
2452
|
]
|
|
723
2453
|
}),
|
|
724
|
-
(0,
|
|
2454
|
+
(0, import_jsx_runtime14.jsx)("div", { className: ChromeMcpCard_default.fieldDesc, children: t("reduceHint") })
|
|
725
2455
|
]
|
|
726
2456
|
})
|
|
727
2457
|
]
|
|
728
2458
|
});
|
|
729
2459
|
}
|
|
730
2460
|
|
|
731
|
-
// src/client/catalog.ts
|
|
732
|
-
var ID_MAX_LENGTH = 1024;
|
|
733
|
-
var PATH_PATTERN = /^[^\x00-\x1f\x7f]{1,1024}$/u;
|
|
734
|
-
var NAME_MAX_LENGTH = 200;
|
|
735
|
-
var ENTRY_CAP = 50;
|
|
736
|
-
function isValidEntryId(id) {
|
|
737
|
-
if (id === "" || id.length > ID_MAX_LENGTH) return false;
|
|
738
|
-
return PATH_PATTERN.test(id);
|
|
739
|
-
}
|
|
740
|
-
function entryLabel(entry) {
|
|
741
|
-
const name = entry.name.trim();
|
|
742
|
-
return name === "" ? entry.id : name;
|
|
743
|
-
}
|
|
744
|
-
function normalizeEntries(value) {
|
|
745
|
-
if (!Array.isArray(value)) return [];
|
|
746
|
-
const out = [];
|
|
747
|
-
const seen = /* @__PURE__ */ new Set();
|
|
748
|
-
for (const item of value) {
|
|
749
|
-
if (out.length === ENTRY_CAP) break;
|
|
750
|
-
if (item === null || typeof item !== "object" || Array.isArray(item)) continue;
|
|
751
|
-
const raw = item;
|
|
752
|
-
const id = typeof raw.id === "string" ? raw.id.trim() : "";
|
|
753
|
-
if (!isValidEntryId(id) || seen.has(id)) continue;
|
|
754
|
-
seen.add(id);
|
|
755
|
-
const name = typeof raw.name === "string" ? raw.name.trim() : "";
|
|
756
|
-
out.push({ id, name: name.slice(0, NAME_MAX_LENGTH) });
|
|
757
|
-
}
|
|
758
|
-
return out;
|
|
759
|
-
}
|
|
760
|
-
|
|
761
2461
|
// src/client/card/view.ts
|
|
762
2462
|
function labelOf(entries, id) {
|
|
763
2463
|
const row = entries.find((entry) => entry.id === id);
|
|
@@ -786,9 +2486,22 @@ function describeCard(state) {
|
|
|
786
2486
|
dotIsError: error !== "",
|
|
787
2487
|
wslWindowsExecutable: state.wslWindowsExecutable === true,
|
|
788
2488
|
windowsChrome: readWindowsChrome(state.windowsChromeStatus),
|
|
789
|
-
|
|
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)
|
|
790
2499
|
};
|
|
791
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
|
+
}
|
|
792
2505
|
function executableLabel(view, id) {
|
|
793
2506
|
return labelOf(view.executableEntries, id);
|
|
794
2507
|
}
|
|
@@ -805,8 +2518,8 @@ function windowsChromeButton(view) {
|
|
|
805
2518
|
const status = view.windowsChrome;
|
|
806
2519
|
if (status.state === "launching") return { labelKey: "openWindowsChromeBusy", titleKey: "openWindowsChromeTitle", disabled: true, busy: true };
|
|
807
2520
|
if (status.state === "not-applicable") return { labelKey: "openWindowsChrome", titleKey: "windowsChromeNotWsl", disabled: true, busy: false };
|
|
808
|
-
if (status.state === "not-found") return { labelKey: "openWindowsChrome", titleKey: "windowsChromeNotFound", disabled:
|
|
809
|
-
if (status.state === "unreachable") return { labelKey: "openWindowsChrome", titleKey: "windowsChromeUnreachable", disabled:
|
|
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 };
|
|
810
2523
|
return { labelKey: "openWindowsChrome", titleKey: "openWindowsChromeTitle", disabled: false, busy: false };
|
|
811
2524
|
}
|
|
812
2525
|
function isBroken(view, id) {
|
|
@@ -829,18 +2542,15 @@ function optionLabel(view, id, t) {
|
|
|
829
2542
|
function ChromeMcpCard(props) {
|
|
830
2543
|
const t = props.t;
|
|
831
2544
|
const state = props.useChromeMcpCard((snapshot) => snapshot);
|
|
832
|
-
const
|
|
833
|
-
const open = openState[0];
|
|
834
|
-
const setOpen = openState[1];
|
|
835
|
-
const menuState = react4.useState(false);
|
|
2545
|
+
const menuState = react8.useState(false);
|
|
836
2546
|
const menuOpen = menuState[0];
|
|
837
2547
|
const setMenuOpen = menuState[1];
|
|
838
|
-
const bodyId = react4.useId();
|
|
839
2548
|
const runs = useRunActions({
|
|
840
2549
|
refreshExecutables: props.refreshExecutables,
|
|
841
2550
|
openWindowsChrome: props.openWindowsChrome,
|
|
842
2551
|
addExecutables: props.addExecutables
|
|
843
2552
|
});
|
|
2553
|
+
if (props.view !== "page") return null;
|
|
844
2554
|
if (!state.available) return null;
|
|
845
2555
|
const view = describeCard(state);
|
|
846
2556
|
const rows = view.executableEntries;
|
|
@@ -848,158 +2558,153 @@ function ChromeMcpCard(props) {
|
|
|
848
2558
|
const options = view.executableOptions.map((option) => ({ id: option.id, label: optionLabel(view, option.id, t) }));
|
|
849
2559
|
const dotLabel = view.error !== "" ? view.error : t("chromeMissing");
|
|
850
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
|
+
});
|
|
851
2567
|
const windowsButton = windowsChromeButton(view);
|
|
852
2568
|
const windowsDisabled = windowsButton.disabled || runs.windowsRunning || !state.writable;
|
|
853
2569
|
const windowsBusy = windowsButton.busy || runs.windowsRunning;
|
|
854
2570
|
const connectLabel = view.windowsChrome.port > 0 ? t("connectModeLabel") + " (http://127.0.0.1:" + String(view.windowsChrome.port) + ")" : t("connectModeLabel");
|
|
855
2571
|
const selectedLabel = view.connectMode ? connectLabel : view.effectivePath === "" ? t("executableNone") : executableLabel(view, view.effectivePath);
|
|
856
|
-
const statusLine = runs.running ? (0,
|
|
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", {
|
|
857
2573
|
className: ChromeMcpCard_default.result,
|
|
858
2574
|
role: "status",
|
|
859
2575
|
children: [
|
|
860
2576
|
t("versionLabel"),
|
|
861
|
-
(0,
|
|
862
|
-
runs.lastProbedAt === 0 ? null : (0,
|
|
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) })
|
|
863
2579
|
]
|
|
864
2580
|
});
|
|
865
|
-
|
|
866
|
-
|
|
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,
|
|
867
2584
|
children: [
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
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);
|
|
877
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",
|
|
878
2633
|
children: [
|
|
879
|
-
(0,
|
|
880
|
-
|
|
881
|
-
children: [
|
|
882
|
-
(0, import_jsx_runtime6.jsxs)("div", {
|
|
883
|
-
className: ChromeMcpCard_default.nameRow,
|
|
884
|
-
children: [
|
|
885
|
-
(0, import_jsx_runtime6.jsx)("span", { className: ChromeMcpCard_default.name, children: t("title") }),
|
|
886
|
-
view.dotIsError || view.missing ? (0, import_jsx_runtime6.jsx)("span", {
|
|
887
|
-
className: ChromeMcpCard_default.dot + " " + ChromeMcpCard_default.dotError,
|
|
888
|
-
role: "img",
|
|
889
|
-
"aria-label": dotAria,
|
|
890
|
-
title: dotLabel
|
|
891
|
-
}) : null
|
|
892
|
-
]
|
|
893
|
-
}),
|
|
894
|
-
(0, import_jsx_runtime6.jsx)("span", { className: ChromeMcpCard_default.desc, children: t("description") })
|
|
895
|
-
]
|
|
896
|
-
}),
|
|
897
|
-
(0, import_jsx_runtime6.jsx)("svg", {
|
|
898
|
-
width: 14,
|
|
899
|
-
height: 14,
|
|
900
|
-
className: ChromeMcpCard_default.chevron + (open ? " " + ChromeMcpCard_default.chevronOpen : ""),
|
|
901
|
-
viewBox: "0 0 14 14",
|
|
902
|
-
fill: "none",
|
|
903
|
-
xmlns: "http://www.w3.org/2000/svg",
|
|
904
|
-
children: (0, import_jsx_runtime6.jsx)("path", { d: CHEVRON_PATH, fill: "currentColor" })
|
|
905
|
-
})
|
|
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") })
|
|
906
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
|
|
907
2645
|
}),
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
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,
|
|
911
2669
|
children: [
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
selectedTitle: view.connectMode ? connectLabel : view.effectivePath !== "" ? view.effectivePath : selectedLabel,
|
|
922
|
-
writable: state.writable,
|
|
923
|
-
busy: runs.running,
|
|
924
|
-
menuOpen,
|
|
925
|
-
setMenuOpen,
|
|
926
|
-
connectMode: view.connectMode,
|
|
927
|
-
selectorLabel: t("executableLabel"),
|
|
928
|
-
hint: view.connectMode ? t("connectModeHint") : t("executableHint"),
|
|
929
|
-
windowsLabel: windowsBusy ? t("openWindowsChromeBusy") : t(windowsButton.labelKey),
|
|
930
|
-
windowsTitle: t(windowsButton.titleKey),
|
|
931
|
-
windowsDisabled,
|
|
932
|
-
windowsOnOpen: runs.runWindowsChrome,
|
|
933
|
-
rowsLabel: t("executableRows"),
|
|
934
|
-
emptyText: t("executableEmpty"),
|
|
935
|
-
idLabel: t("executableIdLabel"),
|
|
936
|
-
nameLabel: t("executableNameLabel"),
|
|
937
|
-
removeLabel: t("removeExecutable"),
|
|
938
|
-
addLabel: t("addExecutable"),
|
|
939
|
-
refreshLabel: t("fetchExecutables"),
|
|
940
|
-
busyLabel: t("fetching"),
|
|
941
|
-
select: (id) => {
|
|
942
|
-
if (typeof props.selectExecutable === "function") void props.selectExecutable(id);
|
|
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();
|
|
943
2679
|
},
|
|
944
|
-
|
|
945
|
-
refresh: runs.runFetch,
|
|
946
|
-
statusLine
|
|
947
|
-
}),
|
|
948
|
-
// The one state no control of this card can express: the
|
|
949
|
-
// host runs under WSL and what is selected is a Windows
|
|
950
|
-
// executable — which the bridge cannot launch, however
|
|
951
|
-
// healthy its `--version` answer looks. Nothing has failed
|
|
952
|
-
// yet, so this is a notice (static copy, shown only while
|
|
953
|
-
// the host reports the state), not a third error surface:
|
|
954
|
-
// the required configuration differs.
|
|
955
|
-
view.wslWindowsExecutable ? (0, import_jsx_runtime6.jsxs)("div", {
|
|
956
|
-
className: ChromeMcpCard_default.notice,
|
|
957
|
-
role: "note",
|
|
958
|
-
children: [
|
|
959
|
-
(0, import_jsx_runtime6.jsx)("div", { className: ChromeMcpCard_default.noticeTitle, children: t("wslWindowsTitle") }),
|
|
960
|
-
(0, import_jsx_runtime6.jsx)("div", { className: ChromeMcpCard_default.noticeBody, children: t("wslWindowsNote") })
|
|
961
|
-
]
|
|
962
|
-
}) : null,
|
|
963
|
-
(0, import_jsx_runtime6.jsx)(ExtraFlagsEditor, {
|
|
964
|
-
t,
|
|
965
|
-
flags: Array.isArray(state.extraFlags) ? state.extraFlags : [],
|
|
966
|
-
defaultFlags: Array.isArray(state.defaultExtraFlags) ? state.defaultExtraFlags : [],
|
|
967
|
-
wslFlags: Array.isArray(state.wslExtraFlags) ? state.wslExtraFlags : [],
|
|
968
|
-
writable: state.writable,
|
|
969
|
-
saveFlags: props.saveFlags
|
|
2680
|
+
children: t("discard")
|
|
970
2681
|
}),
|
|
971
|
-
(0,
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
disabled: !state.writable,
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
t,
|
|
981
|
-
candidates: runs.dialog.candidates,
|
|
982
|
-
savedIds,
|
|
983
|
-
title: t("dialogExecutablesTitle"),
|
|
984
|
-
description: t("dialogExecutablesDescription"),
|
|
985
|
-
searchPlaceholder: t("searchExecutables"),
|
|
986
|
-
onAdd: runs.addFromDialog,
|
|
987
|
-
onClose: runs.closeDialog
|
|
988
|
-
}) : null
|
|
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
|
+
})
|
|
989
2691
|
]
|
|
990
|
-
})
|
|
2692
|
+
})
|
|
991
2693
|
]
|
|
992
2694
|
});
|
|
993
2695
|
}
|
|
994
2696
|
|
|
995
|
-
// src/client/
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
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
|
+
}
|
|
1003
2708
|
function readNumber(value, fallback) {
|
|
1004
2709
|
return typeof value === "number" ? value : fallback;
|
|
1005
2710
|
}
|
|
@@ -1029,323 +2734,163 @@ function readStatus(value) {
|
|
|
1029
2734
|
statuses.push({
|
|
1030
2735
|
path,
|
|
1031
2736
|
version: readString(item.version, ""),
|
|
1032
|
-
error: readString(item.error, "")
|
|
2737
|
+
error: readString(item.error, ""),
|
|
2738
|
+
note: readString(item.note, "")
|
|
1033
2739
|
});
|
|
1034
2740
|
}
|
|
1035
2741
|
return statuses;
|
|
1036
2742
|
}
|
|
1037
2743
|
|
|
1038
|
-
// src/client/
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
const
|
|
1121
|
-
|
|
1122
|
-
const
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
}
|
|
1159
|
-
/**
|
|
1160
|
-
* Pick one saved executable. Writes the persisted `chromePath` (the host
|
|
1161
|
-
* restarts the bridge connection carrying it and re-runs the discovery), then
|
|
1162
|
-
* waits until the served revision advances past the click-time value.
|
|
1163
|
-
*/
|
|
1164
|
-
selectExecutable(id) {
|
|
1165
|
-
if (this.disposed) return Promise.resolve();
|
|
1166
|
-
const target = typeof id === "string" ? id.trim() : "";
|
|
1167
|
-
if (target === "") return Promise.resolve();
|
|
1168
|
-
const baseline = this.store.getSnapshot().executableDiscoveryRevision;
|
|
1169
|
-
const wait = this.waitFor("executableDiscoveryRevision", baseline, Date.now() + CHECK_POLL_TIMEOUT_MS);
|
|
1170
|
-
return this.scope.set("chromePath", target).catch((error) => this.noteError(error)).then(() => wait);
|
|
1171
|
-
}
|
|
1172
|
-
/**
|
|
1173
|
-
* Save the whole rows list: the card owns the draft, the host re-normalizes
|
|
1174
|
-
* on the way in and re-runs the scan the new ids imply.
|
|
1175
|
-
*/
|
|
1176
|
-
saveExecutables(entries) {
|
|
1177
|
-
if (this.disposed) return Promise.resolve();
|
|
1178
|
-
const rows = normalizeEntries(entries);
|
|
1179
|
-
const snapshot = this.store.getSnapshot();
|
|
1180
|
-
const unchanged = JSON.stringify(rows) === JSON.stringify(snapshot.executables);
|
|
1181
|
-
if (unchanged) return Promise.resolve();
|
|
1182
|
-
const baseline = snapshot.executableDiscoveryRevision;
|
|
1183
|
-
const wait = this.waitFor("executableDiscoveryRevision", baseline, Date.now() + CHECK_POLL_TIMEOUT_MS);
|
|
1184
|
-
return this.scope.set("executables", rows).catch((error) => this.noteError(error)).then(() => wait);
|
|
1185
|
-
}
|
|
1186
|
-
/**
|
|
1187
|
-
* Ask the host to re-probe the saved rows and fold what it finds into them,
|
|
1188
|
-
* then wait for the served revision to advance: write the trigger, then poll
|
|
1189
|
-
* the shared describe mirror until it moves — or the budget elapses. Resolves
|
|
1190
|
-
* with every candidate the run answered for and what it said about each, so
|
|
1191
|
-
* the dialog opens over the run's own answer list.
|
|
1192
|
-
*/
|
|
1193
|
-
refreshExecutables() {
|
|
1194
|
-
if (this.disposed) return Promise.resolve([]);
|
|
1195
|
-
const baseline = this.store.getSnapshot().executableDiscoveryRevision;
|
|
1196
|
-
const wait = this.waitFor("executableDiscoveryRevision", baseline, Date.now() + CHECK_POLL_TIMEOUT_MS);
|
|
1197
|
-
return this.scope.set("refreshExecutablesNonce", Date.now()).catch((error) => this.noteError(error)).then(() => wait).then(() => {
|
|
1198
|
-
const served = this.store.getSnapshot();
|
|
1199
|
-
return Array.isArray(served.executableStatus) ? served.executableStatus : [];
|
|
1200
|
-
});
|
|
1201
|
-
}
|
|
1202
|
-
/**
|
|
1203
|
-
* Merge the ids picked in the dialog into the saved rows: every id already
|
|
1204
|
-
* there keeps its place (and its name), the missing ones append nameless.
|
|
1205
|
-
* The host re-normalizes on the way in and re-runs the scan the new ids
|
|
1206
|
-
* imply, so the same revision counter carries the wait.
|
|
1207
|
-
*/
|
|
1208
|
-
addExecutables(ids) {
|
|
1209
|
-
if (this.disposed) return Promise.resolve();
|
|
1210
|
-
const served = this.store.getSnapshot();
|
|
1211
|
-
const rows = normalizeEntries(served.executables);
|
|
1212
|
-
const merged = rows.concat(
|
|
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(
|
|
1213
2864
|
(Array.isArray(ids) ? ids : []).filter((id) => typeof id === "string" && id.trim() !== "").map((id) => ({ id: id.trim(), name: "" }))
|
|
1214
|
-
)
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
* `stderrMode` when set, else the row-config `rowStderr` fallback. The host
|
|
1239
|
-
* restarts the bridge connection on the change.
|
|
1240
|
-
*/
|
|
1241
|
-
toggleStderr() {
|
|
1242
|
-
if (this.disposed) return Promise.resolve();
|
|
1243
|
-
const snapshot = this.store.getSnapshot();
|
|
1244
|
-
const effective = snapshot.stderrMode === "log" || snapshot.stderrMode === "console" ? snapshot.stderrMode : snapshot.rowStderr === "console" ? "console" : "log";
|
|
1245
|
-
const next = effective === "log" ? "console" : "log";
|
|
1246
|
-
return this.scope.set("stderrMode", next).catch((error) => this.noteError(error));
|
|
1247
|
-
}
|
|
1248
|
-
/** The face the card's slot registration injects. */
|
|
1249
|
-
inject() {
|
|
1250
|
-
return {
|
|
1251
|
-
hooks: { chromeMcpCard: this.store },
|
|
1252
|
-
saveFlags: (flags) => this.saveFlags(flags),
|
|
1253
|
-
toggleStderr: () => this.toggleStderr(),
|
|
1254
|
-
selectExecutable: (id) => this.selectExecutable(id),
|
|
1255
|
-
saveExecutables: (entries) => this.saveExecutables(entries),
|
|
1256
|
-
refreshExecutables: () => this.refreshExecutables(),
|
|
1257
|
-
addExecutables: (ids) => this.addExecutables(ids),
|
|
1258
|
-
openWindowsChrome: () => this.openWindowsChrome(),
|
|
1259
|
-
/** One mirror re-read (used when the card opens). */
|
|
1260
|
-
refresh: () => this.refresh()
|
|
1261
|
-
};
|
|
1262
|
-
}
|
|
1263
|
-
/**
|
|
1264
|
-
* Re-read the shared describe mirror once so base-layer status
|
|
1265
|
-
* captured asynchronously by the host (bridge connection errors)
|
|
1266
|
-
* reaches an opened card without waiting for a write or a run.
|
|
1267
|
-
*/
|
|
1268
|
-
refresh() {
|
|
1269
|
-
if (this.disposed) return Promise.resolve();
|
|
1270
|
-
let load;
|
|
1271
|
-
try {
|
|
1272
|
-
load = this.mirror.load();
|
|
1273
|
-
} catch {
|
|
1274
|
-
load = void 0;
|
|
1275
|
-
}
|
|
1276
|
-
return Promise.resolve(load).catch(() => {
|
|
1277
|
-
});
|
|
1278
|
-
}
|
|
1279
|
-
dispose() {
|
|
1280
|
-
this.disposed = true;
|
|
1281
|
-
if (this.pollTimer !== null) {
|
|
1282
|
-
clearTimeout(this.pollTimer);
|
|
1283
|
-
this.pollTimer = null;
|
|
1284
|
-
}
|
|
1285
|
-
this.unsubscribe();
|
|
1286
|
-
}
|
|
1287
|
-
/**
|
|
1288
|
-
* Re-describe the settings mirror every tick until the given revision field
|
|
1289
|
-
* advances past `baseline`, or the deadline passes.
|
|
1290
|
-
*/
|
|
1291
|
-
waitFor(field, baseline, deadline) {
|
|
1292
|
-
const generation = ++this.pollGeneration;
|
|
1293
|
-
const controller = this;
|
|
1294
|
-
return new Promise((resolve) => {
|
|
1295
|
-
let timer;
|
|
1296
|
-
let settled = false;
|
|
1297
|
-
const arm = (delay) => {
|
|
1298
|
-
timer = setTimeout(tick, delay);
|
|
1299
|
-
controller.pollTimer = timer ?? null;
|
|
1300
|
-
};
|
|
1301
|
-
const finish = () => {
|
|
1302
|
-
if (settled) return;
|
|
1303
|
-
settled = true;
|
|
1304
|
-
clearTimeout(timer);
|
|
1305
|
-
if (controller.pollTimer === (timer ?? null)) controller.pollTimer = null;
|
|
1306
|
-
resolve();
|
|
1307
|
-
};
|
|
1308
|
-
const satisfied = () => readNumber(controller.store.getSnapshot()[field], baseline) > baseline || Date.now() >= deadline;
|
|
1309
|
-
const stale = () => controller.disposed || generation !== controller.pollGeneration;
|
|
1310
|
-
const tick = () => {
|
|
1311
|
-
if (stale() || satisfied()) {
|
|
1312
|
-
finish();
|
|
1313
|
-
return;
|
|
1314
|
-
}
|
|
1315
|
-
let loaded;
|
|
1316
|
-
try {
|
|
1317
|
-
loaded = controller.mirror.load();
|
|
1318
|
-
} catch {
|
|
1319
|
-
loaded = void 0;
|
|
1320
|
-
}
|
|
1321
|
-
Promise.resolve(loaded).catch(() => ({})).then(() => {
|
|
1322
|
-
if (stale() || satisfied()) {
|
|
1323
|
-
finish();
|
|
1324
|
-
return;
|
|
1325
|
-
}
|
|
1326
|
-
arm(CHECK_POLL_TICK_MS);
|
|
1327
|
-
});
|
|
1328
|
-
};
|
|
1329
|
-
arm(CHECK_POLL_TICK_MS);
|
|
1330
|
-
});
|
|
1331
|
-
}
|
|
1332
|
-
/** Surface a rejected action on the card (store-only; never host state). */
|
|
1333
|
-
noteError(error) {
|
|
1334
|
-
if (this.disposed) return;
|
|
1335
|
-
const previous = this.store.getSnapshot();
|
|
1336
|
-
this.store.set({
|
|
1337
|
-
...previous,
|
|
1338
|
-
actionError: error != null && typeof error.message === "string" ? error.message : String(error)
|
|
1339
|
-
});
|
|
1340
|
-
}
|
|
1341
|
-
};
|
|
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
|
+
}
|
|
1342
2889
|
|
|
1343
2890
|
// src/client/locales/en-US.ts
|
|
1344
2891
|
var en = {
|
|
1345
|
-
title: "DSH Chrome MCP",
|
|
1346
|
-
description: "DSH Chrome MCP server (chrome-devtools-mcp) settings and status",
|
|
1347
2892
|
executableLabel: "Chrome executable",
|
|
1348
|
-
executableHint: "The
|
|
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.",
|
|
1349
2894
|
executableNone: "No Chrome executable detected",
|
|
1350
2895
|
executableRows: "Saved executables",
|
|
1351
2896
|
executableIdLabel: "Executable path",
|
|
@@ -1368,7 +2913,7 @@ var en = {
|
|
|
1368
2913
|
cancel: "Cancel",
|
|
1369
2914
|
unavailableSuffix: "not runnable",
|
|
1370
2915
|
wslWindowsTitle: "Windows executable under WSL",
|
|
1371
|
-
wslWindowsNote: "This host runs inside Windows Subsystem for Linux and the selected executable is the Windows Chrome, which
|
|
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.",
|
|
1372
2917
|
probing: "Checking the executables\u2026",
|
|
1373
2918
|
versionLabel: "Probed version:",
|
|
1374
2919
|
probeJustNow: "just now",
|
|
@@ -1376,7 +2921,7 @@ var en = {
|
|
|
1376
2921
|
probeMinutesAgo: "minutes ago",
|
|
1377
2922
|
probeHoursAgo: "hours ago",
|
|
1378
2923
|
flagsTitle: "Extra flags",
|
|
1379
|
-
flagsHint: "The 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.",
|
|
1380
2925
|
flagsEmpty: "No extra flags saved. Add one by hand, or use \u201CRestore defaults\u201D.",
|
|
1381
2926
|
flagsRows: "Saved flags",
|
|
1382
2927
|
flagsValueLabel: "Extra flag",
|
|
@@ -1386,63 +2931,90 @@ var en = {
|
|
|
1386
2931
|
flagsRestore: "Restore defaults",
|
|
1387
2932
|
flagsRestoreTitle: "Keep every flag the rows carry and append the defaults that are still missing",
|
|
1388
2933
|
flagsWsl: "Flags WSL",
|
|
1389
|
-
flagsWslTitle: "
|
|
2934
|
+
flagsWslTitle: "Append the recommended WSL<->Windows flags",
|
|
1390
2935
|
openWindowsChrome: "Prelaunch Windows Chrome",
|
|
1391
|
-
openWindowsChromeTitle: "
|
|
1392
|
-
openWindowsChromeBusy: "
|
|
1393
|
-
windowsChromeNotWsl: "Windows Chrome
|
|
1394
|
-
windowsChromeNotFound: "No
|
|
1395
|
-
windowsChromeUnreachable: "
|
|
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.",
|
|
1396
2941
|
connectModeLabel: "Connect mode",
|
|
1397
|
-
connectModeHint: "
|
|
2942
|
+
connectModeHint: "Connect mode: the connection launches no local Chrome (it connects with --browserUrl / --wsEndpoint); the local selection stays put.",
|
|
1398
2943
|
reduceLabel: "Reduce log output",
|
|
1399
|
-
reduceTitle: "Capture the
|
|
1400
|
-
reduceHint: "Captures stderr into the plugin's log file. Turn it off to debug the raw
|
|
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.",
|
|
1401
2954
|
docsMessage: "Find the complete list of server parameters (e.g., --headless, --isolated, --slim) and how to configure WebSocket connections in the Configuration Guide.",
|
|
1402
2955
|
docsLinkLabel: "Configuration Guide",
|
|
1403
2956
|
statusError: "Error",
|
|
1404
2957
|
statusOk: "OK",
|
|
1405
2958
|
chromeMissing: "Chrome executable not found",
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
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."
|
|
1409
2965
|
};
|
|
1410
2966
|
|
|
1411
2967
|
// src/client/locales/index.ts
|
|
1412
|
-
var
|
|
2968
|
+
var DICTIONARIES2 = { en };
|
|
1413
2969
|
|
|
1414
2970
|
// src/client/styles/index.ts
|
|
1415
2971
|
var CARD_CSS_ID = PLUGIN_ID + "/ChromeMcpCard.module.css";
|
|
1416
|
-
function
|
|
2972
|
+
function injectCardStyles2() {
|
|
1417
2973
|
if (typeof document === "undefined") return;
|
|
1418
2974
|
if (document.querySelector('style[data-plugin-css="' + CARD_CSS_ID + '"]') !== null) return;
|
|
1419
2975
|
const styleTag = document.createElement("style");
|
|
1420
2976
|
styleTag.dataset.plugin = PLUGIN_ID;
|
|
1421
2977
|
styleTag.dataset.pluginCss = CARD_CSS_ID;
|
|
1422
|
-
styleTag.textContent =
|
|
2978
|
+
styleTag.textContent = cssText2;
|
|
1423
2979
|
document.head.appendChild(styleTag);
|
|
1424
2980
|
}
|
|
1425
2981
|
|
|
1426
|
-
// src/client/
|
|
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;
|
|
1427
3015
|
function apply(ctx) {
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
const binder = ctx.settingsScope;
|
|
1431
|
-
const scope = binder.bind({ namespace: SETTINGS_NAMESPACE });
|
|
1432
|
-
const controller = new ChromeMcpCardController(scope, binder.describe());
|
|
1433
|
-
ctx.effect(
|
|
1434
|
-
() => () => controller.dispose(),
|
|
1435
|
-
`${SETTINGS_NAMESPACE}: card controller`
|
|
1436
|
-
);
|
|
1437
|
-
ctx.slots.inject("settings.plugin.item", () => ctx.slots.register(
|
|
1438
|
-
{
|
|
1439
|
-
name: "settings.plugin.item",
|
|
1440
|
-
key: SETTINGS_NAMESPACE,
|
|
1441
|
-
locale: LOCALE_NAMESPACE,
|
|
1442
|
-
inject: () => controller.inject()
|
|
1443
|
-
},
|
|
1444
|
-
ChromeMcpCard
|
|
1445
|
-
));
|
|
3016
|
+
injectCardStyles2();
|
|
3017
|
+
card.apply(ctx);
|
|
1446
3018
|
}
|
|
1447
3019
|
return module.exports;
|
|
1448
3020
|
}
|