@adia-ai/web-components 0.8.6 → 0.8.8
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 +14 -0
- package/README.md +3 -3
- package/dist/host.min.css +1 -1
- package/dist/host.sheet.js +1 -1
- package/dist/theme-provider.min.js +2 -2
- package/dist/web-components.min.css +1 -1
- package/dist/web-components.min.js +1 -1
- package/dist/web-components.sheet.js +1 -1
- package/package.json +2 -1
- package/patterns/access-requests/access-requests.examples.html +132 -0
- package/patterns/access-requests/access-requests.html +60 -0
- package/patterns/admin-keys-and-export/admin-keys-and-export.examples.html +236 -0
- package/patterns/admin-keys-and-export/admin-keys-and-export.html +64 -0
- package/patterns/admin-shell/admin-shell.examples.html +327 -0
- package/patterns/admin-shell/admin-shell.html +44 -0
- package/patterns/agent-cost/agent-cost.examples.html +111 -0
- package/patterns/agent-cost/agent-cost.html +62 -0
- package/patterns/agent-memory/agent-memory.examples.html +155 -0
- package/patterns/agent-memory/agent-memory.html +64 -0
- package/patterns/agent-prompt-library/agent-prompt-library.examples.html +181 -0
- package/patterns/agent-prompt-library/agent-prompt-library.html +64 -0
- package/patterns/agent-tool-call/agent-tool-call.examples.html +123 -0
- package/patterns/agent-tool-call/agent-tool-call.html +60 -0
- package/patterns/alert-dialog/alert-dialog.examples.html +105 -0
- package/patterns/alert-dialog/alert-dialog.html +57 -0
- package/patterns/app-nav/app-nav.examples.html +421 -0
- package/patterns/app-nav/app-nav.html +50 -0
- package/patterns/approvals/approvals.examples.html +131 -0
- package/patterns/approvals/approvals.html +58 -0
- package/patterns/audit-log/audit-log.examples.html +74 -0
- package/patterns/audit-log/audit-log.examples.js +60 -0
- package/patterns/audit-log/audit-log.html +63 -0
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.html +89 -0
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.examples.js +69 -0
- package/patterns/bulk-action-toolbar/bulk-action-toolbar.html +62 -0
- package/patterns/changelog-feed/changelog-feed.examples.html +151 -0
- package/patterns/changelog-feed/changelog-feed.html +57 -0
- package/patterns/chart-in-card/chart-in-card.examples.html +193 -0
- package/patterns/chart-in-card/chart-in-card.examples.js +46 -0
- package/patterns/chart-in-card/chart-in-card.html +66 -0
- package/patterns/chat-shell/chat-shell.examples.html +129 -0
- package/patterns/chat-shell/chat-shell.html +46 -0
- package/patterns/comments-and-collaboration/comments-and-collaboration.examples.html +241 -0
- package/patterns/comments-and-collaboration/comments-and-collaboration.html +66 -0
- package/patterns/component-tokens/component-tokens.examples.html +483 -0
- package/patterns/component-tokens/component-tokens.html +42 -0
- package/patterns/conversion-funnel/conversion-funnel.examples.html +158 -0
- package/patterns/conversion-funnel/conversion-funnel.examples.js +4 -0
- package/patterns/conversion-funnel/conversion-funnel.html +64 -0
- package/patterns/data-tables-inline-edit-and-tree/data-tables-inline-edit-and-tree.examples.html +196 -0
- package/patterns/data-tables-inline-edit-and-tree/data-tables-inline-edit-and-tree.html +58 -0
- package/patterns/diff-review/diff-review.examples.html +147 -0
- package/patterns/diff-review/diff-review.html +56 -0
- package/patterns/editor-shell/editor-shell.examples.html +139 -0
- package/patterns/editor-shell/editor-shell.html +62 -0
- package/patterns/export-flow/export-flow.examples.html +152 -0
- package/patterns/export-flow/export-flow.examples.js +37 -0
- package/patterns/export-flow/export-flow.html +65 -0
- package/patterns/filter-bar/filter-bar.examples.html +116 -0
- package/patterns/filter-bar/filter-bar.examples.js +23 -0
- package/patterns/filter-bar/filter-bar.html +70 -0
- package/patterns/form-drawer/form-drawer.examples.html +210 -0
- package/patterns/form-drawer/form-drawer.html +64 -0
- package/patterns/form-system/form-system.examples.html +383 -0
- package/patterns/form-system/form-system.html +48 -0
- package/patterns/forms-conditional-and-autocomplete/forms-conditional-and-autocomplete.examples.html +189 -0
- package/patterns/forms-conditional-and-autocomplete/forms-conditional-and-autocomplete.html +64 -0
- package/patterns/inline-dialog/inline-dialog.examples.html +143 -0
- package/patterns/inline-dialog/inline-dialog.html +59 -0
- package/patterns/kanban-board/kanban-board.examples.html +224 -0
- package/patterns/kanban-board/kanban-board.html +58 -0
- package/patterns/layout/layout.examples.html +365 -0
- package/patterns/layout/layout.html +54 -0
- package/patterns/marketing-engagement/marketing-engagement.examples.html +280 -0
- package/patterns/marketing-engagement/marketing-engagement.html +64 -0
- package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.examples.html +213 -0
- package/patterns/notifications-bell-and-digest/notifications-bell-and-digest.html +58 -0
- package/patterns/overview/overview.examples.html +119 -0
- package/patterns/overview/overview.html +42 -0
- package/patterns/permissions-matrix/permissions-matrix.examples.html +91 -0
- package/patterns/permissions-matrix/permissions-matrix.examples.js +28 -0
- package/patterns/permissions-matrix/permissions-matrix.html +56 -0
- package/patterns/permissions-role-picker/permissions-role-picker.examples.html +81 -0
- package/patterns/permissions-role-picker/permissions-role-picker.html +56 -0
- package/patterns/permissions-sharing/permissions-sharing.examples.html +175 -0
- package/patterns/permissions-sharing/permissions-sharing.html +66 -0
- package/patterns/profile-public-and-verification/profile-public-and-verification.examples.html +227 -0
- package/patterns/profile-public-and-verification/profile-public-and-verification.html +70 -0
- package/patterns/record-detail-drawer/record-detail-drawer.examples.html +164 -0
- package/patterns/record-detail-drawer/record-detail-drawer.html +64 -0
- package/patterns/responsive-shell-sidebar/README.md +37 -0
- package/patterns/responsive-shell-sidebar/responsive-shell-sidebar.css +39 -0
- package/patterns/responsive-shell-sidebar/responsive-shell-sidebar.examples.html +208 -0
- package/patterns/responsive-shell-sidebar/responsive-shell-sidebar.html +47 -0
- package/patterns/retention-cohort/retention-cohort.examples.html +149 -0
- package/patterns/retention-cohort/retention-cohort.examples.js +37 -0
- package/patterns/retention-cohort/retention-cohort.html +62 -0
- package/patterns/search-discovery/search-discovery.examples.html +263 -0
- package/patterns/search-discovery/search-discovery.html +58 -0
- package/patterns/system-banners/system-banners.examples.html +150 -0
- package/patterns/system-banners/system-banners.html +52 -0
- package/patterns/timezone-selector/timezone-selector.examples.html +82 -0
- package/patterns/timezone-selector/timezone-selector.examples.js +72 -0
- package/patterns/timezone-selector/timezone-selector.html +57 -0
- package/patterns/wizard-drawer/wizard-drawer.examples.html +144 -0
- package/patterns/wizard-drawer/wizard-drawer.examples.js +33 -0
- package/patterns/wizard-drawer/wizard-drawer.html +72 -0
- package/styles/type/roles.css +8 -8
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@adia-ai/web-components",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.8",
|
|
4
4
|
"description": "AdiaUI web components \u2014 vanilla custom elements. A2UI runtime (renderer, registry, streams, wiring) lives in @adia-ai/a2ui-runtime.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./index.d.ts",
|
|
@@ -88,6 +88,7 @@
|
|
|
88
88
|
"color/",
|
|
89
89
|
"components/",
|
|
90
90
|
"dist/",
|
|
91
|
+
"patterns/",
|
|
91
92
|
"!components/**/*.html",
|
|
92
93
|
"!components/**/*.examples.js",
|
|
93
94
|
"components/**/*.examples.md",
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
<header>
|
|
2
|
+
<div>
|
|
3
|
+
<h1>Access requests</h1>
|
|
4
|
+
<div data-actions>
|
|
5
|
+
<tag-ui size="sm">card-ui</tag-ui> <tag-ui size="sm">field-ui</tag-ui> <tag-ui size="sm">alert-ui</tag-ui> <tag-ui size="sm">tag-ui</tag-ui>
|
|
6
|
+
</div>
|
|
7
|
+
</div>
|
|
8
|
+
<p>The "Request access" path when a user lacks permission for a resource. Three connected surfaces: the access-denied state with a Request CTA, the request form, and the pending-status follow-up. Sub-flavor of approvals (13d) — same async-gate semantics, different entry point.</p>
|
|
9
|
+
</header>
|
|
10
|
+
|
|
11
|
+
<section data-section data-property="when-to-use">
|
|
12
|
+
<h2 variant="section">When to use</h2>
|
|
13
|
+
<p data-note>
|
|
14
|
+
When a user clicks a link or opens a resource they don't have
|
|
15
|
+
permission to see. Hard-403 the resource but offer a path to
|
|
16
|
+
ask the owner — better UX than a dead end. The owner gets a
|
|
17
|
+
notification (15d) + an entry in their approval queue (13d);
|
|
18
|
+
the requester gets a pending state until the request resolves.
|
|
19
|
+
</p>
|
|
20
|
+
</section>
|
|
21
|
+
|
|
22
|
+
<section data-section data-property="access-denied-cta">
|
|
23
|
+
<h2 variant="section">Access denied — with Request CTA</h2>
|
|
24
|
+
<p data-note>The standard access-denied state (cross-ref 36d) augmented with a "Request access" primary action. <code>alert-ui variant="warning"</code> carries the explanation; the CTA opens the request form.</p>
|
|
25
|
+
<div data-artifact-container>
|
|
26
|
+
<div data-artifact-item data-artifact-label="access denied with request">
|
|
27
|
+
<card-ui data-chunk="access-denied-with-request" style="max-width: 480px;">
|
|
28
|
+
<header>
|
|
29
|
+
<span slot="heading" variant="section">You don't have access to this</span>
|
|
30
|
+
</header>
|
|
31
|
+
<section>
|
|
32
|
+
<alert-ui variant="warning" icon="lock">
|
|
33
|
+
<col-ui slot="content" gap="0-5">
|
|
34
|
+
<text-ui strong>Q4 product roadmap is restricted.</text-ui>
|
|
35
|
+
<text-ui>Owned by Avery Chen. Ask them for access, or check if your team has a different version.</text-ui>
|
|
36
|
+
</col-ui>
|
|
37
|
+
</alert-ui>
|
|
38
|
+
</section>
|
|
39
|
+
<footer divider>
|
|
40
|
+
<button-ui slot="action" text="Go back" variant="ghost"></button-ui>
|
|
41
|
+
<button-ui slot="action" text="Request access" variant="primary" icon-leading="paper-plane-tilt"></button-ui>
|
|
42
|
+
</footer>
|
|
43
|
+
</card-ui>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</section>
|
|
47
|
+
|
|
48
|
+
<section data-section data-property="request-form">
|
|
49
|
+
<h2 variant="section">Request form</h2>
|
|
50
|
+
<p data-note>The form the requester fills. Pre-fills the resource being requested; user picks the role they need + optional reason. Submit fires a notification to the owner.</p>
|
|
51
|
+
<div data-artifact-container>
|
|
52
|
+
<div data-artifact-item data-artifact-label="access request form">
|
|
53
|
+
<card-ui data-chunk="access-request-form" style="max-width: 560px;">
|
|
54
|
+
<header>
|
|
55
|
+
<span slot="heading" variant="section">Request access</span>
|
|
56
|
+
<text-ui slot="description" color="subtle">Avery Chen will be notified</text-ui>
|
|
57
|
+
</header>
|
|
58
|
+
<section>
|
|
59
|
+
<col-ui gap="3">
|
|
60
|
+
<field-ui label="Resource">
|
|
61
|
+
<input-ui name="resource" value="Q4 product roadmap" readonly></input-ui>
|
|
62
|
+
</field-ui>
|
|
63
|
+
<field-ui label="Role you need" required>
|
|
64
|
+
<select-ui name="role">
|
|
65
|
+
<option value="viewer" selected>Viewer — read only</option>
|
|
66
|
+
<option value="commenter">Commenter — read + comment</option>
|
|
67
|
+
<option value="editor">Editor — read + edit</option>
|
|
68
|
+
</select-ui>
|
|
69
|
+
</field-ui>
|
|
70
|
+
<field-ui label="Why do you need access?" hint="Optional but speeds up approval">
|
|
71
|
+
<textarea-ui name="reason" rows="3" placeholder="e.g., I'm reviewing the Q4 plan for the engineering breakdown."></textarea-ui>
|
|
72
|
+
</field-ui>
|
|
73
|
+
</col-ui>
|
|
74
|
+
</section>
|
|
75
|
+
<footer divider>
|
|
76
|
+
<button-ui slot="action" text="Cancel" variant="ghost"></button-ui>
|
|
77
|
+
<button-ui slot="action" text="Send request" variant="primary"></button-ui>
|
|
78
|
+
</footer>
|
|
79
|
+
</card-ui>
|
|
80
|
+
</div>
|
|
81
|
+
</div>
|
|
82
|
+
</section>
|
|
83
|
+
|
|
84
|
+
<section data-section data-property="request-pending">
|
|
85
|
+
<h2 variant="section">Pending status</h2>
|
|
86
|
+
<p data-note>The state the requester sees after submission. <code>alert-ui variant="info"</code> with the reviewer name + reasonable ETA. "Cancel request" + "View other resources" actions.</p>
|
|
87
|
+
<div data-artifact-container>
|
|
88
|
+
<div data-artifact-item data-artifact-label="access request pending">
|
|
89
|
+
<card-ui data-chunk="access-request-pending" style="max-width: 480px;">
|
|
90
|
+
<header>
|
|
91
|
+
<span slot="heading" variant="section">Request sent</span>
|
|
92
|
+
<tag-ui slot="action" variant="warning">Pending</tag-ui>
|
|
93
|
+
</header>
|
|
94
|
+
<section>
|
|
95
|
+
<alert-ui variant="info" icon="clock-counter-clockwise">
|
|
96
|
+
<col-ui slot="content" gap="0-5">
|
|
97
|
+
<text-ui strong>Avery Chen has been notified.</text-ui>
|
|
98
|
+
<text-ui>You'll get an email when they approve or decline. Most requests are answered within a business day.</text-ui>
|
|
99
|
+
</col-ui>
|
|
100
|
+
</alert-ui>
|
|
101
|
+
</section>
|
|
102
|
+
<footer divider>
|
|
103
|
+
<button-ui slot="action" text="Cancel request" variant="ghost"></button-ui>
|
|
104
|
+
<button-ui slot="action" text="View other resources" variant="primary"></button-ui>
|
|
105
|
+
</footer>
|
|
106
|
+
</card-ui>
|
|
107
|
+
</div>
|
|
108
|
+
</div>
|
|
109
|
+
</section>
|
|
110
|
+
|
|
111
|
+
<section data-section data-property="composition">
|
|
112
|
+
<h2 variant="section">Composition rules</h2>
|
|
113
|
+
<ul>
|
|
114
|
+
<li><strong>Always show the owner's name</strong> — "ask Avery" reads as a real path; "ask the owner" reads as a system error. The owner identity comes from the same authorization data that produced the 403.</li>
|
|
115
|
+
<li><strong>Pre-fill the resource</strong> — never make the user re-type the resource name. The link they clicked is the request payload.</li>
|
|
116
|
+
<li><strong>Default role = least-privilege</strong> — Viewer is the default; the user can escalate. This is the same posture the role-picker (36a) uses for new members.</li>
|
|
117
|
+
<li><strong>Reason is optional but encouraged</strong> — a one-line reason cuts approval lag. Frame the hint around speed, not surveillance.</li>
|
|
118
|
+
<li><strong>Pending state shows the reviewer + ETA</strong> — "Avery Chen has been notified · most requests answered within a business day" beats a generic "request sent" toast. The requester can plan around the wait.</li>
|
|
119
|
+
<li><strong>Cancel-request is reversible</strong> — let the user pull the request back without contacting the owner. This is a polite-by-default convention.</li>
|
|
120
|
+
<li><strong>Don't auto-grant after timeout</strong> — pending should stay pending forever (or until manually canceled). Auto-grant is a security smell.</li>
|
|
121
|
+
</ul>
|
|
122
|
+
</section>
|
|
123
|
+
|
|
124
|
+
<section data-section data-property="cross-references">
|
|
125
|
+
<h2 variant="section">See also</h2>
|
|
126
|
+
<ul>
|
|
127
|
+
<li><a href="/site/patterns/approvals">approvals</a> — the owner-side surface (13d). Access requests appear in the approval queue.</li>
|
|
128
|
+
<li><a href="/site/components/alert">alert-ui</a> — explanation copy on all three surfaces.</li>
|
|
129
|
+
<li><a href="/site/components/field">field-ui</a> · <a href="/site/components/select">select-ui</a> · <a href="/site/components/textarea">textarea-ui</a> — request form primitives.</li>
|
|
130
|
+
<li><a href="/site/patterns/permissions-role-picker">permissions-role-picker</a> — same role vocabulary as the role select.</li>
|
|
131
|
+
</ul>
|
|
132
|
+
</section>
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" theme="auto">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>Access requests (pattern) — AdiaUI</title>
|
|
7
|
+
|
|
8
|
+
<!-- Token base -->
|
|
9
|
+
<link rel="stylesheet" href="../../styles/resets.css">
|
|
10
|
+
<link rel="stylesheet" href="../../styles/tokens.css">
|
|
11
|
+
|
|
12
|
+
<!-- Component CSS — primitives this pattern composes -->
|
|
13
|
+
<link rel="stylesheet" href="../../components/alert/alert.css">
|
|
14
|
+
<link rel="stylesheet" href="../../components/button/button.css">
|
|
15
|
+
<link rel="stylesheet" href="../../components/card/card.css">
|
|
16
|
+
<link rel="stylesheet" href="../../components/col/col.css">
|
|
17
|
+
<link rel="stylesheet" href="../../components/field/field.css">
|
|
18
|
+
<link rel="stylesheet" href="../../components/input/input.css">
|
|
19
|
+
<link rel="stylesheet" href="../../components/select/select.css">
|
|
20
|
+
<link rel="stylesheet" href="../../components/tag/tag.css">
|
|
21
|
+
<link rel="stylesheet" href="../../components/text/text.css">
|
|
22
|
+
<link rel="stylesheet" href="../../components/textarea/textarea.css">
|
|
23
|
+
|
|
24
|
+
<!-- Component JS -->
|
|
25
|
+
<script type="module" src="../../components/alert/alert.js"></script>
|
|
26
|
+
<script type="module" src="../../components/button/button.js"></script>
|
|
27
|
+
<script type="module" src="../../components/card/card.js"></script>
|
|
28
|
+
<script type="module" src="../../components/col/col.js"></script>
|
|
29
|
+
<script type="module" src="../../components/field/field.js"></script>
|
|
30
|
+
<script type="module" src="../../components/input/input.js"></script>
|
|
31
|
+
<script type="module" src="../../components/select/select.js"></script>
|
|
32
|
+
<script type="module" src="../../components/tag/tag.js"></script>
|
|
33
|
+
<script type="module" src="../../components/text/text.js"></script>
|
|
34
|
+
<script type="module" src="../../components/textarea/textarea.js"></script>
|
|
35
|
+
|
|
36
|
+
<style>
|
|
37
|
+
:where(html, body) { margin: 0; min-height: 100vh; background: var(--md-sys-color-neutral-background); color: var(--md-sys-color-neutral-on-surface); font-family: var(--a-font-family); }
|
|
38
|
+
main { max-width: 960px; margin-inline: auto; padding: var(--a-space-6) var(--a-space-5); }
|
|
39
|
+
</style>
|
|
40
|
+
</head>
|
|
41
|
+
<body>
|
|
42
|
+
|
|
43
|
+
<main id="demo-root">
|
|
44
|
+
<p>Loading examples…</p>
|
|
45
|
+
</main>
|
|
46
|
+
|
|
47
|
+
<script type="module">
|
|
48
|
+
const root = document.getElementById('demo-root');
|
|
49
|
+
try {
|
|
50
|
+
const res = await fetch('./access-requests.examples.html');
|
|
51
|
+
if (!res.ok) throw new Error(`fetch failed (${res.status})`);
|
|
52
|
+
root.innerHTML = await res.text();
|
|
53
|
+
} catch (err) {
|
|
54
|
+
root.innerHTML = `<p style="color:var(--a-danger-strong);">Failed to load access-requests.examples.html — ${err.message}</p>`;
|
|
55
|
+
console.error('[access-requests.html]', err);
|
|
56
|
+
}
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
</body>
|
|
60
|
+
</html>
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
<header>
|
|
2
|
+
<div>
|
|
3
|
+
<h1>API keys, webhooks & data export</h1>
|
|
4
|
+
<div data-actions>
|
|
5
|
+
<tag-ui size="sm">card-ui</tag-ui> <tag-ui size="sm">field-ui</tag-ui> <tag-ui size="sm">input-ui</tag-ui> <tag-ui size="sm">tag-ui</tag-ui> <tag-ui size="sm">button-ui</tag-ui> <tag-ui size="sm">alert-ui</tag-ui>
|
|
6
|
+
</div>
|
|
7
|
+
</div>
|
|
8
|
+
<p>Two adjacent admin surfaces: API key + webhook management (04g), and data-export / account-portability (04i). Both compose existing primitives — the patterns are in the wiring, the security copy, and the destructive-action flow.</p>
|
|
9
|
+
</header>
|
|
10
|
+
|
|
11
|
+
<section data-section data-property="when-to-use">
|
|
12
|
+
<h2 variant="section">When to use</h2>
|
|
13
|
+
<p data-note>
|
|
14
|
+
API keys: programmatic access to your account — server-side
|
|
15
|
+
integrations, scripts, CI. Distinct from per-user OAuth tokens
|
|
16
|
+
(account login flow); these are long-lived bearer tokens scoped
|
|
17
|
+
to a workspace. Webhooks deliver events to a URL.
|
|
18
|
+
Data export: GDPR / CCPA / SOC-2 compliance + workspace
|
|
19
|
+
migration. The user requests, the system queues, an email
|
|
20
|
+
arrives with a download link.
|
|
21
|
+
</p>
|
|
22
|
+
</section>
|
|
23
|
+
|
|
24
|
+
<section data-section data-property="api-keys-list">
|
|
25
|
+
<h2 variant="section">API keys list</h2>
|
|
26
|
+
<p data-note>The active-keys list. Each row carries a name, prefix (last 4 chars only — never the full secret), scope tag, last-used time, and a kebab menu (Rotate / Revoke). "Create key" header action.</p>
|
|
27
|
+
<div data-artifact-container>
|
|
28
|
+
<div data-artifact-item data-artifact-label="api keys list">
|
|
29
|
+
<card-ui data-chunk="api-keys-list">
|
|
30
|
+
<header>
|
|
31
|
+
<span slot="heading" variant="section">API keys</span>
|
|
32
|
+
<text-ui slot="description" color="subtle">3 active · last rotated 12 days ago</text-ui>
|
|
33
|
+
<button-ui slot="action" text="Create key" variant="primary" size="sm" icon-leading="plus"></button-ui>
|
|
34
|
+
</header>
|
|
35
|
+
<section bleed>
|
|
36
|
+
<list-ui divider contained>
|
|
37
|
+
<list-item-ui text="Production — backend">
|
|
38
|
+
<icon-ui slot="icon" name="key" size="sm"></icon-ui>
|
|
39
|
+
<span slot="description"><code>sk_live_…A4F2</code> · last used 4 minutes ago</span>
|
|
40
|
+
<row-ui slot="action" gap="2" align="center">
|
|
41
|
+
<tag-ui size="sm" variant="primary">read · write</tag-ui>
|
|
42
|
+
<button-ui icon="dots-three-vertical" variant="ghost" size="sm" aria-label="Manage"></button-ui>
|
|
43
|
+
</row-ui>
|
|
44
|
+
</list-item-ui>
|
|
45
|
+
<list-item-ui text="CI — read-only">
|
|
46
|
+
<icon-ui slot="icon" name="key" size="sm"></icon-ui>
|
|
47
|
+
<span slot="description"><code>sk_live_…9821</code> · last used 2 hours ago</span>
|
|
48
|
+
<row-ui slot="action" gap="2" align="center">
|
|
49
|
+
<tag-ui size="sm">read</tag-ui>
|
|
50
|
+
<button-ui icon="dots-three-vertical" variant="ghost" size="sm" aria-label="Manage"></button-ui>
|
|
51
|
+
</row-ui>
|
|
52
|
+
</list-item-ui>
|
|
53
|
+
<list-item-ui text="Local dev — kim">
|
|
54
|
+
<icon-ui slot="icon" name="key" size="sm"></icon-ui>
|
|
55
|
+
<span slot="description"><code>sk_test_…7f0e</code> · last used 18 days ago</span>
|
|
56
|
+
<row-ui slot="action" gap="2" align="center">
|
|
57
|
+
<tag-ui size="sm" variant="muted">test</tag-ui>
|
|
58
|
+
<button-ui icon="dots-three-vertical" variant="ghost" size="sm" aria-label="Manage"></button-ui>
|
|
59
|
+
</row-ui>
|
|
60
|
+
</list-item-ui>
|
|
61
|
+
</list-ui>
|
|
62
|
+
</section>
|
|
63
|
+
</card-ui>
|
|
64
|
+
</div>
|
|
65
|
+
</div>
|
|
66
|
+
</section>
|
|
67
|
+
|
|
68
|
+
<section data-section data-property="api-keys-create">
|
|
69
|
+
<h2 variant="section">Create key — one-time reveal</h2>
|
|
70
|
+
<p data-note>The just-created key shown once. After this view closes, the secret is not retrievable; only the prefix shows in the list. Copy button + alert explaining the one-shot semantics.</p>
|
|
71
|
+
<div data-artifact-container>
|
|
72
|
+
<div data-artifact-item data-artifact-label="key one-time reveal">
|
|
73
|
+
<card-ui data-chunk="api-keys-create" style="max-width: 560px;">
|
|
74
|
+
<header>
|
|
75
|
+
<span slot="heading" variant="section">Your new API key</span>
|
|
76
|
+
<text-ui slot="description" color="subtle">Copy it now — it won't be shown again</text-ui>
|
|
77
|
+
</header>
|
|
78
|
+
<section>
|
|
79
|
+
<col-ui gap="3">
|
|
80
|
+
<field-ui label="Production — backend">
|
|
81
|
+
<input-ui name="api_key" value="sk_live_4f8b2e7c91d2a48fA4F2" readonly icon-trailing="copy"></input-ui>
|
|
82
|
+
</field-ui>
|
|
83
|
+
<alert-ui variant="warning" icon="warning">
|
|
84
|
+
<col-ui slot="content" gap="0-5">
|
|
85
|
+
<text-ui strong>This is the only time we'll show this key.</text-ui>
|
|
86
|
+
<text-ui>Store it in your secrets manager now. If you lose it, you'll need to revoke this key and create a new one.</text-ui>
|
|
87
|
+
</col-ui>
|
|
88
|
+
</alert-ui>
|
|
89
|
+
</col-ui>
|
|
90
|
+
</section>
|
|
91
|
+
<footer divider>
|
|
92
|
+
<button-ui slot="action" text="I've stored it safely" variant="primary"></button-ui>
|
|
93
|
+
</footer>
|
|
94
|
+
</card-ui>
|
|
95
|
+
</div>
|
|
96
|
+
</div>
|
|
97
|
+
</section>
|
|
98
|
+
|
|
99
|
+
<section data-section data-property="webhooks-list">
|
|
100
|
+
<h2 variant="section">Webhooks list</h2>
|
|
101
|
+
<p data-note>Endpoints + the events they subscribe to + last delivery status. Failed deliveries surface as a danger tag with a "Retry" affordance per row.</p>
|
|
102
|
+
<div data-artifact-container>
|
|
103
|
+
<div data-artifact-item data-artifact-label="webhooks list">
|
|
104
|
+
<card-ui data-chunk="webhooks-list">
|
|
105
|
+
<header>
|
|
106
|
+
<span slot="heading" variant="section">Webhooks</span>
|
|
107
|
+
<text-ui slot="description" color="subtle">2 endpoints · 1 failing</text-ui>
|
|
108
|
+
<button-ui slot="action" text="Add endpoint" variant="primary" size="sm" icon-leading="plus"></button-ui>
|
|
109
|
+
</header>
|
|
110
|
+
<section bleed>
|
|
111
|
+
<list-ui divider contained>
|
|
112
|
+
<list-item-ui text="https://api.example.com/adia/events">
|
|
113
|
+
<icon-ui slot="icon" name="webhooks-logo" size="sm"></icon-ui>
|
|
114
|
+
<span slot="description">5 events · last delivery 3 minutes ago</span>
|
|
115
|
+
<row-ui slot="action" gap="2" align="center">
|
|
116
|
+
<tag-ui size="sm" variant="success">200 OK</tag-ui>
|
|
117
|
+
<button-ui icon="dots-three-vertical" variant="ghost" size="sm" aria-label="Manage"></button-ui>
|
|
118
|
+
</row-ui>
|
|
119
|
+
</list-item-ui>
|
|
120
|
+
<list-item-ui text="https://hooks.zapier.com/…/abc123/">
|
|
121
|
+
<icon-ui slot="icon" name="webhooks-logo" size="sm"></icon-ui>
|
|
122
|
+
<span slot="description">3 events · last attempt 2 hours ago · 3 retries</span>
|
|
123
|
+
<row-ui slot="action" gap="2" align="center">
|
|
124
|
+
<tag-ui size="sm" variant="danger">503</tag-ui>
|
|
125
|
+
<button-ui text="Retry" variant="ghost" size="sm"></button-ui>
|
|
126
|
+
<button-ui icon="dots-three-vertical" variant="ghost" size="sm" aria-label="Manage"></button-ui>
|
|
127
|
+
</row-ui>
|
|
128
|
+
</list-item-ui>
|
|
129
|
+
</list-ui>
|
|
130
|
+
</section>
|
|
131
|
+
</card-ui>
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
</section>
|
|
135
|
+
|
|
136
|
+
<section data-section data-property="data-export-request">
|
|
137
|
+
<h2 variant="section">Data export — request</h2>
|
|
138
|
+
<p data-note>Compliance / portability flow. User picks scope (full workspace vs. just my data) + format, the system queues the job, an email arrives with a download link. Async, not synchronous.</p>
|
|
139
|
+
<div data-artifact-container>
|
|
140
|
+
<div data-artifact-item data-artifact-label="data export request">
|
|
141
|
+
<card-ui data-chunk="data-export-request" style="max-width: 560px;">
|
|
142
|
+
<header>
|
|
143
|
+
<span slot="heading" variant="section">Export your data</span>
|
|
144
|
+
<text-ui slot="description" color="subtle">We'll email you when the archive is ready</text-ui>
|
|
145
|
+
</header>
|
|
146
|
+
<section>
|
|
147
|
+
<col-ui gap="3">
|
|
148
|
+
<field-ui label="What to include" required>
|
|
149
|
+
<select-ui name="scope">
|
|
150
|
+
<option value="self">Just my data (GDPR Article 15)</option>
|
|
151
|
+
<option value="workspace" selected>Entire workspace (admin only)</option>
|
|
152
|
+
</select-ui>
|
|
153
|
+
</field-ui>
|
|
154
|
+
<field-ui label="Format" required>
|
|
155
|
+
<select-ui name="format">
|
|
156
|
+
<option value="json" selected>JSON archive (.zip)</option>
|
|
157
|
+
<option value="ndjson">NDJSON (line-delimited)</option>
|
|
158
|
+
<option value="csv">CSV per table</option>
|
|
159
|
+
</select-ui>
|
|
160
|
+
</field-ui>
|
|
161
|
+
<alert-ui variant="info" icon="clock">
|
|
162
|
+
<col-ui slot="content" gap="0-5">
|
|
163
|
+
<text-ui strong>Exports are usually ready within 1 hour.</text-ui>
|
|
164
|
+
<text-ui>Large workspaces (≥ 1M records) can take up to 24 hours. We'll email <code>kim@example.com</code> with a download link valid for 7 days.</text-ui>
|
|
165
|
+
</col-ui>
|
|
166
|
+
</alert-ui>
|
|
167
|
+
</col-ui>
|
|
168
|
+
</section>
|
|
169
|
+
<footer divider>
|
|
170
|
+
<button-ui slot="action" text="Cancel" variant="ghost"></button-ui>
|
|
171
|
+
<button-ui slot="action" text="Request export" variant="primary"></button-ui>
|
|
172
|
+
</footer>
|
|
173
|
+
</card-ui>
|
|
174
|
+
</div>
|
|
175
|
+
</div>
|
|
176
|
+
</section>
|
|
177
|
+
|
|
178
|
+
<section data-section data-property="data-export-history">
|
|
179
|
+
<h2 variant="section">Export history</h2>
|
|
180
|
+
<p data-note>The user's recent export jobs. Status tags (Queued / Running / Ready / Expired). "Ready" rows show a Download button until the link expires; expired rows are still visible for audit but disabled.</p>
|
|
181
|
+
<div data-artifact-container>
|
|
182
|
+
<div data-artifact-item data-artifact-label="export history">
|
|
183
|
+
<card-ui data-chunk="data-export-history">
|
|
184
|
+
<header>
|
|
185
|
+
<span slot="heading" variant="section">Recent exports</span>
|
|
186
|
+
</header>
|
|
187
|
+
<section bleed>
|
|
188
|
+
<list-ui divider contained>
|
|
189
|
+
<list-item-ui text="Workspace · JSON">
|
|
190
|
+
<icon-ui slot="icon" name="download-simple" size="sm"></icon-ui>
|
|
191
|
+
<span slot="description">Requested 12 minutes ago · 1.2M records</span>
|
|
192
|
+
<tag-ui slot="action" size="sm" variant="warning">Running</tag-ui>
|
|
193
|
+
</list-item-ui>
|
|
194
|
+
<list-item-ui text="My data · CSV">
|
|
195
|
+
<icon-ui slot="icon" name="download-simple" size="sm"></icon-ui>
|
|
196
|
+
<span slot="description">Ready 2 hours ago · 4.2 MB · expires in 6 days</span>
|
|
197
|
+
<row-ui slot="action" gap="2" align="center">
|
|
198
|
+
<tag-ui size="sm" variant="success">Ready</tag-ui>
|
|
199
|
+
<button-ui text="Download" variant="primary" size="sm" icon-leading="download-simple"></button-ui>
|
|
200
|
+
</row-ui>
|
|
201
|
+
</list-item-ui>
|
|
202
|
+
<list-item-ui text="Workspace · JSON">
|
|
203
|
+
<icon-ui slot="icon" name="download-simple" size="sm"></icon-ui>
|
|
204
|
+
<span slot="description">Ready 14 days ago · link expired</span>
|
|
205
|
+
<tag-ui slot="action" size="sm" variant="muted">Expired</tag-ui>
|
|
206
|
+
</list-item-ui>
|
|
207
|
+
</list-ui>
|
|
208
|
+
</section>
|
|
209
|
+
</card-ui>
|
|
210
|
+
</div>
|
|
211
|
+
</div>
|
|
212
|
+
</section>
|
|
213
|
+
|
|
214
|
+
<section data-section data-property="composition">
|
|
215
|
+
<h2 variant="section">Composition rules</h2>
|
|
216
|
+
<ul>
|
|
217
|
+
<li><strong>Show the prefix, never the full key</strong> — the list view always renders <code>sk_live_…A4F2</code>. The full secret only ever appears in the one-time reveal card; if the user lost it, they have to revoke + recreate. Storing the full key in the DB plaintext is the smell this convention prevents.</li>
|
|
218
|
+
<li><strong>One-time reveal needs a confirmation gate</strong> — the "I've stored it safely" button is the user's acknowledgment that they grabbed the key. Closing the modal/page without clicking it should still hide the secret (security default).</li>
|
|
219
|
+
<li><strong>Webhook failures are first-class</strong> — a 503 tag + Retry button is the canonical row. Hiding failures in a sub-page guarantees they get ignored.</li>
|
|
220
|
+
<li><strong>Data export is async, not sync</strong> — never block the UI on a "Generate now" call. Queue the job; email the link. Users with 1M-record workspaces shouldn't see a spinner.</li>
|
|
221
|
+
<li><strong>Download links expire</strong> — 7 days is typical; longer for SOC-2 retention requirements. The UI shows the expiry and the "Expired" state retains audit visibility (don't delete the row).</li>
|
|
222
|
+
<li><strong>Scope selection is policy-aware</strong> — "Entire workspace" must be admin-gated; non-admins see only "Just my data" (GDPR Article 15). Don't show the option then 403 the request.</li>
|
|
223
|
+
<li><strong>Format choices match the consumer</strong> — JSON archive for re-import, NDJSON for streaming consumers, CSV for spreadsheets. Three is enough; PDF or XLSX adds support tickets without value.</li>
|
|
224
|
+
</ul>
|
|
225
|
+
</section>
|
|
226
|
+
|
|
227
|
+
<section data-section data-property="cross-references">
|
|
228
|
+
<h2 variant="section">See also</h2>
|
|
229
|
+
<ul>
|
|
230
|
+
<li><a href="/site/components/field">field-ui</a> · <a href="/site/components/input">input-ui</a> · <a href="/site/components/select">select-ui</a> — form primitives.</li>
|
|
231
|
+
<li><a href="/site/components/alert">alert-ui</a> — security + scheduling copy.</li>
|
|
232
|
+
<li><a href="/site/components/tag">tag-ui</a> — status (200 OK / 503 / Running / Ready / Expired).</li>
|
|
233
|
+
<li><a href="/site/patterns/permissions-sharing">permissions-sharing</a> — adjacent (API key scopes overlap with sharing scopes).</li>
|
|
234
|
+
<li><a href="/site/patterns/profile-public-and-verification">profile + verification</a> — adjacent (KYC also gates high-value API actions per 16e).</li>
|
|
235
|
+
</ul>
|
|
236
|
+
</section>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" theme="auto">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>API keys, webhooks & data export (pattern) — AdiaUI</title>
|
|
7
|
+
|
|
8
|
+
<!-- Token base -->
|
|
9
|
+
<link rel="stylesheet" href="../../styles/resets.css">
|
|
10
|
+
<link rel="stylesheet" href="../../styles/tokens.css">
|
|
11
|
+
|
|
12
|
+
<!-- Component CSS — primitives this pattern composes -->
|
|
13
|
+
<link rel="stylesheet" href="../../components/alert/alert.css">
|
|
14
|
+
<link rel="stylesheet" href="../../components/button/button.css">
|
|
15
|
+
<link rel="stylesheet" href="../../components/card/card.css">
|
|
16
|
+
<link rel="stylesheet" href="../../components/col/col.css">
|
|
17
|
+
<link rel="stylesheet" href="../../components/field/field.css">
|
|
18
|
+
<link rel="stylesheet" href="../../components/icon/icon.css">
|
|
19
|
+
<link rel="stylesheet" href="../../components/input/input.css">
|
|
20
|
+
<link rel="stylesheet" href="../../components/list/list.css">
|
|
21
|
+
<link rel="stylesheet" href="../../components/row/row.css">
|
|
22
|
+
<link rel="stylesheet" href="../../components/select/select.css">
|
|
23
|
+
<link rel="stylesheet" href="../../components/tag/tag.css">
|
|
24
|
+
<link rel="stylesheet" href="../../components/text/text.css">
|
|
25
|
+
|
|
26
|
+
<!-- Component JS -->
|
|
27
|
+
<script type="module" src="../../components/alert/alert.js"></script>
|
|
28
|
+
<script type="module" src="../../components/button/button.js"></script>
|
|
29
|
+
<script type="module" src="../../components/card/card.js"></script>
|
|
30
|
+
<script type="module" src="../../components/col/col.js"></script>
|
|
31
|
+
<script type="module" src="../../components/field/field.js"></script>
|
|
32
|
+
<script type="module" src="../../components/icon/icon.js"></script>
|
|
33
|
+
<script type="module" src="../../components/input/input.js"></script>
|
|
34
|
+
<script type="module" src="../../components/list/list.js"></script>
|
|
35
|
+
<script type="module" src="../../components/row/row.js"></script>
|
|
36
|
+
<script type="module" src="../../components/select/select.js"></script>
|
|
37
|
+
<script type="module" src="../../components/tag/tag.js"></script>
|
|
38
|
+
<script type="module" src="../../components/text/text.js"></script>
|
|
39
|
+
|
|
40
|
+
<style>
|
|
41
|
+
:where(html, body) { margin: 0; min-height: 100vh; background: var(--md-sys-color-neutral-background); color: var(--md-sys-color-neutral-on-surface); font-family: var(--a-font-family); }
|
|
42
|
+
main { max-width: 960px; margin-inline: auto; padding: var(--a-space-6) var(--a-space-5); }
|
|
43
|
+
</style>
|
|
44
|
+
</head>
|
|
45
|
+
<body>
|
|
46
|
+
|
|
47
|
+
<main id="demo-root">
|
|
48
|
+
<p>Loading examples…</p>
|
|
49
|
+
</main>
|
|
50
|
+
|
|
51
|
+
<script type="module">
|
|
52
|
+
const root = document.getElementById('demo-root');
|
|
53
|
+
try {
|
|
54
|
+
const res = await fetch('./admin-keys-and-export.examples.html');
|
|
55
|
+
if (!res.ok) throw new Error(`fetch failed (${res.status})`);
|
|
56
|
+
root.innerHTML = await res.text();
|
|
57
|
+
} catch (err) {
|
|
58
|
+
root.innerHTML = `<p style="color:var(--a-danger-strong);">Failed to load admin-keys-and-export.examples.html — ${err.message}</p>`;
|
|
59
|
+
console.error('[admin-keys-and-export.html]', err);
|
|
60
|
+
}
|
|
61
|
+
</script>
|
|
62
|
+
|
|
63
|
+
</body>
|
|
64
|
+
</html>
|