@adia-ai/web-modules 0.8.40 → 0.8.41
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/CHANGELOG.md +27 -0
- package/README.md +6 -6
- package/agent-admin/admin-roster/admin-roster.a2ui.json +1 -0
- package/agent-admin/admin-roster/admin-roster.css +10 -2
- package/agent-admin/admin-roster/admin-roster.js +70 -22
- package/agent-admin/admin-settings/admin-settings.a2ui.json +1 -0
- package/agent-admin/agent-admin/agent-admin.a2ui.json +1 -0
- package/billing/billing-overview/billing-overview.a2ui.json +10 -1
- package/billing/billing-overview/billing-overview.class.js +142 -73
- package/billing/billing-overview/billing-overview.css +70 -57
- package/billing/billing-overview/billing-overview.yaml +5 -0
- package/billing/invoice-detail/invoice-detail.a2ui.json +9 -4
- package/billing/invoice-detail/invoice-detail.class.js +6 -5
- package/billing/invoice-detail/invoice-detail.yaml +9 -4
- package/billing/invoice-history/invoice-history.a2ui.json +7 -4
- package/billing/invoice-history/invoice-history.class.js +29 -18
- package/billing/invoice-history/invoice-history.css +18 -15
- package/billing/invoice-history/invoice-history.yaml +10 -4
- package/billing/payment-method-form/payment-method-form.a2ui.json +1 -0
- package/billing/payment-method-form/payment-method-form.class.js +3 -3
- package/billing/payment-method-form/payment-method-form.css +4 -4
- package/billing/payment-method-list/payment-method-list.a2ui.json +4 -0
- package/billing/payment-method-list/payment-method-list.class.js +31 -11
- package/billing/payment-method-list/payment-method-list.css +13 -10
- package/billing/payment-method-list/payment-method-list.yaml +3 -0
- package/billing/plan-picker/plan-picker.a2ui.json +6 -0
- package/billing/plan-picker/plan-picker.class.js +70 -22
- package/billing/plan-picker/plan-picker.css +21 -38
- package/billing/plan-picker/plan-picker.yaml +5 -0
- package/chat/chat-composer/chat-composer.a2ui.json +1 -0
- package/chat/chat-empty/chat-empty.a2ui.json +4 -0
- package/chat/chat-empty/chat-empty.yaml +2 -0
- package/chat/chat-header/chat-header.a2ui.json +5 -0
- package/chat/chat-header/chat-header.yaml +3 -0
- package/chat/chat-shell/chat-shell.a2ui.json +4 -0
- package/chat/chat-shell/chat-shell.yaml +2 -0
- package/chat/chat-sidebar/chat-sidebar.a2ui.json +4 -0
- package/chat/chat-sidebar/chat-sidebar.yaml +2 -0
- package/chat/chat-status/chat-status.a2ui.json +4 -0
- package/chat/chat-status/chat-status.yaml +2 -0
- package/chat/chat-thread/chat-thread.a2ui.json +4 -0
- package/chat/chat-thread/chat-thread.yaml +2 -0
- package/dashboard/dashboard-layout/dashboard-layout.a2ui.json +8 -8
- package/dashboard/dashboard-layout/dashboard-layout.css +4 -4
- package/dashboard/dashboard-layout/dashboard-layout.js +10 -9
- package/dashboard/dashboard-layout/dashboard-layout.yaml +19 -7
- package/dashboard/date-range-selector/date-range-selector.a2ui.json +4 -3
- package/dashboard/date-range-selector/date-range-selector.yaml +6 -4
- package/dist/chat/chat-shell.min.js +23 -23
- package/dist/editor/editor-shell.min.js +3 -3
- package/dist/everything.min.js +119 -132
- package/dist/shell/admin-shell.min.css +1 -1
- package/dist/shell/admin-shell.min.js +6 -6
- package/dist/simple/simple-shell.min.js +5 -5
- package/dist/web-modules.min.css +1 -1
- package/dist/web-modules.sheet.js +1 -1
- package/editor/editor-canvas/editor-canvas.a2ui.json +4 -0
- package/editor/editor-canvas/editor-canvas.yaml +2 -0
- package/editor/editor-canvas-empty/editor-canvas-empty.a2ui.json +4 -0
- package/editor/editor-canvas-empty/editor-canvas-empty.yaml +2 -0
- package/editor/editor-canvas-toolbar/editor-canvas-toolbar.a2ui.json +4 -0
- package/editor/editor-canvas-toolbar/editor-canvas-toolbar.yaml +2 -0
- package/editor/editor-shell/editor-shell.a2ui.json +5 -0
- package/editor/editor-shell/editor-shell.yaml +3 -0
- package/editor/editor-sidebar/editor-sidebar.a2ui.json +4 -0
- package/editor/editor-sidebar/editor-sidebar.yaml +2 -0
- package/editor/editor-statusbar/editor-statusbar.a2ui.json +4 -0
- package/editor/editor-statusbar/editor-statusbar.yaml +2 -0
- package/editor/editor-toolbar/editor-toolbar.a2ui.json +4 -0
- package/editor/editor-toolbar/editor-toolbar.yaml +2 -0
- package/feedback/confirm-dialog/confirm-dialog.a2ui.json +1 -0
- package/form/form-popover/form-popover.a2ui.json +1 -0
- package/onboarding/onboarding-checklist/onboarding-checklist.a2ui.json +2 -1
- package/onboarding/onboarding-checklist/onboarding-checklist.js +2 -2
- package/onboarding/onboarding-checklist/onboarding-checklist.yaml +1 -1
- package/package.json +6 -6
- package/runtime/a2ui-root/a2ui-root.a2ui.json +6 -5
- package/runtime/a2ui-root/a2ui-root.css +75 -0
- package/runtime/a2ui-root/a2ui-root.js +118 -10
- package/runtime/a2ui-root/a2ui-root.yaml +7 -2
- package/runtime/gen-root/gen-root.a2ui.json +6 -5
- package/runtime/gen-root/gen-root.yaml +10 -2
- package/settings/integrations-page/integrations-page.a2ui.json +3 -2
- package/settings/integrations-page/integrations-page.js +8 -8
- package/settings/integrations-page/integrations-page.yaml +2 -2
- package/settings/notification-preferences/notification-preferences.a2ui.json +1 -0
- package/shell/admin-command/admin-command.a2ui.json +5 -1
- package/shell/admin-command/admin-command.yaml +3 -1
- package/shell/admin-content/admin-content.a2ui.json +4 -0
- package/shell/admin-content/admin-content.yaml +2 -0
- package/shell/admin-entity-item/admin-entity-item.a2ui.json +1 -0
- package/shell/admin-page/admin-page.a2ui.json +5 -0
- package/shell/admin-page/admin-page.yaml +3 -0
- package/shell/admin-page-body/admin-page-body.a2ui.json +4 -0
- package/shell/admin-page-body/admin-page-body.yaml +2 -0
- package/shell/admin-page-footer/admin-page-footer.a2ui.json +4 -0
- package/shell/admin-page-footer/admin-page-footer.yaml +2 -0
- package/shell/admin-page-header/admin-page-header.a2ui.json +4 -0
- package/shell/admin-page-header/admin-page-header.yaml +2 -0
- package/shell/admin-scroll/admin-scroll.a2ui.json +4 -0
- package/shell/admin-scroll/admin-scroll.yaml +2 -0
- package/shell/admin-shell/admin-shell.a2ui.json +7 -3
- package/shell/admin-shell/admin-shell.yaml +3 -1
- package/shell/admin-shell/css/admin-shell.sidebar.css +2 -2
- package/shell/admin-sidebar/admin-sidebar.a2ui.json +4 -0
- package/shell/admin-sidebar/admin-sidebar.yaml +2 -0
- package/shell/admin-statusbar/admin-statusbar.a2ui.json +6 -0
- package/shell/admin-statusbar/admin-statusbar.yaml +4 -0
- package/shell/admin-topbar/admin-topbar.a2ui.json +6 -0
- package/shell/admin-topbar/admin-topbar.yaml +4 -0
- package/shell/embed-shell/embed-shell.a2ui.json +1 -0
- package/simple/simple-content/simple-content.a2ui.json +4 -0
- package/simple/simple-content/simple-content.yaml +2 -0
- package/simple/simple-hero/simple-hero.a2ui.json +4 -0
- package/simple/simple-hero/simple-hero.yaml +2 -0
- package/simple/simple-shell/simple-shell.a2ui.json +4 -0
- package/simple/simple-shell/simple-shell.yaml +2 -0
- package/theme/theme-panel/theme-panel.a2ui.json +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog — @adia-ai/web-modules
|
|
2
2
|
|
|
3
|
+
## [0.8.41] — 2026-08-17
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- **`a2ui-root` — surface lifecycle integration (gh#1364 + follow-up gh#1433; `spec-a2ui-surface-lifecycle.md`, ADR-0061).** The `doc` setter is now an atomic `replaceDoc()`: per surfaceId, an EXISTING surface regenerates through a begin → apply → commit bracket so old content stays visible until the new answer commits (no blank frame — "the blank flash is the bug", OD-2), and surfaces the new doc no longer declares are torn down. New reflected rolled-up `[pending]` attribute (true while any surface has an in-flight generation), driven by the renderer's bubbling `surface-pending`/`surface-committed`/`surface-aborted` events; default pending/stale styling ships in `runtime/a2ui-root/a2ui-root.css`. `runtime/a2ui-root/a2ui-root.js` + `a2ui-root.test.js`.
|
|
7
|
+
|
|
8
|
+
### Changed
|
|
9
|
+
- **BREAKING, no deprecation aliases — composite-side renames from the global-attribute-shadowing sweep (gh#1335).** `invoice-detail-ui`/`invoice-history-ui`/`dashboard-layout-ui[density]` converge onto the global grammar (`compact`/`spacious`/unset — the component-local enums are gone); `dashboard-layout-ui[gap]` → `[band-gap]`. See the migration guide's [§ Shipped in `0.8.41` — global-attribute-shadowing collision sweep](../../.claude/docs/MIGRATION%20GUIDE.md).
|
|
10
|
+
- **BREAKING, no deprecation alias — `data-*` states converge to bare attributes (gh#1332, Category A).** `integrations-page-ui`'s `empty-search`/`empty-data` states (was `[data-empty-search]`/`[data-empty-data]`) and `onboarding-checklist-ui`'s `complete` state (was `[data-complete]`) now match their own sibling states' bare-attribute convention (`loading`, `collapsed`). Any CSS/script targeting the old forms moves to `[empty-search]`/`[empty-data]`/`[complete]`. The same sweep (PR #1438) stamped declared API-state attributes across the module tier per the ADR-0060 anatomy-marker convention.
|
|
11
|
+
- **BREAKING for raw A2UI documents only — `admin-shell`'s catalog identity is now `AdminShell` (gh#1427).** `admin-shell.yaml` and `embed-shell.yaml` both declared `component: AppShell`, so the catalog build silently dropped `admin-shell`'s entry (embed-shell's fragment won); `embed-shell` keeps `AppShell`. A raw a2ui tree with `{"component": "AppShell"}` meaning the stable admin shell updates to `AdminShell`; the `<admin-shell>` tag and JS API are unaffected.
|
|
12
|
+
- **`billing-overview` family recomposed from layout primitives (gh#1519).** The billing overview page family now composes the shared layout primitives instead of bespoke wrappers — `billing/billing-overview/`.
|
|
13
|
+
- **`dashboard-layout` — chart band adopts the chart-in-card bleed/legend convention (#1399).** Charts in the band render with the card-bleed + legend placement the dashboard pattern library established.
|
|
14
|
+
- **`admin-roster` — persona-import composes the `upload-ui` primitive (#1398)** instead of a hand-rolled native file picker.
|
|
15
|
+
|
|
16
|
+
### Fixed
|
|
17
|
+
- **`table-toolbar` hides the title cluster when it has nothing to show (ADIA2-8897).** An empty title/description cluster no longer reserves its grid column, so toolbars with only actions/filters align flush.
|
|
18
|
+
|
|
19
|
+
### Maintenance
|
|
20
|
+
- **`dist/` bundles rebuilt** in this cut's window — carried by the entries above plus the web-components SSR shape-1 sweep (gh#1430/gh#1436) and yaml/sidecar regenerations (ADR-0067 `parts:`, ADR-0069 derived-resync); regenerated artifacts, not independent edits.
|
|
21
|
+
- **`agent-admin/` touched in this release window** (6 file(s), e.g. `admin-roster/admin-roster.a2ui.json`) — carried by the entries above.
|
|
22
|
+
- **`chat/` touched in this release window** (14 file(s), e.g. `chat-composer/chat-composer.a2ui.json`) — carried by the entries above.
|
|
23
|
+
- **`editor/` touched in this release window** (14 file(s), e.g. `editor-canvas-empty/editor-canvas-empty.a2ui.json`) — carried by the entries above.
|
|
24
|
+
- **`feedback/` touched in this release window** (1 file(s), e.g. `confirm-dialog/confirm-dialog.a2ui.json`) — carried by the entries above.
|
|
25
|
+
- **`form/` touched in this release window** (1 file(s), e.g. `form-popover/form-popover.a2ui.json`) — carried by the entries above.
|
|
26
|
+
- **`settings/` touched in this release window** (6 file(s), e.g. `integrations-page/integrations-page.a2ui.json`) — carried by the entries above.
|
|
27
|
+
- **`simple/` touched in this release window** (6 file(s), e.g. `simple-content/simple-content.a2ui.json`) — carried by the entries above.
|
|
28
|
+
- **`theme/` touched in this release window** (1 file(s), e.g. `theme-panel/theme-panel.a2ui.json`) — carried by the entries above.
|
|
29
|
+
|
|
3
30
|
## [0.8.40] — 2026-08-15
|
|
4
31
|
|
|
5
32
|
### Fixed
|
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@ Since **v0.6.30**, both this package and `@adia-ai/web-components` ship pre-flat
|
|
|
22
22
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@adia-ai/web-components@0.8/dist/web-components.min.css">
|
|
23
23
|
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@adia-ai/web-modules@0.8/dist/shell/admin-shell.min.css">
|
|
24
24
|
|
|
25
|
-
<!-- JS: everything in one bundle (primitives + all 4 shells + a2ui
|
|
25
|
+
<!-- JS: everything in one bundle (primitives + all 4 shells + the @adia-ai/a2ui runtime; ~424 KB gzipped) -->
|
|
26
26
|
<script type="module" src="https://cdn.jsdelivr.net/npm/@adia-ai/web-modules@0.8/dist/everything.min.js"></script>
|
|
27
27
|
|
|
28
28
|
<admin-shell mode="rounded borderless">
|
|
@@ -87,7 +87,7 @@ Since **v0.6.30**, both this package and `@adia-ai/web-components` ship pre-flat
|
|
|
87
87
|
|
|
88
88
|
| Bundle | Path | Gzipped | Contents | When to use |
|
|
89
89
|
|---|---|---|---|---|
|
|
90
|
-
| **Everything** | `/dist/everything.min.js` | **~
|
|
90
|
+
| **Everything** | `/dist/everything.min.js` | **~424 KB** | All primitives + the @adia-ai/a2ui runtime + all 4 shells | **CodePen / one-tag demos** |
|
|
91
91
|
| Admin shell | `/dist/shell/admin-shell.min.js` | ~6 KB | Shell registration; needs `web-components.min.js` first | Admin app, no chat/editor |
|
|
92
92
|
| Chat shell | `/dist/chat/chat-shell.min.js` | ~230 KB | Includes chat-thread/composer | Chat surface |
|
|
93
93
|
| Editor shell | `/dist/editor/editor-shell.min.js` | ~6 KB | Shell registration; needs primitives first | Editor surface |
|
|
@@ -119,7 +119,7 @@ When composing UI with an AI coding agent (Claude Code / Cursor / Windsurf / Cla
|
|
|
119
119
|
| Peer dependency | Required when you use |
|
|
120
120
|
|---|---|
|
|
121
121
|
| `@adia-ai/web-components` (always) | Any cluster |
|
|
122
|
-
| `@adia-ai/a2ui
|
|
122
|
+
| `@adia-ai/a2ui` | `runtime` cluster (`<gen-root>`, `<a2ui-root>`) — A2UI message → DOM renderer |
|
|
123
123
|
| `@adia-ai/llm` | `chat` cluster (`<chat-shell>`) — LLM proxy + streaming |
|
|
124
124
|
|
|
125
125
|
If you only use `shell`, `editor`, `simple`, or `theme` clusters, those two peers can be omitted (or kept as `--legacy-peer-deps` warnings under npm). pnpm with auto-install-peers will silently install them.
|
|
@@ -250,7 +250,7 @@ import '@adia-ai/web-components'; // primitives + nav family
|
|
|
250
250
|
import '@adia-ai/web-modules/shell'; // admin-shell + bespoke children
|
|
251
251
|
import '@adia-ai/web-modules/chat'; // chat-shell + bespoke children (needs @adia-ai/llm)
|
|
252
252
|
import '@adia-ai/web-modules/editor'; // editor-shell + bespoke children
|
|
253
|
-
import '@adia-ai/web-modules/runtime'; // gen-root, a2ui-root (needs @adia-ai/a2ui
|
|
253
|
+
import '@adia-ai/web-modules/runtime'; // gen-root, a2ui-root (needs @adia-ai/a2ui)
|
|
254
254
|
import '@adia-ai/web-modules/theme'; // theme-panel (appearance prefs)
|
|
255
255
|
|
|
256
256
|
// CSS — one stylesheet per cluster you use (REQUIRED — see callout above)
|
|
@@ -343,13 +343,13 @@ web-modules/
|
|
|
343
343
|
│ └── simple-{content,hero}/ CSS-only
|
|
344
344
|
├── runtime/ 2 render roots
|
|
345
345
|
│ ├── gen-root/ <gen-root> turns gen-UI intents into DOM
|
|
346
|
-
│ └── a2ui-root/ <a2ui-root> A2UI protocol → DOM (uses @adia-ai/a2ui
|
|
346
|
+
│ └── a2ui-root/ <a2ui-root> A2UI protocol → DOM (uses @adia-ai/a2ui)
|
|
347
347
|
├── theme/ 1 element
|
|
348
348
|
│ └── theme-panel/ <theme-panel> appearance-preferences control surface
|
|
349
349
|
└── index.js barrel re-export of every cluster
|
|
350
350
|
```
|
|
351
351
|
|
|
352
|
-
Each element directory carries its `.js`, `.css`, `.yaml`, and `.a2ui.json` files — same shape as `web-components/components/<x>/`. The yaml + a2ui.json contracts feed the gen-UI catalog at `packages/gen-ui/a2ui/
|
|
352
|
+
Each element directory carries its `.js`, `.css`, `.yaml`, and `.a2ui.json` files — same shape as `web-components/components/<x>/`. The yaml + a2ui.json contracts feed the gen-UI catalog at `packages/gen-ui/a2ui/catalog/catalog-a2ui_0_9.json`; the build script at `scripts/build/components.mjs` scans both `web-components/components/` and `web-modules/<cluster>/`.
|
|
353
353
|
|
|
354
354
|
## Behavior contract
|
|
355
355
|
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
box-sizing: border-box;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
:scope [data-part="row"][
|
|
67
|
+
:scope [data-part="row"][aria-checked="true"] {
|
|
68
68
|
--menu-item-bg: var(--admin-roster-active-bg);
|
|
69
69
|
--menu-item-fg: var(--admin-roster-active-fg);
|
|
70
70
|
--menu-item-fg-hover: var(--admin-roster-active-fg);
|
|
@@ -76,7 +76,7 @@
|
|
|
76
76
|
visibility: hidden;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
:scope [data-part="row"][
|
|
79
|
+
:scope [data-part="row"][aria-checked="true"] [data-part="row-check"] {
|
|
80
80
|
visibility: visible;
|
|
81
81
|
}
|
|
82
82
|
|
|
@@ -90,4 +90,12 @@
|
|
|
90
90
|
display: flex;
|
|
91
91
|
gap: var(--a-space-2);
|
|
92
92
|
}
|
|
93
|
+
|
|
94
|
+
/* Reuses <upload-ui> as the picker engine behind the visible "Import"
|
|
95
|
+
button (gh#1360) — display:none, not visually-hidden-ui: this node
|
|
96
|
+
is never meant to reach AT (aria-hidden + out of tab order above),
|
|
97
|
+
unlike a sr-only label that stays AT-visible on purpose. */
|
|
98
|
+
:scope [data-part="import-file"] {
|
|
99
|
+
display: none;
|
|
100
|
+
}
|
|
93
101
|
}
|
|
@@ -20,20 +20,50 @@
|
|
|
20
20
|
*
|
|
21
21
|
* Import/export rides `@adia-ai/persona`'s persona-file functions
|
|
22
22
|
* verbatim — this composite never re-implements the file format. Export
|
|
23
|
-
* downloads a `.json` via a throwaway object URL; import
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
23
|
+
* downloads a `.json` via a throwaway object URL; import reuses the
|
|
24
|
+
* `<upload-ui>` primitive (packages/web-components/components/upload/) as
|
|
25
|
+
* its file-picking engine — a `display:none` `<upload-ui data-part=
|
|
26
|
+
* "import-file">` sits in the template (`accept="application/json"`
|
|
27
|
+
* shapes its PICKER only — upload-ui's drop path forwards dropped files
|
|
28
|
+
* unfiltered, so this module re-checks "exactly one JSON-named/typed
|
|
29
|
+
* file" itself before importing), and the toolbar's visible "Import" icon button
|
|
30
|
+
* (gh#1360, replacing a hand-rolled `input[type=file]`) delegates the
|
|
31
|
+
* click to upload-ui's own dropzone part (`[data-dropzone]` — this
|
|
32
|
+
* framework's light-DOM "part" hook, styled by upload.css and driven by
|
|
33
|
+
* upload.class.js the same way; there is no public `.open()`/`.pick()`
|
|
34
|
+
* method on the primitive, so this is the narrowest supported trigger
|
|
35
|
+
* point short of a primitive change — see the ticket's Findings for the
|
|
36
|
+
* gap this surfaced). upload-ui's own `showOpenFilePicker` (+
|
|
37
|
+
* `input[type=file]` fallback) does the picking; its documented `change`
|
|
38
|
+
* event (`{ value, files }`, upload.d.ts) is read here, then handed to
|
|
39
|
+
* `importPersona` (which always MINTS a new persona — never overwrites an
|
|
40
|
+
* existing one, even on an id collision) and re-emitted upward as
|
|
41
|
+
* `persona-import` so a host can append it to its own persona list and
|
|
42
|
+
* persist it.
|
|
28
43
|
*
|
|
29
44
|
* Per ADR-0027 — composites that programmatically create primitives in
|
|
30
45
|
* render() do NOT auto-import those primitives; a consumer imports
|
|
31
|
-
* <button-ui> + <icon-ui> + <menu-item-ui> (menu.js)
|
|
46
|
+
* <button-ui> + <icon-ui> + <menu-item-ui> (menu.js) + <upload-ui>
|
|
47
|
+
* alongside this module.
|
|
32
48
|
*/
|
|
33
49
|
|
|
34
50
|
import { UIElement, html } from '@adia-ai/web-components/core/element';
|
|
35
51
|
import { exportPersona, importPersona } from '@adia-ai/persona';
|
|
36
52
|
|
|
53
|
+
// The template's <upload-ui accept="application/json"> — one value, both
|
|
54
|
+
// the picker filter and the drop-side check below derive from it.
|
|
55
|
+
const IMPORT_ACCEPT = 'application/json';
|
|
56
|
+
|
|
57
|
+
// A file "indicates JSON" when either its MIME type is the accept value or
|
|
58
|
+
// its name carries a .json suffix — OS drops routinely leave `type` empty
|
|
59
|
+
// for .json, and a picker-chosen file may be typed but oddly named, so
|
|
60
|
+
// either signal suffices; neither alone is required.
|
|
61
|
+
function isJsonFile(file) {
|
|
62
|
+
if (!file) return false;
|
|
63
|
+
if (file.type === IMPORT_ACCEPT) return true;
|
|
64
|
+
return /\.json$/i.test(String(file.name || ''));
|
|
65
|
+
}
|
|
66
|
+
|
|
37
67
|
class UIAdminRoster extends UIElement {
|
|
38
68
|
static properties = {
|
|
39
69
|
personas: { type: Array, default: [] },
|
|
@@ -43,7 +73,6 @@ class UIAdminRoster extends UIElement {
|
|
|
43
73
|
static template = (host) => host._renderTemplate();
|
|
44
74
|
|
|
45
75
|
#headerId = `admin-roster-h-${Math.random().toString(36).slice(2, 8)}`;
|
|
46
|
-
#fileInput = null;
|
|
47
76
|
|
|
48
77
|
attributeChangedCallback(name, oldVal, newVal) {
|
|
49
78
|
if (name === 'personas') {
|
|
@@ -94,6 +123,7 @@ class UIAdminRoster extends UIElement {
|
|
|
94
123
|
<button-ui data-action="export" text="Export" icon="download-simple" variant="ghost" size="sm"
|
|
95
124
|
.disabled=${!activeId}></button-ui>
|
|
96
125
|
<button-ui data-action="import" text="Import" icon="upload-simple" variant="ghost" size="sm"></button-ui>
|
|
126
|
+
<upload-ui data-part="import-file" accept=${IMPORT_ACCEPT} aria-hidden="true" tabindex="-1"></upload-ui>
|
|
97
127
|
</div>
|
|
98
128
|
`;
|
|
99
129
|
}
|
|
@@ -109,7 +139,6 @@ class UIAdminRoster extends UIElement {
|
|
|
109
139
|
role="menuitemradio"
|
|
110
140
|
tabindex="0"
|
|
111
141
|
aria-checked=${String(isActive)}
|
|
112
|
-
data-active=${isActive}
|
|
113
142
|
text=${persona.label ?? persona.id}
|
|
114
143
|
subtitle=${persona.category ?? ''}
|
|
115
144
|
>
|
|
@@ -175,24 +204,43 @@ class UIAdminRoster extends UIElement {
|
|
|
175
204
|
URL.revokeObjectURL(url);
|
|
176
205
|
}
|
|
177
206
|
|
|
207
|
+
// <upload-ui> exposes no public open()/pick() method (upload.d.ts) — the
|
|
208
|
+
// narrowest supported trigger is clicking its own `[data-dropzone]` part
|
|
209
|
+
// (the same node upload.class.js binds its click/keydown/drag listeners
|
|
210
|
+
// to, and upload.css styles by), so showOpenFilePicker (+ its
|
|
211
|
+
// input[type=file] fallback) runs exactly as it would for a directly
|
|
212
|
+
// clicked <upload-ui>.
|
|
178
213
|
#triggerImport() {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
this.#fileInput.type = 'file';
|
|
182
|
-
this.#fileInput.accept = 'application/json';
|
|
183
|
-
this.#fileInput.setAttribute('data-part', 'import-file');
|
|
184
|
-
this.#fileInput.style.display = 'none';
|
|
185
|
-
this.appendChild(this.#fileInput);
|
|
186
|
-
}
|
|
187
|
-
this.#fileInput.value = '';
|
|
188
|
-
this.#fileInput.click();
|
|
214
|
+
const upload = this.querySelector('[data-part="import-file"]');
|
|
215
|
+
upload?.querySelector('[data-dropzone]')?.click();
|
|
189
216
|
}
|
|
190
217
|
|
|
218
|
+
// Fires on the bubbling `change` <upload-ui> dispatches on itself
|
|
219
|
+
// (upload.d.ts's documented UploadChangeEvent — { value, files }).
|
|
220
|
+
//
|
|
221
|
+
// upload-ui's `accept` / `multiple` only shape its PICKER; its drop path
|
|
222
|
+
// (upload.class.js #onDrop) forwards `dataTransfer.files` unfiltered. So
|
|
223
|
+
// the single-JSON-file contract is enforced here: exactly one file whose
|
|
224
|
+
// name or MIME type says JSON — anything else is rejected through the
|
|
225
|
+
// same `persona-import-error` path a malformed file takes.
|
|
191
226
|
#onImportFileChange = async (e) => {
|
|
192
|
-
const
|
|
193
|
-
if (!
|
|
194
|
-
const
|
|
195
|
-
if (
|
|
227
|
+
const target = e.target;
|
|
228
|
+
if (!target || target.getAttribute?.('data-part') !== 'import-file') return;
|
|
229
|
+
const files = Array.isArray(e.detail?.files) ? e.detail.files : [];
|
|
230
|
+
if (files.length === 0) return;
|
|
231
|
+
const reject = (message) => this.dispatchEvent(new CustomEvent('persona-import-error', {
|
|
232
|
+
bubbles: true,
|
|
233
|
+
detail: { error: message },
|
|
234
|
+
}));
|
|
235
|
+
if (files.length !== 1) {
|
|
236
|
+
reject(`Import expects exactly one .json file (got ${files.length})`);
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
const [file] = files;
|
|
240
|
+
if (!isJsonFile(file)) {
|
|
241
|
+
reject(`Import expects a .json file (got "${file?.name || 'unnamed file'}")`);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
196
244
|
try {
|
|
197
245
|
const text = await file.text();
|
|
198
246
|
const existingIds = (Array.isArray(this.personas) ? this.personas : []).map((p) => p.id);
|
|
@@ -15,7 +15,10 @@
|
|
|
15
15
|
"properties": {
|
|
16
16
|
"account": {
|
|
17
17
|
"description": "Aggregate billing snapshot — source of truth for the whole\ndashboard. Shape:\n {plan: {id, name, price, cycle, currency, status},\n status: \"active\" | \"trialing\" | \"past_due\" | \"canceled\" | \"paused\",\n billingCycle: \"month\" | \"year\",\n currentSpend: number,\n seats: {used: number, total: number},\n nextInvoiceDate: ISO 8601 date string,\n paymentMethods: [...], // forwarded to payment-method-list\n invoices: [...], // forwarded to invoice-history\n plans?: [...], // forwarded to plan-picker; omitted when planSection is \"hidden\"\n dunning?: {amount, currency, dueAt, cardLast4?, reason?}}\nNull + no `data-stream-src` renders the empty state.\n",
|
|
18
|
-
"type":
|
|
18
|
+
"type": [
|
|
19
|
+
"object",
|
|
20
|
+
"null"
|
|
21
|
+
],
|
|
19
22
|
"default": null
|
|
20
23
|
},
|
|
21
24
|
"component": {
|
|
@@ -86,6 +89,11 @@
|
|
|
86
89
|
"tag-ui",
|
|
87
90
|
"text-ui",
|
|
88
91
|
"alert-ui",
|
|
92
|
+
"avatar-ui",
|
|
93
|
+
"col-ui",
|
|
94
|
+
"row-ui",
|
|
95
|
+
"grid-ui",
|
|
96
|
+
"progress-ui",
|
|
89
97
|
"plan-picker-ui",
|
|
90
98
|
"payment-method-list-ui",
|
|
91
99
|
"invoice-history-ui",
|
|
@@ -155,6 +163,7 @@
|
|
|
155
163
|
"past-due"
|
|
156
164
|
],
|
|
157
165
|
"name": "UIBillingOverview",
|
|
166
|
+
"parts": {},
|
|
158
167
|
"related": [
|
|
159
168
|
"PlanPicker",
|
|
160
169
|
"PaymentMethodList",
|