@happyvertical/smrt-svelte 0.55.9 → 0.55.11
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/AGENTS.md +2 -1
- package/agents/cookbook-shell.md +176 -0
- package/agents/overview-presentation.md +8 -0
- package/agents/overview-surfaces.md +133 -17
- package/agents/screens.md +5 -0
- package/agents/workspace.md +6 -0
- package/dist/components/activity/ActivityList.svelte +35 -0
- package/dist/components/activity/ActivityList.svelte.d.ts +11 -0
- package/dist/components/activity/ActivityList.svelte.d.ts.map +1 -0
- package/dist/components/activity/index.d.ts +3 -0
- package/dist/components/activity/index.d.ts.map +1 -0
- package/dist/components/activity/index.js +1 -0
- package/dist/components/activity/safe-href.d.ts +3 -0
- package/dist/components/activity/safe-href.d.ts.map +1 -0
- package/dist/components/activity/safe-href.js +12 -0
- package/dist/components/activity/types.d.ts +9 -0
- package/dist/components/activity/types.d.ts.map +1 -0
- package/dist/components/activity/types.js +1 -0
- package/dist/components/cookbook/CookbookApp.svelte +236 -0
- package/dist/components/cookbook/CookbookApp.svelte.d.ts +5 -0
- package/dist/components/cookbook/CookbookApp.svelte.d.ts.map +1 -0
- package/dist/components/cookbook/CookbookSectionOverview.svelte +71 -0
- package/dist/components/cookbook/CookbookSectionOverview.svelte.d.ts +20 -0
- package/dist/components/cookbook/CookbookSectionOverview.svelte.d.ts.map +1 -0
- package/dist/components/cookbook/CookbookSectionPage.svelte +133 -0
- package/dist/components/cookbook/CookbookSectionPage.svelte.d.ts +5 -0
- package/dist/components/cookbook/CookbookSectionPage.svelte.d.ts.map +1 -0
- package/dist/components/cookbook/brand-theme.d.ts +11 -0
- package/dist/components/cookbook/brand-theme.d.ts.map +1 -0
- package/dist/components/cookbook/brand-theme.js +24 -0
- package/dist/components/cookbook/build.d.ts +8 -0
- package/dist/components/cookbook/build.d.ts.map +1 -0
- package/dist/components/cookbook/build.js +277 -0
- package/dist/components/cookbook/catalog.d.ts +37 -0
- package/dist/components/cookbook/catalog.d.ts.map +1 -0
- package/dist/components/cookbook/catalog.js +99 -0
- package/dist/components/cookbook/context.d.ts +23 -0
- package/dist/components/cookbook/context.d.ts.map +1 -0
- package/dist/components/cookbook/context.js +15 -0
- package/dist/components/cookbook/index.d.ts +22 -0
- package/dist/components/cookbook/index.d.ts.map +1 -0
- package/dist/components/cookbook/index.js +20 -0
- package/dist/components/cookbook/page.d.ts +23 -0
- package/dist/components/cookbook/page.d.ts.map +1 -0
- package/dist/components/cookbook/page.js +32 -0
- package/dist/components/cookbook/registry.d.ts +37 -0
- package/dist/components/cookbook/registry.d.ts.map +1 -0
- package/dist/components/cookbook/registry.js +38 -0
- package/dist/components/cookbook/sections.d.ts +60 -0
- package/dist/components/cookbook/sections.d.ts.map +1 -0
- package/dist/components/cookbook/sections.js +88 -0
- package/dist/components/cookbook/server.d.ts +61 -0
- package/dist/components/cookbook/server.d.ts.map +1 -0
- package/dist/components/cookbook/server.js +108 -0
- package/dist/components/cookbook/theme.d.ts +21 -0
- package/dist/components/cookbook/theme.d.ts.map +1 -0
- package/dist/components/cookbook/theme.js +53 -0
- package/dist/components/cookbook/types.d.ts +204 -0
- package/dist/components/cookbook/types.d.ts.map +1 -0
- package/dist/components/cookbook/types.js +1 -0
- package/dist/components/notifications/LocalizedNotifications.fixture.svelte +16 -0
- package/dist/components/notifications/LocalizedNotifications.fixture.svelte.d.ts +11 -0
- package/dist/components/notifications/LocalizedNotifications.fixture.svelte.d.ts.map +1 -0
- package/dist/components/notifications/NotificationBell.svelte +136 -0
- package/dist/components/notifications/NotificationBell.svelte.d.ts +13 -0
- package/dist/components/notifications/NotificationBell.svelte.d.ts.map +1 -0
- package/dist/components/notifications/index.d.ts +3 -0
- package/dist/components/notifications/index.d.ts.map +1 -0
- package/dist/components/notifications/index.js +1 -0
- package/dist/components/notifications/types.d.ts +27 -0
- package/dist/components/notifications/types.d.ts.map +1 -0
- package/dist/components/notifications/types.js +1 -0
- package/dist/components/overview/OverviewAssistantUndo.svelte +77 -0
- package/dist/components/overview/OverviewAssistantUndo.svelte.d.ts +13 -0
- package/dist/components/overview/OverviewAssistantUndo.svelte.d.ts.map +1 -0
- package/dist/components/overview/OverviewGrid.svelte +5 -2
- package/dist/components/overview/OverviewGrid.svelte.d.ts.map +1 -1
- package/dist/components/overview/assistant-surface.d.ts +90 -0
- package/dist/components/overview/assistant-surface.d.ts.map +1 -0
- package/dist/components/overview/assistant-surface.js +65 -0
- package/dist/components/overview/assistant.svelte.d.ts +115 -0
- package/dist/components/overview/assistant.svelte.d.ts.map +1 -0
- package/dist/components/overview/assistant.svelte.js +260 -0
- package/dist/components/overview/controller.svelte.d.ts +8 -0
- package/dist/components/overview/controller.svelte.d.ts.map +1 -1
- package/dist/components/overview/controller.svelte.js +76 -13
- package/dist/components/overview/grid-types.d.ts +6 -2
- package/dist/components/overview/grid-types.d.ts.map +1 -1
- package/dist/components/overview/index.d.ts +2 -0
- package/dist/components/overview/index.d.ts.map +1 -1
- package/dist/components/overview/index.js +2 -0
- package/dist/components/overview/operations.d.ts +169 -0
- package/dist/components/overview/operations.d.ts.map +1 -0
- package/dist/components/overview/operations.js +358 -0
- package/dist/components/overview/server.d.ts +2 -0
- package/dist/components/overview/server.d.ts.map +1 -1
- package/dist/components/overview/server.js +2 -0
- package/dist/components/workspace/admin-shell/settings-delta.d.ts +21 -0
- package/dist/components/workspace/admin-shell/settings-delta.d.ts.map +1 -0
- package/dist/components/workspace/admin-shell/settings-delta.js +142 -0
- package/dist/components/workspace/index.d.ts +1 -0
- package/dist/components/workspace/index.d.ts.map +1 -1
- package/dist/components/workspace/index.js +1 -0
- package/dist/components/workspace/server/index.d.ts +6 -2
- package/dist/components/workspace/server/index.d.ts.map +1 -1
- package/dist/components/workspace/server/index.js +5 -2
- package/dist/i18n/server.d.ts +1 -0
- package/dist/i18n/server.d.ts.map +1 -1
- package/dist/i18n/server.js +1 -0
- package/dist/i18n/strings.notifications.d.ts +12 -0
- package/dist/i18n/strings.notifications.d.ts.map +1 -0
- package/dist/i18n/strings.notifications.js +13 -0
- package/dist/i18n/strings.overview.d.ts +9 -0
- package/dist/i18n/strings.overview.d.ts.map +1 -1
- package/dist/i18n/strings.overview.js +11 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/package.json +31 -14
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalizedNotifications.fixture.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/notifications/LocalizedNotifications.fixture.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,SAAS,EAAkB,MAAM,6BAA6B,CAAC;AAI7E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGvD,UAAU,KAAK;IACb,KAAK,EAAE,SAAS,CAAC;IACjB,QAAQ,CAAC,EAAE,oBAAoB,CAAC;IAChC,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAeD,QAAA,MAAM,sBAAsB,2CAAwC,CAAC;AACrE,KAAK,sBAAsB,GAAG,UAAU,CAAC,OAAO,sBAAsB,CAAC,CAAC;AACxE,eAAe,sBAAsB,CAAC"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
3
|
+
import { Button } from '@happyvertical/smrt-ui/ui';
|
|
4
|
+
import { M } from '../../i18n/strings.notifications.js';
|
|
5
|
+
import type { NotificationProvider } from './types.js';
|
|
6
|
+
|
|
7
|
+
interface Props {
|
|
8
|
+
/** Authorized provider that supplies this user's notification state. */
|
|
9
|
+
provider: NotificationProvider;
|
|
10
|
+
/** Accessible trigger and panel heading. */
|
|
11
|
+
label?: string;
|
|
12
|
+
/** Maximum number of recent notifications requested from the provider. */
|
|
13
|
+
limit?: number;
|
|
14
|
+
}
|
|
15
|
+
const { t } = useI18n();
|
|
16
|
+
let { provider, label, limit = 20 }: Props = $props();
|
|
17
|
+
const heading = $derived(label ?? t(M['ui.notification_bell.label']));
|
|
18
|
+
const instanceId = $props.id();
|
|
19
|
+
let panel = $state<HTMLDivElement>();
|
|
20
|
+
let open = $state(false);
|
|
21
|
+
$effect(() => {
|
|
22
|
+
if (open) panel?.focus();
|
|
23
|
+
});
|
|
24
|
+
let loading = $state(true);
|
|
25
|
+
let error = $state<string | null>(null);
|
|
26
|
+
let unread = $state(0);
|
|
27
|
+
let items = $state<Awaited<ReturnType<NotificationProvider['list']>>>([]);
|
|
28
|
+
let request = 0;
|
|
29
|
+
let generation = 0;
|
|
30
|
+
let active = false;
|
|
31
|
+
|
|
32
|
+
async function refresh(source = provider, epoch = generation) {
|
|
33
|
+
if (!active || epoch !== generation) return;
|
|
34
|
+
const current = ++request;
|
|
35
|
+
loading = true;
|
|
36
|
+
error = null;
|
|
37
|
+
try {
|
|
38
|
+
const [nextUnread, nextItems] = await Promise.all([
|
|
39
|
+
source.getUnreadCount(),
|
|
40
|
+
source.list({ limit }),
|
|
41
|
+
]);
|
|
42
|
+
if (!active || epoch !== generation || current !== request) return;
|
|
43
|
+
unread =
|
|
44
|
+
Number.isSafeInteger(nextUnread) && nextUnread > 0 ? nextUnread : 0;
|
|
45
|
+
items = nextItems;
|
|
46
|
+
} catch {
|
|
47
|
+
if (!active || epoch !== generation || current !== request) return;
|
|
48
|
+
error = M['ui.notification_bell.unavailable'];
|
|
49
|
+
} finally {
|
|
50
|
+
if (active && epoch === generation && current === request) loading = false;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
function safeHref(value: string | null | undefined): string | null {
|
|
54
|
+
if (!value || value.startsWith('//') || value.includes('\\')) return null;
|
|
55
|
+
try {
|
|
56
|
+
const parsed = new URL(value, 'https://smrt.invalid');
|
|
57
|
+
return parsed.protocol === 'http:' || parsed.protocol === 'https:'
|
|
58
|
+
? value
|
|
59
|
+
: null;
|
|
60
|
+
} catch {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function close() {
|
|
65
|
+
open = false;
|
|
66
|
+
document.getElementById(`${instanceId}-trigger`)?.focus();
|
|
67
|
+
}
|
|
68
|
+
function keydown(event: KeyboardEvent) {
|
|
69
|
+
if (event.key === 'Escape' && open) {
|
|
70
|
+
event.preventDefault();
|
|
71
|
+
close();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
async function mutate(id?: string) {
|
|
75
|
+
const source = provider;
|
|
76
|
+
const epoch = generation;
|
|
77
|
+
try {
|
|
78
|
+
if (id) await source.markRead(id);
|
|
79
|
+
else await source.markAllRead();
|
|
80
|
+
await refresh(source, epoch);
|
|
81
|
+
} catch {
|
|
82
|
+
if (active && epoch === generation)
|
|
83
|
+
error = M['ui.notification_bell.mark_error'];
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
$effect(() => {
|
|
87
|
+
const source = provider;
|
|
88
|
+
const epoch = ++generation;
|
|
89
|
+
active = true;
|
|
90
|
+
items = [];
|
|
91
|
+
unread = 0;
|
|
92
|
+
error = null;
|
|
93
|
+
void refresh(source, epoch);
|
|
94
|
+
let stop: (() => void) | undefined;
|
|
95
|
+
try {
|
|
96
|
+
stop = source.subscribe?.(() => void refresh(source, epoch));
|
|
97
|
+
} catch {
|
|
98
|
+
error = M['ui.notification_bell.live_error'];
|
|
99
|
+
}
|
|
100
|
+
return () => {
|
|
101
|
+
active = false;
|
|
102
|
+
++generation;
|
|
103
|
+
++request;
|
|
104
|
+
stop?.();
|
|
105
|
+
};
|
|
106
|
+
});
|
|
107
|
+
</script>
|
|
108
|
+
|
|
109
|
+
<div class="smrt-notification-bell">
|
|
110
|
+
<Button id={`${instanceId}-trigger`} aria-controls={`${instanceId}-panel`} variant="ghost" aria-haspopup="dialog" aria-expanded={open} onclick={() => (open = !open)}>
|
|
111
|
+
{heading}{#if unread > 0}<span aria-label={t(M['ui.notification_bell.unread'], { count: unread })}> ({unread})</span>{/if}
|
|
112
|
+
</Button>
|
|
113
|
+
{#if open}
|
|
114
|
+
<div bind:this={panel} id={`${instanceId}-panel`} role="dialog" aria-label={heading} tabindex="-1" onkeydown={keydown} class="smrt-notification-bell__panel">
|
|
115
|
+
<header><strong>{heading}</strong><Button variant="ghost" size="sm" disabled={unread === 0 || loading} onclick={() => mutate()}>{t(M['ui.notification_bell.mark_all'])}</Button></header>
|
|
116
|
+
{#if error}<p role="alert">{t(error)}</p>{/if}
|
|
117
|
+
{#if loading}<p role="status">{t(M['ui.notification_bell.loading'])}</p>{:else if items.length === 0}<p>{t(M['ui.notification_bell.empty'])}</p>{:else}<ol>
|
|
118
|
+
{#each items as item (item.id)}<li data-read={item.readAt ? 'true' : 'false'}>
|
|
119
|
+
{#if safeHref(item.href)}<a href={safeHref(item.href) ?? undefined}>{item.title}</a>{:else}<strong>{item.title}</strong>{/if}
|
|
120
|
+
{#if item.body}<p>{item.body}</p>{/if}
|
|
121
|
+
{#if !item.readAt}<Button variant="ghost" size="sm" onclick={() => mutate(item.id)}>{t(M['ui.notification_bell.mark_one'])}</Button>{/if}
|
|
122
|
+
</li>{/each}
|
|
123
|
+
</ol>{/if}
|
|
124
|
+
</div>
|
|
125
|
+
{/if}
|
|
126
|
+
</div>
|
|
127
|
+
|
|
128
|
+
<style>
|
|
129
|
+
.smrt-notification-bell { position: relative; }
|
|
130
|
+
.smrt-notification-bell__panel { position: absolute; z-index: 1; inset-block-start: 100%; inset-inline-end: 0; inline-size: min(24rem, 90vw); padding: var(--smrt-spacing-3); background: var(--smrt-color-surface); border: 1px solid var(--smrt-color-outline); border-radius: var(--smrt-radius-medium); }
|
|
131
|
+
header { display: flex; justify-content: space-between; gap: var(--smrt-spacing-2); }
|
|
132
|
+
ol { display: grid; gap: var(--smrt-spacing-2); padding: 0; list-style: none; }
|
|
133
|
+
li { padding-block: var(--smrt-spacing-2); border-block-end: 1px solid var(--smrt-color-outline-variant); }
|
|
134
|
+
li[data-read='false'] { border-inline-start: 3px solid var(--smrt-color-primary); padding-inline-start: var(--smrt-spacing-2); }
|
|
135
|
+
p { overflow-wrap: anywhere; }
|
|
136
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { NotificationProvider } from './types.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** Authorized provider that supplies this user's notification state. */
|
|
4
|
+
provider: NotificationProvider;
|
|
5
|
+
/** Accessible trigger and panel heading. */
|
|
6
|
+
label?: string;
|
|
7
|
+
/** Maximum number of recent notifications requested from the provider. */
|
|
8
|
+
limit?: number;
|
|
9
|
+
}
|
|
10
|
+
declare const NotificationBell: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type NotificationBell = ReturnType<typeof NotificationBell>;
|
|
12
|
+
export default NotificationBell;
|
|
13
|
+
//# sourceMappingURL=NotificationBell.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"NotificationBell.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/notifications/NotificationBell.svelte.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGvD,UAAU,KAAK;IACb,wEAAwE;IACxE,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,0EAA0E;IAC1E,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AA4HD,QAAA,MAAM,gBAAgB,2CAAwC,CAAC;AAC/D,KAAK,gBAAgB,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAC5D,eAAe,gBAAgB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/notifications/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxE,YAAY,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as NotificationBell } from './NotificationBell.svelte';
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** A browser-safe notification supplied by an application-owned provider. */
|
|
2
|
+
export interface NotificationItem {
|
|
3
|
+
id: string;
|
|
4
|
+
title: string;
|
|
5
|
+
body?: string;
|
|
6
|
+
href?: string | null;
|
|
7
|
+
severity?: 'info' | 'success' | 'warning' | 'error';
|
|
8
|
+
occurredAt: string;
|
|
9
|
+
readAt?: string | null;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Application boundary for the notification bell.
|
|
13
|
+
*
|
|
14
|
+
* Providers authorize their own reads and writes. The component never accepts
|
|
15
|
+
* a user id or tenant id, so it cannot broaden that authority.
|
|
16
|
+
*/
|
|
17
|
+
export interface NotificationProvider {
|
|
18
|
+
getUnreadCount(): Promise<number>;
|
|
19
|
+
list(options?: {
|
|
20
|
+
limit?: number;
|
|
21
|
+
}): Promise<NotificationItem[]>;
|
|
22
|
+
markRead(id: string): Promise<void>;
|
|
23
|
+
markAllRead(): Promise<void>;
|
|
24
|
+
/** Optional live transport subscription. Returns an unsubscribe function. */
|
|
25
|
+
subscribe?(listener: () => void): () => void;
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/components/notifications/types.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,CAAC;IACpD,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,WAAW,oBAAoB;IACnC,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAClC,IAAI,CAAC,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAChE,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,6EAA6E;IAC7E,SAAS,CAAC,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC;CAC9C"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
/**
|
|
3
|
+
* The inline Undo affordance for an assistant's overview edit (#3727 phase
|
|
4
|
+
* 4). While the last batch can be undone it shows a short message with an
|
|
5
|
+
* Undo button and a dismiss button; the outcome of Undo is announced in the
|
|
6
|
+
* same polite live region. Place it next to the `OverviewGrid` it belongs to.
|
|
7
|
+
*/
|
|
8
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
9
|
+
import { Button } from '@happyvertical/smrt-ui/ui';
|
|
10
|
+
import { M } from '../../i18n/strings.overview.js';
|
|
11
|
+
import type {
|
|
12
|
+
OverviewAssistant,
|
|
13
|
+
OverviewAssistantBatch,
|
|
14
|
+
} from './assistant.svelte.js';
|
|
15
|
+
|
|
16
|
+
interface Props {
|
|
17
|
+
/** The browser assistant from `createOverviewAssistant`. */
|
|
18
|
+
assistant: OverviewAssistant;
|
|
19
|
+
/** Message for a batch (default: a generic "updated" line). */
|
|
20
|
+
message?: (batch: OverviewAssistantBatch) => string;
|
|
21
|
+
/** Extra class names for the affordance's row, for host placement. */
|
|
22
|
+
class?: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
let { assistant, message, class: className = '' }: Props = $props();
|
|
26
|
+
const { t } = useI18n();
|
|
27
|
+
const batch = $derived(assistant.lastBatch);
|
|
28
|
+
let outcome = $state('');
|
|
29
|
+
|
|
30
|
+
function undo(): void {
|
|
31
|
+
const current = batch;
|
|
32
|
+
if (!current) return;
|
|
33
|
+
const result = assistant.undo(current.id);
|
|
34
|
+
outcome = result.ok
|
|
35
|
+
? t(M['ui.overview.assistant_undone'])
|
|
36
|
+
: result.reason === 'changed_since'
|
|
37
|
+
? t(M['ui.overview.assistant_changed_since'])
|
|
38
|
+
: t(M['ui.overview.assistant_undo_failed']);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
$effect(() => {
|
|
42
|
+
// A new batch replaces the previous outcome line.
|
|
43
|
+
if (batch) outcome = '';
|
|
44
|
+
});
|
|
45
|
+
</script>
|
|
46
|
+
|
|
47
|
+
<div class="smrt-overview-assistant-undo {className}" data-active={batch ? '' : undefined}>
|
|
48
|
+
<!-- The live region stays mounted so each new message is announced. -->
|
|
49
|
+
<span class="smrt-overview-assistant-undo__message" role="status" aria-live="polite">
|
|
50
|
+
{#if batch}
|
|
51
|
+
{message ? message(batch) : t(M['ui.overview.assistant_applied'])}
|
|
52
|
+
{:else}
|
|
53
|
+
{outcome}
|
|
54
|
+
{/if}
|
|
55
|
+
</span>
|
|
56
|
+
{#if batch}
|
|
57
|
+
<Button size="sm" variant="secondary" onclick={undo}>
|
|
58
|
+
{t(M['ui.overview.assistant_undo'])}
|
|
59
|
+
</Button>
|
|
60
|
+
<Button size="sm" variant="ghost" onclick={() => assistant.dismiss()}>
|
|
61
|
+
{t(M['ui.overview.assistant_dismiss'])}
|
|
62
|
+
</Button>
|
|
63
|
+
{/if}
|
|
64
|
+
</div>
|
|
65
|
+
|
|
66
|
+
<style>
|
|
67
|
+
.smrt-overview-assistant-undo {
|
|
68
|
+
display: flex;
|
|
69
|
+
flex-wrap: wrap;
|
|
70
|
+
align-items: center;
|
|
71
|
+
gap: var(--smrt-spacing-2, 0.5rem);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
.smrt-overview-assistant-undo__message {
|
|
75
|
+
flex: 1 1 12rem;
|
|
76
|
+
}
|
|
77
|
+
</style>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { OverviewAssistant, OverviewAssistantBatch } from './assistant.svelte.js';
|
|
2
|
+
interface Props {
|
|
3
|
+
/** The browser assistant from `createOverviewAssistant`. */
|
|
4
|
+
assistant: OverviewAssistant;
|
|
5
|
+
/** Message for a batch (default: a generic "updated" line). */
|
|
6
|
+
message?: (batch: OverviewAssistantBatch) => string;
|
|
7
|
+
/** Extra class names for the affordance's row, for host placement. */
|
|
8
|
+
class?: string;
|
|
9
|
+
}
|
|
10
|
+
declare const OverviewAssistantUndo: import("svelte").Component<Props, {}, "">;
|
|
11
|
+
type OverviewAssistantUndo = ReturnType<typeof OverviewAssistantUndo>;
|
|
12
|
+
export default OverviewAssistantUndo;
|
|
13
|
+
//# sourceMappingURL=OverviewAssistantUndo.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"OverviewAssistantUndo.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/overview/OverviewAssistantUndo.svelte.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EACV,iBAAiB,EACjB,sBAAsB,EACvB,MAAM,uBAAuB,CAAC;AAG/B,UAAU,KAAK;IACb,4DAA4D;IAC5D,SAAS,EAAE,iBAAiB,CAAC;IAC7B,+DAA+D;IAC/D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,MAAM,CAAC;IACpD,sEAAsE;IACtE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAsDD,QAAA,MAAM,qBAAqB,2CAAwC,CAAC;AACpE,KAAK,qBAAqB,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;AACtE,eAAe,qBAAqB,CAAC"}
|
|
@@ -41,6 +41,8 @@ let {
|
|
|
41
41
|
editing: editingProp,
|
|
42
42
|
label,
|
|
43
43
|
headingLevel = 2,
|
|
44
|
+
heading,
|
|
45
|
+
presentation = 'card',
|
|
44
46
|
models,
|
|
45
47
|
iconComponent,
|
|
46
48
|
}: OverviewGridProps = $props();
|
|
@@ -348,7 +350,7 @@ const headingTag = $derived(`h${headingLevel}`);
|
|
|
348
350
|
{#snippet body(row: Row)}
|
|
349
351
|
{@const Widget = components?.get(row.widget.type) ?? row.def?.component}
|
|
350
352
|
<article class="smrt-overview__widget" aria-labelledby="{uid}-title-{row.widget.id}">
|
|
351
|
-
<svelte:element this={headingTag} class="smrt-overview__title" id="{uid}-title-{row.widget.id}">{row.title}</svelte:element>
|
|
353
|
+
<svelte:element this={headingTag} class="smrt-overview__title" id="{uid}-title-{row.widget.id}">{#if heading}{@render heading(row.widget, row.title)}{:else}{row.title}{/if}</svelte:element>
|
|
352
354
|
<div class="smrt-overview__content" aria-busy={row.status === 'loading'}>
|
|
353
355
|
{#if !row.def}
|
|
354
356
|
<p class="smrt-overview__state">{t(M['ui.overview.unavailable'])}</p>
|
|
@@ -376,7 +378,7 @@ const headingTag = $derived(`h${headingLevel}`);
|
|
|
376
378
|
</article>
|
|
377
379
|
{/snippet}
|
|
378
380
|
|
|
379
|
-
<div class="smrt-overview" bind:this={rootEl} data-editing={editing ? '' : undefined}>
|
|
381
|
+
<div class="smrt-overview" bind:this={rootEl} data-editing={editing ? '' : undefined} data-presentation={presentation}>
|
|
380
382
|
{#if editing}
|
|
381
383
|
<div class="smrt-overview__toolbar" role="toolbar" aria-label={t(M['ui.overview.toolbar'])}>
|
|
382
384
|
<ShellIconButton
|
|
@@ -547,6 +549,7 @@ const headingTag = $derived(`h${headingLevel}`);
|
|
|
547
549
|
.smrt-overview__item[data-drop='before']::before { inset-inline-start: 0; }
|
|
548
550
|
.smrt-overview__item[data-drop='after']::before { inset-inline-end: 0; }
|
|
549
551
|
.smrt-overview__tile { position: relative; block-size: 100%; box-sizing: border-box; padding: var(--smrt-spacing-3); border: 1px solid var(--smrt-color-outline-variant); border-radius: var(--smrt-radius-large, var(--smrt-radius-medium)); background: var(--smrt-color-surface); color: var(--smrt-color-on-surface); }
|
|
552
|
+
[data-presentation='plain']:not([data-editing]) .smrt-overview__tile { padding: 0; border: 0; border-radius: 0; background: transparent; }
|
|
550
553
|
[data-editing] .smrt-overview__tile { border-style: dashed; }
|
|
551
554
|
.smrt-overview__widget { display: grid; gap: var(--smrt-spacing-2); align-content: start; min-inline-size: 0; }
|
|
552
555
|
.smrt-overview__title { margin: 0; color: var(--smrt-color-on-surface-variant); font-size: var(--smrt-typography-title-small-size, 0.875rem); font-weight: var(--smrt-typography-weight-medium, 500); }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OverviewGrid.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/overview/OverviewGrid.svelte.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"OverviewGrid.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/overview/OverviewGrid.svelte.ts"],"names":[],"mappings":"AAiCA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AA4bzD,QAAA,MAAM,YAAY,uDAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The server half of the overview assistant (#3727 phase 4): one overview, for
|
|
3
|
+
* one principal, as the adapter `@happyvertical/smrt-chat`'s
|
|
4
|
+
* `createOverviewTools()` operates on. The chat package depends on no UI
|
|
5
|
+
* package, so it types this object structurally; this module is the
|
|
6
|
+
* implementation a host returns from its `open(run, pageId)`.
|
|
7
|
+
*
|
|
8
|
+
* Every plan and every restore runs through the phase-1 model and
|
|
9
|
+
* `checkOverviewOverride`, so the assistant can only store an override the
|
|
10
|
+
* save endpoint would accept. Persistence stays the host's (phase 3): the
|
|
11
|
+
* surface calls `persist` with the canonical override and keeps its own copy
|
|
12
|
+
* of the value it last persisted.
|
|
13
|
+
*
|
|
14
|
+
* Svelte-free; on `./overview/server`.
|
|
15
|
+
*/
|
|
16
|
+
import { type OverviewOverrideCheck } from './model.js';
|
|
17
|
+
import { type DescribeOverviewInput, type OverviewDescription, type OverviewPlan } from './operations.js';
|
|
18
|
+
import { type WidgetRegistry } from './registry.js';
|
|
19
|
+
import type { OverviewDefinition, OverviewOverride } from './types.js';
|
|
20
|
+
export interface OverviewAssistantSurfaceOptions {
|
|
21
|
+
/** The page's declaration (allowed set, models, defaults, cap). */
|
|
22
|
+
definition: OverviewDefinition;
|
|
23
|
+
/** Defaults to the shared registry. */
|
|
24
|
+
registry?: WidgetRegistry;
|
|
25
|
+
/**
|
|
26
|
+
* The principal's stored override for this page (untrusted JSON; `null`
|
|
27
|
+
* for none), as the host loaded it for this request.
|
|
28
|
+
*/
|
|
29
|
+
override: unknown;
|
|
30
|
+
/**
|
|
31
|
+
* The concurrency token of the stored row the host loaded `override` from
|
|
32
|
+
* (`null` when it loaded no row), echoed back to `persist`. With the
|
|
33
|
+
* phase-3 store (`createOverviewStore` of `@happyvertical/smrt-preferences`)
|
|
34
|
+
* this is `state.user.revision` from its `load`.
|
|
35
|
+
*/
|
|
36
|
+
revision: string | null;
|
|
37
|
+
/** Whether this principal may customize this page (the role gate). */
|
|
38
|
+
canCustomize: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Store the canonical override (`null` = back to the defaults) in the
|
|
41
|
+
* principal's tier, CONDITIONALLY on `expected.revision` still being the
|
|
42
|
+
* stored one: a save that landed since must answer
|
|
43
|
+
* `{ ok: false, reason: 'conflict' }`, never be overwritten. The phase-3
|
|
44
|
+
* store plugs in directly:
|
|
45
|
+
* `(override, { revision }) => store.save(definition, registry, { scope: 'user', override, revision })`
|
|
46
|
+
* with `store = createOverviewStore({ db })` from `@happyvertical/smrt-preferences`.
|
|
47
|
+
*/
|
|
48
|
+
persist: (override: OverviewOverride | null, expected: {
|
|
49
|
+
revision: string | null;
|
|
50
|
+
}) => OverviewAssistantPersistResult | Promise<OverviewAssistantPersistResult>;
|
|
51
|
+
/** Turns titles and labels that are i18n keys into text. */
|
|
52
|
+
translate?: DescribeOverviewInput['translate'];
|
|
53
|
+
/** Batch cap (default 20). */
|
|
54
|
+
maxOperations?: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* A conditional write's outcome. `revision` is the stored row's new token
|
|
58
|
+
* (`null` when the write removed the row); omitted, the surface keeps the
|
|
59
|
+
* token it had. Structurally `OverviewSaveResult` of
|
|
60
|
+
* `@happyvertical/smrt-preferences`.
|
|
61
|
+
*/
|
|
62
|
+
export type OverviewAssistantPersistResult = {
|
|
63
|
+
ok: true;
|
|
64
|
+
revision?: string | null;
|
|
65
|
+
} | {
|
|
66
|
+
ok: false;
|
|
67
|
+
reason: 'conflict' | 'not_allowed' | 'invalid';
|
|
68
|
+
issues?: readonly unknown[];
|
|
69
|
+
};
|
|
70
|
+
/** One overview for one principal; what `createOverviewTools()` drives. */
|
|
71
|
+
export interface OverviewAssistantSurface {
|
|
72
|
+
readonly pageId: string;
|
|
73
|
+
readonly canCustomize: boolean;
|
|
74
|
+
/** Allowed widget types with their option fields, and the arrangement. */
|
|
75
|
+
describe(): OverviewDescription;
|
|
76
|
+
/** The canonical override in effect (`null` = defaults). */
|
|
77
|
+
current(): OverviewOverride | null;
|
|
78
|
+
/** Plan a batch against {@link current}. Applies nothing. */
|
|
79
|
+
plan(operations: unknown): OverviewPlan;
|
|
80
|
+
/** Validate an override (the Undo value) the way a save is validated. */
|
|
81
|
+
check(override: unknown): OverviewOverrideCheck;
|
|
82
|
+
/**
|
|
83
|
+
* Persist a canonical override if the stored row is still the loaded
|
|
84
|
+
* revision; on success {@link current} and the revision follow it.
|
|
85
|
+
*/
|
|
86
|
+
persist(override: OverviewOverride | null): Promise<OverviewAssistantPersistResult>;
|
|
87
|
+
}
|
|
88
|
+
/** Build the assistant adapter for one overview and one principal. */
|
|
89
|
+
export declare function createOverviewAssistantSurface(options: OverviewAssistantSurfaceOptions): OverviewAssistantSurface;
|
|
90
|
+
//# sourceMappingURL=assistant-surface.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assistant-surface.d.ts","sourceRoot":"","sources":["../../../src/components/overview/assistant-surface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAGL,KAAK,qBAAqB,EAE3B,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,KAAK,qBAAqB,EAE1B,KAAK,mBAAmB,EACxB,KAAK,YAAY,EAElB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EAAyB,KAAK,cAAc,EAAE,MAAM,eAAe,CAAC;AAC3E,OAAO,KAAK,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEvE,MAAM,WAAW,+BAA+B;IAC9C,mEAAmE;IACnE,UAAU,EAAE,kBAAkB,CAAC;IAC/B,uCAAuC;IACvC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,sEAAsE;IACtE,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;;;;OAQG;IACH,OAAO,EAAE,CACP,QAAQ,EAAE,gBAAgB,GAAG,IAAI,EACjC,QAAQ,EAAE;QAAE,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,KAClC,8BAA8B,GAAG,OAAO,CAAC,8BAA8B,CAAC,CAAC;IAC9E,4DAA4D;IAC5D,SAAS,CAAC,EAAE,qBAAqB,CAAC,WAAW,CAAC,CAAC;IAC/C,8BAA8B;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;GAKG;AACH,MAAM,MAAM,8BAA8B,GACtC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACtC;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,UAAU,GAAG,aAAa,GAAG,SAAS,CAAC;IAC/C,MAAM,CAAC,EAAE,SAAS,OAAO,EAAE,CAAC;CAC7B,CAAC;AAEN,2EAA2E;AAC3E,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,0EAA0E;IAC1E,QAAQ,IAAI,mBAAmB,CAAC;IAChC,4DAA4D;IAC5D,OAAO,IAAI,gBAAgB,GAAG,IAAI,CAAC;IACnC,6DAA6D;IAC7D,IAAI,CAAC,UAAU,EAAE,OAAO,GAAG,YAAY,CAAC;IACxC,yEAAyE;IACzE,KAAK,CAAC,QAAQ,EAAE,OAAO,GAAG,qBAAqB,CAAC;IAChD;;;OAGG;IACH,OAAO,CACL,QAAQ,EAAE,gBAAgB,GAAG,IAAI,GAChC,OAAO,CAAC,8BAA8B,CAAC,CAAC;CAC5C;AAED,sEAAsE;AACtE,wBAAgB,8BAA8B,CAC5C,OAAO,EAAE,+BAA+B,GACvC,wBAAwB,CA2C1B"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The server half of the overview assistant (#3727 phase 4): one overview, for
|
|
3
|
+
* one principal, as the adapter `@happyvertical/smrt-chat`'s
|
|
4
|
+
* `createOverviewTools()` operates on. The chat package depends on no UI
|
|
5
|
+
* package, so it types this object structurally; this module is the
|
|
6
|
+
* implementation a host returns from its `open(run, pageId)`.
|
|
7
|
+
*
|
|
8
|
+
* Every plan and every restore runs through the phase-1 model and
|
|
9
|
+
* `checkOverviewOverride`, so the assistant can only store an override the
|
|
10
|
+
* save endpoint would accept. Persistence stays the host's (phase 3): the
|
|
11
|
+
* surface calls `persist` with the canonical override and keeps its own copy
|
|
12
|
+
* of the value it last persisted.
|
|
13
|
+
*
|
|
14
|
+
* Svelte-free; on `./overview/server`.
|
|
15
|
+
*/
|
|
16
|
+
import { checkOverviewOverride, diffOverview, resolveOverview, } from './model.js';
|
|
17
|
+
import { describeOverview, planOverviewOperations, } from './operations.js';
|
|
18
|
+
import { defaultWidgetRegistry } from './registry.js';
|
|
19
|
+
/** Build the assistant adapter for one overview and one principal. */
|
|
20
|
+
export function createOverviewAssistantSurface(options) {
|
|
21
|
+
const registry = options.registry ?? defaultWidgetRegistry;
|
|
22
|
+
const { definition } = options;
|
|
23
|
+
const initial = checkOverviewOverride(definition, options.override, registry);
|
|
24
|
+
// A stored value the model no longer accepts resolves leniently on load;
|
|
25
|
+
// its canonical form is whatever survives sanitizing.
|
|
26
|
+
let current = initial.ok
|
|
27
|
+
? initial.override
|
|
28
|
+
: sanitizedCurrent(definition, registry, options.override);
|
|
29
|
+
let revision = options.revision;
|
|
30
|
+
return {
|
|
31
|
+
pageId: definition.id,
|
|
32
|
+
canCustomize: options.canCustomize,
|
|
33
|
+
describe: () => describeOverview({
|
|
34
|
+
definition,
|
|
35
|
+
registry,
|
|
36
|
+
override: current,
|
|
37
|
+
canCustomize: options.canCustomize,
|
|
38
|
+
translate: options.translate,
|
|
39
|
+
maxOperations: options.maxOperations,
|
|
40
|
+
}),
|
|
41
|
+
current: () => current,
|
|
42
|
+
plan: (operations) => planOverviewOperations({
|
|
43
|
+
definition,
|
|
44
|
+
registry,
|
|
45
|
+
override: current,
|
|
46
|
+
operations,
|
|
47
|
+
maxOperations: options.maxOperations,
|
|
48
|
+
}),
|
|
49
|
+
check: (override) => checkOverviewOverride(definition, override, registry),
|
|
50
|
+
async persist(override) {
|
|
51
|
+
const result = await options.persist(override, { revision });
|
|
52
|
+
if (result.ok) {
|
|
53
|
+
current = override;
|
|
54
|
+
if ('revision' in result && result.revision !== undefined) {
|
|
55
|
+
revision = result.revision;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return result;
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
function sanitizedCurrent(definition, registry, override) {
|
|
63
|
+
const resolved = resolveOverview(definition, override, registry);
|
|
64
|
+
return diffOverview(resolved.base, resolved.document);
|
|
65
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The overview assistant in the browser (#3727 phase 4): the structured
|
|
3
|
+
* operations an in-page assistant (the AssistantDock) applies to a mounted
|
|
4
|
+
* overview, with a single-step Undo.
|
|
5
|
+
*
|
|
6
|
+
* A batch is planned with {@link planOverviewOperations} against the
|
|
7
|
+
* controller's definition and current override, so it is atomic (one invalid
|
|
8
|
+
* operation rejects the batch and nothing changes) and can only produce an
|
|
9
|
+
* override the save endpoint accepts. A valid batch lands through
|
|
10
|
+
* `controller.restore`, so the grid updates live and the host's `onchange`
|
|
11
|
+
* persists it like any other edit. The override before the batch is kept for
|
|
12
|
+
* Undo; Undo restores it exactly, and refuses once the overview changed in
|
|
13
|
+
* between (it would discard that edit).
|
|
14
|
+
*
|
|
15
|
+
* The browser tools (`overview_describe`, `overview_apply`, `overview_undo`)
|
|
16
|
+
* register on the page's WebMCP registry through `useWebMcpTool`, the same
|
|
17
|
+
* path every bespoke page tool takes, so the dock offers and runs them like
|
|
18
|
+
* any other page tool (a `write` waits for the person's Allow unless the host
|
|
19
|
+
* policy says otherwise). The browser session is the principal: the
|
|
20
|
+
* controller only holds this viewer's override, and `canCustomize` gates every
|
|
21
|
+
* apply and undo.
|
|
22
|
+
*/
|
|
23
|
+
import type { Toaster } from '@happyvertical/smrt-ui/feedback';
|
|
24
|
+
import type { WebMcpToolSpec } from '../../web/webmcp.svelte.js';
|
|
25
|
+
import type { OverviewController } from './controller.svelte.js';
|
|
26
|
+
import { type OverviewDescription, type OverviewOperationIssue, type OverviewOperationKind, type OverviewOperationResult } from './operations.js';
|
|
27
|
+
import type { OverviewOverride } from './types.js';
|
|
28
|
+
/** One applied batch, kept for Undo. */
|
|
29
|
+
export interface OverviewAssistantBatch {
|
|
30
|
+
/** Opaque id; `undo(id)` only undoes this batch. */
|
|
31
|
+
id: string;
|
|
32
|
+
results: OverviewOperationResult[];
|
|
33
|
+
/** How many operations of each kind the batch applied. */
|
|
34
|
+
counts: Partial<Record<OverviewOperationKind, number>>;
|
|
35
|
+
/** The override before the batch (what Undo restores). */
|
|
36
|
+
before: OverviewOverride | null;
|
|
37
|
+
/** The override the batch produced. */
|
|
38
|
+
after: OverviewOverride | null;
|
|
39
|
+
}
|
|
40
|
+
export type OverviewAssistantApplyResult = {
|
|
41
|
+
ok: true;
|
|
42
|
+
/** `null` when the batch changed nothing (no Undo is offered). */
|
|
43
|
+
batchId: string | null;
|
|
44
|
+
results: OverviewOperationResult[];
|
|
45
|
+
} | {
|
|
46
|
+
ok: false;
|
|
47
|
+
reason: 'not_allowed' | 'invalid';
|
|
48
|
+
issues: OverviewOperationIssue[];
|
|
49
|
+
};
|
|
50
|
+
export type OverviewAssistantUndoResult = {
|
|
51
|
+
ok: true;
|
|
52
|
+
} | {
|
|
53
|
+
ok: false;
|
|
54
|
+
reason: 'not_allowed' | 'nothing_to_undo' | 'changed_since';
|
|
55
|
+
};
|
|
56
|
+
export interface OverviewAssistantOptions {
|
|
57
|
+
/**
|
|
58
|
+
* Tool name prefix (default `overview`): tools are `<prefix>_describe`,
|
|
59
|
+
* `<prefix>_apply` and `<prefix>_undo`. Give each overview on one page its
|
|
60
|
+
* own prefix.
|
|
61
|
+
*/
|
|
62
|
+
toolPrefix?: string;
|
|
63
|
+
/** Turns widget titles and labels that are i18n keys into text. */
|
|
64
|
+
translate?: (key: string) => string;
|
|
65
|
+
/**
|
|
66
|
+
* Also show each applied batch as a toast with an Undo action (the host
|
|
67
|
+
* mounts a smrt-ui `ToastViewport` for it). `OverviewAssistantUndo` is the
|
|
68
|
+
* inline alternative.
|
|
69
|
+
*/
|
|
70
|
+
toaster?: Toaster;
|
|
71
|
+
/** Toast and inline message text; receives the batch. */
|
|
72
|
+
message?: (batch: OverviewAssistantBatch) => string;
|
|
73
|
+
/** Undo button label (default `Undo`). */
|
|
74
|
+
undoLabel?: string;
|
|
75
|
+
/** Called after a batch applies. */
|
|
76
|
+
onapply?: (batch: OverviewAssistantBatch) => void;
|
|
77
|
+
/** Batch cap (default 20). */
|
|
78
|
+
maxOperations?: number;
|
|
79
|
+
}
|
|
80
|
+
export declare class OverviewAssistant {
|
|
81
|
+
#private;
|
|
82
|
+
readonly controller: OverviewController;
|
|
83
|
+
constructor(controller: OverviewController, options?: OverviewAssistantOptions);
|
|
84
|
+
/** The last applied batch while it can still be undone. */
|
|
85
|
+
get lastBatch(): OverviewAssistantBatch | null;
|
|
86
|
+
/** Text for the Undo affordance. */
|
|
87
|
+
message(batch: OverviewAssistantBatch): string;
|
|
88
|
+
get undoLabel(): string;
|
|
89
|
+
/** What the overview allows and shows now. */
|
|
90
|
+
describe(): OverviewDescription;
|
|
91
|
+
/** Apply a batch atomically; the grid updates through the controller. */
|
|
92
|
+
apply(operations: unknown): OverviewAssistantApplyResult;
|
|
93
|
+
/**
|
|
94
|
+
* Restore the override from before the last batch. Refused when the
|
|
95
|
+
* overview changed after that batch (the person edited it), or when `id`
|
|
96
|
+
* names another batch.
|
|
97
|
+
*/
|
|
98
|
+
undo(id?: string): OverviewAssistantUndoResult;
|
|
99
|
+
/** Forget the last batch (hides the Undo affordance). */
|
|
100
|
+
dismiss(): void;
|
|
101
|
+
/** The browser tool specs (register with `useOverviewAssistantTools`). */
|
|
102
|
+
tools(): WebMcpToolSpec[];
|
|
103
|
+
}
|
|
104
|
+
/** Create the browser overview assistant for a controller. */
|
|
105
|
+
export declare function createOverviewAssistant(controller: OverviewController, options?: OverviewAssistantOptions): OverviewAssistant;
|
|
106
|
+
/**
|
|
107
|
+
* Register the assistant's browser tools on the page's WebMCP registry for
|
|
108
|
+
* the calling component's lifetime. Call during component initialization.
|
|
109
|
+
* `apply` and `undo` are `write` tools: the nearest Provider's
|
|
110
|
+
* `webmcp.effects` must allow `write`, or only `describe` is exposed.
|
|
111
|
+
*/
|
|
112
|
+
export declare function useOverviewAssistantTools(assistant: OverviewAssistant, options?: {
|
|
113
|
+
effects?: readonly ('read' | 'write' | 'destructive')[];
|
|
114
|
+
}): void;
|
|
115
|
+
//# sourceMappingURL=assistant.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"assistant.svelte.d.ts","sourceRoot":"","sources":["../../../src/components/overview/assistant.svelte.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iCAAiC,CAAC;AAC/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAEjE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,EAC1B,KAAK,uBAAuB,EAE7B,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,wCAAwC;AACxC,MAAM,WAAW,sBAAsB;IACrC,oDAAoD;IACpD,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,uBAAuB,EAAE,CAAC;IACnC,0DAA0D;IAC1D,MAAM,EAAE,OAAO,CAAC,MAAM,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC,CAAC;IACvD,0DAA0D;IAC1D,MAAM,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAChC,uCAAuC;IACvC,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAChC;AAED,MAAM,MAAM,4BAA4B,GACpC;IACE,EAAE,EAAE,IAAI,CAAC;IACT,kEAAkE;IAClE,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,OAAO,EAAE,uBAAuB,EAAE,CAAC;CACpC,GACD;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,aAAa,GAAG,SAAS,CAAC;IAClC,MAAM,EAAE,sBAAsB,EAAE,CAAC;CAClC,CAAC;AAEN,MAAM,MAAM,2BAA2B,GACnC;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IACE,EAAE,EAAE,KAAK,CAAC;IACV,MAAM,EAAE,aAAa,GAAG,iBAAiB,GAAG,eAAe,CAAC;CAC7D,CAAC;AAEN,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yDAAyD;IACzD,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,MAAM,CAAC;IACpD,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAC;IAClD,8BAA8B;IAC9B,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAcD,qBAAa,iBAAiB;;IAC5B,QAAQ,CAAC,UAAU,EAAE,kBAAkB,CAAC;gBAOtC,UAAU,EAAE,kBAAkB,EAC9B,OAAO,GAAE,wBAA6B;IAaxC,2DAA2D;IAC3D,IAAI,SAAS,IAAI,sBAAsB,GAAG,IAAI,CAE7C;IAED,oCAAoC;IACpC,OAAO,CAAC,KAAK,EAAE,sBAAsB,GAAG,MAAM;IAI9C,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,8CAA8C;IAC9C,QAAQ,IAAI,mBAAmB;IAW/B,yEAAyE;IACzE,KAAK,CAAC,UAAU,EAAE,OAAO,GAAG,4BAA4B;IA4CxD;;;;OAIG;IACH,IAAI,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,2BAA2B;IAmB9C,yDAAyD;IACzD,OAAO,IAAI,IAAI;IAkBf,0EAA0E;IAC1E,KAAK,IAAI,cAAc,EAAE;CAyF1B;AAED,8DAA8D;AAC9D,wBAAgB,uBAAuB,CACrC,UAAU,EAAE,kBAAkB,EAC9B,OAAO,CAAC,EAAE,wBAAwB,GACjC,iBAAiB,CAEnB;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,iBAAiB,EAC5B,OAAO,GAAE;IAAE,OAAO,CAAC,EAAE,SAAS,CAAC,MAAM,GAAG,OAAO,GAAG,aAAa,CAAC,EAAE,CAAA;CAAO,GACxE,IAAI,CAMN"}
|