@agent-native/core 0.128.0 → 0.128.2
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/README.md +1 -1
- package/corpus/core/CHANGELOG.md +27 -0
- package/corpus/core/package.json +3 -1
- package/corpus/core/src/server/builder-design-systems.ts +299 -82
- package/corpus/core/src/server/email-template.ts +33 -0
- package/corpus/core/src/server/index.ts +8 -0
- package/corpus/templates/analytics/_gitignore +2 -0
- package/corpus/templates/assets/_gitignore +2 -0
- package/corpus/templates/calendar/_gitignore +2 -0
- package/corpus/templates/chat/_gitignore +2 -0
- package/corpus/templates/clips/AGENTS.md +6 -1
- package/corpus/templates/clips/_gitignore +2 -0
- package/corpus/templates/clips/actions/complete-transactional-email-summary.ts +56 -0
- package/corpus/templates/clips/actions/import-loom-recording.ts +258 -76
- package/corpus/templates/clips/actions/lib/direct-video.ts +96 -0
- package/corpus/templates/clips/actions/lib/loom-import-job.ts +53 -2
- package/corpus/templates/clips/actions/lib/loom-video.ts +2 -62
- package/corpus/templates/clips/actions/lib/video-download-limits.ts +62 -0
- package/corpus/templates/clips/actions/list-transactional-email-ai-requests.ts +249 -0
- package/corpus/templates/clips/app/components/library/library-grid.tsx +65 -0
- package/corpus/templates/clips/app/components/library/library-layout.tsx +55 -0
- package/corpus/templates/clips/app/components/recorder/pre-record-panel.tsx +28 -126
- package/corpus/templates/clips/app/global.css +23 -0
- package/corpus/templates/clips/app/hooks/use-transactional-email-bridge.ts +98 -0
- package/corpus/templates/clips/app/i18n/en-US.ts +20 -0
- package/corpus/templates/clips/app/routes/_app.tsx +2 -0
- package/corpus/templates/clips/app/routes/import.tsx +396 -0
- package/corpus/templates/clips/app/routes/r.$recordingId.tsx +8 -6
- package/corpus/templates/clips/app/routes/record.tsx +13 -71
- package/corpus/templates/clips/changelog/2026-07-25-two-clip-emails-now-include-a-concise-summary-generated-secu.md +6 -0
- package/corpus/templates/clips/data/clips-transactional-emails/config.json +3 -0
- package/corpus/templates/clips/server/jobs/transactional-emails.ts +1034 -0
- package/corpus/templates/clips/server/lib/transactional-email-store.ts +865 -0
- package/corpus/templates/clips/server/lib/transactional-email-templates.ts +270 -0
- package/corpus/templates/clips/server/plugins/calendar-jobs.ts +2 -0
- package/corpus/templates/clips/server/routes/api/view-event.post.ts +59 -2
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +8 -2
- package/corpus/templates/content/AGENTS.md +8 -0
- package/corpus/templates/content/_gitignore +2 -0
- package/corpus/templates/content/actions/_content-database-personal-view.ts +28 -3
- package/corpus/templates/content/actions/_property-utils.ts +32 -2
- package/corpus/templates/content/actions/configure-document-property.ts +12 -2
- package/corpus/templates/content/actions/delete-document-property.ts +13 -3
- package/corpus/templates/content/actions/duplicate-document-property.ts +13 -3
- package/corpus/templates/content/actions/list-content-spaces.ts +5 -2
- package/corpus/templates/content/actions/list-document-properties.ts +12 -3
- package/corpus/templates/content/actions/move-database-item.ts +74 -55
- package/corpus/templates/content/actions/reorder-document-property.ts +20 -4
- package/corpus/templates/content/actions/set-document-property.ts +10 -1
- package/corpus/templates/content/actions/update-content-database-personal-view.ts +7 -0
- package/corpus/templates/content/app/components/editor/DocumentBlockFields.tsx +31 -21
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +30 -3
- package/corpus/templates/content/app/components/editor/DocumentInfoPanel.tsx +8 -1
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +72 -20
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +79 -10
- package/corpus/templates/content/app/components/editor/database/TimelineView.tsx +8 -1
- package/corpus/templates/content/app/components/editor/database/settings.tsx +6 -0
- package/corpus/templates/content/app/components/editor/database/sidebar.tsx +246 -26
- package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +491 -197
- package/corpus/templates/content/app/components/sidebar/DocumentTreeItem.tsx +3 -3
- package/corpus/templates/content/app/components/sidebar/sidebar-reorder.tsx +409 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +117 -3
- package/corpus/templates/content/app/hooks/use-content-spaces.ts +1 -0
- package/corpus/templates/content/app/hooks/use-document-properties.ts +62 -18
- package/corpus/templates/content/app/hooks/use-documents.ts +13 -5
- package/corpus/templates/content/app/i18n-data.ts +261 -3
- package/corpus/templates/content/app/routes/_app.page.$id.tsx +9 -2
- package/corpus/templates/content/changelog/2026-07-24-database-page-properties-keep-their-context.md +6 -0
- package/corpus/templates/content/changelog/2026-07-26-sidebar-references-can-now-be-personally-reordered.md +6 -0
- package/corpus/templates/content/docs/solutions/2026-07-24-database-property-context-switch-diagnosis.md +249 -0
- package/corpus/templates/content/docs/solutions/content-sidebar-order-shape.md +389 -0
- package/corpus/templates/content/shared/api.ts +28 -0
- package/corpus/templates/design/_gitignore +2 -0
- package/corpus/templates/design/app/i18n-data.ts +10 -0
- package/corpus/templates/design/app/lib/builder-design-system-upload.ts +280 -0
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +90 -54
- package/corpus/templates/design/changelog/2026-07-28-figma-fig-uploads-now-show-indexing-progress-and-an-open-in-.md +6 -0
- package/corpus/templates/design/server/handlers/design-system-decode-job-status.ts +49 -0
- package/corpus/templates/design/server/handlers/design-system-upload-start.ts +87 -0
- package/corpus/templates/design/server/handlers/index-design-system-sources.ts +82 -0
- package/corpus/templates/design/server/routes/api/design-system-decode-job-status.get.ts +1 -0
- package/corpus/templates/design/server/routes/api/design-system-upload-start.post.ts +1 -0
- package/corpus/templates/design/server/routes/api/index-design-system-sources.post.ts +1 -0
- package/corpus/templates/dispatch/_gitignore +2 -0
- package/corpus/templates/forms/_gitignore +2 -0
- package/corpus/templates/macros/_gitignore +2 -0
- package/corpus/templates/mail/_gitignore +2 -0
- package/corpus/templates/plan/_gitignore +2 -0
- package/corpus/templates/slides/_gitignore +2 -0
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +126 -53
- package/corpus/templates/slides/app/components/design-system/builder-design-system-upload.ts +271 -0
- package/corpus/templates/slides/app/components/design-system/builder-index-response.ts +1 -1
- package/corpus/templates/slides/app/i18n/en-US.ts +1 -0
- package/corpus/templates/slides/server/handlers/design-system-decode-job-status.ts +49 -0
- package/corpus/templates/slides/server/handlers/design-system-upload-start.ts +87 -0
- package/corpus/templates/slides/server/handlers/index-design-system-sources.ts +79 -0
- package/corpus/templates/slides/server/routes/api/design-system-decode-job-status.get.ts +1 -0
- package/corpus/templates/slides/server/routes/api/design-system-upload-start.post.ts +1 -0
- package/corpus/templates/slides/server/routes/api/index-design-system-sources.post.ts +1 -0
- package/corpus/templates/tasks/_gitignore +2 -0
- package/corpus/toolkit/CHANGELOG.md +6 -0
- package/corpus/toolkit/package.json +1 -1
- package/corpus/toolkit/src/editor/DragHandle.ts +63 -9
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/observability/routes.d.ts +3 -3
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/actions/custom-provider-registration.d.ts +10 -10
- package/dist/provider-api/actions/provider-api.d.ts +8 -8
- package/dist/server/builder-design-systems.d.ts +49 -0
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +221 -69
- package/dist/server/builder-design-systems.js.map +1 -1
- package/dist/server/email-template.d.ts +7 -0
- package/dist/server/email-template.d.ts.map +1 -1
- package/dist/server/email-template.js +24 -0
- package/dist/server/email-template.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/templates/chat/_gitignore +2 -0
- package/package.json +5 -3
- package/src/server/builder-design-systems.ts +299 -82
- package/src/server/email-template.ts +33 -0
- package/src/server/index.ts +8 -0
- package/src/templates/chat/_gitignore +2 -0
- package/corpus/templates/design/server/handlers/index-design-system-with-builder.ts +0 -151
- package/corpus/templates/design/server/routes/api/index-design-system-with-builder.post.ts +0 -1
- package/corpus/templates/slides/server/handlers/index-design-system-with-builder.ts +0 -119
- package/corpus/templates/slides/server/routes/api/index-design-system-with-builder.post.ts +0 -1
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FeatureNotConfiguredError,
|
|
3
|
+
fetchBuilderDesignSystemDecodeJobStatus,
|
|
4
|
+
getSession,
|
|
5
|
+
runWithRequestContext,
|
|
6
|
+
} from "@agent-native/core/server";
|
|
7
|
+
import { defineEventHandler, getQuery, setResponseStatus } from "h3";
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Reads a Builder design-system decode job's status. The UI polls this after
|
|
11
|
+
* `/api/index-design-system-sources` returns a jobId, until the `.fig` decode
|
|
12
|
+
* job leaves `pending` and exposes a `branchUrl` (or reports an `error`).
|
|
13
|
+
*/
|
|
14
|
+
export const designSystemDecodeJobStatus = defineEventHandler(async (event) => {
|
|
15
|
+
const session = await getSession(event).catch(() => null);
|
|
16
|
+
if (!session?.email) {
|
|
17
|
+
setResponseStatus(event, 401);
|
|
18
|
+
return { error: "Unauthorized" };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const jobId = getQuery(event).jobId;
|
|
22
|
+
if (typeof jobId !== "string" || !jobId.trim()) {
|
|
23
|
+
setResponseStatus(event, 400);
|
|
24
|
+
return { error: "jobId is required." };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
try {
|
|
28
|
+
return await runWithRequestContext(
|
|
29
|
+
{ userEmail: session.email, orgId: session.orgId },
|
|
30
|
+
() => fetchBuilderDesignSystemDecodeJobStatus(jobId.trim()),
|
|
31
|
+
);
|
|
32
|
+
} catch (err) {
|
|
33
|
+
if (err instanceof FeatureNotConfiguredError) {
|
|
34
|
+
setResponseStatus(event, 412);
|
|
35
|
+
return {
|
|
36
|
+
error: err.message,
|
|
37
|
+
builderConnectUrl:
|
|
38
|
+
err.builderConnectUrl ?? "/_agent-native/builder/connect",
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
setResponseStatus(event, 502);
|
|
42
|
+
return {
|
|
43
|
+
error:
|
|
44
|
+
err instanceof Error
|
|
45
|
+
? err.message
|
|
46
|
+
: "Failed to read decode job status.",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FeatureNotConfiguredError,
|
|
3
|
+
getSession,
|
|
4
|
+
runWithRequestContext,
|
|
5
|
+
startBuilderDesignSystemUpload,
|
|
6
|
+
} from "@agent-native/core/server";
|
|
7
|
+
import { defineEventHandler, readBody, setResponseStatus } from "h3";
|
|
8
|
+
|
|
9
|
+
const MAX_FIG_BYTES = 512 * 1024 * 1024;
|
|
10
|
+
|
|
11
|
+
interface AttachmentInput {
|
|
12
|
+
name?: unknown;
|
|
13
|
+
mimetype?: unknown;
|
|
14
|
+
declaredSize?: unknown;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Opens signed resumable-upload slots so the browser can stream large `.fig`
|
|
19
|
+
* bytes straight to storage. Only small JSON metadata rides through the app
|
|
20
|
+
* server; the file bytes never do.
|
|
21
|
+
*/
|
|
22
|
+
export const designSystemUploadStart = defineEventHandler(async (event) => {
|
|
23
|
+
const session = await getSession(event).catch(() => null);
|
|
24
|
+
if (!session?.email) {
|
|
25
|
+
setResponseStatus(event, 401);
|
|
26
|
+
return { error: "Unauthorized" };
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const body = (await readBody(event).catch(() => null)) as {
|
|
30
|
+
attachments?: AttachmentInput[];
|
|
31
|
+
} | null;
|
|
32
|
+
const rawList = Array.isArray(body?.attachments) ? body.attachments : [];
|
|
33
|
+
if (rawList.length === 0) {
|
|
34
|
+
setResponseStatus(event, 400);
|
|
35
|
+
return { error: "No attachments provided." };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const attachments: {
|
|
39
|
+
name: string;
|
|
40
|
+
mimetype: string;
|
|
41
|
+
declaredSize: number;
|
|
42
|
+
}[] = [];
|
|
43
|
+
for (const raw of rawList) {
|
|
44
|
+
const name = typeof raw?.name === "string" ? raw.name.trim() : "";
|
|
45
|
+
const mimetype =
|
|
46
|
+
typeof raw?.mimetype === "string" && raw.mimetype.trim()
|
|
47
|
+
? raw.mimetype.trim()
|
|
48
|
+
: "application/octet-stream";
|
|
49
|
+
const declaredSize = Number(raw?.declaredSize);
|
|
50
|
+
if (!name) {
|
|
51
|
+
setResponseStatus(event, 400);
|
|
52
|
+
return { error: "Attachment name is required." };
|
|
53
|
+
}
|
|
54
|
+
if (!Number.isSafeInteger(declaredSize) || declaredSize <= 0) {
|
|
55
|
+
setResponseStatus(event, 400);
|
|
56
|
+
return { error: "Attachment declaredSize must be a positive integer." };
|
|
57
|
+
}
|
|
58
|
+
if (declaredSize > MAX_FIG_BYTES) {
|
|
59
|
+
setResponseStatus(event, 413);
|
|
60
|
+
return {
|
|
61
|
+
error: `File too large (max ${Math.round(MAX_FIG_BYTES / 1024 / 1024)} MB).`,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
attachments.push({ name, mimetype, declaredSize });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const uploads = await runWithRequestContext(
|
|
69
|
+
{ userEmail: session.email, orgId: session.orgId },
|
|
70
|
+
() => startBuilderDesignSystemUpload(attachments),
|
|
71
|
+
);
|
|
72
|
+
return { uploads };
|
|
73
|
+
} catch (err) {
|
|
74
|
+
if (err instanceof FeatureNotConfiguredError) {
|
|
75
|
+
setResponseStatus(event, 412);
|
|
76
|
+
return {
|
|
77
|
+
error: err.message,
|
|
78
|
+
builderConnectUrl:
|
|
79
|
+
err.builderConnectUrl ?? "/_agent-native/builder/connect",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
setResponseStatus(event, 502);
|
|
83
|
+
return {
|
|
84
|
+
error: err instanceof Error ? err.message : "Failed to start upload.",
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import {
|
|
2
|
+
FeatureNotConfiguredError,
|
|
3
|
+
getSession,
|
|
4
|
+
indexBuilderDesignSystem,
|
|
5
|
+
runWithRequestContext,
|
|
6
|
+
} from "@agent-native/core/server";
|
|
7
|
+
import { defineEventHandler, readBody, setResponseStatus } from "h3";
|
|
8
|
+
|
|
9
|
+
import { upsertBuilderProxyDesignSystem } from "../lib/builder-design-system-proxy.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Finalizes Builder DSI indexing from upload tokens produced by the
|
|
13
|
+
* browser-streamed resumable upload. The file bytes were streamed straight to
|
|
14
|
+
* storage; this endpoint only forwards the opaque tokens.
|
|
15
|
+
*/
|
|
16
|
+
export const indexDesignSystemSources = defineEventHandler(async (event) => {
|
|
17
|
+
const session = await getSession(event).catch(() => null);
|
|
18
|
+
if (!session?.email) {
|
|
19
|
+
setResponseStatus(event, 401);
|
|
20
|
+
return { error: "Unauthorized" };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const body = (await readBody(event).catch(() => null)) as {
|
|
24
|
+
projectName?: unknown;
|
|
25
|
+
uploadTokens?: unknown;
|
|
26
|
+
} | null;
|
|
27
|
+
const uploadTokens = Array.isArray(body?.uploadTokens)
|
|
28
|
+
? body.uploadTokens.filter(
|
|
29
|
+
(token): token is string =>
|
|
30
|
+
typeof token === "string" && token.length > 0,
|
|
31
|
+
)
|
|
32
|
+
: [];
|
|
33
|
+
if (uploadTokens.length === 0) {
|
|
34
|
+
setResponseStatus(event, 400);
|
|
35
|
+
return { error: "No uploaded files to index." };
|
|
36
|
+
}
|
|
37
|
+
const projectName =
|
|
38
|
+
typeof body?.projectName === "string"
|
|
39
|
+
? body.projectName.trim() || undefined
|
|
40
|
+
: undefined;
|
|
41
|
+
|
|
42
|
+
const sources = uploadTokens.map((uploadToken) => ({
|
|
43
|
+
kind: "file" as const,
|
|
44
|
+
uploadToken,
|
|
45
|
+
}));
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
return await runWithRequestContext(
|
|
49
|
+
{ userEmail: session.email, orgId: session.orgId },
|
|
50
|
+
async () => {
|
|
51
|
+
const result = await indexBuilderDesignSystem({ sources, projectName });
|
|
52
|
+
const proxy = await upsertBuilderProxyDesignSystem({
|
|
53
|
+
result,
|
|
54
|
+
ownerEmail: session.email,
|
|
55
|
+
orgId: session.orgId ?? null,
|
|
56
|
+
projectName,
|
|
57
|
+
});
|
|
58
|
+
return {
|
|
59
|
+
...result,
|
|
60
|
+
...proxy,
|
|
61
|
+
uploadedFileCount: uploadTokens.length,
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
);
|
|
65
|
+
} catch (err) {
|
|
66
|
+
if (err instanceof FeatureNotConfiguredError) {
|
|
67
|
+
setResponseStatus(event, 412);
|
|
68
|
+
return {
|
|
69
|
+
error: err.message,
|
|
70
|
+
builderConnectUrl:
|
|
71
|
+
err.builderConnectUrl ?? "/_agent-native/builder/connect",
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
setResponseStatus(event, 502);
|
|
75
|
+
return {
|
|
76
|
+
error:
|
|
77
|
+
err instanceof Error
|
|
78
|
+
? err.message
|
|
79
|
+
: "Builder design-system indexing failed.",
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { designSystemDecodeJobStatus as default } from "../../handlers/design-system-decode-job-status";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { designSystemUploadStart as default } from "../../handlers/design-system-upload-start";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { indexDesignSystemSources as default } from "../../handlers/index-design-system-sources";
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { sendToAgentChat } from "@agent-native/core/client/agent-chat";
|
|
2
|
-
import { appApiPath } from "@agent-native/core/client/api-path";
|
|
3
2
|
import {
|
|
4
3
|
useActionQuery,
|
|
5
4
|
useActionMutation,
|
|
@@ -36,9 +35,13 @@ import { Label } from "@/components/ui/label";
|
|
|
36
35
|
import { ScrollArea } from "@/components/ui/scroll-area";
|
|
37
36
|
import { Textarea } from "@/components/ui/textarea";
|
|
38
37
|
|
|
38
|
+
import {
|
|
39
|
+
uploadAndIndexFigmaFiles,
|
|
40
|
+
pollDecodeJobStatus,
|
|
41
|
+
type DecodeJobStatus,
|
|
42
|
+
} from "./builder-design-system-upload";
|
|
39
43
|
import {
|
|
40
44
|
MAX_BUILDER_INDEX_UPLOAD_BYTES,
|
|
41
|
-
readBuilderIndexResponse,
|
|
42
45
|
formatFileSize,
|
|
43
46
|
type BuilderIndexResult,
|
|
44
47
|
} from "./builder-index-response";
|
|
@@ -117,6 +120,62 @@ export function DesignSystemSetup({
|
|
|
117
120
|
const [builderIndexError, setBuilderIndexError] = useState<string | null>(
|
|
118
121
|
null,
|
|
119
122
|
);
|
|
123
|
+
const [decodeStatus, setDecodeStatus] = useState<DecodeJobStatus | null>(
|
|
124
|
+
null,
|
|
125
|
+
);
|
|
126
|
+
const decodePollRef = useRef<AbortController | null>(null);
|
|
127
|
+
|
|
128
|
+
const stopDecodePolling = useCallback(() => {
|
|
129
|
+
decodePollRef.current?.abort();
|
|
130
|
+
decodePollRef.current = null;
|
|
131
|
+
}, []);
|
|
132
|
+
|
|
133
|
+
const startDecodePolling = useCallback(
|
|
134
|
+
(jobId: string, indexResult: BuilderIndexResult) => {
|
|
135
|
+
decodePollRef.current?.abort();
|
|
136
|
+
const controller = new AbortController();
|
|
137
|
+
decodePollRef.current = controller;
|
|
138
|
+
setDecodeStatus({
|
|
139
|
+
status: "pending",
|
|
140
|
+
branchUrl: null,
|
|
141
|
+
error: null,
|
|
142
|
+
framesProcessed: 0,
|
|
143
|
+
totalFrames: 0,
|
|
144
|
+
});
|
|
145
|
+
pollDecodeJobStatus(jobId, {
|
|
146
|
+
signal: controller.signal,
|
|
147
|
+
onUpdate: (status) => {
|
|
148
|
+
if (!controller.signal.aborted) setDecodeStatus(status);
|
|
149
|
+
},
|
|
150
|
+
})
|
|
151
|
+
.then((status) => {
|
|
152
|
+
if (controller.signal.aborted) return;
|
|
153
|
+
setDecodeStatus(status);
|
|
154
|
+
setBuilderIndexResult(
|
|
155
|
+
status.branchUrl
|
|
156
|
+
? { ...indexResult, builderUrl: status.branchUrl }
|
|
157
|
+
: indexResult,
|
|
158
|
+
);
|
|
159
|
+
setBuilderIndexing(false);
|
|
160
|
+
})
|
|
161
|
+
.catch((err: unknown) => {
|
|
162
|
+
if (controller.signal.aborted) return;
|
|
163
|
+
if (err instanceof DOMException && err.name === "AbortError") return;
|
|
164
|
+
setDecodeStatus((prev) => ({
|
|
165
|
+
status: "error",
|
|
166
|
+
branchUrl: prev?.branchUrl ?? null,
|
|
167
|
+
error: err instanceof Error ? err.message : String(err),
|
|
168
|
+
framesProcessed: prev?.framesProcessed ?? 0,
|
|
169
|
+
totalFrames: prev?.totalFrames ?? 0,
|
|
170
|
+
}));
|
|
171
|
+
setBuilderIndexResult(indexResult);
|
|
172
|
+
setBuilderIndexing(false);
|
|
173
|
+
});
|
|
174
|
+
},
|
|
175
|
+
[],
|
|
176
|
+
);
|
|
177
|
+
|
|
178
|
+
useEffect(() => stopDecodePolling, [stopDecodePolling]);
|
|
120
179
|
|
|
121
180
|
const codeInputRef = useRef<HTMLInputElement>(null);
|
|
122
181
|
const docInputRef = useRef<HTMLInputElement>(null);
|
|
@@ -170,8 +229,10 @@ export function DesignSystemSetup({
|
|
|
170
229
|
setBuilderIndexing(false);
|
|
171
230
|
setBuilderIndexResult(null);
|
|
172
231
|
setBuilderIndexError(null);
|
|
232
|
+
stopDecodePolling();
|
|
233
|
+
setDecodeStatus(null);
|
|
173
234
|
}
|
|
174
|
-
}, [open]);
|
|
235
|
+
}, [open, stopDecodePolling]);
|
|
175
236
|
|
|
176
237
|
const hasAnySources = useMemo(() => {
|
|
177
238
|
return (
|
|
@@ -269,30 +330,34 @@ export function DesignSystemSetup({
|
|
|
269
330
|
|
|
270
331
|
setBuilderIndexError(null);
|
|
271
332
|
setBuilderIndexResult(null);
|
|
333
|
+
stopDecodePolling();
|
|
334
|
+
setDecodeStatus(null);
|
|
272
335
|
setBuilderIndexing(true);
|
|
273
336
|
try {
|
|
274
|
-
const
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
)
|
|
283
|
-
|
|
284
|
-
|
|
337
|
+
const suggestedTitle =
|
|
338
|
+
file.name
|
|
339
|
+
.replace(/\.fig$/i, "")
|
|
340
|
+
.replace(/[-_]+/g, " ")
|
|
341
|
+
.trim() || "Imported brand";
|
|
342
|
+
const parsed = await uploadAndIndexFigmaFiles([file], {
|
|
343
|
+
projectName: suggestedTitle,
|
|
344
|
+
});
|
|
345
|
+
if (parsed.jobId) {
|
|
346
|
+
startDecodePolling(parsed.jobId, parsed);
|
|
347
|
+
} else {
|
|
348
|
+
setBuilderIndexResult(parsed);
|
|
349
|
+
setBuilderIndexing(false);
|
|
350
|
+
}
|
|
285
351
|
} catch (err) {
|
|
286
352
|
setBuilderIndexError(
|
|
287
353
|
err instanceof Error
|
|
288
354
|
? err.message
|
|
289
355
|
: t("designSystemSetup.figParseFailed"),
|
|
290
356
|
);
|
|
291
|
-
} finally {
|
|
292
357
|
setBuilderIndexing(false);
|
|
293
358
|
}
|
|
294
359
|
},
|
|
295
|
-
[t],
|
|
360
|
+
[t, startDecodePolling, stopDecodePolling],
|
|
296
361
|
);
|
|
297
362
|
|
|
298
363
|
const handleEditSave = async () => {
|
|
@@ -543,7 +608,10 @@ export function DesignSystemSetup({
|
|
|
543
608
|
) : (
|
|
544
609
|
<BuilderIndexPreview
|
|
545
610
|
result={builderIndexResult}
|
|
611
|
+
decodeStatus={decodeStatus}
|
|
546
612
|
onReset={() => {
|
|
613
|
+
stopDecodePolling();
|
|
614
|
+
setDecodeStatus(null);
|
|
547
615
|
setBuilderIndexResult(null);
|
|
548
616
|
setBuilderIndexError(null);
|
|
549
617
|
}}
|
|
@@ -880,12 +948,22 @@ function TagList({
|
|
|
880
948
|
|
|
881
949
|
function BuilderIndexPreview({
|
|
882
950
|
result,
|
|
951
|
+
decodeStatus,
|
|
883
952
|
onReset,
|
|
884
953
|
}: {
|
|
885
954
|
result: BuilderIndexResult;
|
|
955
|
+
decodeStatus: DecodeJobStatus | null;
|
|
886
956
|
onReset: () => void;
|
|
887
957
|
}) {
|
|
888
958
|
const t = useT();
|
|
959
|
+
const decodeDone =
|
|
960
|
+
decodeStatus == null ||
|
|
961
|
+
Boolean(decodeStatus.branchUrl) ||
|
|
962
|
+
decodeStatus.status === "complete";
|
|
963
|
+
const decodeFailed = decodeStatus?.status === "error";
|
|
964
|
+
const decodeText = decodeFailed
|
|
965
|
+
? t("designSystemSetup.decodeFailed", { error: decodeStatus?.error ?? "" })
|
|
966
|
+
: null;
|
|
889
967
|
return (
|
|
890
968
|
<div className="space-y-4 rounded-lg border border-border bg-accent/40 p-4">
|
|
891
969
|
<div className="flex items-start gap-3">
|
|
@@ -905,44 +983,39 @@ function BuilderIndexPreview({
|
|
|
905
983
|
</div>
|
|
906
984
|
</div>
|
|
907
985
|
|
|
908
|
-
|
|
909
|
-
<
|
|
910
|
-
{
|
|
911
|
-
</
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
<
|
|
916
|
-
{
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
986
|
+
{decodeText && (
|
|
987
|
+
<div className="border-t border-border pt-3 text-xs text-destructive">
|
|
988
|
+
{decodeText}
|
|
989
|
+
</div>
|
|
990
|
+
)}
|
|
991
|
+
|
|
992
|
+
{(decodeDone || decodeFailed) && (
|
|
993
|
+
<div className="flex flex-wrap items-center gap-2 border-t border-border pt-3">
|
|
994
|
+
{decodeDone && !decodeFailed && (
|
|
995
|
+
<Button size="sm" asChild className="cursor-pointer">
|
|
996
|
+
<a
|
|
997
|
+
href={withBuilderUtmTrackingParams(result.builderUrl, {
|
|
998
|
+
campaign: "product",
|
|
999
|
+
content: "design_system_intelligence",
|
|
1000
|
+
})}
|
|
1001
|
+
target="_blank"
|
|
1002
|
+
rel="noreferrer"
|
|
1003
|
+
>
|
|
1004
|
+
<IconExternalLink className="w-3.5 h-3.5" />
|
|
1005
|
+
{t("designSystemSetup.openInBuilder")}
|
|
1006
|
+
</a>
|
|
1007
|
+
</Button>
|
|
1008
|
+
)}
|
|
1009
|
+
<Button
|
|
1010
|
+
size="sm"
|
|
1011
|
+
variant="ghost"
|
|
1012
|
+
onClick={onReset}
|
|
1013
|
+
className="cursor-pointer"
|
|
932
1014
|
>
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
<Button
|
|
938
|
-
size="sm"
|
|
939
|
-
variant="ghost"
|
|
940
|
-
onClick={onReset}
|
|
941
|
-
className="cursor-pointer"
|
|
942
|
-
>
|
|
943
|
-
{t("designSystemSetup.chooseAnotherFile")}
|
|
944
|
-
</Button>
|
|
945
|
-
</div>
|
|
1015
|
+
{t("designSystemSetup.chooseAnotherFile")}
|
|
1016
|
+
</Button>
|
|
1017
|
+
</div>
|
|
1018
|
+
)}
|
|
946
1019
|
</div>
|
|
947
1020
|
);
|
|
948
1021
|
}
|