@n24q02m/mcp-core 1.19.0 → 1.20.0-beta.1
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 +91 -1
- package/build/auth/credential-form.d.ts +49 -5
- package/build/auth/credential-form.d.ts.map +1 -1
- package/build/auth/credential-form.js +939 -5
- package/build/auth/credential-form.js.map +1 -1
- package/build/schema/types.d.ts +25 -0
- package/build/schema/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,6 +33,7 @@
|
|
|
33
33
|
- [What you get](#what-you-get)
|
|
34
34
|
- [Quick start (Python)](#quick-start-python)
|
|
35
35
|
- [Quick start (TypeScript)](#quick-start-typescript)
|
|
36
|
+
- [CLI](#cli)
|
|
36
37
|
- [Documentation](#documentation)
|
|
37
38
|
- [Development](#development)
|
|
38
39
|
- [License](#license)
|
|
@@ -192,6 +193,95 @@ await http.connect()
|
|
|
192
193
|
// Then mount http.handleRequest(req, res) on your http.Server / Express / Hono.
|
|
193
194
|
```
|
|
194
195
|
|
|
196
|
+
## CLI
|
|
197
|
+
|
|
198
|
+
`mcp_core.cli.build_cli` (re-exported as `from mcp_core import build_cli`) is the
|
|
199
|
+
console-script builder every Python MCP server mounts as its entry point. It wraps
|
|
200
|
+
a server's existing `serve(argv) -> int | None` function with subcommand dispatch,
|
|
201
|
+
so every server exposes the **same** operator subcommands for free while `serve`'s
|
|
202
|
+
own behaviour stays byte-for-byte unchanged. It has no TypeScript counterpart.
|
|
203
|
+
|
|
204
|
+
A downstream server mounts it as its console script:
|
|
205
|
+
|
|
206
|
+
```python
|
|
207
|
+
# wet_mcp/cli.py
|
|
208
|
+
from mcp_core import build_cli
|
|
209
|
+
|
|
210
|
+
def main() -> int:
|
|
211
|
+
return build_cli("wet-mcp", serve=_serve, extra=_extras(), version=_version())(None)
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
```toml
|
|
215
|
+
# pyproject.toml
|
|
216
|
+
[project.scripts]
|
|
217
|
+
wet-mcp = "wet_mcp.cli:main"
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
### Dispatch rules
|
|
221
|
+
|
|
222
|
+
`build_cli(...)` returns `run(argv=None) -> int`, which inspects `argv[0]`:
|
|
223
|
+
|
|
224
|
+
- **No args** — start the server (`serve([])`), the normal stdio launch.
|
|
225
|
+
- **A flag** (`--http`, ...) — passed byte-for-byte to `serve`; existing flag
|
|
226
|
+
semantics are untouched.
|
|
227
|
+
- **`-h` / `--help`** — print the subcommand list and exit without starting the
|
|
228
|
+
server (which would otherwise hang waiting on stdin in stdio mode).
|
|
229
|
+
- **`--version` / `-V`** — print `<server> <version>`, but only when `version=` is
|
|
230
|
+
passed; otherwise it falls through to `serve` like any other flag.
|
|
231
|
+
- **A positional name** — routed as a subcommand through argparse; an unknown name
|
|
232
|
+
exits `2`.
|
|
233
|
+
|
|
234
|
+
STDOUT is the MCP protocol channel in stdio mode, so only the subcommand path prints
|
|
235
|
+
to stdout: informational results (status, session details, `doctor`'s
|
|
236
|
+
`[ok]`/`[warn]`/`[fail]` lines) go to stdout, while failures and prompts go to stderr
|
|
237
|
+
with a non-zero exit code. Credential **values** are never printed — only names, keys,
|
|
238
|
+
and status.
|
|
239
|
+
|
|
240
|
+
### Built-in subcommands
|
|
241
|
+
|
|
242
|
+
Every server gets three reserved subcommands without writing any code:
|
|
243
|
+
|
|
244
|
+
| Subcommand | Purpose |
|
|
245
|
+
|---|---|
|
|
246
|
+
| `config status` | Report whether a config is stored: `configured`, `not configured`, or `corrupt` (undecryptable). |
|
|
247
|
+
| `config delete [--yes]` | Delete the stored config. Prompts to confirm; `--yes` skips the prompt and is required in non-interactive mode. |
|
|
248
|
+
| `relay status` | Show the active relay session (id prefix, relay URL, age) or report that none is active. |
|
|
249
|
+
| `relay open` | Open the active relay URL in a browser. |
|
|
250
|
+
| `relay reset` | Clear the relay session lock and the stored transport mode. |
|
|
251
|
+
| `doctor` | Environment diagnostics — Python 3.13, credential-backend init, store-dir writability, config state, relay session, transport mode. Exits non-zero on any `[fail]`. |
|
|
252
|
+
|
|
253
|
+
```bash
|
|
254
|
+
wet-mcp doctor
|
|
255
|
+
wet-mcp config status
|
|
256
|
+
wet-mcp relay status
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
### Server-specific subcommands (`extra`)
|
|
260
|
+
|
|
261
|
+
`build_cli(..., extra=...)` adds server-specific subcommands. Names in `extra` take
|
|
262
|
+
precedence over the built-ins, so a server can replace `config` / `relay` / `doctor`
|
|
263
|
+
with its own wiring. Each `extra` value is one of two shapes:
|
|
264
|
+
|
|
265
|
+
```python
|
|
266
|
+
ExtraHandler = Callable[[argparse.Namespace], int]
|
|
267
|
+
ExtraSpec = ExtraHandler | tuple[Callable[[argparse.ArgumentParser], None], ExtraHandler]
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
- A **bare handler** — registered as an argument-less subcommand.
|
|
271
|
+
- A **`(configure, handler)` tuple** — `configure` receives that subcommand's own
|
|
272
|
+
`argparse.ArgumentParser` to add positionals/flags before argv is parsed, then
|
|
273
|
+
`handler` receives the parsed `Namespace` and returns the exit code.
|
|
274
|
+
|
|
275
|
+
wet-mcp, for example, registers one bare handler and two configured ones:
|
|
276
|
+
|
|
277
|
+
```python
|
|
278
|
+
extra = {
|
|
279
|
+
"warmup": _handle_warmup, # wet-mcp warmup
|
|
280
|
+
"auth": (_configure_auth, _handle_auth), # wet-mcp auth google [--client-id ...]
|
|
281
|
+
"docs": (_configure_docs, _handle_docs), # wet-mcp docs reindex <library>
|
|
282
|
+
}
|
|
283
|
+
```
|
|
284
|
+
|
|
195
285
|
## Documentation
|
|
196
286
|
|
|
197
287
|
Full docs at **[mcp.n24q02m.com/servers/mcp-core/architecture/](https://mcp.n24q02m.com/servers/mcp-core/architecture/)** (Foundation library section in the MCP n24q02m unified docs site):
|
|
@@ -225,4 +315,4 @@ bun run build
|
|
|
225
315
|
|
|
226
316
|
## License
|
|
227
317
|
|
|
228
|
-
MIT
|
|
318
|
+
MIT
|
|
@@ -16,6 +16,8 @@ export interface ConfigField {
|
|
|
16
16
|
helpText?: string;
|
|
17
17
|
helpUrl?: string;
|
|
18
18
|
required?: boolean;
|
|
19
|
+
/** Regex string for client-side validation; rendered as the input's `pattern` attribute. */
|
|
20
|
+
validation?: string;
|
|
19
21
|
}
|
|
20
22
|
/**
|
|
21
23
|
* Return true iff every required field in `schema` has a non-empty value in
|
|
@@ -32,12 +34,39 @@ export interface CapabilityInfo {
|
|
|
32
34
|
priority?: string;
|
|
33
35
|
description?: string;
|
|
34
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* A credential-form tab (schema-level `tabs` capability). Each tab is a
|
|
39
|
+
* mutually-exclusive credential mode; only the active tab's fields submit.
|
|
40
|
+
*/
|
|
41
|
+
export interface TabGroup {
|
|
42
|
+
id: string;
|
|
43
|
+
label: string;
|
|
44
|
+
fields: ConfigField[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A repeatable field group (schema-level `cardGroup` capability). Renders
|
|
48
|
+
* Add/Remove cards, each cloning `fields`; submitted as a JSON array under
|
|
49
|
+
* `key` (e.g. `{ accounts: [{...}, {...}] }`).
|
|
50
|
+
*/
|
|
51
|
+
export interface CardGroup {
|
|
52
|
+
key: string;
|
|
53
|
+
fields: ConfigField[];
|
|
54
|
+
itemLabel?: string;
|
|
55
|
+
heading?: string;
|
|
56
|
+
addButtonLabel?: string;
|
|
57
|
+
minItems?: number;
|
|
58
|
+
titleField?: string;
|
|
59
|
+
}
|
|
35
60
|
export interface RelayConfigSchema {
|
|
36
61
|
server: string;
|
|
37
62
|
displayName?: string;
|
|
38
63
|
description?: string;
|
|
39
|
-
fields
|
|
64
|
+
fields?: ConfigField[];
|
|
40
65
|
capabilityInfo?: CapabilityInfo[];
|
|
66
|
+
/** Mutually-exclusive credential modes; see the tabbed render path. */
|
|
67
|
+
tabs?: TabGroup[];
|
|
68
|
+
/** One repeatable field group; see the card-group render path. */
|
|
69
|
+
cardGroup?: CardGroup;
|
|
41
70
|
}
|
|
42
71
|
export interface RenderOptions {
|
|
43
72
|
submitUrl: string;
|
|
@@ -50,14 +79,29 @@ export interface RenderOptions {
|
|
|
50
79
|
* keys are ignored.
|
|
51
80
|
*/
|
|
52
81
|
prefill?: Record<string, string>;
|
|
82
|
+
/**
|
|
83
|
+
* For a `tabs` schema, the id of the tab to render active on load (defaults
|
|
84
|
+
* to the first tab). Ignored for non-tabbed schemas.
|
|
85
|
+
*/
|
|
86
|
+
initialTab?: string;
|
|
87
|
+
/**
|
|
88
|
+
* Opt-in workspace-username field (multi-user stable-sub). Honoured by the
|
|
89
|
+
* `tabs` and `cardGroup` render paths.
|
|
90
|
+
*/
|
|
91
|
+
includeUsernameField?: boolean;
|
|
53
92
|
}
|
|
54
93
|
/**
|
|
55
94
|
* Wrap `bodyHtml` in the shared dark-theme HTML shell.
|
|
56
95
|
*
|
|
57
|
-
* The shell provides `<!DOCTYPE html>`, `<head>` (charset, viewport,
|
|
58
|
-
* `<title>`, embedded `FORM_SHELL_CSS`)
|
|
59
|
-
* `bodyHtml`. `bodyHtml` is inserted
|
|
60
|
-
* untrusted values they interpolate.
|
|
96
|
+
* The shell provides `<!DOCTYPE html>`, `<head>` (charset, viewport, a
|
|
97
|
+
* Content-Security-Policy meta, escaped `<title>`, embedded `FORM_SHELL_CSS`)
|
|
98
|
+
* and a `<body>` whose only child is `bodyHtml`. `bodyHtml` is inserted
|
|
99
|
+
* verbatim, so callers MUST pre-escape any untrusted values they interpolate.
|
|
100
|
+
*
|
|
101
|
+
* The CSP (`default-src 'none'; style-src 'unsafe-inline'; script-src
|
|
102
|
+
* 'unsafe-inline'; connect-src 'self'`) permits the page's own inline
|
|
103
|
+
* `<style>`/`<script>` and same-origin `fetch` submits while blocking any
|
|
104
|
+
* external resource load.
|
|
61
105
|
*
|
|
62
106
|
* `title` is HTML-escaped before being placed in `<title>`.
|
|
63
107
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credential-form.d.ts","sourceRoot":"","sources":["../../src/auth/credential-form.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"credential-form.d.ts","sourceRoot":"","sources":["../../src/auth/credential-form.ts"],"names":[],"mappings":"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"}
|
|
@@ -388,14 +388,86 @@ const FORM_SHELL_CSS = ` *, *::before, *::after {
|
|
|
388
388
|
font-size: 0.8125rem;
|
|
389
389
|
color: #9ca3af;
|
|
390
390
|
}
|
|
391
|
+
|
|
392
|
+
:root {
|
|
393
|
+
color-scheme: light dark;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
@media (prefers-color-scheme: light) {
|
|
397
|
+
body {
|
|
398
|
+
background-color: #f4f5f7;
|
|
399
|
+
color: #1f2937;
|
|
400
|
+
}
|
|
401
|
+
.card {
|
|
402
|
+
background-color: #ffffff;
|
|
403
|
+
border-color: #e5e7eb;
|
|
404
|
+
}
|
|
405
|
+
.server-name {
|
|
406
|
+
color: #111827;
|
|
407
|
+
}
|
|
408
|
+
.server-id,
|
|
409
|
+
.server-description,
|
|
410
|
+
.help-text,
|
|
411
|
+
.mc-badge,
|
|
412
|
+
.form-title,
|
|
413
|
+
.capabilities-title,
|
|
414
|
+
.capability-desc {
|
|
415
|
+
color: #6b7280;
|
|
416
|
+
}
|
|
417
|
+
.field-label,
|
|
418
|
+
.capability-label {
|
|
419
|
+
color: #374151;
|
|
420
|
+
}
|
|
421
|
+
.field-input {
|
|
422
|
+
background-color: #ffffff;
|
|
423
|
+
border-color: #d1d5db;
|
|
424
|
+
color: #1f2937;
|
|
425
|
+
}
|
|
426
|
+
.field-input::placeholder {
|
|
427
|
+
color: #9ca3af;
|
|
428
|
+
}
|
|
429
|
+
.field-input:disabled {
|
|
430
|
+
background-color: #f3f4f6;
|
|
431
|
+
}
|
|
432
|
+
.optional-badge {
|
|
433
|
+
color: #6b7280;
|
|
434
|
+
background-color: #f3f4f6;
|
|
435
|
+
border-color: #d1d5db;
|
|
436
|
+
}
|
|
437
|
+
.capability-item {
|
|
438
|
+
background-color: #f9fafb;
|
|
439
|
+
border-color: #e5e7eb;
|
|
440
|
+
}
|
|
441
|
+
.model-chain {
|
|
442
|
+
background: #f9fafb;
|
|
443
|
+
border-color: #d1d5db;
|
|
444
|
+
}
|
|
445
|
+
.mc-chip {
|
|
446
|
+
background: #eef1f6;
|
|
447
|
+
border-color: #d1d5db;
|
|
448
|
+
}
|
|
449
|
+
.mc-dropdown {
|
|
450
|
+
background: #ffffff;
|
|
451
|
+
border-color: #d1d5db;
|
|
452
|
+
}
|
|
453
|
+
.mc-dropdown label:hover,
|
|
454
|
+
.mc-dropdown label:focus-within {
|
|
455
|
+
background: #eef1f6;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
391
458
|
`;
|
|
392
459
|
/**
|
|
393
460
|
* Wrap `bodyHtml` in the shared dark-theme HTML shell.
|
|
394
461
|
*
|
|
395
|
-
* The shell provides `<!DOCTYPE html>`, `<head>` (charset, viewport,
|
|
396
|
-
* `<title>`, embedded `FORM_SHELL_CSS`)
|
|
397
|
-
* `bodyHtml`. `bodyHtml` is inserted
|
|
398
|
-
* untrusted values they interpolate.
|
|
462
|
+
* The shell provides `<!DOCTYPE html>`, `<head>` (charset, viewport, a
|
|
463
|
+
* Content-Security-Policy meta, escaped `<title>`, embedded `FORM_SHELL_CSS`)
|
|
464
|
+
* and a `<body>` whose only child is `bodyHtml`. `bodyHtml` is inserted
|
|
465
|
+
* verbatim, so callers MUST pre-escape any untrusted values they interpolate.
|
|
466
|
+
*
|
|
467
|
+
* The CSP (`default-src 'none'; style-src 'unsafe-inline'; script-src
|
|
468
|
+
* 'unsafe-inline'; connect-src 'self'`) permits the page's own inline
|
|
469
|
+
* `<style>`/`<script>` and same-origin `fetch` submits while blocking any
|
|
470
|
+
* external resource load.
|
|
399
471
|
*
|
|
400
472
|
* `title` is HTML-escaped before being placed in `<title>`.
|
|
401
473
|
*
|
|
@@ -412,6 +484,7 @@ export function renderFormShell(title, bodyHtml) {
|
|
|
412
484
|
<head>
|
|
413
485
|
<meta charset="UTF-8" />
|
|
414
486
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
487
|
+
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; script-src 'unsafe-inline'; connect-src 'self'" />
|
|
415
488
|
<title>${safeTitle}</title>
|
|
416
489
|
<style>
|
|
417
490
|
${FORM_SHELL_CSS} </style>
|
|
@@ -434,6 +507,7 @@ function renderField(field, value = '') {
|
|
|
434
507
|
? '<span class="required-badge" aria-hidden="true">Required</span>'
|
|
435
508
|
: '<span class="optional-badge" aria-hidden="true">Optional</span>';
|
|
436
509
|
const valueAttr = value ? ` value="${escapeHtml(value)}"` : '';
|
|
510
|
+
const patternAttr = field.validation ? ` pattern="${escapeHtml(field.validation)}"` : '';
|
|
437
511
|
let helpHtml = '';
|
|
438
512
|
let ariaDescribedby = '';
|
|
439
513
|
if (helpText) {
|
|
@@ -460,7 +534,7 @@ function renderField(field, value = '') {
|
|
|
460
534
|
autocomplete="off"
|
|
461
535
|
autocorrect="off"
|
|
462
536
|
autocapitalize="off"
|
|
463
|
-
spellcheck="false"${valueAttr}${requiredAttr}${ariaDescribedby}
|
|
537
|
+
spellcheck="false"${valueAttr}${patternAttr}${requiredAttr}${ariaDescribedby}
|
|
464
538
|
/>
|
|
465
539
|
${helpHtml}
|
|
466
540
|
</div>`;
|
|
@@ -480,6 +554,858 @@ function renderCapability(cap) {
|
|
|
480
554
|
${descHtml}
|
|
481
555
|
</li>`;
|
|
482
556
|
}
|
|
557
|
+
// ===========================================================================
|
|
558
|
+
// Schema-level tabs + dynamic card group (W4.1)
|
|
559
|
+
// ---------------------------------------------------------------------------
|
|
560
|
+
// Two OPT-IN capabilities that let servers declare richer credential UIs
|
|
561
|
+
// through the schema alone (no forked renderer):
|
|
562
|
+
// * `tabs` -> mutually-exclusive credential modes (e.g. telegram
|
|
563
|
+
// bot-token vs phone/OTP), only the active tab submits.
|
|
564
|
+
// * `cardGroup` -> a repeatable field group with Add/Remove (e.g. email
|
|
565
|
+
// multi-account), submitted as a JSON array.
|
|
566
|
+
// A schema that declares NEITHER key renders through the unchanged flat-field
|
|
567
|
+
// path in `renderCredentialForm` below, byte-for-byte identical to before.
|
|
568
|
+
// The feature CSS ships as a `<style>` block inside the body — only when the
|
|
569
|
+
// feature is used — so the shared `FORM_SHELL_CSS` (and the flat form) stay
|
|
570
|
+
// untouched. Kept in parity with core-py `credential_form.py`.
|
|
571
|
+
// ===========================================================================
|
|
572
|
+
// Tab CSS (scoped `.tabs`/`.tab`/`.tab-panel`); emitted in-body only for
|
|
573
|
+
// tabbed forms. Palette mirrors the shared shell so tabs blend into the card.
|
|
574
|
+
const TABS_CSS = ` <style>
|
|
575
|
+
.tabs {
|
|
576
|
+
display: flex;
|
|
577
|
+
gap: 0;
|
|
578
|
+
margin-bottom: 1.5rem;
|
|
579
|
+
border-bottom: 1px solid #2a2a2a;
|
|
580
|
+
}
|
|
581
|
+
.tab {
|
|
582
|
+
flex: 1;
|
|
583
|
+
padding: 0.75rem 1rem;
|
|
584
|
+
background: transparent;
|
|
585
|
+
border: none;
|
|
586
|
+
color: #9ca3af;
|
|
587
|
+
cursor: pointer;
|
|
588
|
+
font-size: 0.9rem;
|
|
589
|
+
font-weight: 500;
|
|
590
|
+
border-bottom: 2px solid transparent;
|
|
591
|
+
transition: color 0.15s ease, border-color 0.15s ease;
|
|
592
|
+
font-family: inherit;
|
|
593
|
+
}
|
|
594
|
+
.tab:not(:disabled):hover {
|
|
595
|
+
color: #ccc;
|
|
596
|
+
}
|
|
597
|
+
.tab:focus-visible {
|
|
598
|
+
outline: 2px solid #4a6fa5;
|
|
599
|
+
outline-offset: -2px;
|
|
600
|
+
border-radius: 4px;
|
|
601
|
+
}
|
|
602
|
+
.tab.active {
|
|
603
|
+
color: #fff;
|
|
604
|
+
border-bottom-color: #4a6fa5;
|
|
605
|
+
}
|
|
606
|
+
.tab:disabled {
|
|
607
|
+
cursor: not-allowed;
|
|
608
|
+
opacity: 0.5;
|
|
609
|
+
}
|
|
610
|
+
.tab-panel {
|
|
611
|
+
display: none;
|
|
612
|
+
}
|
|
613
|
+
.tab-panel.active {
|
|
614
|
+
display: block;
|
|
615
|
+
}
|
|
616
|
+
@media (prefers-color-scheme: light) {
|
|
617
|
+
.tabs {
|
|
618
|
+
border-bottom-color: #e5e7eb;
|
|
619
|
+
}
|
|
620
|
+
.tab {
|
|
621
|
+
color: #6b7280;
|
|
622
|
+
}
|
|
623
|
+
.tab:not(:disabled):hover {
|
|
624
|
+
color: #374151;
|
|
625
|
+
}
|
|
626
|
+
.tab.active {
|
|
627
|
+
color: #111827;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
</style>
|
|
631
|
+
`;
|
|
632
|
+
// Card-group CSS (scoped `.card-group-*`); emitted in-body only for card
|
|
633
|
+
// forms. `.card-group-item` avoids the shell's `.card` name deliberately.
|
|
634
|
+
const CARD_GROUP_CSS = ` <style>
|
|
635
|
+
.card-group-item {
|
|
636
|
+
border: 1px solid #2a2a2a;
|
|
637
|
+
border-radius: 10px;
|
|
638
|
+
padding: 1rem;
|
|
639
|
+
margin-bottom: 0.875rem;
|
|
640
|
+
background-color: #121212;
|
|
641
|
+
}
|
|
642
|
+
.card-group-header {
|
|
643
|
+
display: flex;
|
|
644
|
+
justify-content: space-between;
|
|
645
|
+
align-items: center;
|
|
646
|
+
margin-bottom: 0.75rem;
|
|
647
|
+
}
|
|
648
|
+
.card-group-title {
|
|
649
|
+
font-size: 0.95rem;
|
|
650
|
+
font-weight: 600;
|
|
651
|
+
color: #ddd;
|
|
652
|
+
max-width: 300px;
|
|
653
|
+
white-space: nowrap;
|
|
654
|
+
overflow: hidden;
|
|
655
|
+
text-overflow: ellipsis;
|
|
656
|
+
}
|
|
657
|
+
.card-group-remove {
|
|
658
|
+
background: transparent;
|
|
659
|
+
color: #f87171;
|
|
660
|
+
border: 1px solid rgba(248, 113, 113, 0.3);
|
|
661
|
+
border-radius: 6px;
|
|
662
|
+
padding: 0.25rem 0.6rem;
|
|
663
|
+
cursor: pointer;
|
|
664
|
+
font-size: 0.75rem;
|
|
665
|
+
font-family: inherit;
|
|
666
|
+
}
|
|
667
|
+
.card-group-remove:hover:not(:disabled) {
|
|
668
|
+
background-color: rgba(248, 113, 113, 0.08);
|
|
669
|
+
}
|
|
670
|
+
.card-group-remove:focus-visible {
|
|
671
|
+
outline: 2px solid #f87171;
|
|
672
|
+
outline-offset: 2px;
|
|
673
|
+
}
|
|
674
|
+
.card-group-add {
|
|
675
|
+
width: 100%;
|
|
676
|
+
background-color: transparent;
|
|
677
|
+
color: #6c9bd2;
|
|
678
|
+
border: 1px dashed #3a5a8a;
|
|
679
|
+
border-radius: 8px;
|
|
680
|
+
padding: 0.625rem 1rem;
|
|
681
|
+
cursor: pointer;
|
|
682
|
+
font-size: 0.875rem;
|
|
683
|
+
margin-bottom: 1rem;
|
|
684
|
+
font-family: inherit;
|
|
685
|
+
transition: background-color 0.15s ease, border-color 0.15s ease;
|
|
686
|
+
}
|
|
687
|
+
.card-group-add:hover:not(:disabled) {
|
|
688
|
+
background-color: rgba(108, 155, 210, 0.08);
|
|
689
|
+
border-color: #4a6fa5;
|
|
690
|
+
}
|
|
691
|
+
.card-group-add:focus-visible {
|
|
692
|
+
outline: 2px solid #6c9bd2;
|
|
693
|
+
outline-offset: 2px;
|
|
694
|
+
}
|
|
695
|
+
.card-group-add:disabled {
|
|
696
|
+
opacity: 0.5;
|
|
697
|
+
cursor: not-allowed;
|
|
698
|
+
border-color: #2a3a4a;
|
|
699
|
+
}
|
|
700
|
+
@media (prefers-color-scheme: light) {
|
|
701
|
+
.card-group-item {
|
|
702
|
+
background-color: #f9fafb;
|
|
703
|
+
border-color: #e5e7eb;
|
|
704
|
+
}
|
|
705
|
+
.card-group-title {
|
|
706
|
+
color: #374151;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
</style>
|
|
710
|
+
`;
|
|
711
|
+
// Multi-step (OTP / 2FA) step-input UI, shared by tab forms. Mirrors the flat
|
|
712
|
+
// form's `showStepInput`/`submitStep` semantics (same `/otp` POST, same
|
|
713
|
+
// redirect-follow on completion) so a tabbed server's phone->OTP->2FA chain
|
|
714
|
+
// behaves identically to the default form.
|
|
715
|
+
const STEP_UI_JS = `
|
|
716
|
+
function showStepInput(ns) {
|
|
717
|
+
if (form && form.style.display !== "none") { form.style.display = "none"; }
|
|
718
|
+
var tabsEl = document.querySelector(".tabs");
|
|
719
|
+
if (tabsEl) { tabsEl.style.display = "none"; }
|
|
720
|
+
var container = document.getElementById("step-container");
|
|
721
|
+
var promptEl, inputEl, buttonEl, errorEl;
|
|
722
|
+
if (container) {
|
|
723
|
+
promptEl = document.getElementById("step-prompt");
|
|
724
|
+
inputEl = document.getElementById("step-input");
|
|
725
|
+
buttonEl = document.getElementById("step-submit");
|
|
726
|
+
errorEl = document.getElementById("step-error");
|
|
727
|
+
errorEl.style.display = "none"; errorEl.textContent = "";
|
|
728
|
+
inputEl.value = ""; inputEl.disabled = false;
|
|
729
|
+
buttonEl.disabled = false; buttonEl.removeAttribute("aria-busy"); buttonEl.textContent = "Verify";
|
|
730
|
+
} else {
|
|
731
|
+
var card = form.parentNode;
|
|
732
|
+
container = document.createElement("div"); container.id = "step-container";
|
|
733
|
+
promptEl = document.createElement("label"); promptEl.id = "step-prompt";
|
|
734
|
+
promptEl.setAttribute("for", "step-input"); promptEl.className = "form-title";
|
|
735
|
+
container.appendChild(promptEl);
|
|
736
|
+
var fieldGroup = document.createElement("div"); fieldGroup.className = "field-group";
|
|
737
|
+
inputEl = document.createElement("input"); inputEl.id = "step-input"; inputEl.className = "field-input";
|
|
738
|
+
inputEl.setAttribute("autocomplete", "off"); inputEl.setAttribute("autocorrect", "off");
|
|
739
|
+
inputEl.setAttribute("autocapitalize", "off"); inputEl.setAttribute("spellcheck", "false");
|
|
740
|
+
fieldGroup.appendChild(inputEl); container.appendChild(fieldGroup);
|
|
741
|
+
buttonEl = document.createElement("button"); buttonEl.type = "button"; buttonEl.id = "step-submit";
|
|
742
|
+
buttonEl.className = "submit-btn"; buttonEl.textContent = "Verify"; container.appendChild(buttonEl);
|
|
743
|
+
errorEl = document.createElement("div"); errorEl.id = "step-error"; errorEl.className = "status-box error";
|
|
744
|
+
errorEl.setAttribute("role", "alert"); errorEl.style.display = "none"; container.appendChild(errorEl);
|
|
745
|
+
card.appendChild(container);
|
|
746
|
+
buttonEl.addEventListener("click", function () { submitStep(); });
|
|
747
|
+
inputEl.addEventListener("keydown", function (evt) { if (evt.key === "Enter") { evt.preventDefault(); submitStep(); } });
|
|
748
|
+
inputEl.addEventListener("input", function () { inputEl.removeAttribute("aria-invalid"); inputEl.removeAttribute("aria-errormessage"); errorEl.style.display = "none"; });
|
|
749
|
+
}
|
|
750
|
+
promptEl.textContent = ns.text || "";
|
|
751
|
+
inputEl.setAttribute("type", ns.input_type || "text");
|
|
752
|
+
inputEl.setAttribute("placeholder", ns.placeholder || "");
|
|
753
|
+
inputEl.dataset.field = ns.field || "value";
|
|
754
|
+
inputEl.focus();
|
|
755
|
+
}
|
|
756
|
+
function submitStep() {
|
|
757
|
+
var inputEl = document.getElementById("step-input");
|
|
758
|
+
var buttonEl = document.getElementById("step-submit");
|
|
759
|
+
var errorEl = document.getElementById("step-error");
|
|
760
|
+
var fieldName = inputEl.dataset.field || "value";
|
|
761
|
+
var value = inputEl.value;
|
|
762
|
+
inputEl.removeAttribute("aria-invalid");
|
|
763
|
+
if (value.trim() === "") {
|
|
764
|
+
errorEl.textContent = "Please enter a value."; errorEl.style.display = "block";
|
|
765
|
+
inputEl.setAttribute("aria-invalid", "true"); inputEl.setAttribute("aria-errormessage", "step-error");
|
|
766
|
+
inputEl.focus(); return;
|
|
767
|
+
}
|
|
768
|
+
errorEl.style.display = "none"; errorEl.textContent = "";
|
|
769
|
+
buttonEl.disabled = true; buttonEl.textContent = "Verifying..."; buttonEl.setAttribute("aria-busy", "true");
|
|
770
|
+
inputEl.disabled = true;
|
|
771
|
+
var body = {}; body[fieldName] = value;
|
|
772
|
+
fetch(otpUrl(), { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(body) })
|
|
773
|
+
.then(function (response) { return response.json().then(function (data) {
|
|
774
|
+
if (data.ok) {
|
|
775
|
+
if (data.next_step && (data.next_step.type === "otp_required" || data.next_step.type === "password_required")) {
|
|
776
|
+
showStepInput(data.next_step);
|
|
777
|
+
} else if (typeof data.redirect_url === "string" && data.redirect_url.length > 0) {
|
|
778
|
+
var c = document.getElementById("step-container"); while (c.firstChild) { c.removeChild(c.firstChild); }
|
|
779
|
+
var done = document.createElement("div"); done.className = "status-box success"; done.style.display = "block";
|
|
780
|
+
done.setAttribute("role", "alert"); done.textContent = "Setup complete! Redirecting..."; c.appendChild(done);
|
|
781
|
+
window.location.replace(data.redirect_url);
|
|
782
|
+
} else {
|
|
783
|
+
var c2 = document.getElementById("step-container"); while (c2.firstChild) { c2.removeChild(c2.firstChild); }
|
|
784
|
+
var done2 = document.createElement("div"); done2.className = "status-box success"; done2.style.display = "block";
|
|
785
|
+
done2.setAttribute("role", "alert"); done2.textContent = "Setup complete! You can close this tab."; c2.appendChild(done2);
|
|
786
|
+
}
|
|
787
|
+
} else {
|
|
788
|
+
errorEl.textContent = data.error || data.error_description || "Verification failed."; errorEl.style.display = "block";
|
|
789
|
+
inputEl.disabled = false; inputEl.setAttribute("aria-invalid", "true"); inputEl.setAttribute("aria-errormessage", "step-error");
|
|
790
|
+
buttonEl.disabled = false; buttonEl.textContent = "Verify"; buttonEl.removeAttribute("aria-busy"); inputEl.focus();
|
|
791
|
+
}
|
|
792
|
+
}); })
|
|
793
|
+
.catch(function (err) {
|
|
794
|
+
errorEl.textContent = "Network error: " + err.message; errorEl.style.display = "block";
|
|
795
|
+
inputEl.disabled = false; inputEl.setAttribute("aria-invalid", "true"); inputEl.setAttribute("aria-errormessage", "step-error");
|
|
796
|
+
buttonEl.disabled = false; buttonEl.textContent = "Verify"; buttonEl.removeAttribute("aria-busy"); inputEl.focus();
|
|
797
|
+
});
|
|
798
|
+
}
|
|
799
|
+
`;
|
|
800
|
+
// Tab form behaviour: tab switching (click + ARIA-tablist arrow keys), then a
|
|
801
|
+
// submit that collects ONLY the active panel's fields. `__SUBMIT_URL__` and
|
|
802
|
+
// `__INITIAL_TAB__` are substituted at render time; `STEP_UI_JS` is spliced in
|
|
803
|
+
// for OTP/2FA support.
|
|
804
|
+
const TABS_SCRIPT = ` <script>
|
|
805
|
+
(function () {
|
|
806
|
+
var form = document.getElementById("credential-form");
|
|
807
|
+
var submitBtn = document.getElementById("submit-btn");
|
|
808
|
+
var statusBox = document.getElementById("status-box");
|
|
809
|
+
var submitUrl = "__SUBMIT_URL__";
|
|
810
|
+
var activeTab = "__INITIAL_TAB__";
|
|
811
|
+
var tabs = document.querySelectorAll(".tab");
|
|
812
|
+
var tabsArray = Array.prototype.slice.call(tabs);
|
|
813
|
+
var pendingRedirectUrl = null;
|
|
814
|
+
|
|
815
|
+
function showStatus(type, message) {
|
|
816
|
+
statusBox.className = "status-box " + type;
|
|
817
|
+
statusBox.textContent = message;
|
|
818
|
+
statusBox.style.display = "block";
|
|
819
|
+
}
|
|
820
|
+
function otpUrl() {
|
|
821
|
+
return submitUrl.replace(/\\/authorize.*/, "/otp");
|
|
822
|
+
}
|
|
823
|
+
${STEP_UI_JS}
|
|
824
|
+
tabs.forEach(function (tab, index) {
|
|
825
|
+
tab.addEventListener("click", function () {
|
|
826
|
+
if (tab.disabled) { return; }
|
|
827
|
+
activeTab = tab.dataset.tab;
|
|
828
|
+
tabs.forEach(function (t) {
|
|
829
|
+
t.classList.remove("active");
|
|
830
|
+
t.setAttribute("aria-selected", "false");
|
|
831
|
+
t.setAttribute("tabindex", "-1");
|
|
832
|
+
});
|
|
833
|
+
tab.classList.add("active");
|
|
834
|
+
tab.setAttribute("aria-selected", "true");
|
|
835
|
+
tab.setAttribute("tabindex", "0");
|
|
836
|
+
document.querySelectorAll(".tab-panel").forEach(function (p) { p.classList.remove("active"); });
|
|
837
|
+
var panel = document.querySelector('.tab-panel[data-panel="' + activeTab + '"]');
|
|
838
|
+
if (panel) { panel.classList.add("active"); }
|
|
839
|
+
statusBox.style.display = "none";
|
|
840
|
+
statusBox.textContent = "";
|
|
841
|
+
form.querySelectorAll(".field-input").forEach(function (i) { i.removeAttribute("aria-invalid"); });
|
|
842
|
+
});
|
|
843
|
+
tab.addEventListener("keydown", function (e) {
|
|
844
|
+
var targetIndex = -1;
|
|
845
|
+
if (e.key === "ArrowRight") { targetIndex = index + 1; if (targetIndex >= tabsArray.length) { targetIndex = 0; } }
|
|
846
|
+
else if (e.key === "ArrowLeft") { targetIndex = index - 1; if (targetIndex < 0) { targetIndex = tabsArray.length - 1; } }
|
|
847
|
+
if (targetIndex !== -1) { e.preventDefault(); tabsArray[targetIndex].focus(); tabsArray[targetIndex].click(); }
|
|
848
|
+
});
|
|
849
|
+
});
|
|
850
|
+
|
|
851
|
+
form.addEventListener("input", function (event) {
|
|
852
|
+
if (event.target.classList.contains("field-input")) {
|
|
853
|
+
event.target.removeAttribute("aria-invalid");
|
|
854
|
+
event.target.removeAttribute("aria-errormessage");
|
|
855
|
+
statusBox.style.display = "none";
|
|
856
|
+
}
|
|
857
|
+
});
|
|
858
|
+
|
|
859
|
+
form.addEventListener("submit", function (event) {
|
|
860
|
+
event.preventDefault();
|
|
861
|
+
var activePanel = document.querySelector(".tab-panel.active");
|
|
862
|
+
var inputs = activePanel ? activePanel.querySelectorAll(".field-input") : [];
|
|
863
|
+
var payload = {};
|
|
864
|
+
var valid = true;
|
|
865
|
+
var firstInvalid = null;
|
|
866
|
+
inputs.forEach(function (input) {
|
|
867
|
+
if (input.hasAttribute("required") && input.value.trim() === "") {
|
|
868
|
+
valid = false;
|
|
869
|
+
input.setAttribute("aria-invalid", "true");
|
|
870
|
+
input.setAttribute("aria-errormessage", "status-box");
|
|
871
|
+
if (!firstInvalid) { firstInvalid = input; }
|
|
872
|
+
} else {
|
|
873
|
+
input.removeAttribute("aria-invalid");
|
|
874
|
+
input.removeAttribute("aria-errormessage");
|
|
875
|
+
payload[input.name] = input.value;
|
|
876
|
+
}
|
|
877
|
+
});
|
|
878
|
+
if (!valid) {
|
|
879
|
+
showStatus("error", "Please fill in all required fields.");
|
|
880
|
+
if (firstInvalid) { firstInvalid.focus(); }
|
|
881
|
+
return;
|
|
882
|
+
}
|
|
883
|
+
submitBtn.disabled = true;
|
|
884
|
+
submitBtn.textContent = "Connecting...";
|
|
885
|
+
submitBtn.setAttribute("aria-busy", "true");
|
|
886
|
+
statusBox.style.display = "none";
|
|
887
|
+
tabs.forEach(function (t) { t.disabled = true; });
|
|
888
|
+
function reenable() {
|
|
889
|
+
submitBtn.disabled = false;
|
|
890
|
+
submitBtn.textContent = "Connect";
|
|
891
|
+
submitBtn.removeAttribute("aria-busy");
|
|
892
|
+
form.querySelectorAll(".field-input").forEach(function (i) { i.disabled = false; });
|
|
893
|
+
tabs.forEach(function (t) { t.disabled = false; });
|
|
894
|
+
}
|
|
895
|
+
function lockConnected() {
|
|
896
|
+
form.querySelectorAll(".field-input").forEach(function (i) { i.disabled = true; });
|
|
897
|
+
submitBtn.disabled = true;
|
|
898
|
+
submitBtn.removeAttribute("aria-busy");
|
|
899
|
+
submitBtn.textContent = "Connected";
|
|
900
|
+
}
|
|
901
|
+
fetch(submitUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) })
|
|
902
|
+
.then(function (response) { return response.json().then(function (data) {
|
|
903
|
+
if (data.ok) {
|
|
904
|
+
if (typeof data.redirect_url === "string" && data.redirect_url.length > 0) { pendingRedirectUrl = data.redirect_url; }
|
|
905
|
+
if (data.next_step && (data.next_step.type === "otp_required" || data.next_step.type === "password_required")) {
|
|
906
|
+
statusBox.style.display = "none";
|
|
907
|
+
showStepInput(data.next_step);
|
|
908
|
+
} else if (data.next_step && data.next_step.type === "info") {
|
|
909
|
+
lockConnected();
|
|
910
|
+
showStatus("success", data.next_step.message || "Setup saved. Additional steps may be required.");
|
|
911
|
+
} else if (pendingRedirectUrl) {
|
|
912
|
+
lockConnected();
|
|
913
|
+
showStatus("success", "Credentials saved. Redirecting...");
|
|
914
|
+
window.location.replace(pendingRedirectUrl);
|
|
915
|
+
} else {
|
|
916
|
+
lockConnected();
|
|
917
|
+
showStatus("success", data.message || "Connected successfully. You can close this window.");
|
|
918
|
+
}
|
|
919
|
+
} else {
|
|
920
|
+
showStatus("error", data.error || data.error_description || "Request failed.");
|
|
921
|
+
reenable();
|
|
922
|
+
}
|
|
923
|
+
}); })
|
|
924
|
+
.catch(function (err) {
|
|
925
|
+
showStatus("error", "Network error: " + err.message);
|
|
926
|
+
reenable();
|
|
927
|
+
});
|
|
928
|
+
});
|
|
929
|
+
})();
|
|
930
|
+
</script>`;
|
|
931
|
+
// Card-group behaviour: a JS builder that clones the declared fields per card,
|
|
932
|
+
// Add/Remove with focus management, and a submit that serialises every card into
|
|
933
|
+
// a JSON array under `__GROUP_KEY__`. All DOM is built with
|
|
934
|
+
// createElement/textContent/setAttribute (no innerHTML with user values).
|
|
935
|
+
const CARD_GROUP_SCRIPT = ` <script>
|
|
936
|
+
(function () {
|
|
937
|
+
var submitUrl = "__SUBMIT_URL__";
|
|
938
|
+
var CARD_FIELDS = __CARD_FIELDS__;
|
|
939
|
+
var GROUP_KEY = "__GROUP_KEY__";
|
|
940
|
+
var TITLE_FIELD = "__TITLE_FIELD__";
|
|
941
|
+
var ITEM_LABEL = "__ITEM_LABEL__";
|
|
942
|
+
var MIN_ITEMS = __MIN_ITEMS__;
|
|
943
|
+
|
|
944
|
+
var container = document.getElementById("card-group-container");
|
|
945
|
+
var addBtn = document.getElementById("card-group-add");
|
|
946
|
+
var form = document.getElementById("credential-form");
|
|
947
|
+
var submitBtn = document.getElementById("submit-btn");
|
|
948
|
+
var statusBox = document.getElementById("status-box");
|
|
949
|
+
var formFieldset = document.getElementById("form-fieldset");
|
|
950
|
+
var uid = 0;
|
|
951
|
+
var pendingRedirectUrl = null;
|
|
952
|
+
|
|
953
|
+
function showStatus(type, message) {
|
|
954
|
+
statusBox.className = "status-box " + type;
|
|
955
|
+
statusBox.textContent = message;
|
|
956
|
+
statusBox.style.display = "block";
|
|
957
|
+
}
|
|
958
|
+
function safeRedirect(url) {
|
|
959
|
+
try {
|
|
960
|
+
var parsed = new URL(url, window.location.origin);
|
|
961
|
+
if (parsed.protocol === "http:" || parsed.protocol === "https:") {
|
|
962
|
+
window.location.replace(parsed.href);
|
|
963
|
+
return true;
|
|
964
|
+
}
|
|
965
|
+
} catch (e) { /* fail safe */ }
|
|
966
|
+
return false;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
function buildField(spec, cardUid) {
|
|
970
|
+
var group = document.createElement("div");
|
|
971
|
+
group.className = "field-group";
|
|
972
|
+
var fid = "field-" + GROUP_KEY + "-" + spec.key + "-" + cardUid;
|
|
973
|
+
|
|
974
|
+
var label = document.createElement("label");
|
|
975
|
+
label.className = "field-label";
|
|
976
|
+
label.setAttribute("for", fid);
|
|
977
|
+
label.textContent = spec.label || "";
|
|
978
|
+
var badge = document.createElement("span");
|
|
979
|
+
badge.setAttribute("aria-hidden", "true");
|
|
980
|
+
if (spec.required) { badge.className = "required-badge"; badge.textContent = "Required"; }
|
|
981
|
+
else { badge.className = "optional-badge"; badge.textContent = "Optional"; }
|
|
982
|
+
label.appendChild(document.createTextNode(" "));
|
|
983
|
+
label.appendChild(badge);
|
|
984
|
+
group.appendChild(label);
|
|
985
|
+
|
|
986
|
+
var input = document.createElement("input");
|
|
987
|
+
input.id = fid;
|
|
988
|
+
input.className = "field-input";
|
|
989
|
+
input.setAttribute("type", spec.type || "text");
|
|
990
|
+
input.setAttribute("name", GROUP_KEY + "[" + cardUid + "]." + spec.key);
|
|
991
|
+
input.dataset.field = spec.key;
|
|
992
|
+
input.setAttribute("autocomplete", "off");
|
|
993
|
+
input.setAttribute("autocorrect", "off");
|
|
994
|
+
input.setAttribute("autocapitalize", "off");
|
|
995
|
+
input.setAttribute("spellcheck", "false");
|
|
996
|
+
if (spec.placeholder) { input.setAttribute("placeholder", spec.placeholder); }
|
|
997
|
+
if (spec.required) { input.setAttribute("required", "required"); }
|
|
998
|
+
group.appendChild(input);
|
|
999
|
+
|
|
1000
|
+
if (spec.helpText) {
|
|
1001
|
+
var help = document.createElement("p");
|
|
1002
|
+
help.className = "help-text";
|
|
1003
|
+
help.id = "help-" + GROUP_KEY + "-" + spec.key + "-" + cardUid;
|
|
1004
|
+
if (spec.helpUrl) {
|
|
1005
|
+
var a = document.createElement("a");
|
|
1006
|
+
a.setAttribute("href", spec.helpUrl);
|
|
1007
|
+
a.setAttribute("target", "_blank");
|
|
1008
|
+
a.setAttribute("rel", "noopener noreferrer");
|
|
1009
|
+
a.textContent = spec.helpText;
|
|
1010
|
+
help.appendChild(a);
|
|
1011
|
+
} else {
|
|
1012
|
+
help.textContent = spec.helpText;
|
|
1013
|
+
}
|
|
1014
|
+
input.setAttribute("aria-describedby", help.id);
|
|
1015
|
+
group.appendChild(help);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
input.addEventListener("input", function () {
|
|
1019
|
+
if (input.hasAttribute("aria-invalid")) { input.removeAttribute("aria-invalid"); }
|
|
1020
|
+
});
|
|
1021
|
+
return input;
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
function updateTitles() {
|
|
1025
|
+
var cards = container.querySelectorAll(".card-group-item");
|
|
1026
|
+
for (var i = 0; i < cards.length; i++) {
|
|
1027
|
+
var titleEl = cards[i].querySelector(".card-group-title");
|
|
1028
|
+
var titleInput = TITLE_FIELD ? cards[i].querySelector('input[data-field="' + TITLE_FIELD + '"]') : null;
|
|
1029
|
+
var titleVal = titleInput && titleInput.value ? titleInput.value.trim() : "";
|
|
1030
|
+
var titleStr = titleVal ? titleVal : (ITEM_LABEL + " " + (i + 1));
|
|
1031
|
+
if (titleEl) { titleEl.textContent = titleStr; titleEl.title = titleStr; }
|
|
1032
|
+
var removeBtn = cards[i].querySelector(".card-group-remove");
|
|
1033
|
+
if (removeBtn) {
|
|
1034
|
+
removeBtn.style.display = cards.length > MIN_ITEMS ? "" : "none";
|
|
1035
|
+
removeBtn.setAttribute("aria-label", "Remove " + titleStr);
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
function createCard() {
|
|
1041
|
+
var cardUid = uid++;
|
|
1042
|
+
var card = document.createElement("div");
|
|
1043
|
+
card.className = "card-group-item";
|
|
1044
|
+
card.dataset.uid = String(cardUid);
|
|
1045
|
+
card.setAttribute("role", "group");
|
|
1046
|
+
var titleId = "card-group-title-" + cardUid;
|
|
1047
|
+
card.setAttribute("aria-labelledby", titleId);
|
|
1048
|
+
|
|
1049
|
+
var header = document.createElement("div");
|
|
1050
|
+
header.className = "card-group-header";
|
|
1051
|
+
var title = document.createElement("h3");
|
|
1052
|
+
title.id = titleId;
|
|
1053
|
+
title.className = "card-group-title";
|
|
1054
|
+
title.textContent = ITEM_LABEL;
|
|
1055
|
+
header.appendChild(title);
|
|
1056
|
+
|
|
1057
|
+
var removeBtn = document.createElement("button");
|
|
1058
|
+
removeBtn.type = "button";
|
|
1059
|
+
removeBtn.className = "card-group-remove";
|
|
1060
|
+
removeBtn.textContent = "Remove";
|
|
1061
|
+
removeBtn.addEventListener("click", function () {
|
|
1062
|
+
var inputs = card.querySelectorAll("input");
|
|
1063
|
+
var hasData = false;
|
|
1064
|
+
for (var i = 0; i < inputs.length; i++) { if (inputs[i].value.trim() !== "") { hasData = true; break; } }
|
|
1065
|
+
if (hasData && !window.confirm("This " + ITEM_LABEL.toLowerCase() + " has unsaved data. Remove it?")) { return; }
|
|
1066
|
+
var prev = card.previousElementSibling;
|
|
1067
|
+
var next = card.nextElementSibling;
|
|
1068
|
+
var focusTarget = (prev && prev.classList && prev.classList.contains("card-group-item")) ? prev :
|
|
1069
|
+
(next && next.classList && next.classList.contains("card-group-item")) ? next : null;
|
|
1070
|
+
card.remove();
|
|
1071
|
+
updateTitles();
|
|
1072
|
+
if (focusTarget) {
|
|
1073
|
+
var fi = focusTarget.querySelector("input");
|
|
1074
|
+
if (fi) { fi.focus(); return; }
|
|
1075
|
+
}
|
|
1076
|
+
if (addBtn) { addBtn.focus(); }
|
|
1077
|
+
});
|
|
1078
|
+
header.appendChild(removeBtn);
|
|
1079
|
+
card.appendChild(header);
|
|
1080
|
+
|
|
1081
|
+
for (var f = 0; f < CARD_FIELDS.length; f++) {
|
|
1082
|
+
var input = buildField(CARD_FIELDS[f], cardUid);
|
|
1083
|
+
card.appendChild(input.parentNode);
|
|
1084
|
+
if (CARD_FIELDS[f].key === TITLE_FIELD) {
|
|
1085
|
+
input.addEventListener("input", updateTitles);
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
return card;
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
function collectCards() {
|
|
1092
|
+
var cards = container.querySelectorAll(".card-group-item");
|
|
1093
|
+
var arr = [];
|
|
1094
|
+
for (var i = 0; i < cards.length; i++) {
|
|
1095
|
+
var inputs = cards[i].querySelectorAll(".field-input");
|
|
1096
|
+
var obj = {};
|
|
1097
|
+
var hasAny = false;
|
|
1098
|
+
for (var j = 0; j < inputs.length; j++) {
|
|
1099
|
+
obj[inputs[j].dataset.field] = inputs[j].value;
|
|
1100
|
+
if (inputs[j].value.trim() !== "") { hasAny = true; }
|
|
1101
|
+
}
|
|
1102
|
+
if (hasAny) { arr.push(obj); }
|
|
1103
|
+
}
|
|
1104
|
+
return arr;
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
function renderOAuthDeviceCode(nextStep) {
|
|
1108
|
+
statusBox.className = "status-box info";
|
|
1109
|
+
statusBox.style.display = "block";
|
|
1110
|
+
while (statusBox.firstChild) { statusBox.removeChild(statusBox.firstChild); }
|
|
1111
|
+
var strong = document.createElement("strong");
|
|
1112
|
+
strong.textContent = "Finish sign-in";
|
|
1113
|
+
statusBox.appendChild(strong);
|
|
1114
|
+
statusBox.appendChild(document.createElement("br"));
|
|
1115
|
+
statusBox.appendChild(document.createElement("br"));
|
|
1116
|
+
statusBox.appendChild(document.createTextNode("Visit:"));
|
|
1117
|
+
statusBox.appendChild(document.createElement("br"));
|
|
1118
|
+
var link = document.createElement("a");
|
|
1119
|
+
link.setAttribute("href", nextStep.verification_url);
|
|
1120
|
+
link.setAttribute("target", "_blank");
|
|
1121
|
+
link.setAttribute("rel", "noopener noreferrer");
|
|
1122
|
+
link.textContent = nextStep.verification_url;
|
|
1123
|
+
statusBox.appendChild(link);
|
|
1124
|
+
statusBox.appendChild(document.createElement("br"));
|
|
1125
|
+
statusBox.appendChild(document.createElement("br"));
|
|
1126
|
+
statusBox.appendChild(document.createTextNode("Enter code: "));
|
|
1127
|
+
var codeEl = document.createElement("strong");
|
|
1128
|
+
codeEl.style.fontSize = "1.2em";
|
|
1129
|
+
codeEl.style.letterSpacing = "0.1em";
|
|
1130
|
+
codeEl.textContent = nextStep.user_code;
|
|
1131
|
+
statusBox.appendChild(codeEl);
|
|
1132
|
+
statusBox.appendChild(document.createElement("br"));
|
|
1133
|
+
statusBox.appendChild(document.createElement("br"));
|
|
1134
|
+
var waiting = document.createElement("span");
|
|
1135
|
+
waiting.id = "device-waiting";
|
|
1136
|
+
waiting.setAttribute("role", "alert");
|
|
1137
|
+
waiting.style.color = "#9ca3af";
|
|
1138
|
+
waiting.textContent = "Waiting for authorization...";
|
|
1139
|
+
statusBox.appendChild(waiting);
|
|
1140
|
+
var statusUrl = submitUrl.replace(/\\/authorize.*/, "/setup-status");
|
|
1141
|
+
var pollId = setInterval(function () {
|
|
1142
|
+
fetch(statusUrl)
|
|
1143
|
+
.then(function (r) { return r.json(); })
|
|
1144
|
+
.then(function (s) {
|
|
1145
|
+
if (s && s.outlook === "complete") {
|
|
1146
|
+
clearInterval(pollId);
|
|
1147
|
+
statusBox.className = "status-box success";
|
|
1148
|
+
while (statusBox.firstChild) { statusBox.removeChild(statusBox.firstChild); }
|
|
1149
|
+
var done = document.createElement("strong");
|
|
1150
|
+
done.textContent = "Setup complete!";
|
|
1151
|
+
statusBox.appendChild(done);
|
|
1152
|
+
submitBtn.textContent = "Connected";
|
|
1153
|
+
if (typeof pendingRedirectUrl === "string" && pendingRedirectUrl.length > 0) {
|
|
1154
|
+
statusBox.appendChild(document.createElement("br"));
|
|
1155
|
+
statusBox.appendChild(document.createTextNode("Redirecting..."));
|
|
1156
|
+
safeRedirect(pendingRedirectUrl);
|
|
1157
|
+
} else {
|
|
1158
|
+
statusBox.appendChild(document.createElement("br"));
|
|
1159
|
+
statusBox.appendChild(document.createTextNode("You can close this tab."));
|
|
1160
|
+
}
|
|
1161
|
+
} else if (s && typeof s.outlook === "string" && s.outlook.indexOf("error:") === 0) {
|
|
1162
|
+
clearInterval(pollId);
|
|
1163
|
+
var w = document.getElementById("device-waiting");
|
|
1164
|
+
if (w) { w.style.color = "#ff453a"; w.textContent = "Authorization failed: " + s.outlook.slice(6) + ". Please retry setup."; }
|
|
1165
|
+
}
|
|
1166
|
+
})
|
|
1167
|
+
.catch(function () {});
|
|
1168
|
+
}, 3000);
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
container.appendChild(createCard());
|
|
1172
|
+
for (var s = 1; s < MIN_ITEMS; s++) { container.appendChild(createCard()); }
|
|
1173
|
+
updateTitles();
|
|
1174
|
+
|
|
1175
|
+
addBtn.addEventListener("click", function () {
|
|
1176
|
+
var newCard = createCard();
|
|
1177
|
+
container.appendChild(newCard);
|
|
1178
|
+
updateTitles();
|
|
1179
|
+
var fi = newCard.querySelector("input");
|
|
1180
|
+
if (fi) { fi.focus(); }
|
|
1181
|
+
});
|
|
1182
|
+
|
|
1183
|
+
form.addEventListener("submit", function (evt) {
|
|
1184
|
+
evt.preventDefault();
|
|
1185
|
+
statusBox.style.display = "none";
|
|
1186
|
+
if (!form.checkValidity()) {
|
|
1187
|
+
var firstInvalid = form.querySelector(":invalid");
|
|
1188
|
+
if (firstInvalid) {
|
|
1189
|
+
firstInvalid.setAttribute("aria-invalid", "true");
|
|
1190
|
+
firstInvalid.focus();
|
|
1191
|
+
}
|
|
1192
|
+
return;
|
|
1193
|
+
}
|
|
1194
|
+
var items = collectCards();
|
|
1195
|
+
if (items.length === 0) {
|
|
1196
|
+
showStatus("error", "Please add at least one " + ITEM_LABEL.toLowerCase() + ".");
|
|
1197
|
+
return;
|
|
1198
|
+
}
|
|
1199
|
+
var payload = {};
|
|
1200
|
+
payload[GROUP_KEY] = items;
|
|
1201
|
+
|
|
1202
|
+
formFieldset.disabled = true;
|
|
1203
|
+
submitBtn.setAttribute("aria-busy", "true");
|
|
1204
|
+
submitBtn.textContent = "Connecting...";
|
|
1205
|
+
|
|
1206
|
+
fetch(submitUrl, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(payload) })
|
|
1207
|
+
.then(function (resp) { return resp.json().then(function (data) {
|
|
1208
|
+
if (!data.ok) {
|
|
1209
|
+
showStatus("error", data.error || data.error_description || "Request failed.");
|
|
1210
|
+
formFieldset.disabled = false;
|
|
1211
|
+
submitBtn.removeAttribute("aria-busy");
|
|
1212
|
+
submitBtn.textContent = "Connect";
|
|
1213
|
+
submitBtn.focus();
|
|
1214
|
+
return;
|
|
1215
|
+
}
|
|
1216
|
+
if (typeof data.redirect_url === "string" && data.redirect_url.length > 0) { pendingRedirectUrl = data.redirect_url; }
|
|
1217
|
+
if (data.next_step && data.next_step.type === "oauth_device_code") {
|
|
1218
|
+
submitBtn.textContent = "Awaiting authorization...";
|
|
1219
|
+
submitBtn.removeAttribute("aria-busy");
|
|
1220
|
+
renderOAuthDeviceCode(data.next_step);
|
|
1221
|
+
return;
|
|
1222
|
+
}
|
|
1223
|
+
if (pendingRedirectUrl) {
|
|
1224
|
+
showStatus("success", "Credentials saved. Redirecting...");
|
|
1225
|
+
submitBtn.textContent = "Connected";
|
|
1226
|
+
submitBtn.removeAttribute("aria-busy");
|
|
1227
|
+
if (!safeRedirect(pendingRedirectUrl)) {
|
|
1228
|
+
showStatus("error", "Setup complete, but refused to redirect to unsafe URL.");
|
|
1229
|
+
}
|
|
1230
|
+
return;
|
|
1231
|
+
}
|
|
1232
|
+
showStatus("success", data.message || "Setup complete! You can close this tab.");
|
|
1233
|
+
submitBtn.textContent = "Connected";
|
|
1234
|
+
submitBtn.removeAttribute("aria-busy");
|
|
1235
|
+
}); })
|
|
1236
|
+
.catch(function (err) {
|
|
1237
|
+
showStatus("error", "Network error: " + err.message);
|
|
1238
|
+
formFieldset.disabled = false;
|
|
1239
|
+
submitBtn.removeAttribute("aria-busy");
|
|
1240
|
+
submitBtn.textContent = "Connect";
|
|
1241
|
+
submitBtn.focus();
|
|
1242
|
+
});
|
|
1243
|
+
});
|
|
1244
|
+
})();
|
|
1245
|
+
</script>`;
|
|
1246
|
+
/** Escape a string for safe embedding inside a double-quoted JS literal. */
|
|
1247
|
+
function jsString(value) {
|
|
1248
|
+
return value.replaceAll('\\', '\\\\').replaceAll('"', '\\"').replaceAll('<', '\\u003c');
|
|
1249
|
+
}
|
|
1250
|
+
/**
|
|
1251
|
+
* Return the id of the tab that should render active on load. Defaults to the
|
|
1252
|
+
* first tab; a valid `initialTab` hint wins, an unknown hint falls back.
|
|
1253
|
+
*/
|
|
1254
|
+
function resolveActiveTab(tabs, initialTab) {
|
|
1255
|
+
const ids = tabs.map((t) => String(t.id ?? ''));
|
|
1256
|
+
if (initialTab !== undefined && ids.includes(initialTab)) {
|
|
1257
|
+
return initialTab;
|
|
1258
|
+
}
|
|
1259
|
+
return ids.length > 0 ? ids[0] : '';
|
|
1260
|
+
}
|
|
1261
|
+
/**
|
|
1262
|
+
* Optional workspace-username field shared by the flat + feature forms. Carries
|
|
1263
|
+
* the `.field-input` class so the form collector picks it into the POST as
|
|
1264
|
+
* `__sub_username`. Optional, so it never blocks submit.
|
|
1265
|
+
*/
|
|
1266
|
+
function usernameFieldHtml() {
|
|
1267
|
+
return ('<div class="field-group">' +
|
|
1268
|
+
'<label for="field-__sub_username" class="field-label">Workspace / username' +
|
|
1269
|
+
' <span class="optional-badge" aria-hidden="true">Optional</span></label>' +
|
|
1270
|
+
'<input id="field-__sub_username" type="text" name="__sub_username"' +
|
|
1271
|
+
' class="field-input" placeholder="e.g. alice"' +
|
|
1272
|
+
' autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" />' +
|
|
1273
|
+
'<p class="help-text">Leave blank for a one-off session. Set the same value on' +
|
|
1274
|
+
' every device to keep your saved data (one shared bucket per username).</p>' +
|
|
1275
|
+
'</div>');
|
|
1276
|
+
}
|
|
1277
|
+
function renderCapabilitiesSection(capabilityInfo) {
|
|
1278
|
+
if (capabilityInfo.length === 0) {
|
|
1279
|
+
return '';
|
|
1280
|
+
}
|
|
1281
|
+
const itemsHtml = capabilityInfo.map(renderCapability).join('');
|
|
1282
|
+
return `
|
|
1283
|
+
<section class="capabilities-section" aria-labelledby="capabilities-title">
|
|
1284
|
+
<h2 class="capabilities-title" id="capabilities-title">Capabilities Requested</h2>
|
|
1285
|
+
<ul class="capabilities-list">${itemsHtml}
|
|
1286
|
+
</ul>
|
|
1287
|
+
</section>`;
|
|
1288
|
+
}
|
|
1289
|
+
/**
|
|
1290
|
+
* Render a credential form whose fields are split across mutually-exclusive
|
|
1291
|
+
* tabs. Only the active tab's fields are collected on submit. Multi-step
|
|
1292
|
+
* (OTP / 2FA) chaining works exactly as the flat form.
|
|
1293
|
+
*/
|
|
1294
|
+
function renderTabbedCredentialForm(schema, options) {
|
|
1295
|
+
const displayName = escapeHtml(schema.displayName ?? schema.server ?? 'Configuration');
|
|
1296
|
+
const server = escapeHtml(schema.server ?? '');
|
|
1297
|
+
const description = escapeHtml(schema.description ?? '');
|
|
1298
|
+
const title = options.pageTitle !== undefined ? escapeHtml(options.pageTitle) : displayName;
|
|
1299
|
+
const submitUrlEscaped = escapeHtml(options.submitUrl);
|
|
1300
|
+
const prefill = options.prefill ?? {};
|
|
1301
|
+
const tabs = schema.tabs ?? [];
|
|
1302
|
+
const activeId = resolveActiveTab(tabs, options.initialTab);
|
|
1303
|
+
const tabButtons = [];
|
|
1304
|
+
const tabPanels = [];
|
|
1305
|
+
for (const tab of tabs) {
|
|
1306
|
+
const tid = escapeHtml(tab.id ?? '');
|
|
1307
|
+
const label = escapeHtml(tab.label ?? '');
|
|
1308
|
+
const isActive = (tab.id ?? '') === activeId;
|
|
1309
|
+
const activeCls = isActive ? ' active' : '';
|
|
1310
|
+
const ariaSelected = isActive ? 'true' : 'false';
|
|
1311
|
+
const tabindex = isActive ? '0' : '-1';
|
|
1312
|
+
tabButtons.push(`<button type="button" id="tab-${tid}" class="tab${activeCls}" data-tab="${tid}"` +
|
|
1313
|
+
` role="tab" aria-selected="${ariaSelected}" tabindex="${tabindex}"` +
|
|
1314
|
+
` aria-controls="panel-${tid}">${label}</button>`);
|
|
1315
|
+
const panelFields = (tab.fields ?? []).map((f) => renderField(f, prefill[f.key] ?? '')).join('');
|
|
1316
|
+
tabPanels.push(`<div id="panel-${tid}" class="tab-panel${activeCls}" data-panel="${tid}"` +
|
|
1317
|
+
` role="tabpanel" aria-labelledby="tab-${tid}">${panelFields}\n </div>`);
|
|
1318
|
+
}
|
|
1319
|
+
const tabsHtml = tabButtons.join('\n ');
|
|
1320
|
+
const panelsHtml = tabPanels.join('\n ');
|
|
1321
|
+
const usernameHtml = options.includeUsernameField ? usernameFieldHtml() : '';
|
|
1322
|
+
const capabilitiesHtml = renderCapabilitiesSection(schema.capabilityInfo ?? []);
|
|
1323
|
+
const descriptionHtml = description ? `<p class="server-description" id="server-desc">${description}</p>` : '';
|
|
1324
|
+
const script = TABS_SCRIPT.replaceAll('__SUBMIT_URL__', submitUrlEscaped).replaceAll('__INITIAL_TAB__', activeId);
|
|
1325
|
+
const bodyHtml = `${TABS_CSS} <div class="container">
|
|
1326
|
+
<div class="card">
|
|
1327
|
+
<div class="server-header">
|
|
1328
|
+
<h1 class="server-name">${displayName}</h1>
|
|
1329
|
+
<div class="server-id">${server}</div>
|
|
1330
|
+
${descriptionHtml}
|
|
1331
|
+
</div>
|
|
1332
|
+
|
|
1333
|
+
<div class="tabs" role="tablist" aria-label="Credential mode">
|
|
1334
|
+
${tabsHtml}
|
|
1335
|
+
</div>
|
|
1336
|
+
|
|
1337
|
+
<form id="credential-form" novalidate>
|
|
1338
|
+
${usernameHtml}${panelsHtml}
|
|
1339
|
+
|
|
1340
|
+
<button type="submit" class="submit-btn" id="submit-btn">Connect</button>
|
|
1341
|
+
|
|
1342
|
+
<div class="status-box" id="status-box" role="alert"></div>
|
|
1343
|
+
</form>
|
|
1344
|
+
</div>
|
|
1345
|
+
${capabilitiesHtml}
|
|
1346
|
+
</div>
|
|
1347
|
+
${script}`;
|
|
1348
|
+
return renderFormShell(title, bodyHtml);
|
|
1349
|
+
}
|
|
1350
|
+
/**
|
|
1351
|
+
* Render a credential form built around one repeatable card group. The group's
|
|
1352
|
+
* fields are cloned per card (Add/Remove) and submitted as a JSON array under
|
|
1353
|
+
* the group `key`. An Outlook-style device-code follow-up is supported.
|
|
1354
|
+
*/
|
|
1355
|
+
function renderCardGroupCredentialForm(schema, options) {
|
|
1356
|
+
const displayName = escapeHtml(schema.displayName ?? schema.server ?? 'Configuration');
|
|
1357
|
+
const server = escapeHtml(schema.server ?? '');
|
|
1358
|
+
const description = escapeHtml(schema.description ?? '');
|
|
1359
|
+
const title = options.pageTitle !== undefined ? escapeHtml(options.pageTitle) : displayName;
|
|
1360
|
+
const submitUrlEscaped = escapeHtml(options.submitUrl);
|
|
1361
|
+
const group = schema.cardGroup;
|
|
1362
|
+
const groupKey = String(group.key ?? 'items');
|
|
1363
|
+
const itemLabel = String(group.itemLabel ?? 'Item');
|
|
1364
|
+
const addLabel = escapeHtml(group.addButtonLabel ?? '+ Add');
|
|
1365
|
+
const minItems = Number(group.minItems ?? 1);
|
|
1366
|
+
const titleField = String(group.titleField ?? '');
|
|
1367
|
+
const groupHeading = escapeHtml(group.heading ?? `${itemLabel}s`);
|
|
1368
|
+
const fields = group.fields ?? [];
|
|
1369
|
+
// `<` is escaped to `<` so the JSON cannot terminate the <script> early.
|
|
1370
|
+
const fieldsJson = JSON.stringify(fields).replaceAll('<', '\\u003c');
|
|
1371
|
+
const usernameHtml = options.includeUsernameField ? usernameFieldHtml() : '';
|
|
1372
|
+
const capabilitiesHtml = renderCapabilitiesSection(schema.capabilityInfo ?? []);
|
|
1373
|
+
const descriptionHtml = description ? `<p class="server-description" id="server-desc">${description}</p>` : '';
|
|
1374
|
+
// `__CARD_FIELDS__` (the only placeholder carrying user-controlled JSON) is
|
|
1375
|
+
// substituted LAST so a crafted field value cannot masquerade as another token.
|
|
1376
|
+
const script = CARD_GROUP_SCRIPT.replaceAll('__SUBMIT_URL__', submitUrlEscaped)
|
|
1377
|
+
.replaceAll('__GROUP_KEY__', jsString(groupKey))
|
|
1378
|
+
.replaceAll('__TITLE_FIELD__', jsString(titleField))
|
|
1379
|
+
.replaceAll('__ITEM_LABEL__', jsString(itemLabel))
|
|
1380
|
+
.replaceAll('__MIN_ITEMS__', String(minItems))
|
|
1381
|
+
.replaceAll('__CARD_FIELDS__', fieldsJson);
|
|
1382
|
+
const bodyHtml = `${CARD_GROUP_CSS} <div class="container">
|
|
1383
|
+
<div class="card">
|
|
1384
|
+
<div class="server-header">
|
|
1385
|
+
<h1 class="server-name">${displayName}</h1>
|
|
1386
|
+
<div class="server-id">${server}</div>
|
|
1387
|
+
${descriptionHtml}
|
|
1388
|
+
</div>
|
|
1389
|
+
|
|
1390
|
+
<h2 class="form-title" id="form-title">${groupHeading}</h2>
|
|
1391
|
+
|
|
1392
|
+
<form id="credential-form" aria-labelledby="form-title" novalidate>
|
|
1393
|
+
<fieldset id="form-fieldset" style="border: none; padding: 0; margin: 0;">
|
|
1394
|
+
${usernameHtml}<div id="card-group-container"></div>
|
|
1395
|
+
|
|
1396
|
+
<button type="button" class="card-group-add" id="card-group-add">${addLabel}</button>
|
|
1397
|
+
|
|
1398
|
+
<button type="submit" class="submit-btn" id="submit-btn">Connect</button>
|
|
1399
|
+
</fieldset>
|
|
1400
|
+
|
|
1401
|
+
<div class="status-box" id="status-box" role="alert"></div>
|
|
1402
|
+
</form>
|
|
1403
|
+
</div>
|
|
1404
|
+
${capabilitiesHtml}
|
|
1405
|
+
</div>
|
|
1406
|
+
${script}`;
|
|
1407
|
+
return renderFormShell(title, bodyHtml);
|
|
1408
|
+
}
|
|
483
1409
|
/**
|
|
484
1410
|
* Render a dark-themed HTML credential form from a RelayConfigSchema.
|
|
485
1411
|
*
|
|
@@ -490,6 +1416,14 @@ function renderCapability(cap) {
|
|
|
490
1416
|
* @returns Complete HTML document string, XSS-safe with all dynamic content escaped.
|
|
491
1417
|
*/
|
|
492
1418
|
export function renderCredentialForm(schema, options) {
|
|
1419
|
+
// Schema-level capabilities (opt-in): dispatch to the dedicated renderer.
|
|
1420
|
+
// A schema declaring neither key falls through to the unchanged flat form.
|
|
1421
|
+
if (schema.tabs && schema.tabs.length > 0) {
|
|
1422
|
+
return renderTabbedCredentialForm(schema, options);
|
|
1423
|
+
}
|
|
1424
|
+
if (schema.cardGroup) {
|
|
1425
|
+
return renderCardGroupCredentialForm(schema, options);
|
|
1426
|
+
}
|
|
493
1427
|
const displayName = escapeHtml(schema.displayName ?? schema.server ?? 'Configuration');
|
|
494
1428
|
const server = escapeHtml(schema.server ?? '');
|
|
495
1429
|
const description = escapeHtml(schema.description ?? '');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"credential-form.js","sourceRoot":"","sources":["../../src/auth/credential-form.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"credential-form.js","sourceRoot":"","sources":["../../src/auth/credential-form.ts"],"names":[],"mappings":"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"}
|
package/build/schema/types.d.ts
CHANGED
|
@@ -31,6 +31,29 @@ export interface DynamicFlow {
|
|
|
31
31
|
entryField: ConfigField;
|
|
32
32
|
routes: (OAuthRoute | CredentialsRoute)[];
|
|
33
33
|
}
|
|
34
|
+
/**
|
|
35
|
+
* A credential-form tab (schema-level `tabs` capability). Each tab is a
|
|
36
|
+
* mutually-exclusive credential mode; only the active tab's fields submit.
|
|
37
|
+
*/
|
|
38
|
+
export interface TabGroup {
|
|
39
|
+
id: string;
|
|
40
|
+
label: string;
|
|
41
|
+
fields: ConfigField[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* A repeatable field group (schema-level `cardGroup` capability). Renders
|
|
45
|
+
* Add/Remove cards, each cloning `fields`; submitted as a JSON array under
|
|
46
|
+
* `key` (e.g. `{ accounts: [{...}, {...}] }`).
|
|
47
|
+
*/
|
|
48
|
+
export interface CardGroup {
|
|
49
|
+
key: string;
|
|
50
|
+
fields: ConfigField[];
|
|
51
|
+
itemLabel?: string;
|
|
52
|
+
heading?: string;
|
|
53
|
+
addButtonLabel?: string;
|
|
54
|
+
minItems?: number;
|
|
55
|
+
titleField?: string;
|
|
56
|
+
}
|
|
34
57
|
export interface RelayConfigSchema {
|
|
35
58
|
server: string;
|
|
36
59
|
displayName: string;
|
|
@@ -38,5 +61,7 @@ export interface RelayConfigSchema {
|
|
|
38
61
|
fields?: ConfigField[];
|
|
39
62
|
optional?: ConfigField[];
|
|
40
63
|
dynamicFlow?: DynamicFlow;
|
|
64
|
+
tabs?: TabGroup[];
|
|
65
|
+
cardGroup?: CardGroup;
|
|
41
66
|
}
|
|
42
67
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/schema/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;IACzE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,WAAW,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,MAAM,EAAE,oBAAoB,CAAA;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACrC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,MAAM,EAAE,aAAa,CAAA;IACrB,MAAM,EAAE,WAAW,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,WAAW,CAAA;IACvB,MAAM,EAAE,CAAC,UAAU,GAAG,gBAAgB,CAAC,EAAE,CAAA;CAC1C;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAA;IACpB,MAAM,CAAC,EAAE,WAAW,EAAE,CAAA;IACtB,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;IACxB,WAAW,CAAC,EAAE,WAAW,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/schema/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,KAAK,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAA;IACzE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAA;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,WAAW,EAAE,MAAM,CAAA;IACnB,MAAM,EAAE,WAAW,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,MAAM,EAAE,oBAAoB,CAAA;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CACrC;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,EAAE,CAAA;IACf,MAAM,EAAE,aAAa,CAAA;IACrB,MAAM,EAAE,WAAW,EAAE,CAAA;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,WAAW,CAAA;IACvB,MAAM,EAAE,CAAC,UAAU,GAAG,gBAAgB,CAAC,EAAE,CAAA;CAC1C;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,WAAW,EAAE,CAAA;CACtB;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,WAAW,EAAE,CAAA;IACrB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,CAAC,EAAE,UAAU,EAAE,CAAA;IACpB,MAAM,CAAC,EAAE,WAAW,EAAE,CAAA;IACtB,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAA;IACxB,WAAW,CAAC,EAAE,WAAW,CAAA;IACzB,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAA;IACjB,SAAS,CAAC,EAAE,SAAS,CAAA;CACtB"}
|