@prenta/admin 1.12.0 → 1.14.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/CHANGELOG.md +43 -0
- package/dist/__tests__/lib/seo-service-errors.test.js +34 -1
- package/dist/__tests__/lib/seo-service-errors.test.js.map +1 -1
- package/dist/__tests__/lib/seo-service-proposals.test.d.ts +2 -0
- package/dist/__tests__/lib/seo-service-proposals.test.d.ts.map +1 -0
- package/dist/__tests__/lib/seo-service-proposals.test.js +71 -0
- package/dist/__tests__/lib/seo-service-proposals.test.js.map +1 -0
- package/dist/__tests__/router/seo-tab-for-path.test.js +1 -0
- package/dist/__tests__/router/seo-tab-for-path.test.js.map +1 -1
- package/dist/__tests__/views/seo-proposals-tab.render.test.d.ts +2 -0
- package/dist/__tests__/views/seo-proposals-tab.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/seo-proposals-tab.render.test.js +292 -0
- package/dist/__tests__/views/seo-proposals-tab.render.test.js.map +1 -0
- package/dist/__tests__/views/seo-settings.render.test.js +73 -6
- package/dist/__tests__/views/seo-settings.render.test.js.map +1 -1
- package/dist/components/seo/ChangePreview.d.ts +6 -0
- package/dist/components/seo/ChangePreview.d.ts.map +1 -0
- package/dist/components/seo/ChangePreview.js +18 -0
- package/dist/components/seo/ChangePreview.js.map +1 -0
- package/dist/components/seo/SeoIssueFixPanel.d.ts.map +1 -1
- package/dist/components/seo/SeoIssueFixPanel.js +1 -14
- package/dist/components/seo/SeoIssueFixPanel.js.map +1 -1
- package/dist/lib/seo-service.d.ts +106 -0
- package/dist/lib/seo-service.d.ts.map +1 -1
- package/dist/lib/seo-service.js +67 -0
- package/dist/lib/seo-service.js.map +1 -1
- package/dist/prenta-admin.css +1 -1
- package/dist/views/SEO.d.ts +5 -1
- package/dist/views/SEO.d.ts.map +1 -1
- package/dist/views/SEO.js +28 -9
- package/dist/views/SEO.js.map +1 -1
- package/dist/views/seo/ProposalsTab.d.ts +7 -0
- package/dist/views/seo/ProposalsTab.d.ts.map +1 -0
- package/dist/views/seo/ProposalsTab.js +298 -0
- package/dist/views/seo/ProposalsTab.js.map +1 -0
- package/dist/views/settings/SeoDigestCard.d.ts +9 -0
- package/dist/views/settings/SeoDigestCard.d.ts.map +1 -0
- package/dist/views/settings/SeoDigestCard.js +77 -0
- package/dist/views/settings/SeoDigestCard.js.map +1 -0
- package/dist/views/settings/SeoSettingsTab.d.ts.map +1 -1
- package/dist/views/settings/SeoSettingsTab.js +2 -1
- package/dist/views/settings/SeoSettingsTab.js.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/lib/seo-service-errors.test.ts +38 -0
- package/src/__tests__/lib/seo-service-proposals.test.ts +79 -0
- package/src/__tests__/router/seo-tab-for-path.test.ts +1 -0
- package/src/__tests__/views/seo-proposals-tab.render.test.tsx +370 -0
- package/src/__tests__/views/seo-settings.render.test.tsx +104 -5
- package/src/components/seo/ChangePreview.tsx +47 -0
- package/src/components/seo/SeoIssueFixPanel.tsx +1 -44
- package/src/lib/seo-service.ts +168 -0
- package/src/views/SEO.tsx +40 -7
- package/src/views/seo/ProposalsTab.tsx +681 -0
- package/src/views/settings/SeoDigestCard.tsx +164 -0
- package/src/views/settings/SeoSettingsTab.tsx +2 -0
package/dist/views/SEO.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
/**
|
|
4
|
-
* SEO Operations Center —
|
|
5
|
-
* Technical / Redirects / Audit). Tab + deep-link state is
|
|
6
|
-
* `?tab=` query string so audits, issues, redirects,
|
|
7
|
-
* all linkable. All data flows through
|
|
4
|
+
* SEO Operations Center — seven-tab workflow surface (Overview / Content /
|
|
5
|
+
* Links / Technical / Redirects / Audit / Proposals). Tab + deep-link state is
|
|
6
|
+
* driven by the `?tab=` query string so audits, issues, redirects, proposals,
|
|
7
|
+
* and content editors are all linkable. All data flows through
|
|
8
|
+
* `lib/seo-service.ts`.
|
|
8
9
|
*/
|
|
9
10
|
import * as Tabs from '@radix-ui/react-tabs';
|
|
10
|
-
import { LayoutDashboard, FileText, Settings2, ArrowRightLeft, ClipboardCheck, RefreshCw, Bot, Link2, } from 'lucide-react';
|
|
11
|
+
import { LayoutDashboard, FileText, Settings2, ArrowRightLeft, ClipboardCheck, RefreshCw, Bot, Link2, Inbox, } from 'lucide-react';
|
|
11
12
|
import { useCallback, useEffect, useMemo, useState } from 'react';
|
|
12
13
|
import { toast } from 'sonner';
|
|
13
14
|
import { parseRouteQuery } from '../router/index.js';
|
|
@@ -23,6 +24,7 @@ import { TechnicalTab } from './seo/TechnicalTab.js';
|
|
|
23
24
|
import { RedirectsTab } from './seo/RedirectsTab.js';
|
|
24
25
|
import { AuditTab } from './seo/AuditTab.js';
|
|
25
26
|
import { LinksTab } from './seo/LinksTab.js';
|
|
27
|
+
import { ProposalsTab } from './seo/ProposalsTab.js';
|
|
26
28
|
const TABS = [
|
|
27
29
|
{ id: 'overview', label: 'Overview', icon: LayoutDashboard },
|
|
28
30
|
{ id: 'content', label: 'Content SEO', icon: FileText },
|
|
@@ -30,6 +32,7 @@ const TABS = [
|
|
|
30
32
|
{ id: 'technical', label: 'Technical', icon: Settings2 },
|
|
31
33
|
{ id: 'redirects', label: 'Redirects', icon: ArrowRightLeft },
|
|
32
34
|
{ id: 'audit', label: 'Audit', icon: ClipboardCheck },
|
|
35
|
+
{ id: 'proposals', label: 'Proposals', icon: Inbox },
|
|
33
36
|
];
|
|
34
37
|
function normalizeTab(tab) {
|
|
35
38
|
const valid = TABS.map((t) => t.id);
|
|
@@ -50,6 +53,7 @@ export const SEO_DEEP_PATHS = [
|
|
|
50
53
|
'/seo/technical',
|
|
51
54
|
'/seo/links',
|
|
52
55
|
'/seo/audit',
|
|
56
|
+
'/seo/proposals',
|
|
53
57
|
'/seo',
|
|
54
58
|
];
|
|
55
59
|
/** Map an SEO deep path to the tab it should open, or null if it isn't one. */
|
|
@@ -69,6 +73,8 @@ export function seoTabForPath(pathname) {
|
|
|
69
73
|
return 'technical';
|
|
70
74
|
case '/seo/audit':
|
|
71
75
|
return 'audit';
|
|
76
|
+
case '/seo/proposals':
|
|
77
|
+
return 'proposals';
|
|
72
78
|
case '/seo':
|
|
73
79
|
return 'overview';
|
|
74
80
|
default:
|
|
@@ -137,12 +143,25 @@ export function SEO({ onNavigate, initialTab = 'overview' }) {
|
|
|
137
143
|
const score = overviewResource.data?.siteScore.score;
|
|
138
144
|
const badgeCounts = useMemo(() => {
|
|
139
145
|
const summary = overviewResource.data?.issuesSummary;
|
|
140
|
-
|
|
146
|
+
const pending = overviewResource.data?.pendingProposals;
|
|
147
|
+
return {
|
|
148
|
+
audit: summary ? summary.critical + summary.warning : 0,
|
|
149
|
+
proposals: pending ? pending.issueFixes + pending.redirects : 0,
|
|
150
|
+
};
|
|
141
151
|
}, [overviewResource.data]);
|
|
142
152
|
return (_jsxs("div", { className: "space-y-6 p-6", children: [_jsxs("header", { className: "flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-foreground", children: "SEO Operations Center" }), _jsx("p", { className: "text-muted-foreground mt-1 text-sm", children: "Monitor, fix, and automate SEO across your content, redirects, and technical setup." })] }), _jsxs("div", { className: "flex items-center gap-3", children: [typeof score === 'number' && (_jsxs("span", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: ["Site score ", _jsx(ScorePill, { score: score })] })), _jsxs("button", { className: btnSecondary, onClick: () => setCopilotOpen(true), children: [_jsx(Bot, { className: "h-4 w-4", "aria-hidden": true }), "AI Copilot"] }), _jsxs("button", { className: btnPrimary, onClick: handleRunAudit, disabled: auditing, children: [_jsx(RefreshCw, { className: `h-4 w-4 ${auditing ? 'animate-spin' : ''}`, "aria-hidden": true }), auditing ? 'Running audit…' : 'Run audit'] })] })] }), _jsx(SeoCopilotDrawer, { open: copilotOpen, onOpenChange: setCopilotOpen }), _jsxs(Tabs.Root, { value: activeTab, onValueChange: changeTab, children: [_jsx(Tabs.List, { className: "border-border flex gap-1 overflow-x-auto border-b", "aria-label": "SEO sections", children: TABS.map((t) => {
|
|
143
153
|
const Icon = t.icon;
|
|
144
|
-
const badge = t.id === 'audit'
|
|
145
|
-
|
|
146
|
-
|
|
154
|
+
const badge = t.id === 'audit'
|
|
155
|
+
? badgeCounts.audit
|
|
156
|
+
: t.id === 'proposals'
|
|
157
|
+
? badgeCounts.proposals
|
|
158
|
+
: 0;
|
|
159
|
+
// The proposals count is informational (items awaiting review),
|
|
160
|
+
// not a warning like the audit issue count.
|
|
161
|
+
const badgeClass = t.id === 'proposals'
|
|
162
|
+
? 'bg-muted text-muted-foreground'
|
|
163
|
+
: 'bg-destructive/10 text-destructive';
|
|
164
|
+
return (_jsxs(Tabs.Trigger, { value: t.id, className: "text-muted-foreground hover:text-foreground data-[state=active]:text-foreground data-[state=active]:border-primary focus-visible:ring-ring -mb-px flex items-center gap-2 border-b-2 border-transparent px-3 py-2.5 text-sm font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none", children: [_jsx(Icon, { className: "h-4 w-4", "aria-hidden": true }), t.label, badge > 0 && (_jsx("span", { className: `${badgeClass} ml-1 rounded-full px-1.5 py-0.5 text-xs font-medium tabular-nums`, children: badge }))] }, t.id));
|
|
165
|
+
}) }), _jsx("div", { className: "pt-6", children: _jsxs(ErrorBoundary, { children: [_jsx(Tabs.Content, { value: "overview", tabIndex: -1, children: activeTab === 'overview' && (_jsx(OverviewTab, { resource: overviewResource, onOpenIssue: (issueId) => onNavigate?.(`/seo?tab=audit&issueId=${issueId}`) })) }), _jsx(Tabs.Content, { value: "content", tabIndex: -1, children: activeTab === 'content' && (_jsx(ContentTab, { initialEntityType: deepLink.entityType, initialEntityId: deepLink.entityId, onNavigate: onNavigate })) }), _jsx(Tabs.Content, { value: "links", tabIndex: -1, children: activeTab === 'links' && _jsx(LinksTab, { onNavigate: onNavigate, planInfo: planInfo }) }), _jsx(Tabs.Content, { value: "technical", tabIndex: -1, children: activeTab === 'technical' && _jsx(TechnicalTab, {}) }), _jsx(Tabs.Content, { value: "redirects", tabIndex: -1, children: activeTab === 'redirects' && _jsx(RedirectsTab, {}) }), _jsx(Tabs.Content, { value: "audit", tabIndex: -1, children: activeTab === 'audit' && (_jsx(AuditTab, { refetchKey: refetchKey, initialIssueId: deepLink.issueId, onNavigate: onNavigate, planInfo: planInfo })) }), _jsx(Tabs.Content, { value: "proposals", tabIndex: -1, children: activeTab === 'proposals' && (_jsx(ProposalsTab, { planInfo: planInfo, onChanged: () => setRefetchKey((k) => k + 1), onNavigate: onNavigate })) })] }) })] })] }));
|
|
147
166
|
}
|
|
148
167
|
//# sourceMappingURL=SEO.js.map
|
package/dist/views/SEO.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SEO.js","sourceRoot":"","sources":["../../src/views/SEO.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ
|
|
1
|
+
{"version":3,"file":"SEO.js","sourceRoot":"","sources":["../../src/views/SEO.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type PlanInfo } from '../../lib/plan.js';
|
|
2
|
+
export declare function ProposalsTab({ planInfo, onChanged, onNavigate, }: {
|
|
3
|
+
planInfo: PlanInfo | null;
|
|
4
|
+
onChanged?: () => void;
|
|
5
|
+
onNavigate?: (path: string) => void;
|
|
6
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
7
|
+
//# sourceMappingURL=ProposalsTab.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProposalsTab.d.ts","sourceRoot":"","sources":["../../../src/views/seo/ProposalsTab.tsx"],"names":[],"mappings":"AA8BA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,mBAAmB,CAAA;AA8FjE,wBAAgB,YAAY,CAAC,EAC3B,QAAQ,EACR,SAAS,EACT,UAAU,GACX,EAAE;IACD,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CACpC,2CA8ZA"}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
/**
|
|
4
|
+
* SEO → Proposals: every cached AI issue fix and open 404-redirect suggestion
|
|
5
|
+
* in one review surface. Batch approve honours server governance
|
|
6
|
+
* (`allowBulkApply`); the UI only pre-disables the button using the flags the
|
|
7
|
+
* list payload exposes. Generation is human-triggered, capped per pass, and
|
|
8
|
+
* loops client-side while the server reports `remaining > 0`.
|
|
9
|
+
*/
|
|
10
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
11
|
+
import { ArrowRightLeft, Check, ChevronDown, Inbox, Loader2, Sparkles, Square, X, } from 'lucide-react';
|
|
12
|
+
import { toast } from 'sonner';
|
|
13
|
+
import { bulkApplySeoProposals, dismissRedirectSuggestion, dismissSeoIssueFix, fetchSeoProposals, generateSeoProposals, } from '../../lib/seo-service.js';
|
|
14
|
+
import { hasPlanFeature } from '../../lib/plan.js';
|
|
15
|
+
import { brandAlignmentLabel, brandAlignmentTone } from '../../lib/brand-voice-client.js';
|
|
16
|
+
import { PlanUpgradeCallout } from '../../components/PlanUpgradeCallout.js';
|
|
17
|
+
import { ChangePreview } from '../../components/seo/ChangePreview.js';
|
|
18
|
+
import { SectionCard, SeoEmptyState, SeoErrorState, SeoLoading, SeoStatusBadge, btnPrimary, btnSecondary, } from '../../components/seo/primitives.js';
|
|
19
|
+
import { ConfirmDialog } from '../../components/ui/ConfirmDialog.js';
|
|
20
|
+
import { useSeoResource } from './useSeoResource.js';
|
|
21
|
+
const GENERATE_BATCH_SIZE = 10;
|
|
22
|
+
const AI_SETTINGS_PATH = '/settings?tab=ai';
|
|
23
|
+
/** Stable empty list so memoised derivations don't recompute while loading. */
|
|
24
|
+
const NO_PROPOSALS = [];
|
|
25
|
+
function errorMessage(err) {
|
|
26
|
+
return err instanceof Error && err.message ? err.message : 'Request failed.';
|
|
27
|
+
}
|
|
28
|
+
function relativeAge(iso) {
|
|
29
|
+
if (!iso)
|
|
30
|
+
return '';
|
|
31
|
+
const ms = Date.now() - new Date(iso).getTime();
|
|
32
|
+
if (!Number.isFinite(ms) || ms < 0)
|
|
33
|
+
return '';
|
|
34
|
+
const minutes = Math.round(ms / 60_000);
|
|
35
|
+
if (minutes < 60)
|
|
36
|
+
return `${Math.max(1, minutes)}m ago`;
|
|
37
|
+
const hours = Math.round(minutes / 60);
|
|
38
|
+
if (hours < 48)
|
|
39
|
+
return `${hours}h ago`;
|
|
40
|
+
return `${Math.round(hours / 24)}d ago`;
|
|
41
|
+
}
|
|
42
|
+
function confidenceTone(c) {
|
|
43
|
+
return c >= 0.7 ? 'good' : c >= 0.4 ? 'fair' : 'poor';
|
|
44
|
+
}
|
|
45
|
+
function plural(count, noun) {
|
|
46
|
+
return `${count} ${noun}${count === 1 ? '' : 's'}`;
|
|
47
|
+
}
|
|
48
|
+
function toBulkItem(p) {
|
|
49
|
+
return p.kind === 'redirect'
|
|
50
|
+
? { kind: 'redirect', id: p.suggestionId ?? '' }
|
|
51
|
+
: { kind: 'issue-fix', id: p.issueId ?? '', fingerprint: p.fingerprint ?? undefined };
|
|
52
|
+
}
|
|
53
|
+
function BrandScoreBadge({ score }) {
|
|
54
|
+
return (_jsxs("span", { className: "border-border bg-muted/40 inline-flex items-center gap-1.5 rounded-md border px-2 py-0.5 text-xs", "aria-label": `Brand voice score ${score} out of 100`, children: [_jsxs("span", { className: `font-medium ${brandAlignmentTone(score)}`, children: [score, "/100"] }), _jsx("span", { className: "text-muted-foreground", children: brandAlignmentLabel(score) })] }));
|
|
55
|
+
}
|
|
56
|
+
function SourceBadge({ source }) {
|
|
57
|
+
switch (source) {
|
|
58
|
+
case 'ai':
|
|
59
|
+
return (_jsxs("span", { className: "bg-primary/10 text-primary inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium", children: [_jsx(Sparkles, { className: "h-3 w-3", "aria-hidden": true }), "AI"] }));
|
|
60
|
+
case 'ai-404-recovery':
|
|
61
|
+
return (_jsxs("span", { className: "bg-primary/10 text-primary inline-flex items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium", children: [_jsx(ArrowRightLeft, { className: "h-3 w-3", "aria-hidden": true }), "404 recovery"] }));
|
|
62
|
+
case 'deterministic':
|
|
63
|
+
return (_jsx("span", { className: "bg-muted text-muted-foreground rounded-full px-2 py-0.5 text-xs font-medium", children: "Rule-based" }));
|
|
64
|
+
default: {
|
|
65
|
+
const _exhaustive = source;
|
|
66
|
+
return _exhaustive;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export function ProposalsTab({ planInfo, onChanged, onNavigate, }) {
|
|
71
|
+
const { data, loading, error, refetch } = useSeoResource(fetchSeoProposals, []);
|
|
72
|
+
const [selected, setSelected] = useState(new Set());
|
|
73
|
+
const [expanded, setExpanded] = useState(new Set());
|
|
74
|
+
const [confirmApply, setConfirmApply] = useState(false);
|
|
75
|
+
const [confirmGenerate, setConfirmGenerate] = useState(false);
|
|
76
|
+
const [mutation, setMutation] = useState(null);
|
|
77
|
+
const [pendingItems, setPendingItems] = useState([]);
|
|
78
|
+
const [generating, setGenerating] = useState(null);
|
|
79
|
+
const stopRef = useRef(false);
|
|
80
|
+
/** Mirrors `mutation` synchronously so a second call in the same tick cannot slip past. */
|
|
81
|
+
const mutationRef = useRef(null);
|
|
82
|
+
const mountedRef = useRef(true);
|
|
83
|
+
const busy = mutation !== null;
|
|
84
|
+
useEffect(() => {
|
|
85
|
+
mountedRef.current = true;
|
|
86
|
+
return () => {
|
|
87
|
+
mountedRef.current = false;
|
|
88
|
+
stopRef.current = true;
|
|
89
|
+
};
|
|
90
|
+
}, []);
|
|
91
|
+
/** Claims the mutation slot; returns false when another mutation is already running. */
|
|
92
|
+
const beginMutation = useCallback((kind) => {
|
|
93
|
+
if (mutationRef.current !== null)
|
|
94
|
+
return false;
|
|
95
|
+
mutationRef.current = kind;
|
|
96
|
+
setMutation(kind);
|
|
97
|
+
return true;
|
|
98
|
+
}, []);
|
|
99
|
+
const endMutation = useCallback(() => {
|
|
100
|
+
mutationRef.current = null;
|
|
101
|
+
if (mountedRef.current)
|
|
102
|
+
setMutation(null);
|
|
103
|
+
}, []);
|
|
104
|
+
const inlineApplyEnabled = hasPlanFeature(planInfo, 'seo.inlineApply');
|
|
105
|
+
const proposals = data?.proposals ?? NO_PROPOSALS;
|
|
106
|
+
const live = useMemo(() => proposals.filter((p) => !p.stale), [proposals]);
|
|
107
|
+
const selectedProposals = useMemo(() => live.filter((p) => selected.has(p.id)), [live, selected]);
|
|
108
|
+
const bulkBlockedReason = useMemo(() => {
|
|
109
|
+
if (!data || selectedProposals.length <= 1)
|
|
110
|
+
return null;
|
|
111
|
+
const hasIssue = selectedProposals.some((p) => p.kind === 'issue-fix');
|
|
112
|
+
const hasRedirect = selectedProposals.some((p) => p.kind === 'redirect');
|
|
113
|
+
if (hasIssue && !data.governance.issueFixBulk)
|
|
114
|
+
return 'SEO metadata generation';
|
|
115
|
+
if (hasRedirect && !data.governance.redirectBulk)
|
|
116
|
+
return '404 recovery';
|
|
117
|
+
return null;
|
|
118
|
+
}, [data, selectedProposals]);
|
|
119
|
+
const allSelected = live.length > 0 && selected.size === live.length;
|
|
120
|
+
const toggleSelectAll = useCallback(() => {
|
|
121
|
+
setSelected((cur) => (cur.size === live.length ? new Set() : new Set(live.map((p) => p.id))));
|
|
122
|
+
}, [live]);
|
|
123
|
+
const toggleSelect = useCallback((id) => {
|
|
124
|
+
setSelected((cur) => {
|
|
125
|
+
const next = new Set(cur);
|
|
126
|
+
if (next.has(id))
|
|
127
|
+
next.delete(id);
|
|
128
|
+
else
|
|
129
|
+
next.add(id);
|
|
130
|
+
return next;
|
|
131
|
+
});
|
|
132
|
+
}, []);
|
|
133
|
+
const toggleExpanded = useCallback((id) => {
|
|
134
|
+
setExpanded((cur) => {
|
|
135
|
+
const next = new Set(cur);
|
|
136
|
+
if (next.has(id))
|
|
137
|
+
next.delete(id);
|
|
138
|
+
else
|
|
139
|
+
next.add(id);
|
|
140
|
+
return next;
|
|
141
|
+
});
|
|
142
|
+
}, []);
|
|
143
|
+
const afterMutation = useCallback(() => {
|
|
144
|
+
setSelected(new Set());
|
|
145
|
+
refetch();
|
|
146
|
+
onChanged?.();
|
|
147
|
+
}, [refetch, onChanged]);
|
|
148
|
+
const runApply = useCallback(async (items) => {
|
|
149
|
+
if (items.length === 0)
|
|
150
|
+
return;
|
|
151
|
+
if (!beginMutation('apply'))
|
|
152
|
+
return;
|
|
153
|
+
try {
|
|
154
|
+
const res = await bulkApplySeoProposals(items);
|
|
155
|
+
if (!mountedRef.current)
|
|
156
|
+
return;
|
|
157
|
+
const result = res.result;
|
|
158
|
+
if (res.error || !result) {
|
|
159
|
+
toast.error(res.error ?? 'Unexpected response from the server.');
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (result.applied > 0) {
|
|
163
|
+
toast.success(`${plural(result.applied, 'proposal')} applied.`);
|
|
164
|
+
}
|
|
165
|
+
if (result.failed > 0) {
|
|
166
|
+
const reasons = result.results
|
|
167
|
+
.filter((r) => r.status !== 'applied' && r.status !== 'pending')
|
|
168
|
+
.map((r) => `${r.id}: ${r.reason ?? r.status}`)
|
|
169
|
+
.slice(0, 3)
|
|
170
|
+
.join('; ');
|
|
171
|
+
toast.error(`${result.failed} could not be applied. ${reasons}`);
|
|
172
|
+
}
|
|
173
|
+
const pendingIds = new Set(result.results.filter((r) => r.status === 'pending').map((r) => r.id));
|
|
174
|
+
setPendingItems(items.filter((i) => pendingIds.has(i.id)));
|
|
175
|
+
afterMutation();
|
|
176
|
+
}
|
|
177
|
+
catch (err) {
|
|
178
|
+
if (mountedRef.current)
|
|
179
|
+
toast.error(errorMessage(err));
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
endMutation();
|
|
183
|
+
}
|
|
184
|
+
}, [afterMutation, beginMutation, endMutation]);
|
|
185
|
+
const handleDismissSelected = useCallback(async () => {
|
|
186
|
+
const targets = selectedProposals;
|
|
187
|
+
if (targets.length === 0)
|
|
188
|
+
return;
|
|
189
|
+
if (!beginMutation('dismiss'))
|
|
190
|
+
return;
|
|
191
|
+
try {
|
|
192
|
+
const results = await Promise.allSettled(targets.map((p) => p.kind === 'redirect'
|
|
193
|
+
? dismissRedirectSuggestion(p.suggestionId ?? '')
|
|
194
|
+
: dismissSeoIssueFix(p.issueId ?? '')));
|
|
195
|
+
if (!mountedRef.current)
|
|
196
|
+
return;
|
|
197
|
+
const failed = results.filter((r) => r.status === 'rejected' || r.value.error).length;
|
|
198
|
+
if (failed > 0)
|
|
199
|
+
toast.error(`${failed} of ${targets.length} could not be dismissed.`);
|
|
200
|
+
else
|
|
201
|
+
toast.success(`${plural(targets.length, 'proposal')} dismissed.`);
|
|
202
|
+
afterMutation();
|
|
203
|
+
}
|
|
204
|
+
finally {
|
|
205
|
+
endMutation();
|
|
206
|
+
}
|
|
207
|
+
}, [selectedProposals, afterMutation, beginMutation, endMutation]);
|
|
208
|
+
const handleDismissOne = useCallback(async (p) => {
|
|
209
|
+
if (!beginMutation('dismiss'))
|
|
210
|
+
return;
|
|
211
|
+
try {
|
|
212
|
+
const res = p.kind === 'redirect'
|
|
213
|
+
? await dismissRedirectSuggestion(p.suggestionId ?? '')
|
|
214
|
+
: await dismissSeoIssueFix(p.issueId ?? '');
|
|
215
|
+
if (!mountedRef.current)
|
|
216
|
+
return;
|
|
217
|
+
if (res.error) {
|
|
218
|
+
toast.error(res.error);
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
afterMutation();
|
|
222
|
+
}
|
|
223
|
+
catch (err) {
|
|
224
|
+
if (mountedRef.current)
|
|
225
|
+
toast.error(errorMessage(err));
|
|
226
|
+
}
|
|
227
|
+
finally {
|
|
228
|
+
endMutation();
|
|
229
|
+
}
|
|
230
|
+
}, [afterMutation, beginMutation, endMutation]);
|
|
231
|
+
const handleGenerate = useCallback(async () => {
|
|
232
|
+
if (!beginMutation('generate'))
|
|
233
|
+
return;
|
|
234
|
+
const eligible = data?.counts.eligibleForGeneration ?? 0;
|
|
235
|
+
stopRef.current = false;
|
|
236
|
+
let total = 0;
|
|
237
|
+
let done = 0;
|
|
238
|
+
let transportError = false;
|
|
239
|
+
setGenerating({ done: 0, total: eligible });
|
|
240
|
+
try {
|
|
241
|
+
for (;;) {
|
|
242
|
+
const res = await generateSeoProposals();
|
|
243
|
+
// The tab may have unmounted mid-pass; stop issuing requests and stay silent.
|
|
244
|
+
if (!mountedRef.current)
|
|
245
|
+
return;
|
|
246
|
+
const r = res.result;
|
|
247
|
+
if (res.error || !r) {
|
|
248
|
+
toast.error(res.error ?? 'Unexpected response from the server.');
|
|
249
|
+
transportError = true;
|
|
250
|
+
break;
|
|
251
|
+
}
|
|
252
|
+
total += r.generated;
|
|
253
|
+
done += r.generated + r.skipped + r.failed;
|
|
254
|
+
setGenerating({ done, total: eligible });
|
|
255
|
+
if (r.haltedReason) {
|
|
256
|
+
toast.error(`Generation stopped: ${r.haltedReason}`);
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
if (r.failed > 0) {
|
|
260
|
+
toast.error(`${plural(r.failed, 'issue')} failed to generate.`);
|
|
261
|
+
break;
|
|
262
|
+
}
|
|
263
|
+
if (r.remaining <= 0 || stopRef.current)
|
|
264
|
+
break;
|
|
265
|
+
}
|
|
266
|
+
if (!transportError)
|
|
267
|
+
toast.success(`${plural(total, 'proposal')} generated.`);
|
|
268
|
+
afterMutation();
|
|
269
|
+
}
|
|
270
|
+
catch (err) {
|
|
271
|
+
if (mountedRef.current)
|
|
272
|
+
toast.error(errorMessage(err));
|
|
273
|
+
}
|
|
274
|
+
finally {
|
|
275
|
+
if (mountedRef.current)
|
|
276
|
+
setGenerating(null);
|
|
277
|
+
endMutation();
|
|
278
|
+
}
|
|
279
|
+
}, [data, afterMutation, beginMutation, endMutation]);
|
|
280
|
+
const eligible = data?.counts.eligibleForGeneration ?? 0;
|
|
281
|
+
const generateAction = inlineApplyEnabled ? (generating ? (_jsxs("div", { className: "flex items-center gap-2", children: [_jsxs("span", { className: "text-muted-foreground flex items-center gap-2 text-sm", role: "status", "aria-live": "polite", children: [_jsx(Loader2, { className: "h-4 w-4 motion-safe:animate-spin", "aria-hidden": true }), "Generating\u2026 ", generating.done, " of ", generating.total] }), _jsxs("button", { type: "button", className: btnSecondary, onClick: () => {
|
|
282
|
+
stopRef.current = true;
|
|
283
|
+
}, children: [_jsx(Square, { className: "h-4 w-4", "aria-hidden": true }), "Stop"] })] })) : (_jsxs("button", { type: "button", className: btnPrimary, onClick: () => setConfirmGenerate(true), disabled: eligible === 0 || loading || busy, children: [_jsx(Sparkles, { className: "h-4 w-4", "aria-hidden": true }), "Generate proposals (", eligible, " eligible)"] }))) : null;
|
|
284
|
+
return (_jsxs("div", { className: "space-y-6", children: [!inlineApplyEnabled ? (_jsx(PlanUpgradeCallout, { feature: "seo.inlineApply", upgradeUrl: planInfo?.upgradeUrl })) : null, _jsx(SectionCard, { title: "Proposals", description: "Review, approve, or dismiss what the AI proposes across issue fixes and 404 redirects.", action: generateAction, children: loading ? (_jsx(SeoLoading, {})) : error ? (_jsx(SeoErrorState, { message: error, onRetry: refetch })) : proposals.length === 0 ? (_jsx(SeoEmptyState, { icon: _jsx(Inbox, { size: 24 }), title: "No proposals yet", description: "Generate proposals to draft fixes for open, fixable issues, or run 404 recovery from the Redirects tab." })) : (_jsxs("div", { className: "space-y-3", children: [pendingItems.length > 0 && (_jsxs("div", { className: "border-border bg-muted/40 flex flex-wrap items-center gap-2 rounded-lg border px-3 py-2 text-sm", role: "status", "aria-live": "polite", children: [_jsxs("span", { className: "text-foreground", children: [plural(pendingItems.length, 'proposal'), " not reached within the time budget."] }), _jsxs("button", { type: "button", className: "text-primary hover:bg-accent focus-visible:ring-ring rounded-md px-2 py-1 font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none disabled:opacity-60", onClick: () => void runApply(pendingItems), disabled: busy, children: ["Apply remaining (", pendingItems.length, ")"] }), _jsx("button", { type: "button", className: "text-muted-foreground hover:text-foreground focus-visible:ring-ring ml-auto rounded-md px-2 py-1 font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none", onClick: () => setPendingItems([]), children: "Dismiss" })] })), selected.size > 0 && (_jsxs("div", { className: "border-border bg-accent/40 flex flex-wrap items-center gap-2 rounded-lg border px-3 py-2 text-sm", role: "region", "aria-label": "Bulk actions", children: [_jsxs("span", { className: "text-foreground font-medium", children: [selected.size, " selected"] }), _jsx("span", { className: "bg-border mx-1 h-4 w-px", "aria-hidden": true }), _jsx("button", { type: "button", className: "text-foreground hover:bg-accent focus-visible:ring-ring rounded-md px-2 py-1 font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none disabled:opacity-60", onClick: () => setConfirmApply(true), disabled: busy || bulkBlockedReason !== null, children: "Approve selected" }), _jsx("button", { type: "button", className: "text-foreground hover:bg-accent focus-visible:ring-ring rounded-md px-2 py-1 font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none disabled:opacity-60", onClick: () => void handleDismissSelected(), disabled: busy, children: "Dismiss selected" }), _jsx("button", { type: "button", className: "text-muted-foreground hover:text-foreground focus-visible:ring-ring ml-auto rounded-md px-2 py-1 font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none", onClick: () => setSelected(new Set()), children: "Clear" }), bulkBlockedReason && (_jsxs("p", { className: "text-muted-foreground basis-full text-sm", role: "status", children: ["Applying several ", bulkBlockedReason, " proposals at once needs \u201CAllow bulk apply\u201D.", onNavigate ? (_jsx("button", { type: "button", onClick: () => onNavigate(AI_SETTINGS_PATH), className: "text-primary focus-visible:ring-ring ml-1 rounded-sm font-medium hover:underline focus-visible:ring-2 focus-visible:outline-none", children: "Open Settings \u2192 AI" })) : null] }))] })), _jsx("div", { className: "border-border overflow-x-auto rounded-md border", children: _jsxs("table", { className: "w-full text-sm", "aria-label": "AI proposals", children: [_jsx("thead", { children: _jsxs("tr", { className: "border-border bg-muted/40 text-muted-foreground border-b text-left text-xs", children: [_jsx("th", { scope: "col", className: "w-10 px-3 py-2.5", children: _jsx("input", { type: "checkbox", checked: allSelected, onChange: toggleSelectAll, disabled: live.length === 0, "aria-label": "Select all proposals", className: "border-border text-primary focus-visible:ring-ring h-4 w-4 rounded" }) }), _jsx("th", { scope: "col", className: "px-3 py-2.5 font-medium", children: "Proposal" }), _jsx("th", { scope: "col", className: "px-3 py-2.5 font-medium", children: "Change" }), _jsx("th", { scope: "col", className: "px-3 py-2.5 font-medium", children: "Signals" }), _jsx("th", { scope: "col", className: "px-3 py-2.5 font-medium", children: "Age" }), _jsx("th", { scope: "col", className: "px-3 py-2.5", children: _jsx("span", { className: "sr-only", children: "Actions" }) })] }) }), _jsx("tbody", { className: "divide-border divide-y", children: proposals.map((p) => {
|
|
285
|
+
const first = p.changes[0];
|
|
286
|
+
return (_jsx(ProposalRow, { proposal: p, selected: selected.has(p.id), expanded: expanded.has(p.id), summary: first
|
|
287
|
+
? `${String(first.before ?? '—')} → ${String(first.after ?? '—')}`
|
|
288
|
+
: p.justification, onToggleSelect: () => toggleSelect(p.id), onToggleExpanded: () => toggleExpanded(p.id), onApprove: () => void runApply([toBulkItem(p)]), onDismiss: () => void handleDismissOne(p), busy: busy, canApply: inlineApplyEnabled || p.kind === 'redirect' }, p.id));
|
|
289
|
+
}) })] }) })] })) }), _jsx(ConfirmDialog, { open: confirmApply, onClose: () => setConfirmApply(false), onConfirm: () => void runApply(selectedProposals.map(toBulkItem)), title: `Apply ${plural(selectedProposals.length, 'proposal')}?`, description: "Approved fixes write SEO fields, content links, or redirects immediately and mark their issues resolved. Each document keeps a version you can restore.", confirmLabel: `Apply ${plural(selectedProposals.length, 'proposal')}` }), _jsx(ConfirmDialog, { open: confirmGenerate, onClose: () => setConfirmGenerate(false), onConfirm: () => void handleGenerate(), title: `Generate proposals for ${plural(eligible, 'eligible issue')}?`, description: `Runs in passes of ${GENERATE_BATCH_SIZE}. AI tokens are spent for each issue; you can stop between passes.`, confirmLabel: "Generate" })] }));
|
|
290
|
+
}
|
|
291
|
+
function ProposalRow({ proposal: p, selected, expanded, summary, onToggleSelect, onToggleExpanded, onApprove, onDismiss, busy, canApply, }) {
|
|
292
|
+
return (_jsxs(_Fragment, { children: [_jsxs("tr", { className: `${selected ? 'bg-accent/30' : ''} hover:bg-accent/20 transition-colors`, children: [_jsx("td", { className: "px-3 py-3 align-top", children: p.stale ? null : (_jsx("input", { type: "checkbox", checked: selected, onChange: onToggleSelect, "aria-label": `Select proposal ${p.title}`, className: "border-border text-primary focus-visible:ring-ring h-4 w-4 rounded" })) }), _jsxs("td", { className: "px-3 py-3 align-top", children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx("span", { className: "text-foreground font-medium", children: p.title }), p.severity ? (_jsx(SeoStatusBadge, { label: p.severity, tone: p.severity === 'critical'
|
|
293
|
+
? 'critical'
|
|
294
|
+
: p.severity === 'warning'
|
|
295
|
+
? 'fair'
|
|
296
|
+
: 'neutral' })) : null, p.stale ? _jsx(SeoStatusBadge, { label: "Stale \u2014 regenerate", tone: "poor" }) : null] }), p.entity.title || p.entity.url ? (_jsxs("p", { className: "text-muted-foreground mt-0.5 text-xs", children: [p.entity.title ?? '', p.entity.title && p.entity.url ? ' · ' : '', p.entity.url ?? ''] })) : null] }), _jsxs("td", { className: "px-3 py-3 align-top", children: [_jsx("p", { className: "text-foreground max-w-md truncate", children: summary }), _jsxs("button", { type: "button", className: "text-primary hover:bg-accent focus-visible:ring-ring mt-1 inline-flex items-center gap-1 rounded-md px-1.5 py-0.5 text-xs focus-visible:ring-2 focus-visible:outline-none", onClick: onToggleExpanded, "aria-expanded": expanded, "aria-label": `${expanded ? 'Hide' : 'Show'} changes for ${p.title}`, children: [expanded ? 'Hide changes' : 'Show changes', _jsx(ChevronDown, { className: `h-3 w-3 motion-safe:transition-transform ${expanded ? 'rotate-180' : ''}`, "aria-hidden": true })] })] }), _jsx("td", { className: "px-3 py-3 align-top", children: _jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [_jsx(SourceBadge, { source: p.source }), typeof p.confidence === 'number' ? (_jsx(SeoStatusBadge, { label: `${Math.round(p.confidence * 100)}%`, tone: confidenceTone(p.confidence) })) : null, typeof p.brandAlignment === 'number' ? (_jsx(BrandScoreBadge, { score: p.brandAlignment })) : null] }) }), _jsx("td", { className: "text-muted-foreground px-3 py-3 align-top text-xs whitespace-nowrap", children: relativeAge(p.generatedAt) }), _jsx("td", { className: "px-3 py-3 align-top", children: _jsxs("div", { className: "flex items-center justify-end gap-1", children: [!p.stale && canApply ? (_jsx("button", { type: "button", onClick: onApprove, disabled: busy, className: "text-success hover:bg-accent focus-visible:ring-ring rounded-md p-1.5 focus-visible:ring-2 focus-visible:outline-none disabled:opacity-60", "aria-label": `Approve ${p.title}`, children: _jsx(Check, { className: "h-4 w-4", "aria-hidden": true }) })) : null, _jsx("button", { type: "button", onClick: onDismiss, disabled: busy, className: "text-muted-foreground hover:bg-accent focus-visible:ring-ring rounded-md p-1.5 focus-visible:ring-2 focus-visible:outline-none disabled:opacity-60", "aria-label": `Dismiss ${p.title}`, children: _jsx(X, { className: "h-4 w-4", "aria-hidden": true }) })] }) })] }), expanded ? (_jsx("tr", { children: _jsx("td", { colSpan: 6, className: "bg-muted/30 px-4 py-4", children: _jsxs("div", { className: "space-y-3", children: [_jsx("p", { className: "text-foreground text-sm", children: p.justification }), _jsx(ChangePreview, { changes: p.changes })] }) }) })) : null] }));
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=ProposalsTab.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProposalsTab.js","sourceRoot":"","sources":["../../../src/views/seo/ProposalsTab.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ;;;;;;GAMG;AACH,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AACzE,OAAO,EACL,cAAc,EACd,KAAK,EACL,WAAW,EACX,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,EACN,CAAC,GACF,MAAM,cAAc,CAAA;AACrB,OAAO,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AAC9B,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,kBAAkB,EAClB,iBAAiB,EACjB,oBAAoB,GAGrB,MAAM,0BAA0B,CAAA;AACjC,OAAO,EAAE,cAAc,EAAiB,MAAM,mBAAmB,CAAA;AACjE,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACzF,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAA;AAC3E,OAAO,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAA;AACrE,OAAO,EACL,WAAW,EACX,aAAa,EACb,aAAa,EACb,UAAU,EACV,cAAc,EACd,UAAU,EACV,YAAY,GACb,MAAM,oCAAoC,CAAA;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,sCAAsC,CAAA;AACpE,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAEpD,MAAM,mBAAmB,GAAG,EAAE,CAAA;AAC9B,MAAM,gBAAgB,GAAG,kBAAkB,CAAA;AAC3C,+EAA+E;AAC/E,MAAM,YAAY,GAAkB,EAAE,CAAA;AAKtC,SAAS,YAAY,CAAC,GAAY;IAChC,OAAO,GAAG,YAAY,KAAK,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,iBAAiB,CAAA;AAC9E,CAAC;AAED,SAAS,WAAW,CAAC,GAAkB;IACrC,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,CAAA;IACnB,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,CAAA;IAC/C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,GAAG,CAAC;QAAE,OAAO,EAAE,CAAA;IAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,GAAG,MAAM,CAAC,CAAA;IACvC,IAAI,OAAO,GAAG,EAAE;QAAE,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC,OAAO,CAAA;IACvD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,GAAG,EAAE,CAAC,CAAA;IACtC,IAAI,KAAK,GAAG,EAAE;QAAE,OAAO,GAAG,KAAK,OAAO,CAAA;IACtC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,EAAE,CAAC,OAAO,CAAA;AACzC,CAAC;AAED,SAAS,cAAc,CAAC,CAAS;IAC/B,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAA;AACvD,CAAC;AAED,SAAS,MAAM,CAAC,KAAa,EAAE,IAAY;IACzC,OAAO,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,CAAA;AACpD,CAAC;AAED,SAAS,UAAU,CAAC,CAAc;IAChC,OAAO,CAAC,CAAC,IAAI,KAAK,UAAU;QAC1B,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE,EAAE,CAAC,CAAC,YAAY,IAAI,EAAE,EAAE;QAChD,CAAC,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,IAAI,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,SAAS,EAAE,CAAA;AACzF,CAAC;AAED,SAAS,eAAe,CAAC,EAAE,KAAK,EAAqB;IACnD,OAAO,CACL,gBACE,SAAS,EAAC,kGAAkG,gBAChG,qBAAqB,KAAK,aAAa,aAEnD,gBAAM,SAAS,EAAE,eAAe,kBAAkB,CAAC,KAAK,CAAC,EAAE,aAAG,KAAK,YAAY,EAC/E,eAAM,SAAS,EAAC,uBAAuB,YAAE,mBAAmB,CAAC,KAAK,CAAC,GAAQ,IACtE,CACR,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAAC,EAAE,MAAM,EAAqC;IAChE,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,IAAI;YACP,OAAO,CACL,gBAAM,SAAS,EAAC,wGAAwG,aACtH,KAAC,QAAQ,IAAC,SAAS,EAAC,SAAS,wBAAe,UAEvC,CACR,CAAA;QACH,KAAK,iBAAiB;YACpB,OAAO,CACL,gBAAM,SAAS,EAAC,wGAAwG,aACtH,KAAC,cAAc,IAAC,SAAS,EAAC,SAAS,wBAAe,oBAE7C,CACR,CAAA;QACH,KAAK,eAAe;YAClB,OAAO,CACL,eAAM,SAAS,EAAC,6EAA6E,2BAEtF,CACR,CAAA;QACH,OAAO,CAAC,CAAC,CAAC;YACR,MAAM,WAAW,GAAU,MAAM,CAAA;YACjC,OAAO,WAAW,CAAA;QACpB,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,EAC3B,QAAQ,EACR,SAAS,EACT,UAAU,GAKX;IACC,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,cAAc,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAA;IAC/E,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAc,IAAI,GAAG,EAAE,CAAC,CAAA;IAChE,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAc,IAAI,GAAG,EAAE,CAAC,CAAA;IAChE,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IACvD,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7D,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAkB,IAAI,CAAC,CAAA;IAC/D,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAA6B,EAAE,CAAC,CAAA;IAChF,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAyC,IAAI,CAAC,CAAA;IAC1F,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC7B,2FAA2F;IAC3F,MAAM,WAAW,GAAG,MAAM,CAAkB,IAAI,CAAC,CAAA;IACjD,MAAM,UAAU,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;IAC/B,MAAM,IAAI,GAAG,QAAQ,KAAK,IAAI,CAAA;IAE9B,SAAS,CAAC,GAAG,EAAE;QACb,UAAU,CAAC,OAAO,GAAG,IAAI,CAAA;QACzB,OAAO,GAAG,EAAE;YACV,UAAU,CAAC,OAAO,GAAG,KAAK,CAAA;YAC1B,OAAO,CAAC,OAAO,GAAG,IAAI,CAAA;QACxB,CAAC,CAAA;IACH,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,wFAAwF;IACxF,MAAM,aAAa,GAAG,WAAW,CAAC,CAAC,IAAc,EAAW,EAAE;QAC5D,IAAI,WAAW,CAAC,OAAO,KAAK,IAAI;YAAE,OAAO,KAAK,CAAA;QAC9C,WAAW,CAAC,OAAO,GAAG,IAAI,CAAA;QAC1B,WAAW,CAAC,IAAI,CAAC,CAAA;QACjB,OAAO,IAAI,CAAA;IACb,CAAC,EAAE,EAAE,CAAC,CAAA;IACN,MAAM,WAAW,GAAG,WAAW,CAAC,GAAG,EAAE;QACnC,WAAW,CAAC,OAAO,GAAG,IAAI,CAAA;QAC1B,IAAI,UAAU,CAAC,OAAO;YAAE,WAAW,CAAC,IAAI,CAAC,CAAA;IAC3C,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,kBAAkB,GAAG,cAAc,CAAC,QAAQ,EAAE,iBAAiB,CAAC,CAAA;IACtE,MAAM,SAAS,GAAG,IAAI,EAAE,SAAS,IAAI,YAAY,CAAA;IACjD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAA;IAC1E,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAA;IAEjG,MAAM,iBAAiB,GAAG,OAAO,CAAC,GAAG,EAAE;QACrC,IAAI,CAAC,IAAI,IAAI,iBAAiB,CAAC,MAAM,IAAI,CAAC;YAAE,OAAO,IAAI,CAAA;QACvD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,CAAA;QACtE,MAAM,WAAW,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,CAAA;QACxE,IAAI,QAAQ,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY;YAAE,OAAO,yBAAyB,CAAA;QAC/E,IAAI,WAAW,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY;YAAE,OAAO,cAAc,CAAA;QACvE,OAAO,IAAI,CAAA;IACb,CAAC,EAAE,CAAC,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAA;IAE7B,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,QAAQ,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAA;IACpE,MAAM,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;QACvC,WAAW,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAA;IAC/F,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAA;IACV,MAAM,YAAY,GAAG,WAAW,CAAC,CAAC,EAAU,EAAE,EAAE;QAC9C,WAAW,CAAC,CAAC,GAAG,EAAE,EAAE;YAClB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;YACzB,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;;gBAC5B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YACjB,OAAO,IAAI,CAAA;QACb,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,EAAE,CAAC,CAAA;IACN,MAAM,cAAc,GAAG,WAAW,CAAC,CAAC,EAAU,EAAE,EAAE;QAChD,WAAW,CAAC,CAAC,GAAG,EAAE,EAAE;YAClB,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;YACzB,IAAI,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAA;;gBAC5B,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAA;YACjB,OAAO,IAAI,CAAA;QACb,CAAC,CAAC,CAAA;IACJ,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,aAAa,GAAG,WAAW,CAAC,GAAG,EAAE;QACrC,WAAW,CAAC,IAAI,GAAG,EAAE,CAAC,CAAA;QACtB,OAAO,EAAE,CAAA;QACT,SAAS,EAAE,EAAE,CAAA;IACf,CAAC,EAAE,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC,CAAA;IAExB,MAAM,QAAQ,GAAG,WAAW,CAC1B,KAAK,EAAE,KAAiC,EAAE,EAAE;QAC1C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAC9B,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;YAAE,OAAM;QACnC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,qBAAqB,CAAC,KAAK,CAAC,CAAA;YAC9C,IAAI,CAAC,UAAU,CAAC,OAAO;gBAAE,OAAM;YAC/B,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,CAAA;YACzB,IAAI,GAAG,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC;gBACzB,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,sCAAsC,CAAC,CAAA;gBAChE,OAAM;YACR,CAAC;YACD,IAAI,MAAM,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;gBACvB,KAAK,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,WAAW,CAAC,CAAA;YACjE,CAAC;YACD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACtB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO;qBAC3B,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC;qBAC/D,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;qBAC9C,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;qBACX,IAAI,CAAC,IAAI,CAAC,CAAA;gBACb,KAAK,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,MAAM,0BAA0B,OAAO,EAAE,CAAC,CAAA;YAClE,CAAC;YACD,MAAM,UAAU,GAAG,IAAI,GAAG,CACxB,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CACtE,CAAA;YACD,eAAe,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;YAC1D,aAAa,EAAE,CAAA;QACjB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,UAAU,CAAC,OAAO;gBAAE,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAA;QACxD,CAAC;gBAAS,CAAC;YACT,WAAW,EAAE,CAAA;QACf,CAAC;IACH,CAAC,EACD,CAAC,aAAa,EAAE,aAAa,EAAE,WAAW,CAAC,CAC5C,CAAA;IAED,MAAM,qBAAqB,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QACnD,MAAM,OAAO,GAAG,iBAAiB,CAAA;QACjC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAChC,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC;YAAE,OAAM;QACrC,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CACtC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAChB,CAAC,CAAC,IAAI,KAAK,UAAU;gBACnB,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,YAAY,IAAI,EAAE,CAAC;gBACjD,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CACxC,CACF,CAAA;YACD,IAAI,CAAC,UAAU,CAAC,OAAO;gBAAE,OAAM;YAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,UAAU,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAA;YACrF,IAAI,MAAM,GAAG,CAAC;gBAAE,KAAK,CAAC,KAAK,CAAC,GAAG,MAAM,OAAO,OAAO,CAAC,MAAM,0BAA0B,CAAC,CAAA;;gBAChF,KAAK,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,aAAa,CAAC,CAAA;YACtE,aAAa,EAAE,CAAA;QACjB,CAAC;gBAAS,CAAC;YACT,WAAW,EAAE,CAAA;QACf,CAAC;IACH,CAAC,EAAE,CAAC,iBAAiB,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC,CAAA;IAElE,MAAM,gBAAgB,GAAG,WAAW,CAClC,KAAK,EAAE,CAAc,EAAE,EAAE;QACvB,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC;YAAE,OAAM;QACrC,IAAI,CAAC;YACH,MAAM,GAAG,GACP,CAAC,CAAC,IAAI,KAAK,UAAU;gBACnB,CAAC,CAAC,MAAM,yBAAyB,CAAC,CAAC,CAAC,YAAY,IAAI,EAAE,CAAC;gBACvD,CAAC,CAAC,MAAM,kBAAkB,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAA;YAC/C,IAAI,CAAC,UAAU,CAAC,OAAO;gBAAE,OAAM;YAC/B,IAAI,GAAG,CAAC,KAAK,EAAE,CAAC;gBACd,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;gBACtB,OAAM;YACR,CAAC;YACD,aAAa,EAAE,CAAA;QACjB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,UAAU,CAAC,OAAO;gBAAE,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAA;QACxD,CAAC;gBAAS,CAAC;YACT,WAAW,EAAE,CAAA;QACf,CAAC;IACH,CAAC,EACD,CAAC,aAAa,EAAE,aAAa,EAAE,WAAW,CAAC,CAC5C,CAAA;IAED,MAAM,cAAc,GAAG,WAAW,CAAC,KAAK,IAAI,EAAE;QAC5C,IAAI,CAAC,aAAa,CAAC,UAAU,CAAC;YAAE,OAAM;QACtC,MAAM,QAAQ,GAAG,IAAI,EAAE,MAAM,CAAC,qBAAqB,IAAI,CAAC,CAAA;QACxD,OAAO,CAAC,OAAO,GAAG,KAAK,CAAA;QACvB,IAAI,KAAK,GAAG,CAAC,CAAA;QACb,IAAI,IAAI,GAAG,CAAC,CAAA;QACZ,IAAI,cAAc,GAAG,KAAK,CAAA;QAC1B,aAAa,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;QAC3C,IAAI,CAAC;YACH,SAAS,CAAC;gBACR,MAAM,GAAG,GAAG,MAAM,oBAAoB,EAAE,CAAA;gBACxC,8EAA8E;gBAC9E,IAAI,CAAC,UAAU,CAAC,OAAO;oBAAE,OAAM;gBAC/B,MAAM,CAAC,GAAG,GAAG,CAAC,MAAM,CAAA;gBACpB,IAAI,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,EAAE,CAAC;oBACpB,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,sCAAsC,CAAC,CAAA;oBAChE,cAAc,GAAG,IAAI,CAAA;oBACrB,MAAK;gBACP,CAAC;gBACD,KAAK,IAAI,CAAC,CAAC,SAAS,CAAA;gBACpB,IAAI,IAAI,CAAC,CAAC,SAAS,GAAG,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,MAAM,CAAA;gBAC1C,aAAa,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;gBACxC,IAAI,CAAC,CAAC,YAAY,EAAE,CAAC;oBACnB,KAAK,CAAC,KAAK,CAAC,uBAAuB,CAAC,CAAC,YAAY,EAAE,CAAC,CAAA;oBACpD,MAAK;gBACP,CAAC;gBACD,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACjB,KAAK,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,sBAAsB,CAAC,CAAA;oBAC/D,MAAK;gBACP,CAAC;gBACD,IAAI,CAAC,CAAC,SAAS,IAAI,CAAC,IAAI,OAAO,CAAC,OAAO;oBAAE,MAAK;YAChD,CAAC;YACD,IAAI,CAAC,cAAc;gBAAE,KAAK,CAAC,OAAO,CAAC,GAAG,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,aAAa,CAAC,CAAA;YAC7E,aAAa,EAAE,CAAA;QACjB,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,UAAU,CAAC,OAAO;gBAAE,KAAK,CAAC,KAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAA;QACxD,CAAC;gBAAS,CAAC;YACT,IAAI,UAAU,CAAC,OAAO;gBAAE,aAAa,CAAC,IAAI,CAAC,CAAA;YAC3C,WAAW,EAAE,CAAA;QACf,CAAC;IACH,CAAC,EAAE,CAAC,IAAI,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,CAAC,CAAC,CAAA;IAErD,MAAM,QAAQ,GAAG,IAAI,EAAE,MAAM,CAAC,qBAAqB,IAAI,CAAC,CAAA;IAExD,MAAM,cAAc,GAAG,kBAAkB,CAAC,CAAC,CAAC,CAC1C,UAAU,CAAC,CAAC,CAAC,CACX,eAAK,SAAS,EAAC,yBAAyB,aACtC,gBACE,SAAS,EAAC,uDAAuD,EACjE,IAAI,EAAC,QAAQ,eACH,QAAQ,aAElB,KAAC,OAAO,IAAC,SAAS,EAAC,kCAAkC,wBAAe,uBACvD,UAAU,CAAC,IAAI,UAAM,UAAU,CAAC,KAAK,IAC7C,EACP,kBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAE,YAAY,EACvB,OAAO,EAAE,GAAG,EAAE;oBACZ,OAAO,CAAC,OAAO,GAAG,IAAI,CAAA;gBACxB,CAAC,aAED,KAAC,MAAM,IAAC,SAAS,EAAC,SAAS,wBAAe,YAEnC,IACL,CACP,CAAC,CAAC,CAAC,CACF,kBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAE,UAAU,EACrB,OAAO,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,IAAI,CAAC,EACvC,QAAQ,EAAE,QAAQ,KAAK,CAAC,IAAI,OAAO,IAAI,IAAI,aAE3C,KAAC,QAAQ,IAAC,SAAS,EAAC,SAAS,wBAAe,0BACvB,QAAQ,kBACtB,CACV,CACF,CAAC,CAAC,CAAC,IAAI,CAAA;IAER,OAAO,CACL,eAAK,SAAS,EAAC,WAAW,aACvB,CAAC,kBAAkB,CAAC,CAAC,CAAC,CACrB,KAAC,kBAAkB,IAAC,OAAO,EAAC,iBAAiB,EAAC,UAAU,EAAE,QAAQ,EAAE,UAAU,GAAI,CACnF,CAAC,CAAC,CAAC,IAAI,EAER,KAAC,WAAW,IACV,KAAK,EAAC,WAAW,EACjB,WAAW,EAAC,wFAAwF,EACpG,MAAM,EAAE,cAAc,YAErB,OAAO,CAAC,CAAC,CAAC,CACT,KAAC,UAAU,KAAG,CACf,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CACV,KAAC,aAAa,IAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,GAAI,CACpD,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,CAC3B,KAAC,aAAa,IACZ,IAAI,EAAE,KAAC,KAAK,IAAC,IAAI,EAAE,EAAE,GAAI,EACzB,KAAK,EAAC,kBAAkB,EACxB,WAAW,EAAC,yGAAyG,GACrH,CACH,CAAC,CAAC,CAAC,CACF,eAAK,SAAS,EAAC,WAAW,aACvB,YAAY,CAAC,MAAM,GAAG,CAAC,IAAI,CAC1B,eACE,SAAS,EAAC,iGAAiG,EAC3G,IAAI,EAAC,QAAQ,eACH,QAAQ,aAElB,gBAAM,SAAS,EAAC,iBAAiB,aAC9B,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,UAAU,CAAC,4CACnC,EACP,kBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,6KAA6K,EACvL,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,YAAY,CAAC,EAC1C,QAAQ,EAAE,IAAI,kCAEI,YAAY,CAAC,MAAM,SAC9B,EACT,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,gLAAgL,EAC1L,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,wBAG3B,IACL,CACP,EAEA,QAAQ,CAAC,IAAI,GAAG,CAAC,IAAI,CACpB,eACE,SAAS,EAAC,kGAAkG,EAC5G,IAAI,EAAC,QAAQ,gBACF,cAAc,aAEzB,gBAAM,SAAS,EAAC,6BAA6B,aAAE,QAAQ,CAAC,IAAI,iBAAiB,EAC7E,eAAM,SAAS,EAAC,yBAAyB,wBAAe,EACxD,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,gLAAgL,EAC1L,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,EACpC,QAAQ,EAAE,IAAI,IAAI,iBAAiB,KAAK,IAAI,iCAGrC,EACT,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,gLAAgL,EAC1L,OAAO,EAAE,GAAG,EAAE,CAAC,KAAK,qBAAqB,EAAE,EAC3C,QAAQ,EAAE,IAAI,iCAGP,EACT,iBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,gLAAgL,EAC1L,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,IAAI,GAAG,EAAE,CAAC,sBAG9B,EACR,iBAAiB,IAAI,CACpB,aAAG,SAAS,EAAC,0CAA0C,EAAC,IAAI,EAAC,QAAQ,kCACjD,iBAAiB,4DAClC,UAAU,CAAC,CAAC,CAAC,CACZ,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAC3C,SAAS,EAAC,kIAAkI,wCAGrI,CACV,CAAC,CAAC,CAAC,IAAI,IACN,CACL,IACG,CACP,EAED,cAAK,SAAS,EAAC,iDAAiD,YAC9D,iBAAO,SAAS,EAAC,gBAAgB,gBAAY,cAAc,aACzD,0BACE,cAAI,SAAS,EAAC,4EAA4E,aACxF,aAAI,KAAK,EAAC,KAAK,EAAC,SAAS,EAAC,kBAAkB,YAC1C,gBACE,IAAI,EAAC,UAAU,EACf,OAAO,EAAE,WAAW,EACpB,QAAQ,EAAE,eAAe,EACzB,QAAQ,EAAE,IAAI,CAAC,MAAM,KAAK,CAAC,gBAChB,sBAAsB,EACjC,SAAS,EAAC,oEAAoE,GAC9E,GACC,EACL,aAAI,KAAK,EAAC,KAAK,EAAC,SAAS,EAAC,yBAAyB,yBAE9C,EACL,aAAI,KAAK,EAAC,KAAK,EAAC,SAAS,EAAC,yBAAyB,uBAE9C,EACL,aAAI,KAAK,EAAC,KAAK,EAAC,SAAS,EAAC,yBAAyB,wBAE9C,EACL,aAAI,KAAK,EAAC,KAAK,EAAC,SAAS,EAAC,yBAAyB,oBAE9C,EACL,aAAI,KAAK,EAAC,KAAK,EAAC,SAAS,EAAC,aAAa,YACrC,eAAM,SAAS,EAAC,SAAS,wBAAe,GACrC,IACF,GACC,EACR,gBAAO,SAAS,EAAC,wBAAwB,YACtC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;4CACnB,MAAM,KAAK,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;4CAC1B,OAAO,CACL,KAAC,WAAW,IAEV,QAAQ,EAAE,CAAC,EACX,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAC5B,QAAQ,EAAE,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAC5B,OAAO,EACL,KAAK;oDACH,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC,MAAM,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,GAAG,CAAC,EAAE;oDAClE,CAAC,CAAC,CAAC,CAAC,aAAa,EAErB,cAAc,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,EACxC,gBAAgB,EAAE,GAAG,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,EAC5C,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,EAC/C,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,gBAAgB,CAAC,CAAC,CAAC,EACzC,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,kBAAkB,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU,IAdhD,CAAC,CAAC,EAAE,CAeT,CACH,CAAA;wCACH,CAAC,CAAC,GACI,IACF,GACJ,IACF,CACP,GACW,EAEd,KAAC,aAAa,IACZ,IAAI,EAAE,YAAY,EAClB,OAAO,EAAE,GAAG,EAAE,CAAC,eAAe,CAAC,KAAK,CAAC,EACrC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,QAAQ,CAAC,iBAAiB,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,EACjE,KAAK,EAAE,SAAS,MAAM,CAAC,iBAAiB,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,EAC/D,WAAW,EAAC,yJAAyJ,EACrK,YAAY,EAAE,SAAS,MAAM,CAAC,iBAAiB,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,GACrE,EACF,KAAC,aAAa,IACZ,IAAI,EAAE,eAAe,EACrB,OAAO,EAAE,GAAG,EAAE,CAAC,kBAAkB,CAAC,KAAK,CAAC,EACxC,SAAS,EAAE,GAAG,EAAE,CAAC,KAAK,cAAc,EAAE,EACtC,KAAK,EAAE,0BAA0B,MAAM,CAAC,QAAQ,EAAE,gBAAgB,CAAC,GAAG,EACtE,WAAW,EAAE,qBAAqB,mBAAmB,oEAAoE,EACzH,YAAY,EAAC,UAAU,GACvB,IACE,CACP,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAAC,EACnB,QAAQ,EAAE,CAAC,EACX,QAAQ,EACR,QAAQ,EACR,OAAO,EACP,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,SAAS,EACT,IAAI,EACJ,QAAQ,GAYT;IACC,OAAO,CACL,8BACE,cAAI,SAAS,EAAE,GAAG,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,EAAE,uCAAuC,aACrF,aAAI,SAAS,EAAC,qBAAqB,YAChC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAChB,gBACE,IAAI,EAAC,UAAU,EACf,OAAO,EAAE,QAAQ,EACjB,QAAQ,EAAE,cAAc,gBACZ,mBAAmB,CAAC,CAAC,KAAK,EAAE,EACxC,SAAS,EAAC,oEAAoE,GAC9E,CACH,GACE,EACL,cAAI,SAAS,EAAC,qBAAqB,aACjC,eAAK,SAAS,EAAC,mCAAmC,aAChD,eAAM,SAAS,EAAC,6BAA6B,YAAE,CAAC,CAAC,KAAK,GAAQ,EAC7D,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CACZ,KAAC,cAAc,IACb,KAAK,EAAE,CAAC,CAAC,QAAQ,EACjB,IAAI,EACF,CAAC,CAAC,QAAQ,KAAK,UAAU;4CACvB,CAAC,CAAC,UAAU;4CACZ,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS;gDACxB,CAAC,CAAC,MAAM;gDACR,CAAC,CAAC,SAAS,GAEjB,CACH,CAAC,CAAC,CAAC,IAAI,EACP,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAC,cAAc,IAAC,KAAK,EAAC,yBAAoB,EAAC,IAAI,EAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,IACvE,EACL,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAChC,aAAG,SAAS,EAAC,sCAAsC,aAChD,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,EACpB,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAC3C,CAAC,CAAC,MAAM,CAAC,GAAG,IAAI,EAAE,IACjB,CACL,CAAC,CAAC,CAAC,IAAI,IACL,EACL,cAAI,SAAS,EAAC,qBAAqB,aACjC,YAAG,SAAS,EAAC,mCAAmC,YAAE,OAAO,GAAK,EAC9D,kBACE,IAAI,EAAC,QAAQ,EACb,SAAS,EAAC,2KAA2K,EACrL,OAAO,EAAE,gBAAgB,mBACV,QAAQ,gBACX,GAAG,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,gBAAgB,CAAC,CAAC,KAAK,EAAE,aAEjE,QAAQ,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,cAAc,EAC3C,KAAC,WAAW,IACV,SAAS,EAAE,4CAA4C,QAAQ,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,wBAErF,IACK,IACN,EACL,aAAI,SAAS,EAAC,qBAAqB,YACjC,eAAK,SAAS,EAAC,mCAAmC,aAChD,KAAC,WAAW,IAAC,MAAM,EAAE,CAAC,CAAC,MAAM,GAAI,EAChC,OAAO,CAAC,CAAC,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,CAClC,KAAC,cAAc,IACb,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,GAAG,GAAG,CAAC,GAAG,EAC3C,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC,UAAU,CAAC,GAClC,CACH,CAAC,CAAC,CAAC,IAAI,EACP,OAAO,CAAC,CAAC,cAAc,KAAK,QAAQ,CAAC,CAAC,CAAC,CACtC,KAAC,eAAe,IAAC,KAAK,EAAE,CAAC,CAAC,cAAc,GAAI,CAC7C,CAAC,CAAC,CAAC,IAAI,IACJ,GACH,EACL,aAAI,SAAS,EAAC,qEAAqE,YAChF,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,GACxB,EACL,aAAI,SAAS,EAAC,qBAAqB,YACjC,eAAK,SAAS,EAAC,qCAAqC,aACjD,CAAC,CAAC,CAAC,KAAK,IAAI,QAAQ,CAAC,CAAC,CAAC,CACtB,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,SAAS,EAClB,QAAQ,EAAE,IAAI,EACd,SAAS,EAAC,2IAA2I,gBACzI,WAAW,CAAC,CAAC,KAAK,EAAE,YAEhC,KAAC,KAAK,IAAC,SAAS,EAAC,SAAS,wBAAe,GAClC,CACV,CAAC,CAAC,CAAC,IAAI,EACR,iBACE,IAAI,EAAC,QAAQ,EACb,OAAO,EAAE,SAAS,EAClB,QAAQ,EAAE,IAAI,EACd,SAAS,EAAC,oJAAoJ,gBAClJ,WAAW,CAAC,CAAC,KAAK,EAAE,YAEhC,KAAC,CAAC,IAAC,SAAS,EAAC,SAAS,wBAAe,GAC9B,IACL,GACH,IACF,EACJ,QAAQ,CAAC,CAAC,CAAC,CACV,uBACE,aAAI,OAAO,EAAE,CAAC,EAAE,SAAS,EAAC,uBAAuB,YAC/C,eAAK,SAAS,EAAC,WAAW,aACxB,YAAG,SAAS,EAAC,yBAAyB,YAAE,CAAC,CAAC,aAAa,GAAK,EAC5D,KAAC,aAAa,IAAC,OAAO,EAAE,CAAC,CAAC,OAAO,GAAI,IACjC,GACH,GACF,CACN,CAAC,CAAC,CAAC,IAAI,IACP,CACJ,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Settings → SEO "Weekly SEO digest" card: opt-in toggle, explicit recipient
|
|
3
|
+
* list, last-sent status, and a rate-limited test send. The digest itself is
|
|
4
|
+
* sent by the Monday /cron/seo-scan tick after the persisted audit.
|
|
5
|
+
*/
|
|
6
|
+
export declare function SeoDigestCard({ canEdit }: {
|
|
7
|
+
canEdit: boolean;
|
|
8
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
//# sourceMappingURL=SeoDigestCard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SeoDigestCard.d.ts","sourceRoot":"","sources":["../../../src/views/settings/SeoDigestCard.tsx"],"names":[],"mappings":"AAgBA;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAAE,OAAO,EAAE,EAAE;IAAE,OAAO,EAAE,OAAO,CAAA;CAAE,2CA8I9D"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useCallback, useEffect, useId, useState } from 'react';
|
|
4
|
+
import { Loader2, Send } from 'lucide-react';
|
|
5
|
+
import { toast } from 'sonner';
|
|
6
|
+
import { fetchDigestSettings, sendTestDigest, updateDigestSettings, } from '../../lib/seo-service.js';
|
|
7
|
+
import { SettingsCard, SettingsToggleRow } from './components.js';
|
|
8
|
+
const INPUT_CLASS = 'w-full rounded-md border border-border bg-input-background px-3 py-2 text-base text-foreground focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-60';
|
|
9
|
+
/**
|
|
10
|
+
* Settings → SEO "Weekly SEO digest" card: opt-in toggle, explicit recipient
|
|
11
|
+
* list, last-sent status, and a rate-limited test send. The digest itself is
|
|
12
|
+
* sent by the Monday /cron/seo-scan tick after the persisted audit.
|
|
13
|
+
*/
|
|
14
|
+
export function SeoDigestCard({ canEdit }) {
|
|
15
|
+
const recipientsId = useId();
|
|
16
|
+
const [settings, setSettings] = useState(null);
|
|
17
|
+
const [loading, setLoading] = useState(true);
|
|
18
|
+
const [recipientsText, setRecipientsText] = useState('');
|
|
19
|
+
const [saving, setSaving] = useState(false);
|
|
20
|
+
const [sendingTest, setSendingTest] = useState(false);
|
|
21
|
+
const load = useCallback(async () => {
|
|
22
|
+
setLoading(true);
|
|
23
|
+
const s = await fetchDigestSettings();
|
|
24
|
+
if (s) {
|
|
25
|
+
setSettings(s);
|
|
26
|
+
setRecipientsText(s.recipients.join(', '));
|
|
27
|
+
}
|
|
28
|
+
setLoading(false);
|
|
29
|
+
}, []);
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
void load();
|
|
32
|
+
}, [load]);
|
|
33
|
+
async function handleToggle(enabled) {
|
|
34
|
+
const res = await updateDigestSettings({ enabled });
|
|
35
|
+
if (!res.ok) {
|
|
36
|
+
toast.error(res.error ?? 'Failed to update digest settings');
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
toast.success(enabled ? 'Weekly digest enabled' : 'Weekly digest disabled');
|
|
40
|
+
await load();
|
|
41
|
+
}
|
|
42
|
+
async function handleSaveRecipients() {
|
|
43
|
+
setSaving(true);
|
|
44
|
+
const recipients = recipientsText
|
|
45
|
+
.split(',')
|
|
46
|
+
.map((r) => r.trim())
|
|
47
|
+
.filter((r) => r.length > 0);
|
|
48
|
+
const res = await updateDigestSettings({ recipients });
|
|
49
|
+
setSaving(false);
|
|
50
|
+
if (!res.ok) {
|
|
51
|
+
toast.error(res.error ?? 'Failed to save recipients');
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
toast.success('Digest recipients saved');
|
|
55
|
+
await load();
|
|
56
|
+
}
|
|
57
|
+
async function handleTestSend() {
|
|
58
|
+
setSendingTest(true);
|
|
59
|
+
const res = await sendTestDigest();
|
|
60
|
+
setSendingTest(false);
|
|
61
|
+
if (!res.ok) {
|
|
62
|
+
toast.error(res.error ?? 'Test digest failed');
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
toast.success(`Test digest sent to ${res.to ?? 'your email'}`);
|
|
66
|
+
}
|
|
67
|
+
if (loading) {
|
|
68
|
+
return (_jsx(SettingsCard, { title: "Weekly SEO digest", children: _jsxs("div", { className: "text-muted-foreground flex items-center gap-2 text-sm", children: [_jsx(Loader2, { size: 16, className: "motion-safe:animate-spin", "aria-hidden": "true" }), "Loading\u2026"] }) }));
|
|
69
|
+
}
|
|
70
|
+
if (!settings) {
|
|
71
|
+
return (_jsx(SettingsCard, { title: "Weekly SEO digest", children: _jsx("p", { className: "text-destructive text-sm", children: "Failed to load digest settings." }) }));
|
|
72
|
+
}
|
|
73
|
+
return (_jsx(SettingsCard, { title: "Weekly SEO digest", description: "A Monday email with the site score, search performance, quick wins, new issues, and pending proposals. Sent by the weekly audit cron.", children: _jsxs("div", { className: "flex flex-col gap-4", children: [_jsx(SettingsToggleRow, { label: "Send weekly digest", description: "Requires at least one recipient below.", checked: settings.enabled, onChange: handleToggle, disabled: !canEdit }), _jsxs("div", { children: [_jsx("label", { htmlFor: recipientsId, className: "text-foreground mb-1 flex items-center gap-2 text-sm font-medium", children: "Recipients" }), _jsx("input", { id: recipientsId, type: "text", className: INPUT_CLASS, placeholder: "owner@example.com, seo@example.com", value: recipientsText, onChange: (e) => setRecipientsText(e.target.value), disabled: !canEdit }), _jsx("p", { className: "text-muted-foreground mt-1 text-sm", children: "Comma-separated, up to 10 addresses." })] }), _jsxs("div", { className: "flex items-center gap-3", children: [_jsx("button", { type: "button", className: "bg-primary text-primary-foreground rounded-md px-4 py-2 text-base font-medium disabled:cursor-not-allowed disabled:opacity-60", onClick: () => void handleSaveRecipients(), disabled: !canEdit || saving, children: saving ? 'Saving…' : 'Save recipients' }), _jsxs("button", { type: "button", className: "border-border text-foreground inline-flex items-center gap-2 rounded-md border px-4 py-2 text-base font-medium disabled:cursor-not-allowed disabled:opacity-60", onClick: () => void handleTestSend(), disabled: !canEdit || sendingTest, children: [sendingTest ? (_jsx(Loader2, { size: 16, className: "motion-safe:animate-spin", "aria-hidden": "true" })) : (_jsx(Send, { size: 16, "aria-hidden": "true" })), "Send test digest"] })] }), _jsxs("p", { className: "text-muted-foreground text-sm", children: [settings.lastSentAt
|
|
74
|
+
? `Last sent ${new Date(settings.lastSentAt).toLocaleString()}`
|
|
75
|
+
: 'Never sent', settings.lastError ? (_jsxs("span", { className: "text-destructive", children: [" \u00B7 ", settings.lastError] })) : null] })] }) }));
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=SeoDigestCard.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SeoDigestCard.js","sourceRoot":"","sources":["../../../src/views/settings/SeoDigestCard.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SeoSettingsTab.d.ts","sourceRoot":"","sources":["../../../src/views/settings/SeoSettingsTab.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"SeoSettingsTab.d.ts","sourceRoot":"","sources":["../../../src/views/settings/SeoSettingsTab.tsx"],"names":[],"mappings":"AAyEA,MAAM,WAAW,mBAAmB;IAClC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACnC,2DAA2D;IAC3D,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED,wBAAgB,cAAc,CAAC,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,mBAAmB,2CA0HvE"}
|