@agent-native/core 0.185.0-nightly-20260923150956 → 0.185.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/corpus/templates/analytics/CHANGELOG.md +6 -0
- package/corpus/templates/brain/CHANGELOG.md +6 -0
- package/corpus/templates/calendar/CHANGELOG.md +11 -0
- package/corpus/templates/clips/CHANGELOG.md +37 -0
- package/corpus/templates/content/CHANGELOG.md +6 -0
- package/corpus/templates/design/CHANGELOG.md +9 -0
- package/corpus/templates/design/actions/get-design-system-index-status.ts +2 -5
- package/corpus/templates/design/actions/get-design-system.ts +6 -3
- package/corpus/templates/design/actions/list-design-systems.ts +53 -1
- package/corpus/templates/design/app/components/editor/design-start-pickers.tsx +10 -0
- package/corpus/templates/design/app/i18n-data.ts +10 -0
- package/corpus/templates/design/app/lib/design-system-data.ts +13 -10
- package/corpus/templates/design/app/pages/DesignSystems.tsx +11 -8
- package/corpus/templates/design/app/pages/Templates.tsx +6 -1
- package/corpus/templates/design/changelog/2026-09-22-fixed-the-design-system-picker-showing-a-still-indexing-buil.md +6 -0
- package/corpus/templates/design/server/lib/builder-design-system-proxy.ts +11 -30
- package/corpus/templates/mail/CHANGELOG.md +5 -0
- package/corpus/templates/slides/CHANGELOG.md +13 -0
- package/corpus/templates/slides/actions/apply-design-system.ts +2 -22
- package/corpus/templates/slides/actions/create-deck.ts +4 -54
- package/corpus/templates/slides/actions/get-design-system.ts +40 -3
- package/corpus/templates/slides/actions/list-design-systems.ts +26 -11
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +16 -23
- package/corpus/templates/slides/app/components/editor/NewDeckReferenceStep.tsx +14 -51
- package/corpus/templates/slides/app/hooks/use-design-systems.ts +1 -191
- package/corpus/templates/slides/app/i18n/en-US.ts +0 -4
- package/corpus/templates/slides/app/lib/design-system-selection.ts +4 -19
- package/corpus/templates/slides/app/pages/Index.tsx +3 -16
- package/corpus/templates/slides/shared/design-system-validation.ts +16 -18
- package/dist/automation/index.d.ts +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/secrets/routes.d.ts +3 -3
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/builder-design-systems.d.ts +23 -1
- package/dist/server/builder-design-systems.js +58 -17
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/docs/content/toolkit-settings.mdx +32 -0
- package/package.json +4 -4
- package/corpus/templates/slides/actions/refresh-design-system-indexing-status.ts +0 -120
|
@@ -5,14 +5,11 @@ import { z } from "zod";
|
|
|
5
5
|
|
|
6
6
|
import { getDb, schema } from "../server/db/index.js";
|
|
7
7
|
import { notifyClients } from "../server/handlers/decks.js";
|
|
8
|
-
import { parseDesignSystemIndexingStatus } from "../shared/design-system-validation.js";
|
|
9
8
|
|
|
10
9
|
export default defineAction({
|
|
11
10
|
description:
|
|
12
11
|
"Link a design system to a deck. The deck will use this design system's " +
|
|
13
|
-
"colors, typography, and styling. Requires editor access on the deck.
|
|
14
|
-
"The design system must have finished Builder indexing (list-design-systems " +
|
|
15
|
-
"reports indexingStatus 'ready'); a still-indexing or unavailable system is rejected.",
|
|
12
|
+
"colors, typography, and styling. Requires editor access on the deck.",
|
|
16
13
|
schema: z.object({
|
|
17
14
|
deckId: z.string().describe("Deck ID to apply the design system to"),
|
|
18
15
|
designSystemId: z.string().describe("Design system ID to link to the deck"),
|
|
@@ -20,24 +17,7 @@ export default defineAction({
|
|
|
20
17
|
run: async ({ deckId, designSystemId }) => {
|
|
21
18
|
// Verify access to both the deck and the design system
|
|
22
19
|
await assertAccess("deck", deckId, "editor");
|
|
23
|
-
|
|
24
|
-
"design-system",
|
|
25
|
-
designSystemId,
|
|
26
|
-
"viewer",
|
|
27
|
-
);
|
|
28
|
-
const indexingStatus = parseDesignSystemIndexingStatus(
|
|
29
|
-
designSystemAccess.resource.data,
|
|
30
|
-
);
|
|
31
|
-
if (indexingStatus !== "ready") {
|
|
32
|
-
throw Object.assign(
|
|
33
|
-
new Error(
|
|
34
|
-
indexingStatus === "indexing"
|
|
35
|
-
? `Design system ${designSystemId} is still indexing and has no usable tokens/components yet. Wait for indexing to finish, or use a different design system.`
|
|
36
|
-
: `Design system ${designSystemId} is unavailable (indexing failed or its data could not be read). Choose a different design system.`,
|
|
37
|
-
),
|
|
38
|
-
{ statusCode: 409 },
|
|
39
|
-
);
|
|
40
|
-
}
|
|
20
|
+
await assertAccess("design-system", designSystemId, "viewer");
|
|
41
21
|
|
|
42
22
|
const db = getDb();
|
|
43
23
|
const now = new Date().toISOString();
|
|
@@ -30,7 +30,6 @@ import {
|
|
|
30
30
|
assertHumanReadableDeckTitle,
|
|
31
31
|
repairGeneratedDeckTitle,
|
|
32
32
|
} from "../shared/deck-title.js";
|
|
33
|
-
import { parseDesignSystemIndexingStatus } from "../shared/design-system-validation.js";
|
|
34
33
|
import {
|
|
35
34
|
ensureUniqueSlideIds,
|
|
36
35
|
rebindCreativeContextSlideLabels,
|
|
@@ -117,25 +116,6 @@ function deckNavigationCommand(deckId: string): Record<string, string> {
|
|
|
117
116
|
};
|
|
118
117
|
}
|
|
119
118
|
|
|
120
|
-
/**
|
|
121
|
-
* `list-design-systems` tells agents not to pass a non-'ready' id here, but an
|
|
122
|
-
* agent can still race a status change or ignore that guidance — this is the
|
|
123
|
-
* boundary that actually owns linking a design system, so it re-checks rather
|
|
124
|
-
* than trusting the caller.
|
|
125
|
-
*/
|
|
126
|
-
function assertDesignSystemReady(designSystemId: string, data: string): void {
|
|
127
|
-
const status = parseDesignSystemIndexingStatus(data);
|
|
128
|
-
if (status === "ready") return;
|
|
129
|
-
throw Object.assign(
|
|
130
|
-
new Error(
|
|
131
|
-
status === "indexing"
|
|
132
|
-
? `Design system ${designSystemId} is still indexing and has no usable tokens/components yet. Wait for indexing to finish, or use a different design system.`
|
|
133
|
-
: `Design system ${designSystemId} is unavailable (indexing failed or its data could not be read). Choose a different design system.`,
|
|
134
|
-
),
|
|
135
|
-
{ statusCode: 409 },
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
119
|
export default defineAction({
|
|
140
120
|
title: "Create Slides deck",
|
|
141
121
|
description:
|
|
@@ -310,15 +290,7 @@ export default defineAction({
|
|
|
310
290
|
|
|
311
291
|
if (deckId) {
|
|
312
292
|
if (designSystemId) {
|
|
313
|
-
|
|
314
|
-
"design-system",
|
|
315
|
-
designSystemId,
|
|
316
|
-
"viewer",
|
|
317
|
-
);
|
|
318
|
-
assertDesignSystemReady(
|
|
319
|
-
designSystemId,
|
|
320
|
-
designSystemAccess.resource.data,
|
|
321
|
-
);
|
|
293
|
+
await assertAccess("design-system", designSystemId, "viewer");
|
|
322
294
|
}
|
|
323
295
|
// Update existing deck — requires editor access.
|
|
324
296
|
await assertAccess("deck", deckId, "editor");
|
|
@@ -426,32 +398,10 @@ export default defineAction({
|
|
|
426
398
|
|
|
427
399
|
let resolvedDesignSystemId = designSystemId;
|
|
428
400
|
if (resolvedDesignSystemId) {
|
|
429
|
-
|
|
430
|
-
"design-system",
|
|
431
|
-
resolvedDesignSystemId,
|
|
432
|
-
"viewer",
|
|
433
|
-
);
|
|
434
|
-
assertDesignSystemReady(
|
|
435
|
-
resolvedDesignSystemId,
|
|
436
|
-
designSystemAccess.resource.data,
|
|
437
|
-
);
|
|
401
|
+
await assertAccess("design-system", resolvedDesignSystemId, "viewer");
|
|
438
402
|
} else {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
// An implicit default is a convenience, not an explicit request —
|
|
442
|
-
// fall back to no design system instead of failing deck creation
|
|
443
|
-
// outright when the caller's default happens to still be indexing.
|
|
444
|
-
const [defaultRow] = await db
|
|
445
|
-
.select({ data: schema.designSystems.data })
|
|
446
|
-
.from(schema.designSystems)
|
|
447
|
-
.where(eq(schema.designSystems.id, candidateDefaultId))
|
|
448
|
-
.limit(1);
|
|
449
|
-
resolvedDesignSystemId =
|
|
450
|
-
defaultRow &&
|
|
451
|
-
parseDesignSystemIndexingStatus(defaultRow.data) === "ready"
|
|
452
|
-
? candidateDefaultId
|
|
453
|
-
: undefined;
|
|
454
|
-
}
|
|
403
|
+
resolvedDesignSystemId =
|
|
404
|
+
(await resolveDefaultDesignSystemId(ownerEmail)) ?? undefined;
|
|
455
405
|
}
|
|
456
406
|
|
|
457
407
|
const id = `deck-${Date.now()}-${Math.random().toString(36).slice(2, 7)}`;
|
|
@@ -4,9 +4,10 @@ import {
|
|
|
4
4
|
parseBuilderDesignSystemProxyReference,
|
|
5
5
|
} from "@agent-native/core/server";
|
|
6
6
|
import { resolveAccess } from "@agent-native/core/sharing";
|
|
7
|
+
import { and, eq } from "drizzle-orm";
|
|
7
8
|
import { z } from "zod";
|
|
8
9
|
|
|
9
|
-
import "../server/db/index.js";
|
|
10
|
+
import { getDb, schema } from "../server/db/index.js";
|
|
10
11
|
|
|
11
12
|
const MAX_AGENT_CONTEXT_CHARS = 14_000;
|
|
12
13
|
const MAX_JSON_CONTEXT_CHARS = 2_500;
|
|
@@ -32,7 +33,8 @@ interface BuilderGenerationContext {
|
|
|
32
33
|
tokenValues?: Record<string, string>;
|
|
33
34
|
}>;
|
|
34
35
|
tokenValues: Record<string, string>;
|
|
35
|
-
|
|
36
|
+
/** null when Builder could not be read at all; 0 means still indexing. */
|
|
37
|
+
docCount: number | null;
|
|
36
38
|
warning?: string;
|
|
37
39
|
}
|
|
38
40
|
|
|
@@ -41,6 +43,37 @@ function truncate(value: string, maxChars: number): string {
|
|
|
41
43
|
return `${value.slice(0, maxChars).trimEnd()}\n[truncated]`;
|
|
42
44
|
}
|
|
43
45
|
|
|
46
|
+
// list-design-systems only ever reads the docCount baked into row.data at
|
|
47
|
+
// proxy creation time (always absent) - this is the one place that hydrates
|
|
48
|
+
// a live count from Builder, so it is the one place that can refresh the
|
|
49
|
+
// cache. Compare-and-set against the exact data snapshot this request read
|
|
50
|
+
// avoids clobbering a concurrent sync/update; a lost race just leaves the
|
|
51
|
+
// next call to persist it. Never bumps updatedAt, so a background count
|
|
52
|
+
// refresh doesn't reorder the list.
|
|
53
|
+
async function persistBuilderDocCount(
|
|
54
|
+
row: { id: string; data: string | null },
|
|
55
|
+
docCount: number,
|
|
56
|
+
): Promise<void> {
|
|
57
|
+
if (!row.data) return;
|
|
58
|
+
let parsed: Record<string, unknown>;
|
|
59
|
+
try {
|
|
60
|
+
parsed = JSON.parse(row.data);
|
|
61
|
+
} catch {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (parsed.docCount === docCount) return;
|
|
65
|
+
const db = getDb();
|
|
66
|
+
await db
|
|
67
|
+
.update(schema.designSystems)
|
|
68
|
+
.set({ data: JSON.stringify({ ...parsed, docCount }) })
|
|
69
|
+
.where(
|
|
70
|
+
and(
|
|
71
|
+
eq(schema.designSystems.id, row.id),
|
|
72
|
+
eq(schema.designSystems.data, row.data),
|
|
73
|
+
),
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
44
77
|
function parseJson(value: string | null | undefined): unknown {
|
|
45
78
|
if (!value) return null;
|
|
46
79
|
try {
|
|
@@ -282,7 +315,7 @@ export default defineAction({
|
|
|
282
315
|
...builderReference,
|
|
283
316
|
docs: [],
|
|
284
317
|
tokenValues: {},
|
|
285
|
-
docCount:
|
|
318
|
+
docCount: null,
|
|
286
319
|
warning:
|
|
287
320
|
error instanceof Error
|
|
288
321
|
? error.message
|
|
@@ -291,6 +324,10 @@ export default defineAction({
|
|
|
291
324
|
)
|
|
292
325
|
: null;
|
|
293
326
|
|
|
327
|
+
if (builder && typeof builder.docCount === "number") {
|
|
328
|
+
await persistBuilderDocCount(row, builder.docCount);
|
|
329
|
+
}
|
|
330
|
+
|
|
294
331
|
return {
|
|
295
332
|
id: row.id,
|
|
296
333
|
title: row.title,
|
|
@@ -13,7 +13,6 @@ import { z } from "zod";
|
|
|
13
13
|
|
|
14
14
|
import { getDb, schema } from "../server/db/index.js";
|
|
15
15
|
import { resolveDefaultDesignSystemId } from "../server/workspace-defaults.js";
|
|
16
|
-
import { parseDesignSystemIndexingStatus } from "../shared/design-system-validation.js";
|
|
17
16
|
|
|
18
17
|
type EffectiveRole = "owner" | ShareRole;
|
|
19
18
|
|
|
@@ -35,16 +34,32 @@ function strongerRole(current: ShareRole | null, next: ShareRole): ShareRole {
|
|
|
35
34
|
return current;
|
|
36
35
|
}
|
|
37
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Builder-reported indexed document count cached on the row. Undefined means
|
|
39
|
+
* "not measured yet", which is not the same as a system with zero documents.
|
|
40
|
+
*/
|
|
41
|
+
function cachedBuilderDocCount(data: string | null): number | undefined {
|
|
42
|
+
if (!data) return undefined;
|
|
43
|
+
let parsed: unknown;
|
|
44
|
+
try {
|
|
45
|
+
parsed = JSON.parse(data);
|
|
46
|
+
} catch {
|
|
47
|
+
// coercion-ok: unparseable row data leaves the count unknown, and
|
|
48
|
+
// undefined stays distinguishable from a measured zero.
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
if (!parsed || typeof parsed !== "object") return undefined;
|
|
52
|
+
const docCount = (parsed as Record<string, unknown>).docCount;
|
|
53
|
+
return typeof docCount === "number" ? docCount : undefined;
|
|
54
|
+
}
|
|
55
|
+
|
|
38
56
|
export default defineAction({
|
|
39
57
|
description:
|
|
40
58
|
"List all design systems accessible to the current user. Returns title, " +
|
|
41
|
-
"id, isDefault (true only for the caller's effective default)
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
"
|
|
45
|
-
"status if unsure. For a named system, match the exact title and pass " +
|
|
46
|
-
"its id as designSystemId — or pass the title as `designSystem` on " +
|
|
47
|
-
"create-deck — then call get-design-system once before authoring.",
|
|
59
|
+
"id, and isDefault (true only for the caller's effective default). For a " +
|
|
60
|
+
"named system, match the exact title and pass its id as designSystemId " +
|
|
61
|
+
"— or pass the title as `designSystem` on create-deck — then call " +
|
|
62
|
+
"get-design-system once before authoring.",
|
|
48
63
|
schema: z.object({
|
|
49
64
|
compact: z
|
|
50
65
|
.enum(["true", "false"])
|
|
@@ -145,8 +160,8 @@ export default defineAction({
|
|
|
145
160
|
role = "owner";
|
|
146
161
|
}
|
|
147
162
|
const canManage = canManageRole(role);
|
|
148
|
-
const indexingStatus = parseDesignSystemIndexingStatus(row.data);
|
|
149
163
|
|
|
164
|
+
const docCount = cachedBuilderDocCount(row.data);
|
|
150
165
|
if (args.compact === "true") {
|
|
151
166
|
return {
|
|
152
167
|
id: row.id,
|
|
@@ -154,7 +169,7 @@ export default defineAction({
|
|
|
154
169
|
isDefault: row.id === effectiveDefaultId,
|
|
155
170
|
accessRole: role,
|
|
156
171
|
canManage,
|
|
157
|
-
|
|
172
|
+
docCount,
|
|
158
173
|
};
|
|
159
174
|
}
|
|
160
175
|
return {
|
|
@@ -162,13 +177,13 @@ export default defineAction({
|
|
|
162
177
|
title: row.title,
|
|
163
178
|
description: row.description,
|
|
164
179
|
data: row.data,
|
|
180
|
+
docCount,
|
|
165
181
|
isDefault: row.id === effectiveDefaultId,
|
|
166
182
|
visibility: row.visibility,
|
|
167
183
|
accessRole: role,
|
|
168
184
|
canManage,
|
|
169
185
|
createdAt: row.createdAt,
|
|
170
186
|
updatedAt: row.updatedAt,
|
|
171
|
-
indexingStatus,
|
|
172
187
|
};
|
|
173
188
|
});
|
|
174
189
|
|
|
@@ -97,9 +97,9 @@ interface BuilderSourceDetails {
|
|
|
97
97
|
builderUrl?: string;
|
|
98
98
|
builderStatus?: string;
|
|
99
99
|
sourceKind?: BuilderSourceKind;
|
|
100
|
-
docs?: Array<unknown>;
|
|
101
100
|
tokenValues?: Record<string, string>;
|
|
102
|
-
|
|
101
|
+
/** null when Builder could not be read at all; 0 means still indexing. */
|
|
102
|
+
docCount?: number | null;
|
|
103
103
|
warning?: string;
|
|
104
104
|
githubSources?: Array<{
|
|
105
105
|
repoUrl: string;
|
|
@@ -276,10 +276,11 @@ export function DesignSystemSetup({
|
|
|
276
276
|
editingId ? { id: editingId } : undefined,
|
|
277
277
|
{
|
|
278
278
|
enabled: !!editingId && open,
|
|
279
|
+
// Builder's status string lags the real index state; a zero document
|
|
280
|
+
// count is the only reliable "still indexing" signal. A null count
|
|
281
|
+
// means Builder could not be read, so stop rather than spin.
|
|
279
282
|
refetchInterval: (query) =>
|
|
280
|
-
query.state.data?.builder?.
|
|
281
|
-
? 5_000
|
|
282
|
-
: false,
|
|
283
|
+
query.state.data?.builder?.docCount === 0 ? 5_000 : false,
|
|
283
284
|
},
|
|
284
285
|
);
|
|
285
286
|
|
|
@@ -1544,26 +1545,18 @@ function BuilderSourceStatus({
|
|
|
1544
1545
|
syncing?: boolean;
|
|
1545
1546
|
}) {
|
|
1546
1547
|
const t = useT();
|
|
1547
|
-
|
|
1548
|
+
// Builder's status string drifts out of sync with the real index state, so
|
|
1549
|
+
// the reported document count decides: absent means Builder could not be
|
|
1550
|
+
// read at all, zero means indexing, positive means ready.
|
|
1551
|
+
const docCount = builder.docCount;
|
|
1552
|
+
const docs = docCount ?? 0;
|
|
1548
1553
|
const tokens = Object.keys(builder.tokenValues ?? {}).length;
|
|
1549
|
-
const normalizedStatus = builder.builderStatus?.toLowerCase();
|
|
1550
1554
|
const hasIndexedResults = docs > 0 || tokens > 0;
|
|
1551
|
-
const
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
const isIndexing = ["in-progress", "pending", "processing"].includes(
|
|
1557
|
-
normalizedStatus ?? "",
|
|
1558
|
-
);
|
|
1559
|
-
const state =
|
|
1560
|
-
isIndexing && !isIndexed
|
|
1561
|
-
? "indexing"
|
|
1562
|
-
: builder.warning
|
|
1563
|
-
? "unavailable"
|
|
1564
|
-
: isIndexed
|
|
1565
|
-
? "indexed"
|
|
1566
|
-
: "indexing";
|
|
1555
|
+
const state = hasIndexedResults
|
|
1556
|
+
? "indexed"
|
|
1557
|
+
: builder.warning
|
|
1558
|
+
? "unavailable"
|
|
1559
|
+
: "indexing";
|
|
1567
1560
|
const sourceKind = builder.sourceKind;
|
|
1568
1561
|
const SourceIcon =
|
|
1569
1562
|
sourceKind === "figma"
|
|
@@ -7,7 +7,6 @@ import {
|
|
|
7
7
|
IconChevronDown,
|
|
8
8
|
IconFileText,
|
|
9
9
|
IconFileTypePdf,
|
|
10
|
-
IconLoader2,
|
|
11
10
|
IconPresentation,
|
|
12
11
|
IconWorld,
|
|
13
12
|
} from "@tabler/icons-react";
|
|
@@ -39,13 +38,9 @@ import {
|
|
|
39
38
|
} from "@/components/ui/select";
|
|
40
39
|
import type { Deck } from "@/context/DeckContext";
|
|
41
40
|
import { sortDecksByRecency } from "@/lib/deck-sorting";
|
|
42
|
-
import {
|
|
43
|
-
isDesignSystemSelectable,
|
|
44
|
-
resolveSelectableDesignSystemId,
|
|
45
|
-
} from "@/lib/design-system-selection";
|
|
41
|
+
import { resolveSelectableDesignSystemId } from "@/lib/design-system-selection";
|
|
46
42
|
import { cn } from "@/lib/utils";
|
|
47
43
|
|
|
48
|
-
import type { DesignSystemIndexingStatus } from "../../../shared/design-system-validation";
|
|
49
44
|
import { GoogleDriveConnectionCta } from "./GoogleDriveConnectionCta";
|
|
50
45
|
export interface NewDeckReferenceSelection {
|
|
51
46
|
designSystemId?: string | null;
|
|
@@ -82,7 +77,6 @@ interface DesignSystemOption {
|
|
|
82
77
|
id: string;
|
|
83
78
|
title: string;
|
|
84
79
|
isDefault?: boolean;
|
|
85
|
-
indexingStatus?: DesignSystemIndexingStatus;
|
|
86
80
|
}
|
|
87
81
|
|
|
88
82
|
interface NewDeckReferenceStepProps {
|
|
@@ -137,9 +131,7 @@ export function NewDeckReferenceStep({
|
|
|
137
131
|
const t = useT();
|
|
138
132
|
const [selectedDesignSystemId, setSelectedDesignSystemId] = useState<
|
|
139
133
|
string | null
|
|
140
|
-
>(()
|
|
141
|
-
resolveSelectableDesignSystemId(designSystems, defaultDesignSystemId),
|
|
142
|
-
);
|
|
134
|
+
>(resolveSelectableDesignSystemId(designSystems, defaultDesignSystemId));
|
|
143
135
|
const [selectedReferenceDeckId, setSelectedReferenceDeckId] = useState<
|
|
144
136
|
string | null
|
|
145
137
|
>(defaultReferenceDeckId);
|
|
@@ -157,6 +149,9 @@ export function NewDeckReferenceStep({
|
|
|
157
149
|
const [showDesignSystemSetup, setShowDesignSystemSetup] = useState(false);
|
|
158
150
|
const busy = importing || continuing;
|
|
159
151
|
|
|
152
|
+
// True while the picker still reflects an auto-applied default rather than
|
|
153
|
+
// an explicit user choice, so a default that resolves after this step is
|
|
154
|
+
// already open can still land - see the hydration effects below.
|
|
160
155
|
const designSystemAutoRef = useRef(true);
|
|
161
156
|
const referenceDeckAutoRef = useRef(true);
|
|
162
157
|
|
|
@@ -165,14 +160,6 @@ export function NewDeckReferenceStep({
|
|
|
165
160
|
const selectedReferenceDeck = selectedReferenceDeckId
|
|
166
161
|
? deckById.get(selectedReferenceDeckId)
|
|
167
162
|
: undefined;
|
|
168
|
-
const selectedDesignSystem = selectedDesignSystemId
|
|
169
|
-
? designSystems.find((ds) => ds.id === selectedDesignSystemId)
|
|
170
|
-
: undefined;
|
|
171
|
-
// Selecting one from the list below already disables non-ready rows; this
|
|
172
|
-
// also covers a system that starts re-indexing after it was selected.
|
|
173
|
-
const selectedDesignSystemUnavailable = Boolean(
|
|
174
|
-
selectedDesignSystem && !isDesignSystemSelectable(selectedDesignSystem),
|
|
175
|
-
);
|
|
176
163
|
const hasSelection = Boolean(
|
|
177
164
|
selectedDesignSystemId ||
|
|
178
165
|
selectedReferenceDeckId ||
|
|
@@ -183,7 +170,9 @@ export function NewDeckReferenceStep({
|
|
|
183
170
|
if (!open) return;
|
|
184
171
|
designSystemAutoRef.current = true;
|
|
185
172
|
referenceDeckAutoRef.current = true;
|
|
186
|
-
setSelectedDesignSystemId(
|
|
173
|
+
setSelectedDesignSystemId(
|
|
174
|
+
resolveSelectableDesignSystemId(designSystems, defaultDesignSystemId),
|
|
175
|
+
);
|
|
187
176
|
setSelectedReferenceDeckId(defaultReferenceDeckId);
|
|
188
177
|
setReferenceDeckTouched(defaultReferenceDeckId !== null);
|
|
189
178
|
setImportedReference(null);
|
|
@@ -235,7 +224,7 @@ export function NewDeckReferenceStep({
|
|
|
235
224
|
};
|
|
236
225
|
|
|
237
226
|
const handleContinue = async () => {
|
|
238
|
-
if (busy ||
|
|
227
|
+
if (busy || !hasSelection) return;
|
|
239
228
|
const trimmedSource =
|
|
240
229
|
selectedSource && selectedSource.value.trim()
|
|
241
230
|
? { ...selectedSource, value: selectedSource.value.trim() }
|
|
@@ -376,38 +365,13 @@ export function NewDeckReferenceStep({
|
|
|
376
365
|
</SelectTrigger>
|
|
377
366
|
<SelectContent>
|
|
378
367
|
<SelectItem value="none">{t("home.none")}</SelectItem>
|
|
379
|
-
{designSystems.map((designSystem) =>
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
value={designSystem.id}
|
|
385
|
-
disabled={!selectable}
|
|
386
|
-
>
|
|
387
|
-
<span className="flex items-center gap-1.5">
|
|
388
|
-
{designSystem.title}
|
|
389
|
-
{designSystem.indexingStatus === "indexing" && (
|
|
390
|
-
<span className="inline-flex items-center gap-1 text-xs text-muted-foreground">
|
|
391
|
-
<IconLoader2 className="size-3 animate-spin" />
|
|
392
|
-
{t("home.designSystemIndexing")}
|
|
393
|
-
</span>
|
|
394
|
-
)}
|
|
395
|
-
{designSystem.indexingStatus === "unavailable" && (
|
|
396
|
-
<span className="text-xs text-muted-foreground">
|
|
397
|
-
({t("home.designSystemUnavailable")})
|
|
398
|
-
</span>
|
|
399
|
-
)}
|
|
400
|
-
</span>
|
|
401
|
-
</SelectItem>
|
|
402
|
-
);
|
|
403
|
-
})}
|
|
368
|
+
{designSystems.map((designSystem) => (
|
|
369
|
+
<SelectItem key={designSystem.id} value={designSystem.id}>
|
|
370
|
+
{designSystem.title}
|
|
371
|
+
</SelectItem>
|
|
372
|
+
))}
|
|
404
373
|
</SelectContent>
|
|
405
374
|
</Select>
|
|
406
|
-
{selectedDesignSystemUnavailable && (
|
|
407
|
-
<p className="text-xs text-amber-500">
|
|
408
|
-
{t("home.designSystemIndexingNotice")}
|
|
409
|
-
</p>
|
|
410
|
-
)}
|
|
411
375
|
</div>
|
|
412
376
|
|
|
413
377
|
<div className="grid gap-2">
|
|
@@ -644,7 +608,6 @@ export function NewDeckReferenceStep({
|
|
|
644
608
|
aria-busy={busy}
|
|
645
609
|
disabled={
|
|
646
610
|
busy ||
|
|
647
|
-
selectedDesignSystemUnavailable ||
|
|
648
611
|
!hasSelection ||
|
|
649
612
|
Boolean(selectedSource && !selectedSource.value.trim())
|
|
650
613
|
}
|