@happyvertical/smrt-reports 0.55.23 → 0.56.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +26 -3
- package/README.md +9 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +471 -112
- package/dist/index.js.map +1 -1
- package/dist/manifest.json +174 -5
- package/dist/playground.d.ts +2 -0
- package/dist/playground.d.ts.map +1 -0
- package/dist/playground.js +154 -0
- package/dist/playground.js.map +1 -0
- package/dist/recipes.d.ts +55 -0
- package/dist/recipes.d.ts.map +1 -1
- package/dist/runtime-report.d.ts +9 -0
- package/dist/runtime-report.d.ts.map +1 -1
- package/dist/runtime-server.d.ts +77 -0
- package/dist/runtime-server.d.ts.map +1 -0
- package/dist/runtime-spec.d.ts +2 -1
- package/dist/runtime-spec.d.ts.map +1 -1
- package/dist/smrt-knowledge.json +203 -11
- package/dist/state.js +1 -1
- package/dist/state.js.map +1 -1
- package/dist/svelte/ReportConfirmation.svelte +99 -0
- package/dist/svelte/ReportConfirmation.svelte.d.ts +15 -0
- package/dist/svelte/ReportConfirmation.svelte.d.ts.map +1 -0
- package/dist/svelte/ReportDetail.svelte +69 -0
- package/dist/svelte/ReportDetail.svelte.d.ts +11 -0
- package/dist/svelte/ReportDetail.svelte.d.ts.map +1 -0
- package/dist/svelte/ReportPicker.svelte +73 -0
- package/dist/svelte/ReportPicker.svelte.d.ts +16 -0
- package/dist/svelte/ReportPicker.svelte.d.ts.map +1 -0
- package/dist/svelte/ReportResult.svelte +69 -0
- package/dist/svelte/ReportResult.svelte.d.ts +10 -0
- package/dist/svelte/ReportResult.svelte.d.ts.map +1 -0
- package/dist/svelte/RuntimeReportChartWidget.svelte +20 -0
- package/dist/svelte/RuntimeReportChartWidget.svelte.d.ts +11 -0
- package/dist/svelte/RuntimeReportChartWidget.svelte.d.ts.map +1 -0
- package/dist/svelte/RuntimeReportDetailRoute.svelte +67 -0
- package/dist/svelte/RuntimeReportDetailRoute.svelte.d.ts +21 -0
- package/dist/svelte/RuntimeReportDetailRoute.svelte.d.ts.map +1 -0
- package/dist/svelte/RuntimeReportToolResult.svelte +26 -0
- package/dist/svelte/RuntimeReportToolResult.svelte.d.ts +8 -0
- package/dist/svelte/RuntimeReportToolResult.svelte.d.ts.map +1 -0
- package/dist/svelte/RuntimeReportWidgetOptions.svelte +58 -0
- package/dist/svelte/RuntimeReportWidgetOptions.svelte.d.ts +14 -0
- package/dist/svelte/RuntimeReportWidgetOptions.svelte.d.ts.map +1 -0
- package/dist/svelte/RuntimeReportsRoute.svelte +67 -0
- package/dist/svelte/RuntimeReportsRoute.svelte.d.ts +19 -0
- package/dist/svelte/RuntimeReportsRoute.svelte.d.ts.map +1 -0
- package/dist/svelte/SavedReports.svelte +114 -0
- package/dist/svelte/SavedReports.svelte.d.ts +11 -0
- package/dist/svelte/SavedReports.svelte.d.ts.map +1 -0
- package/dist/svelte/browser-client.d.ts +10 -0
- package/dist/svelte/browser-client.d.ts.map +1 -0
- package/dist/svelte/browser-client.js +16 -0
- package/dist/svelte/client.d.ts +15 -0
- package/dist/svelte/client.d.ts.map +1 -0
- package/dist/svelte/client.js +179 -0
- package/dist/svelte/index.d.ts +15 -0
- package/dist/svelte/index.d.ts.map +1 -0
- package/dist/svelte/index.js +13 -0
- package/dist/svelte/messages.d.ts +72 -0
- package/dist/svelte/messages.d.ts.map +1 -0
- package/dist/svelte/messages.js +72 -0
- package/dist/svelte/playground.d.ts +132 -0
- package/dist/svelte/playground.d.ts.map +1 -0
- package/dist/svelte/playground.js +62 -0
- package/dist/svelte/preview-data.d.ts +7 -0
- package/dist/svelte/preview-data.d.ts.map +1 -0
- package/dist/svelte/preview-data.js +59 -0
- package/dist/svelte/result.d.ts +8 -0
- package/dist/svelte/result.d.ts.map +1 -0
- package/dist/svelte/result.js +99 -0
- package/dist/svelte/spec.d.ts +5 -0
- package/dist/svelte/spec.d.ts.map +1 -0
- package/dist/svelte/spec.js +282 -0
- package/dist/svelte/tool-result.d.ts +11 -0
- package/dist/svelte/tool-result.d.ts.map +1 -0
- package/dist/svelte/tool-result.js +19 -0
- package/dist/svelte/types.d.ts +38 -0
- package/dist/svelte/types.d.ts.map +1 -0
- package/dist/svelte/types.js +1 -0
- package/package.json +36 -12
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
3
|
+
import { Button } from '@happyvertical/smrt-ui/ui';
|
|
4
|
+
import { M } from './messages.js';
|
|
5
|
+
import ReportResult from './ReportResult.svelte';
|
|
6
|
+
import { reportError, validReportProposal } from './result.js';
|
|
7
|
+
import type { RuntimeReportProposal, SavedRuntimeReport } from './types.js';
|
|
8
|
+
|
|
9
|
+
export interface Props {
|
|
10
|
+
proposal: RuntimeReportProposal;
|
|
11
|
+
/** Posts the exact displayed spec and hash to the authenticated confirm route. */
|
|
12
|
+
confirm: (proposal: RuntimeReportProposal) => Promise<SavedRuntimeReport>;
|
|
13
|
+
reportHref?: (id: string) => string;
|
|
14
|
+
ondecline?: () => void;
|
|
15
|
+
onsaved?: (report: SavedRuntimeReport) => void;
|
|
16
|
+
locale?: string;
|
|
17
|
+
currency?: string;
|
|
18
|
+
}
|
|
19
|
+
let {
|
|
20
|
+
proposal,
|
|
21
|
+
confirm,
|
|
22
|
+
reportHref = (id) => `/reports/${encodeURIComponent(id)}`,
|
|
23
|
+
ondecline,
|
|
24
|
+
onsaved,
|
|
25
|
+
locale = 'en',
|
|
26
|
+
currency = 'USD',
|
|
27
|
+
}: Props = $props();
|
|
28
|
+
const { t } = useI18n();
|
|
29
|
+
let status = $state<'idle' | 'saving' | 'declined' | 'saved'>('idle');
|
|
30
|
+
let saved = $state<SavedRuntimeReport | null>(null);
|
|
31
|
+
let error = $state<ReturnType<typeof reportError> | null>(null);
|
|
32
|
+
let epoch = 0;
|
|
33
|
+
$effect(() => {
|
|
34
|
+
proposal;
|
|
35
|
+
confirm;
|
|
36
|
+
++epoch;
|
|
37
|
+
status = 'idle';
|
|
38
|
+
saved = null;
|
|
39
|
+
error = null;
|
|
40
|
+
return () => {
|
|
41
|
+
++epoch;
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
const valid = $derived(validReportProposal(proposal));
|
|
45
|
+
const label = (field: string) => field;
|
|
46
|
+
async function approve(event: MouseEvent) {
|
|
47
|
+
// Approval is an immediate local human action, never a model-callable tool.
|
|
48
|
+
if (!event.isTrusted || status !== 'idle' || !valid) return;
|
|
49
|
+
const current = epoch;
|
|
50
|
+
const specHash = proposal.specHash;
|
|
51
|
+
status = 'saving';
|
|
52
|
+
error = null;
|
|
53
|
+
try {
|
|
54
|
+
const result = await confirm({ ...proposal, specHash });
|
|
55
|
+
if (current !== epoch) return;
|
|
56
|
+
saved = result;
|
|
57
|
+
status = 'saved';
|
|
58
|
+
onsaved?.(result);
|
|
59
|
+
} catch (e) {
|
|
60
|
+
if (current === epoch) {
|
|
61
|
+
status = 'idle';
|
|
62
|
+
error = reportError(e);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function decline() {
|
|
67
|
+
if (status !== 'idle') return;
|
|
68
|
+
status = 'declined';
|
|
69
|
+
ondecline?.();
|
|
70
|
+
}
|
|
71
|
+
</script>
|
|
72
|
+
|
|
73
|
+
<section data-smrt-component="ReportConfirmation" aria-label={t(M['reports.confirm_title'])}>
|
|
74
|
+
<h2>{valid ? proposal.spec.title : t(M['reports.confirm_title'])}</h2>
|
|
75
|
+
{#if !valid}
|
|
76
|
+
<p role="alert">{t(M['reports.invalid'])}</p>
|
|
77
|
+
{:else if saved}
|
|
78
|
+
<p role="status">{t(M['reports.saved'])}</p>
|
|
79
|
+
<a href={reportHref(saved.id)}>{saved.title}</a>
|
|
80
|
+
{:else if status === 'declined'}
|
|
81
|
+
<p role="status">{t(M['reports.declined'])}</p>
|
|
82
|
+
{:else}
|
|
83
|
+
{#if proposal.spec.description}<p>{proposal.spec.description}</p>{/if}
|
|
84
|
+
<dl>
|
|
85
|
+
<dt>{t(M['reports.source'])}</dt><dd>{proposal.sourceLabel}</dd>
|
|
86
|
+
<dt>{t(M['reports.groupings'])}</dt>
|
|
87
|
+
<dd>{#each proposal.spec.dimensions as d (d.as)}<p>{label(d.field)}{#if d.bucket} · {t(`reports.bucket.${d.bucket}`)}{/if}</p>{:else}{t(M['reports.none'])}{/each}</dd>
|
|
88
|
+
<dt>{t(M['reports.measures'])}</dt>
|
|
89
|
+
<dd>{#each proposal.spec.measures as m (m.as)}<p>{t(`reports.aggregate.${m.fn}`, { field: m.field ? label(m.field) : t(M['reports.rows']) })}</p>{/each}</dd>
|
|
90
|
+
<dt>{t(M['reports.filters'])}</dt>
|
|
91
|
+
<dd>{#each proposal.spec.filters as f, i (i)}<p>{label(f.field)} {t(`reports.operator.${f.op}`)} {Array.isArray(f.value) ? f.value.join(', ') : String(f.value ?? '')}</p>{:else}{t(M['reports.none'])}{/each}</dd>
|
|
92
|
+
{#if proposal.spec.having.length}<dt>{t(M['reports.having'])}</dt><dd>{#each proposal.spec.having as h, i (i)}<p>{h.measure} {t(`reports.operator.${h.op}`)} {h.value}</p>{/each}</dd>{/if}
|
|
93
|
+
</dl>
|
|
94
|
+
<ReportResult result={proposal.preview} {locale} {currency} />
|
|
95
|
+
{#if error}<p role="alert">{t(M[error])}</p>{/if}
|
|
96
|
+
<Button disabled={status === 'saving'} onclick={approve}>{t(M[status === 'saving' ? 'reports.saving' : 'reports.approve'])}</Button>
|
|
97
|
+
<Button disabled={status === 'saving'} onclick={decline}>{t(M['reports.decline'])}</Button>
|
|
98
|
+
{/if}
|
|
99
|
+
</section>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { RuntimeReportProposal, SavedRuntimeReport } from './types.js';
|
|
2
|
+
export interface Props {
|
|
3
|
+
proposal: RuntimeReportProposal;
|
|
4
|
+
/** Posts the exact displayed spec and hash to the authenticated confirm route. */
|
|
5
|
+
confirm: (proposal: RuntimeReportProposal) => Promise<SavedRuntimeReport>;
|
|
6
|
+
reportHref?: (id: string) => string;
|
|
7
|
+
ondecline?: () => void;
|
|
8
|
+
onsaved?: (report: SavedRuntimeReport) => void;
|
|
9
|
+
locale?: string;
|
|
10
|
+
currency?: string;
|
|
11
|
+
}
|
|
12
|
+
declare const ReportConfirmation: import("svelte").Component<Props, {}, "">;
|
|
13
|
+
type ReportConfirmation = ReturnType<typeof ReportConfirmation>;
|
|
14
|
+
export default ReportConfirmation;
|
|
15
|
+
//# sourceMappingURL=ReportConfirmation.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReportConfirmation.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/ReportConfirmation.svelte.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,qBAAqB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAG5E,MAAM,WAAW,KAAK;IACpB,QAAQ,EAAE,qBAAqB,CAAC;IAChC,kFAAkF;IAClF,OAAO,EAAE,CAAC,QAAQ,EAAE,qBAAqB,KAAK,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAC1E,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA6FD,QAAA,MAAM,kBAAkB,2CAAwC,CAAC;AACjE,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAChE,eAAe,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
3
|
+
import { Button } from '@happyvertical/smrt-ui/ui';
|
|
4
|
+
import { M } from './messages.js';
|
|
5
|
+
import ReportResult from './ReportResult.svelte';
|
|
6
|
+
import { reportError, validReportResult } from './result.js';
|
|
7
|
+
import type {
|
|
8
|
+
RuntimeReportResult,
|
|
9
|
+
RuntimeReportsClient,
|
|
10
|
+
SavedRuntimeReport,
|
|
11
|
+
} from './types.js';
|
|
12
|
+
|
|
13
|
+
export interface Props {
|
|
14
|
+
id: string;
|
|
15
|
+
client?: RuntimeReportsClient;
|
|
16
|
+
locale?: string;
|
|
17
|
+
currency?: string;
|
|
18
|
+
}
|
|
19
|
+
let { id, client, locale = 'en', currency = 'USD' }: Props = $props();
|
|
20
|
+
const { t } = useI18n();
|
|
21
|
+
let report = $state<SavedRuntimeReport | null>(null);
|
|
22
|
+
let result = $state<RuntimeReportResult | null>(null);
|
|
23
|
+
let error = $state<ReturnType<typeof reportError> | null>(null);
|
|
24
|
+
let loading = $state(false);
|
|
25
|
+
let revision = $state(0);
|
|
26
|
+
$effect(() => {
|
|
27
|
+
const transport = client;
|
|
28
|
+
const reportId = id;
|
|
29
|
+
revision;
|
|
30
|
+
let active = true;
|
|
31
|
+
report = null;
|
|
32
|
+
result = null;
|
|
33
|
+
error = null;
|
|
34
|
+
loading = !!transport;
|
|
35
|
+
if (transport) {
|
|
36
|
+
void (async () => {
|
|
37
|
+
try {
|
|
38
|
+
const saved = await transport.get(reportId);
|
|
39
|
+
if (!active) return;
|
|
40
|
+
report = saved;
|
|
41
|
+
const value = await transport.run(reportId);
|
|
42
|
+
if (!active) return;
|
|
43
|
+
if (!validReportResult(value)) error = 'reports.invalid';
|
|
44
|
+
else result = value;
|
|
45
|
+
} catch (e) {
|
|
46
|
+
if (active) error = reportError(e);
|
|
47
|
+
} finally {
|
|
48
|
+
if (active) loading = false;
|
|
49
|
+
}
|
|
50
|
+
})();
|
|
51
|
+
}
|
|
52
|
+
return () => {
|
|
53
|
+
active = false;
|
|
54
|
+
};
|
|
55
|
+
});
|
|
56
|
+
</script>
|
|
57
|
+
|
|
58
|
+
<section data-smrt-component="ReportDetail" aria-label={t(M['reports.title'])}>
|
|
59
|
+
<h1>{report?.title ?? t(M['reports.title'])}</h1>
|
|
60
|
+
{#if !client}
|
|
61
|
+
<p>{t(M['reports.unavailable'])}</p>
|
|
62
|
+
{:else}
|
|
63
|
+
{#if report?.description}<p>{report.description}</p>{/if}
|
|
64
|
+
<Button disabled={loading} onclick={() => revision++}>{t(M['reports.rerun'])}</Button>
|
|
65
|
+
{#if loading}<p role="status">{t(M['reports.running'])}</p>{/if}
|
|
66
|
+
{#if error}<p role="alert">{t(M[error])}</p>{/if}
|
|
67
|
+
{#if result}<ReportResult {result} {locale} {currency} />{/if}
|
|
68
|
+
{/if}
|
|
69
|
+
</section>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { RuntimeReportsClient } from './types.js';
|
|
2
|
+
export interface Props {
|
|
3
|
+
id: string;
|
|
4
|
+
client?: RuntimeReportsClient;
|
|
5
|
+
locale?: string;
|
|
6
|
+
currency?: string;
|
|
7
|
+
}
|
|
8
|
+
declare const ReportDetail: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type ReportDetail = ReturnType<typeof ReportDetail>;
|
|
10
|
+
export default ReportDetail;
|
|
11
|
+
//# sourceMappingURL=ReportDetail.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReportDetail.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/ReportDetail.svelte.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAEV,oBAAoB,EAErB,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA+DD,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Select } from '@happyvertical/smrt-ui/forms';
|
|
3
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
4
|
+
import { M } from './messages.js';
|
|
5
|
+
import { reportError } from './result.js';
|
|
6
|
+
import type { RuntimeReportsClient, SavedRuntimeReport } from './types.js';
|
|
7
|
+
|
|
8
|
+
export interface Props {
|
|
9
|
+
client?: RuntimeReportsClient;
|
|
10
|
+
reportId?: string;
|
|
11
|
+
measure?: string;
|
|
12
|
+
dimension?: string;
|
|
13
|
+
onchange: (value: {
|
|
14
|
+
reportId: string;
|
|
15
|
+
measure: string;
|
|
16
|
+
dimension: string;
|
|
17
|
+
}) => void;
|
|
18
|
+
}
|
|
19
|
+
let {
|
|
20
|
+
client,
|
|
21
|
+
reportId = '',
|
|
22
|
+
measure = '',
|
|
23
|
+
dimension = '',
|
|
24
|
+
onchange,
|
|
25
|
+
}: Props = $props();
|
|
26
|
+
const { t } = useI18n();
|
|
27
|
+
let reports = $state<SavedRuntimeReport[]>([]);
|
|
28
|
+
let loading = $state(false);
|
|
29
|
+
let error = $state<ReturnType<typeof reportError> | null>(null);
|
|
30
|
+
const selected = $derived(reports.find((r) => r.id === reportId));
|
|
31
|
+
$effect(() => {
|
|
32
|
+
const transport = client;
|
|
33
|
+
let active = true;
|
|
34
|
+
reports = [];
|
|
35
|
+
error = null;
|
|
36
|
+
loading = !!transport;
|
|
37
|
+
if (transport)
|
|
38
|
+
void transport
|
|
39
|
+
.list({ onlyMine: false, includeArchived: false })
|
|
40
|
+
.then((rows) => {
|
|
41
|
+
if (active) reports = rows;
|
|
42
|
+
})
|
|
43
|
+
.catch((e) => {
|
|
44
|
+
if (active) error = reportError(e);
|
|
45
|
+
})
|
|
46
|
+
.finally(() => {
|
|
47
|
+
if (active) loading = false;
|
|
48
|
+
});
|
|
49
|
+
return () => {
|
|
50
|
+
active = false;
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
</script>
|
|
54
|
+
|
|
55
|
+
<div data-smrt-component="ReportPicker">
|
|
56
|
+
{#if !client}<p>{t(M['reports.unavailable'])}</p>
|
|
57
|
+
{:else}
|
|
58
|
+
{#if loading}<p role="status">{t(M['reports.loading'])}</p>{/if}
|
|
59
|
+
{#if error}<p role="alert">{t(M[error])}</p>{/if}
|
|
60
|
+
<Select aria-label={t(M['reports.select_report'])} value={reportId} disabled={loading || !!error} onchange={event => onchange({ reportId: event.currentTarget.value, measure: '', dimension: '' })}>
|
|
61
|
+
<option value="">{t(M['reports.choose_report'])}</option>
|
|
62
|
+
{#each reports as report (report.id)}<option value={report.id}>{report.title}</option>{/each}
|
|
63
|
+
</Select>
|
|
64
|
+
<Select aria-label={t(M['reports.select_measure'])} value={measure} disabled={!selected} onchange={event => onchange({ reportId, measure: event.currentTarget.value, dimension })}>
|
|
65
|
+
<option value="">{t(M['reports.choose_measure'])}</option>
|
|
66
|
+
{#each selected?.spec.measures ?? [] as m (m.as)}<option value={m.as}>{m.as}</option>{/each}
|
|
67
|
+
</Select>
|
|
68
|
+
<Select aria-label={t(M['reports.select_dimension'])} value={dimension} disabled={!selected} onchange={event => onchange({ reportId, measure, dimension: event.currentTarget.value })}>
|
|
69
|
+
<option value="">{t(M['reports.choose_dimension'])}</option>
|
|
70
|
+
{#each selected?.spec.dimensions ?? [] as d (d.as)}<option value={d.as}>{d.as}</option>{/each}
|
|
71
|
+
</Select>
|
|
72
|
+
{/if}
|
|
73
|
+
</div>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { RuntimeReportsClient } from './types.js';
|
|
2
|
+
export interface Props {
|
|
3
|
+
client?: RuntimeReportsClient;
|
|
4
|
+
reportId?: string;
|
|
5
|
+
measure?: string;
|
|
6
|
+
dimension?: string;
|
|
7
|
+
onchange: (value: {
|
|
8
|
+
reportId: string;
|
|
9
|
+
measure: string;
|
|
10
|
+
dimension: string;
|
|
11
|
+
}) => void;
|
|
12
|
+
}
|
|
13
|
+
declare const ReportPicker: import("svelte").Component<Props, {}, "">;
|
|
14
|
+
type ReportPicker = ReturnType<typeof ReportPicker>;
|
|
15
|
+
export default ReportPicker;
|
|
16
|
+
//# sourceMappingURL=ReportPicker.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReportPicker.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/ReportPicker.svelte.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,oBAAoB,EAAsB,MAAM,YAAY,CAAC;AAG3E,MAAM,WAAW,KAAK;IACpB,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE;QAChB,QAAQ,EAAE,MAAM,CAAC;QACjB,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,EAAE,MAAM,CAAC;KACnB,KAAK,IAAI,CAAC;CACZ;AAkED,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Chart } from '@happyvertical/smrt-ui/charts';
|
|
3
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
4
|
+
import { Button } from '@happyvertical/smrt-ui/ui';
|
|
5
|
+
import { M } from './messages.js';
|
|
6
|
+
import { reportCell, validReportResult } from './result.js';
|
|
7
|
+
import type { RuntimeReportResult } from './types.js';
|
|
8
|
+
|
|
9
|
+
export interface Props {
|
|
10
|
+
result: RuntimeReportResult;
|
|
11
|
+
locale?: string;
|
|
12
|
+
currency?: string;
|
|
13
|
+
}
|
|
14
|
+
let { result, locale = 'en', currency = 'USD' }: Props = $props();
|
|
15
|
+
const { t } = useI18n();
|
|
16
|
+
let table = $state(false);
|
|
17
|
+
const valid = $derived(validReportResult(result));
|
|
18
|
+
const measures = $derived(
|
|
19
|
+
valid
|
|
20
|
+
? result.columns.filter((c) =>
|
|
21
|
+
(
|
|
22
|
+
result.chart.y ??
|
|
23
|
+
result.columns.filter((c) => c.role === 'measure').map((c) => c.id)
|
|
24
|
+
).includes(c.id),
|
|
25
|
+
)
|
|
26
|
+
: [],
|
|
27
|
+
);
|
|
28
|
+
function cell(value: unknown, column: RuntimeReportResult['columns'][number]) {
|
|
29
|
+
return typeof value === 'boolean'
|
|
30
|
+
? t(M[value ? 'reports.yes' : 'reports.no'])
|
|
31
|
+
: reportCell(value, column, locale, currency);
|
|
32
|
+
}
|
|
33
|
+
</script>
|
|
34
|
+
|
|
35
|
+
<div data-smrt-component="ReportResult">
|
|
36
|
+
{#if !valid}
|
|
37
|
+
<p role="alert">{t(M['reports.invalid'])}</p>
|
|
38
|
+
{:else if result.rows.length === 0}
|
|
39
|
+
<p>{t(M['reports.no_rows'])}</p>
|
|
40
|
+
{:else}
|
|
41
|
+
{#if result.chart.type !== 'table'}
|
|
42
|
+
<Button type="button" onclick={() => table = !table}>{t(M[table ? 'reports.chart' : 'reports.table'])}</Button>
|
|
43
|
+
{/if}
|
|
44
|
+
{#if table || result.chart.type === 'table'}
|
|
45
|
+
<table>
|
|
46
|
+
<caption>{result.title}</caption>
|
|
47
|
+
<thead><tr>{#each result.columns as column (column.id)}<th scope="col">{column.label}</th>{/each}</tr></thead>
|
|
48
|
+
<tbody>{#each result.rows as row, i (i)}<tr>{#each result.columns as column (column.id)}<td>{cell(row[column.id], column)}</td>{/each}</tr>{/each}</tbody>
|
|
49
|
+
</table>
|
|
50
|
+
{:else}
|
|
51
|
+
{#each measures as column (column.id)}
|
|
52
|
+
<Chart title={column.label} style={result.chart.type} {locale} data={{
|
|
53
|
+
points: result.rows.filter(row => typeof row[column.id] === 'number').map(row => ({ label: result.chart.x ? String(row[result.chart.x] ?? '–') : column.label, value: row[column.id] as number })),
|
|
54
|
+
format: column.format === 'money' ? 'money' : column.type === 'integer' ? 'integer' : 'decimal', currency,
|
|
55
|
+
}} />
|
|
56
|
+
{/each}
|
|
57
|
+
{/if}
|
|
58
|
+
{#if result.truncated}<p>{t(M['reports.truncated'])}</p>{/if}
|
|
59
|
+
{/if}
|
|
60
|
+
</div>
|
|
61
|
+
|
|
62
|
+
<style>
|
|
63
|
+
@layer smrt.reset, smrt.structure, smrt.theme;
|
|
64
|
+
@layer smrt.theme {
|
|
65
|
+
[data-smrt-component='ReportResult'] { display: grid; gap: var(--smrt-spacing-3); overflow: auto; }
|
|
66
|
+
table { border-collapse: collapse; inline-size: 100%; }
|
|
67
|
+
th, td { padding: var(--smrt-spacing-2); border-block-end: var(--smrt-hairline); text-align: start; font-variant-numeric: tabular-nums; }
|
|
68
|
+
}
|
|
69
|
+
</style>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RuntimeReportResult } from './types.js';
|
|
2
|
+
export interface Props {
|
|
3
|
+
result: RuntimeReportResult;
|
|
4
|
+
locale?: string;
|
|
5
|
+
currency?: string;
|
|
6
|
+
}
|
|
7
|
+
declare const ReportResult: import("svelte").Component<Props, {}, "">;
|
|
8
|
+
type ReportResult = ReturnType<typeof ReportResult>;
|
|
9
|
+
export default ReportResult;
|
|
10
|
+
//# sourceMappingURL=ReportResult.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ReportResult.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/ReportResult.svelte.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAGtD,MAAM,WAAW,KAAK;IACpB,MAAM,EAAE,mBAAmB,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA6DD,QAAA,MAAM,YAAY,2CAAwC,CAAC;AAC3D,KAAK,YAAY,GAAG,UAAU,CAAC,OAAO,YAAY,CAAC,CAAC;AACpD,eAAe,YAAY,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Chart, type ChartData } from '@happyvertical/smrt-ui/charts';
|
|
3
|
+
|
|
4
|
+
export interface Props {
|
|
5
|
+
options: Record<string, string | number | boolean | null>;
|
|
6
|
+
data?: ChartData;
|
|
7
|
+
title: string;
|
|
8
|
+
locale: string;
|
|
9
|
+
}
|
|
10
|
+
let { options, data, title, locale }: Props = $props();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<div data-smrt-component="RuntimeReportChartWidget">
|
|
14
|
+
<Chart
|
|
15
|
+
data={data ?? null}
|
|
16
|
+
style={typeof options.style === 'string' ? options.style : 'bar'}
|
|
17
|
+
{title}
|
|
18
|
+
{locale}
|
|
19
|
+
/>
|
|
20
|
+
</div>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type ChartData } from '@happyvertical/smrt-ui/charts';
|
|
2
|
+
export interface Props {
|
|
3
|
+
options: Record<string, string | number | boolean | null>;
|
|
4
|
+
data?: ChartData;
|
|
5
|
+
title: string;
|
|
6
|
+
locale: string;
|
|
7
|
+
}
|
|
8
|
+
declare const RuntimeReportChartWidget: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type RuntimeReportChartWidget = ReturnType<typeof RuntimeReportChartWidget>;
|
|
10
|
+
export default RuntimeReportChartWidget;
|
|
11
|
+
//# sourceMappingURL=RuntimeReportChartWidget.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RuntimeReportChartWidget.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/RuntimeReportChartWidget.svelte.ts"],"names":[],"mappings":"AAGA,OAAO,EAAS,KAAK,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAGtE,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;IAC1D,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAaD,QAAA,MAAM,wBAAwB,2CAAwC,CAAC;AACvE,KAAK,wBAAwB,GAAG,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC5E,eAAe,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
3
|
+
import { onMount } from 'svelte';
|
|
4
|
+
import { getRuntimeReportsBrowserClient } from './browser-client.js';
|
|
5
|
+
import { M } from './messages.js';
|
|
6
|
+
import ReportDetail from './ReportDetail.svelte';
|
|
7
|
+
import type { RuntimeReportsClient } from './types.js';
|
|
8
|
+
|
|
9
|
+
export interface Props {
|
|
10
|
+
id?: string;
|
|
11
|
+
params?: { id?: string };
|
|
12
|
+
client?: RuntimeReportsClient;
|
|
13
|
+
serverAvailable?: boolean;
|
|
14
|
+
/** Authenticated user id projected by the server route host. */
|
|
15
|
+
currentUserId?: string;
|
|
16
|
+
/** Opaque active tenant/session key used only to isolate browser hints. */
|
|
17
|
+
clientScope?: string;
|
|
18
|
+
/** Server-derived capability hint used by the shared session client. */
|
|
19
|
+
canArchive?: boolean;
|
|
20
|
+
locale?: string;
|
|
21
|
+
currency?: string;
|
|
22
|
+
}
|
|
23
|
+
let {
|
|
24
|
+
id,
|
|
25
|
+
params,
|
|
26
|
+
client,
|
|
27
|
+
serverAvailable = true,
|
|
28
|
+
currentUserId,
|
|
29
|
+
clientScope,
|
|
30
|
+
canArchive = false,
|
|
31
|
+
locale,
|
|
32
|
+
currency,
|
|
33
|
+
}: Props = $props();
|
|
34
|
+
const reportId = $derived(id ?? params?.id ?? '');
|
|
35
|
+
let browserClient = $state<RuntimeReportsClient | undefined>();
|
|
36
|
+
let mounted = $state(false);
|
|
37
|
+
const { t } = useI18n();
|
|
38
|
+
$effect(() => {
|
|
39
|
+
browserClient = client;
|
|
40
|
+
if (!client && mounted && serverAvailable) {
|
|
41
|
+
browserClient = getRuntimeReportsBrowserClient({
|
|
42
|
+
scopeKey: clientScope,
|
|
43
|
+
currentUserId,
|
|
44
|
+
canArchive,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
onMount(() => {
|
|
49
|
+
mounted = true;
|
|
50
|
+
return () => {
|
|
51
|
+
mounted = false;
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
</script>
|
|
55
|
+
|
|
56
|
+
<div data-smrt-component="RuntimeReportDetailRoute">
|
|
57
|
+
{#if serverAvailable && !browserClient}
|
|
58
|
+
<p role="status">{t(M['reports.loading'])}</p>
|
|
59
|
+
{:else}
|
|
60
|
+
<ReportDetail
|
|
61
|
+
id={reportId}
|
|
62
|
+
client={serverAvailable ? browserClient : undefined}
|
|
63
|
+
{locale}
|
|
64
|
+
{currency}
|
|
65
|
+
/>
|
|
66
|
+
{/if}
|
|
67
|
+
</div>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { RuntimeReportsClient } from './types.js';
|
|
2
|
+
export interface Props {
|
|
3
|
+
id?: string;
|
|
4
|
+
params?: {
|
|
5
|
+
id?: string;
|
|
6
|
+
};
|
|
7
|
+
client?: RuntimeReportsClient;
|
|
8
|
+
serverAvailable?: boolean;
|
|
9
|
+
/** Authenticated user id projected by the server route host. */
|
|
10
|
+
currentUserId?: string;
|
|
11
|
+
/** Opaque active tenant/session key used only to isolate browser hints. */
|
|
12
|
+
clientScope?: string;
|
|
13
|
+
/** Server-derived capability hint used by the shared session client. */
|
|
14
|
+
canArchive?: boolean;
|
|
15
|
+
locale?: string;
|
|
16
|
+
currency?: string;
|
|
17
|
+
}
|
|
18
|
+
declare const RuntimeReportDetailRoute: import("svelte").Component<Props, {}, "">;
|
|
19
|
+
type RuntimeReportDetailRoute = ReturnType<typeof RuntimeReportDetailRoute>;
|
|
20
|
+
export default RuntimeReportDetailRoute;
|
|
21
|
+
//# sourceMappingURL=RuntimeReportDetailRoute.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RuntimeReportDetailRoute.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/RuntimeReportDetailRoute.svelte.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAGvD,MAAM,WAAW,KAAK;IACpB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzB,MAAM,CAAC,EAAE,oBAAoB,CAAC;IAC9B,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,gEAAgE;IAChE,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,wEAAwE;IACxE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAoDD,QAAA,MAAM,wBAAwB,2CAAwC,CAAC;AACvE,KAAK,wBAAwB,GAAG,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAC5E,eAAe,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
import { getRuntimeReportsBrowserClient } from './browser-client.js';
|
|
4
|
+
import ReportConfirmation from './ReportConfirmation.svelte';
|
|
5
|
+
import {
|
|
6
|
+
runtimeReportProposalFromMessage,
|
|
7
|
+
type ToolResultMessage,
|
|
8
|
+
} from './tool-result.js';
|
|
9
|
+
import type { RuntimeReportsClient } from './types.js';
|
|
10
|
+
|
|
11
|
+
export interface Props {
|
|
12
|
+
message: ToolResultMessage;
|
|
13
|
+
}
|
|
14
|
+
let { message }: Props = $props();
|
|
15
|
+
const proposal = $derived(runtimeReportProposalFromMessage(message));
|
|
16
|
+
let client = $state<RuntimeReportsClient | undefined>();
|
|
17
|
+
onMount(() => {
|
|
18
|
+
client = getRuntimeReportsBrowserClient();
|
|
19
|
+
});
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<div data-smrt-component="RuntimeReportToolResult">
|
|
23
|
+
{#if proposal && client}
|
|
24
|
+
<ReportConfirmation {proposal} confirm={client.confirm} />
|
|
25
|
+
{/if}
|
|
26
|
+
</div>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ToolResultMessage } from './tool-result.js';
|
|
2
|
+
export interface Props {
|
|
3
|
+
message: ToolResultMessage;
|
|
4
|
+
}
|
|
5
|
+
declare const RuntimeReportToolResult: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type RuntimeReportToolResult = ReturnType<typeof RuntimeReportToolResult>;
|
|
7
|
+
export default RuntimeReportToolResult;
|
|
8
|
+
//# sourceMappingURL=RuntimeReportToolResult.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RuntimeReportToolResult.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/RuntimeReportToolResult.svelte.ts"],"names":[],"mappings":"AAMA,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,kBAAkB,CAAC;AAI1B,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,iBAAiB,CAAC;CAC5B;AAwBD,QAAA,MAAM,uBAAuB,2CAAwC,CAAC;AACtE,KAAK,uBAAuB,GAAG,UAAU,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAC1E,eAAe,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { FormActionBar } from '@happyvertical/smrt-ui/forms';
|
|
3
|
+
import { useI18n } from '@happyvertical/smrt-ui/i18n';
|
|
4
|
+
import { Button } from '@happyvertical/smrt-ui/ui';
|
|
5
|
+
import { onMount, untrack } from 'svelte';
|
|
6
|
+
import { getRuntimeReportsBrowserClient } from './browser-client.js';
|
|
7
|
+
import { M } from './messages.js';
|
|
8
|
+
import ReportPicker from './ReportPicker.svelte';
|
|
9
|
+
import type { RuntimeReportsClient } from './types.js';
|
|
10
|
+
|
|
11
|
+
type Options = Record<string, string | number | boolean | null>;
|
|
12
|
+
interface Issue {
|
|
13
|
+
key: string;
|
|
14
|
+
code: string;
|
|
15
|
+
}
|
|
16
|
+
export interface Props {
|
|
17
|
+
initial: Options;
|
|
18
|
+
onsave: (options: Options) => Issue[] | null;
|
|
19
|
+
oncancel: () => void;
|
|
20
|
+
}
|
|
21
|
+
let { initial, onsave, oncancel }: Props = $props();
|
|
22
|
+
const { t } = useI18n();
|
|
23
|
+
let client = $state<RuntimeReportsClient | undefined>();
|
|
24
|
+
let value = $state(
|
|
25
|
+
untrack(() => ({
|
|
26
|
+
reportId: typeof initial.reportId === 'string' ? initial.reportId : '',
|
|
27
|
+
measure: typeof initial.measure === 'string' ? initial.measure : '',
|
|
28
|
+
dimension: typeof initial.dimension === 'string' ? initial.dimension : '',
|
|
29
|
+
})),
|
|
30
|
+
);
|
|
31
|
+
let failed = $state(false);
|
|
32
|
+
onMount(() => {
|
|
33
|
+
client = getRuntimeReportsBrowserClient();
|
|
34
|
+
});
|
|
35
|
+
function save() {
|
|
36
|
+
const options: Options = {
|
|
37
|
+
reportId: value.reportId,
|
|
38
|
+
measure: value.measure,
|
|
39
|
+
...(value.dimension ? { dimension: value.dimension } : {}),
|
|
40
|
+
};
|
|
41
|
+
failed = onsave(options) !== null;
|
|
42
|
+
}
|
|
43
|
+
</script>
|
|
44
|
+
|
|
45
|
+
<div data-smrt-component="RuntimeReportWidgetOptions">
|
|
46
|
+
<ReportPicker
|
|
47
|
+
{client}
|
|
48
|
+
reportId={value.reportId}
|
|
49
|
+
measure={value.measure}
|
|
50
|
+
dimension={value.dimension}
|
|
51
|
+
onchange={(next) => (value = next)}
|
|
52
|
+
/>
|
|
53
|
+
{#if failed}<p role="alert">{t(M['reports.options_invalid'])}</p>{/if}
|
|
54
|
+
<FormActionBar>
|
|
55
|
+
<Button type="button" variant="ghost" onclick={oncancel}>{t(M['reports.cancel'])}</Button>
|
|
56
|
+
<Button type="button" variant="primary" onclick={save}>{t(M['reports.save'])}</Button>
|
|
57
|
+
</FormActionBar>
|
|
58
|
+
</div>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
type Options = Record<string, string | number | boolean | null>;
|
|
2
|
+
interface Issue {
|
|
3
|
+
key: string;
|
|
4
|
+
code: string;
|
|
5
|
+
}
|
|
6
|
+
export interface Props {
|
|
7
|
+
initial: Options;
|
|
8
|
+
onsave: (options: Options) => Issue[] | null;
|
|
9
|
+
oncancel: () => void;
|
|
10
|
+
}
|
|
11
|
+
declare const RuntimeReportWidgetOptions: import("svelte").Component<Props, {}, "">;
|
|
12
|
+
type RuntimeReportWidgetOptions = ReturnType<typeof RuntimeReportWidgetOptions>;
|
|
13
|
+
export default RuntimeReportWidgetOptions;
|
|
14
|
+
//# sourceMappingURL=RuntimeReportWidgetOptions.svelte.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RuntimeReportWidgetOptions.svelte.d.ts","sourceRoot":"","sources":["../../src/svelte/RuntimeReportWidgetOptions.svelte.ts"],"names":[],"mappings":"AAaA,KAAK,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC,CAAC;AAChE,UAAU,KAAK;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;CACd;AACD,MAAM,WAAW,KAAK;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,KAAK,EAAE,GAAG,IAAI,CAAC;IAC7C,QAAQ,EAAE,MAAM,IAAI,CAAC;CACtB;AAgDD,QAAA,MAAM,0BAA0B,2CAAwC,CAAC;AACzE,KAAK,0BAA0B,GAAG,UAAU,CAAC,OAAO,0BAA0B,CAAC,CAAC;AAChF,eAAe,0BAA0B,CAAC"}
|