@agent-native/core 0.114.12 → 0.114.15
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 +2 -2
- package/corpus/core/CHANGELOG.md +21 -0
- package/corpus/core/docs/content/deployment.mdx +1 -1
- package/corpus/core/docs/content/frames.mdx +1 -1
- package/corpus/core/docs/content/integrations.mdx +27 -27
- package/corpus/core/docs/content/pr-visual-recap.mdx +17 -13
- package/corpus/core/docs/content/workspace-management.mdx +1 -1
- package/corpus/core/package.json +2 -1
- package/corpus/core/src/agent/engine/builder-engine.ts +4 -0
- package/corpus/core/src/application-state/index.ts +3 -0
- package/corpus/core/src/application-state/script-helpers.ts +12 -1
- package/corpus/core/src/application-state/store.ts +216 -15
- package/corpus/core/src/client/AgentPanel.tsx +10 -4
- package/corpus/core/src/client/ConnectBuilderCard.tsx +5 -1
- package/corpus/core/src/client/chat/markdown-renderer.tsx +3 -5
- package/corpus/core/src/client/error-format.ts +2 -1
- package/corpus/core/src/client/index.ts +1 -0
- package/corpus/core/src/client/integrations/IntegrationsPanel.tsx +2 -18
- package/corpus/core/src/client/resources/McpIntegrationDialog.tsx +43 -32
- package/corpus/core/src/client/resources/mcp-integration-catalog.ts +4 -2
- package/corpus/core/src/client/settings/BackgroundAgentSection.tsx +5 -1
- package/corpus/core/src/client/settings/SettingsPanel.tsx +4 -4
- package/corpus/core/src/client/settings/useBuilderStatus.ts +3 -0
- package/corpus/core/src/db/client.ts +44 -1
- package/corpus/core/src/localization/default-messages.ts +1 -7
- package/corpus/core/src/server/builder-browser.ts +4 -0
- package/corpus/core/src/server/builder-design-systems.ts +6 -1
- package/corpus/core/src/server/fusion-app.ts +5 -1
- package/corpus/core/src/shared/builder-link-tracking.ts +41 -0
- package/corpus/core/src/shared/index.ts +1 -0
- package/corpus/templates/analytics/AGENTS.md +10 -1
- package/corpus/templates/analytics/actions/save-dashboard-report-subscription.ts +10 -2
- package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +5 -4
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +20 -32
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/report-panel-window.ts +62 -0
- package/corpus/templates/analytics/changelog/2026-07-21-chart-series-controls-stay-open-while-moving-from-the-legend.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-21-dashboard-email-captures-complete-large-dashboards-in-chunks.md +6 -0
- package/corpus/templates/analytics/seeds/dashboards/agent-native-templates-first-party.json +4 -4
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +1 -8
- package/corpus/templates/analytics/server/lib/dashboard-report-subscriptions.ts +39 -7
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +341 -251
- package/corpus/templates/analytics/server/lib/first-party-dashboard-repair.ts +114 -0
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +84 -6
- package/corpus/templates/analytics/server/plugins/db.ts +13 -0
- package/corpus/templates/clips/app/components/player/video-player.tsx +10 -4
- package/corpus/templates/clips/changelog/2026-07-21-choose-which-whisper-model-to-use-in-settings.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-21-fixed-organization-recording-visibility-default.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-21-live-dictation-text-now-appears-above-the-desktop-recording-.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-21-meeting-notes-stop-when-calls-end.md +6 -0
- package/corpus/templates/clips/desktop/src/app.tsx +66 -75
- package/corpus/templates/clips/desktop/src/hooks/useMeetingTranscription.ts +2 -0
- package/corpus/templates/clips/desktop/src/hooks/useWhisperSettings.ts +172 -0
- package/corpus/templates/clips/desktop/src/lib/meeting-call-app.ts +41 -0
- package/corpus/templates/clips/desktop/src/lib/silence-events.ts +1 -0
- package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +14 -3
- package/corpus/templates/clips/desktop/src/overlays/flow-bar.tsx +25 -0
- package/corpus/templates/clips/desktop/src/shared/config.ts +1 -0
- package/corpus/templates/clips/desktop/src/styles.css +100 -7
- package/corpus/templates/clips/desktop/src-tauri/src/clips/mod.rs +3 -4
- package/corpus/templates/clips/desktop/src-tauri/src/config.rs +32 -0
- package/corpus/templates/clips/desktop/src-tauri/src/lib.rs +3 -0
- package/corpus/templates/clips/desktop/src-tauri/src/native_screen/custom_capture.rs +11 -4
- package/corpus/templates/clips/desktop/src-tauri/src/silence_detector.rs +268 -20
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_model.rs +285 -164
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +18 -7
- package/corpus/templates/clips/learnings.defaults.md +1 -1
- package/corpus/templates/clips/server/plugins/db.ts +11 -0
- package/corpus/templates/clips/shared/builder-credits.ts +1 -1
- package/corpus/templates/design/AGENTS.md +7 -3
- package/corpus/templates/design/actions/begin-node-rewrite-request.ts +78 -0
- package/corpus/templates/design/actions/cancel-node-rewrite-request.ts +17 -7
- package/corpus/templates/design/actions/propose-node-rewrite.ts +26 -18
- package/corpus/templates/design/actions/resolve-node-rewrite.ts +67 -19
- package/corpus/templates/design/app/components/design/FusionAppBanner.tsx +9 -1
- package/corpus/templates/design/app/components/design/edit-panel/component-section.tsx +5 -1
- package/corpus/templates/design/app/components/visual-editor/NodeRewriteProposal.tsx +1 -4
- package/corpus/templates/design/app/components/visual-editor/ReviewCanvasPins.tsx +2 -6
- package/corpus/templates/design/app/pages/DesignSystemSetup.tsx +9 -1
- package/corpus/templates/design/shared/node-rewrite.ts +32 -0
- package/corpus/templates/forms/app/components/layout/Sidebar.tsx +6 -3
- package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +11 -18
- package/corpus/templates/forms/app/pages/FormsListPage.tsx +9 -5
- package/corpus/templates/slides/app/components/design-system/DesignSystemSetup.tsx +9 -1
- package/corpus/templates/slides/app/context/DeckContext.tsx +18 -0
- package/corpus/templates/slides/changelog/2026-07-21-decks-list-now-refreshes-when-you-switch-organizations.md +6 -0
- package/corpus/templates/tasks/app/components/custom-fields/FieldCreateBar.tsx +13 -19
- package/corpus/templates/tasks/app/components/custom-fields/FieldListRow.tsx +27 -22
- package/corpus/templates/tasks/app/components/custom-fields/FieldsList.tsx +26 -22
- package/corpus/templates/tasks/app/components/custom-fields/FieldsListSkeleton.tsx +4 -1
- package/corpus/templates/tasks/app/components/custom-fields/FieldsPage.tsx +4 -2
- package/corpus/templates/tasks/app/components/custom-fields/editor/FieldEditorSidebar.tsx +12 -3
- package/corpus/templates/tasks/app/components/custom-fields/editor/FieldTitleSection.tsx +6 -3
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/CurrencyConfigControl.tsx +5 -2
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/NumberConfigControl.tsx +5 -2
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/PercentConfigControl.tsx +4 -1
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/SelectConfigControl.tsx +17 -7
- package/corpus/templates/tasks/app/components/custom-fields/editor/config/select-colors.ts +37 -9
- package/corpus/templates/tasks/app/components/custom-fields/field-types.ts +23 -0
- package/corpus/templates/tasks/app/components/inbox/InboxList.tsx +24 -16
- package/corpus/templates/tasks/app/components/inbox/InboxListPage.tsx +5 -3
- package/corpus/templates/tasks/app/components/inbox/InboxListRow.tsx +7 -5
- package/corpus/templates/tasks/app/components/layout/Header.tsx +10 -10
- package/corpus/templates/tasks/app/components/layout/Layout.tsx +11 -7
- package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +17 -10
- package/corpus/templates/tasks/app/components/shared/AddListItemInput.tsx +14 -8
- package/corpus/templates/tasks/app/components/shared/AlertDialog.tsx +6 -2
- package/corpus/templates/tasks/app/components/shared/BulkDeleteDialog.tsx +13 -6
- package/corpus/templates/tasks/app/components/shared/ChipSelect.tsx +12 -5
- package/corpus/templates/tasks/app/components/shared/DeleteItemDialog.tsx +6 -6
- package/corpus/templates/tasks/app/components/shared/ListViewHeader.tsx +3 -1
- package/corpus/templates/tasks/app/components/shared/SidePanel.tsx +5 -2
- package/corpus/templates/tasks/app/components/shared/list/ListRowDragHandle.tsx +3 -1
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionBar.tsx +46 -20
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionHeaderToggle.tsx +3 -1
- package/corpus/templates/tasks/app/components/shared/selection/ListSelectionToolbar.tsx +10 -6
- package/corpus/templates/tasks/app/components/tasks/TaskList.tsx +24 -13
- package/corpus/templates/tasks/app/components/tasks/TaskListHeaderRow.tsx +4 -1
- package/corpus/templates/tasks/app/components/tasks/TaskListPage.tsx +5 -3
- package/corpus/templates/tasks/app/components/tasks/TaskListRow.tsx +15 -6
- package/corpus/templates/tasks/app/components/tasks/fields/TaskFieldsSidebar.tsx +11 -6
- package/corpus/templates/tasks/app/components/tasks/fields/TaskTitleSection.tsx +8 -3
- package/corpus/templates/tasks/app/components/tasks/fields/controls/RichTextValueControl.tsx +12 -6
- package/corpus/templates/tasks/app/components/tasks/fields/controls/SingleSelectValueControl.tsx +6 -1
- package/corpus/templates/tasks/app/i18n/en-US.ts +209 -0
- package/corpus/templates/tasks/app/i18n/index.ts +34 -0
- package/corpus/templates/tasks/app/root.tsx +34 -2
- package/corpus/templates/tasks/app/routes/extensions.$id.tsx +2 -1
- package/corpus/templates/tasks/app/routes/extensions._index.tsx +2 -1
- package/corpus/templates/tasks/app/routes/fields.tsx +2 -1
- package/corpus/templates/tasks/app/routes/inbox.tsx +2 -1
- package/corpus/templates/tasks/app/routes/tasks.tsx +2 -1
- package/corpus/templates/tasks/app/routes/team.tsx +6 -3
- package/corpus/templates/tasks/changelog/2026-07-20-tasks-is-now-available-in-10-additional-languages.md +6 -0
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/engine/builder-engine.js +4 -0
- package/dist/agent/engine/builder-engine.js.map +1 -1
- package/dist/application-state/index.d.ts +2 -2
- package/dist/application-state/index.d.ts.map +1 -1
- package/dist/application-state/index.js +2 -2
- package/dist/application-state/index.js.map +1 -1
- package/dist/application-state/script-helpers.d.ts +3 -1
- package/dist/application-state/script-helpers.d.ts.map +1 -1
- package/dist/application-state/script-helpers.js +7 -1
- package/dist/application-state/script-helpers.js.map +1 -1
- package/dist/application-state/store.d.ts +7 -1
- package/dist/application-state/store.d.ts.map +1 -1
- package/dist/application-state/store.js +143 -17
- package/dist/application-state/store.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +10 -3
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/ConnectBuilderCard.d.ts.map +1 -1
- package/dist/client/ConnectBuilderCard.js +5 -1
- package/dist/client/ConnectBuilderCard.js.map +1 -1
- package/dist/client/chat/markdown-renderer.d.ts.map +1 -1
- package/dist/client/chat/markdown-renderer.js +3 -2
- package/dist/client/chat/markdown-renderer.js.map +1 -1
- package/dist/client/error-format.d.ts +1 -1
- package/dist/client/error-format.d.ts.map +1 -1
- package/dist/client/error-format.js +1 -1
- package/dist/client/error-format.js.map +1 -1
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.d.ts.map +1 -1
- package/dist/client/integrations/IntegrationsPanel.js +3 -4
- package/dist/client/integrations/IntegrationsPanel.js.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.d.ts.map +1 -1
- package/dist/client/resources/McpIntegrationDialog.js +21 -7
- package/dist/client/resources/McpIntegrationDialog.js.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.d.ts.map +1 -1
- package/dist/client/resources/mcp-integration-catalog.js +2 -2
- package/dist/client/resources/mcp-integration-catalog.js.map +1 -1
- package/dist/client/settings/BackgroundAgentSection.d.ts.map +1 -1
- package/dist/client/settings/BackgroundAgentSection.js +5 -1
- package/dist/client/settings/BackgroundAgentSection.js.map +1 -1
- package/dist/client/settings/SettingsPanel.js +1 -1
- package/dist/client/settings/SettingsPanel.js.map +1 -1
- package/dist/client/settings/useBuilderStatus.d.ts.map +1 -1
- package/dist/client/settings/useBuilderStatus.js +2 -0
- package/dist/client/settings/useBuilderStatus.js.map +1 -1
- package/dist/collab/routes.d.ts +1 -1
- package/dist/db/client.d.ts +7 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +39 -1
- package/dist/db/client.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts +1 -1
- package/dist/localization/default-messages.d.ts +0 -6
- package/dist/localization/default-messages.d.ts.map +1 -1
- package/dist/localization/default-messages.js +1 -7
- package/dist/localization/default-messages.js.map +1 -1
- package/dist/notifications/routes.d.ts +2 -2
- package/dist/observability/routes.d.ts +3 -3
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/server/builder-browser.d.ts.map +1 -1
- package/dist/server/builder-browser.js +4 -0
- package/dist/server/builder-browser.js.map +1 -1
- package/dist/server/builder-design-systems.d.ts.map +1 -1
- package/dist/server/builder-design-systems.js +6 -1
- package/dist/server/builder-design-systems.js.map +1 -1
- package/dist/server/fusion-app.d.ts.map +1 -1
- package/dist/server/fusion-app.js +2 -1
- package/dist/server/fusion-app.js.map +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/shared/builder-link-tracking.d.ts +14 -0
- package/dist/shared/builder-link-tracking.d.ts.map +1 -0
- package/dist/shared/builder-link-tracking.js +26 -0
- package/dist/shared/builder-link-tracking.js.map +1 -0
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/index.js +1 -0
- package/dist/shared/index.js.map +1 -1
- package/docs/content/deployment.mdx +1 -1
- package/docs/content/frames.mdx +1 -1
- package/docs/content/integrations.mdx +27 -27
- package/docs/content/pr-visual-recap.mdx +17 -13
- package/docs/content/workspace-management.mdx +1 -1
- package/package.json +3 -2
- package/src/agent/engine/builder-engine.ts +4 -0
- package/src/application-state/index.ts +3 -0
- package/src/application-state/script-helpers.ts +12 -1
- package/src/application-state/store.ts +216 -15
- package/src/client/AgentPanel.tsx +10 -4
- package/src/client/ConnectBuilderCard.tsx +5 -1
- package/src/client/chat/markdown-renderer.tsx +3 -5
- package/src/client/error-format.ts +2 -1
- package/src/client/index.ts +1 -0
- package/src/client/integrations/IntegrationsPanel.tsx +2 -18
- package/src/client/resources/McpIntegrationDialog.tsx +43 -32
- package/src/client/resources/mcp-integration-catalog.ts +4 -2
- package/src/client/settings/BackgroundAgentSection.tsx +5 -1
- package/src/client/settings/SettingsPanel.tsx +4 -4
- package/src/client/settings/useBuilderStatus.ts +3 -0
- package/src/db/client.ts +44 -1
- package/src/localization/default-messages.ts +1 -7
- package/src/server/builder-browser.ts +4 -0
- package/src/server/builder-design-systems.ts +6 -1
- package/src/server/fusion-app.ts +5 -1
- package/src/shared/builder-link-tracking.ts +41 -0
- package/src/shared/index.ts +1 -0
|
@@ -288,11 +288,15 @@ ladder.
|
|
|
288
288
|
`view-screen`; not rendered as canvas overlays).
|
|
289
289
|
- `design-reprompt-pending:<designId>:<fileId>` is the client-captured source
|
|
290
290
|
selection, instruction, base hash, and authoritative current request id for
|
|
291
|
-
a scoped regenerate request.
|
|
291
|
+
a scoped regenerate request. The frontend starts requests through the
|
|
292
|
+
compare-and-set `begin-node-rewrite-request` action and must not overwrite a
|
|
293
|
+
`resolving` acceptance reservation.
|
|
292
294
|
- `design-reprompt-proposal:<designId>:<fileId>:<repromptId>` is one
|
|
293
295
|
request-specific preview-only subtree proposal. Candidate payloads have a
|
|
294
|
-
256 KiB aggregate serialized limit.
|
|
295
|
-
compare-and-set
|
|
296
|
+
256 KiB aggregate serialized limit. Proposal publication, resolution, and
|
|
297
|
+
cancellation use atomic multi-key compare-and-set transitions. Acceptance
|
|
298
|
+
reserves its matching pending request before writing design content, so a
|
|
299
|
+
newer request and an older acceptance cannot both win.
|
|
296
300
|
`view-screen` lists only proposals paired to the current pending request as
|
|
297
301
|
`pendingCandidateReviews`.
|
|
298
302
|
- `show-design-questions` opens focused pre-generation questions in the main
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { defineAction } from "@agent-native/core";
|
|
2
|
+
import {
|
|
3
|
+
compareAndSetAppState,
|
|
4
|
+
readAppState,
|
|
5
|
+
} from "@agent-native/core/application-state";
|
|
6
|
+
import { assertAccess } from "@agent-native/core/sharing";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
designRepromptPendingStateKey,
|
|
11
|
+
isNodeRewriteResolutionClaim,
|
|
12
|
+
isPendingDesignReprompt,
|
|
13
|
+
type PendingDesignReprompt,
|
|
14
|
+
} from "../shared/node-rewrite.js";
|
|
15
|
+
|
|
16
|
+
const targetSchema = z
|
|
17
|
+
.object({
|
|
18
|
+
nodeId: z.string().min(1).optional(),
|
|
19
|
+
selector: z.string().min(1).optional(),
|
|
20
|
+
})
|
|
21
|
+
.refine((target) => target.nodeId || target.selector, {
|
|
22
|
+
message: "target.nodeId or target.selector is required",
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
export default defineAction({
|
|
26
|
+
agentTool: false,
|
|
27
|
+
description:
|
|
28
|
+
"Atomically starts or supersedes one pending node rewrite unless its current proposal is being accepted.",
|
|
29
|
+
schema: z.object({
|
|
30
|
+
repromptId: z.string().min(1),
|
|
31
|
+
designId: z.string().min(1),
|
|
32
|
+
fileId: z.string().min(1),
|
|
33
|
+
target: targetSchema,
|
|
34
|
+
baseVersionHash: z.string().min(1),
|
|
35
|
+
instruction: z.string().trim().min(1),
|
|
36
|
+
createdAt: z.string().min(1),
|
|
37
|
+
priorProposalId: z.string().min(1).optional(),
|
|
38
|
+
priorRepromptId: z.string().min(1).optional(),
|
|
39
|
+
}),
|
|
40
|
+
run: async (request) => {
|
|
41
|
+
await assertAccess("design", request.designId, "editor");
|
|
42
|
+
const pendingKey = designRepromptPendingStateKey(
|
|
43
|
+
request.designId,
|
|
44
|
+
request.fileId,
|
|
45
|
+
);
|
|
46
|
+
const current = await readAppState(pendingKey);
|
|
47
|
+
if (isNodeRewriteResolutionClaim(current)) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
"This candidate is currently being accepted. Wait for it to finish before regenerating.",
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if (
|
|
53
|
+
request.priorRepromptId &&
|
|
54
|
+
(!isPendingDesignReprompt(current) ||
|
|
55
|
+
current.repromptId !== request.priorRepromptId)
|
|
56
|
+
) {
|
|
57
|
+
throw new Error(
|
|
58
|
+
"The candidates changed before refinement started. Review the latest candidates instead.",
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const pending: PendingDesignReprompt = {
|
|
63
|
+
...request,
|
|
64
|
+
status: "pending",
|
|
65
|
+
};
|
|
66
|
+
const started = await compareAndSetAppState(
|
|
67
|
+
pendingKey,
|
|
68
|
+
current,
|
|
69
|
+
pending as unknown as Record<string, unknown>,
|
|
70
|
+
);
|
|
71
|
+
if (!started) {
|
|
72
|
+
throw new Error(
|
|
73
|
+
"The regeneration request changed concurrently. Try again with the latest candidates.",
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
return { started: true, repromptId: request.repromptId };
|
|
77
|
+
},
|
|
78
|
+
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import {
|
|
3
3
|
compareAndSetAppState,
|
|
4
|
+
compareAndSetManyAppState,
|
|
4
5
|
readAppState,
|
|
5
6
|
} from "@agent-native/core/application-state";
|
|
6
7
|
import { assertAccess } from "@agent-native/core/sharing";
|
|
@@ -39,15 +40,24 @@ export default defineAction({
|
|
|
39
40
|
repromptId,
|
|
40
41
|
);
|
|
41
42
|
const proposal = await readAppState(proposalKey);
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
43
|
+
const proposalCancelled = isNodeRewriteProposal(proposal);
|
|
44
|
+
const pendingCancelled = proposalCancelled
|
|
45
|
+
? await compareAndSetManyAppState([
|
|
46
|
+
{
|
|
47
|
+
key: pendingKey,
|
|
48
|
+
expectedValue: pending,
|
|
49
|
+
nextValue: null,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
key: proposalKey,
|
|
53
|
+
expectedValue: proposal,
|
|
54
|
+
nextValue: null,
|
|
55
|
+
},
|
|
56
|
+
])
|
|
57
|
+
: await compareAndSetAppState(pendingKey, pending, null);
|
|
48
58
|
return {
|
|
49
59
|
cancelled: pendingCancelled,
|
|
50
|
-
proposalCancelled,
|
|
60
|
+
proposalCancelled: proposalCancelled && pendingCancelled,
|
|
51
61
|
superseded: !pendingCancelled,
|
|
52
62
|
};
|
|
53
63
|
},
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
compareAndSetManyAppState,
|
|
4
4
|
readAppState,
|
|
5
|
-
|
|
5
|
+
type AppStateCompareAndSetOperation,
|
|
6
6
|
} from "@agent-native/core/application-state";
|
|
7
7
|
import { accessFilter, assertAccess } from "@agent-native/core/sharing";
|
|
8
8
|
import { and, eq } from "drizzle-orm";
|
|
@@ -68,6 +68,7 @@ const variantSchema = z.object({
|
|
|
68
68
|
});
|
|
69
69
|
|
|
70
70
|
const pendingRepromptSchema = z.object({
|
|
71
|
+
status: z.literal("pending").optional(),
|
|
71
72
|
repromptId: z.string().min(1),
|
|
72
73
|
designId: z.string().min(1),
|
|
73
74
|
fileId: z.string().min(1),
|
|
@@ -241,21 +242,18 @@ export default defineAction({
|
|
|
241
242
|
file.id,
|
|
242
243
|
repromptId,
|
|
243
244
|
);
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
proposalKey,
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
"This regeneration was superseded by a newer request before its candidates were published.",
|
|
257
|
-
);
|
|
258
|
-
}
|
|
245
|
+
const publishOperations: AppStateCompareAndSetOperation[] = [
|
|
246
|
+
{
|
|
247
|
+
key: pendingKey,
|
|
248
|
+
expectedValue: pending as unknown as Record<string, unknown>,
|
|
249
|
+
nextValue: pending as unknown as Record<string, unknown>,
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
key: proposalKey,
|
|
253
|
+
expectedValue: null,
|
|
254
|
+
nextValue: proposal as unknown as Record<string, unknown>,
|
|
255
|
+
},
|
|
256
|
+
];
|
|
259
257
|
if (pending.priorProposalId && pending.priorRepromptId) {
|
|
260
258
|
const priorProposalKey = designRepromptProposalStateKey(
|
|
261
259
|
file.designId,
|
|
@@ -264,9 +262,19 @@ export default defineAction({
|
|
|
264
262
|
);
|
|
265
263
|
const priorProposal = await readAppState(priorProposalKey);
|
|
266
264
|
if (priorProposal?.proposalId === pending.priorProposalId) {
|
|
267
|
-
|
|
265
|
+
publishOperations.push({
|
|
266
|
+
key: priorProposalKey,
|
|
267
|
+
expectedValue: priorProposal,
|
|
268
|
+
nextValue: null,
|
|
269
|
+
});
|
|
268
270
|
}
|
|
269
271
|
}
|
|
272
|
+
const published = await compareAndSetManyAppState(publishOperations);
|
|
273
|
+
if (!published) {
|
|
274
|
+
throw new Error(
|
|
275
|
+
"This regeneration was superseded by a newer request before its candidates were published.",
|
|
276
|
+
);
|
|
277
|
+
}
|
|
270
278
|
|
|
271
279
|
const bridgeMessages: NodeHtmlPreviewBridgeMessage[] = [
|
|
272
280
|
{
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { defineAction } from "@agent-native/core";
|
|
2
2
|
import {
|
|
3
3
|
compareAndSetAppState,
|
|
4
|
+
compareAndSetManyAppState,
|
|
4
5
|
listAppState,
|
|
5
6
|
readAppState,
|
|
6
7
|
} from "@agent-native/core/application-state";
|
|
7
8
|
import { accessFilter, assertAccess } from "@agent-native/core/sharing";
|
|
8
9
|
import { and, eq } from "drizzle-orm";
|
|
10
|
+
import { nanoid } from "nanoid";
|
|
9
11
|
import { z } from "zod";
|
|
10
12
|
|
|
11
13
|
import { getDb, schema } from "../server/db/index.js";
|
|
@@ -22,6 +24,7 @@ import {
|
|
|
22
24
|
isPendingDesignReprompt,
|
|
23
25
|
spliceNodeRewriteVariant,
|
|
24
26
|
type NodeHtmlPreviewBridgeMessage,
|
|
27
|
+
type NodeRewriteResolutionClaim,
|
|
25
28
|
type NodeRewriteProposal,
|
|
26
29
|
} from "../shared/node-rewrite.js";
|
|
27
30
|
import { designSourceTypeFromData } from "../shared/source-mode.js";
|
|
@@ -142,22 +145,19 @@ async function clearProposalState(
|
|
|
142
145
|
proposalKey: string,
|
|
143
146
|
proposal: NodeRewriteProposal,
|
|
144
147
|
pending: Record<string, unknown>,
|
|
145
|
-
): Promise<
|
|
148
|
+
): Promise<boolean> {
|
|
146
149
|
const pendingKey = designRepromptPendingStateKey(
|
|
147
150
|
proposal.designId,
|
|
148
151
|
proposal.fileId,
|
|
149
152
|
);
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
proposalKey,
|
|
153
|
-
proposal as unknown as Record<string, unknown>,
|
|
154
|
-
null,
|
|
155
|
-
|
|
156
|
-
|
|
153
|
+
return compareAndSetManyAppState([
|
|
154
|
+
{
|
|
155
|
+
key: proposalKey,
|
|
156
|
+
expectedValue: proposal as unknown as Record<string, unknown>,
|
|
157
|
+
nextValue: null,
|
|
158
|
+
},
|
|
159
|
+
{ key: pendingKey, expectedValue: pending, nextValue: null },
|
|
157
160
|
]);
|
|
158
|
-
if (!proposalCleared) {
|
|
159
|
-
throw new Error("Node rewrite proposal changed while it was resolving.");
|
|
160
|
-
}
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
export default defineAction({
|
|
@@ -195,7 +195,16 @@ export default defineAction({
|
|
|
195
195
|
|
|
196
196
|
if (resolution === "reject") {
|
|
197
197
|
await assertAccess("design", proposal.designId, "editor");
|
|
198
|
-
await clearProposalState(
|
|
198
|
+
const cleanupComplete = await clearProposalState(
|
|
199
|
+
proposalKey,
|
|
200
|
+
proposal,
|
|
201
|
+
pending,
|
|
202
|
+
);
|
|
203
|
+
if (!cleanupComplete) {
|
|
204
|
+
throw new Error(
|
|
205
|
+
"The proposal changed while it was being rejected. Review the latest candidates instead.",
|
|
206
|
+
);
|
|
207
|
+
}
|
|
199
208
|
return {
|
|
200
209
|
proposalId,
|
|
201
210
|
repromptId: proposal.repromptId,
|
|
@@ -234,13 +243,51 @@ export default defineAction({
|
|
|
234
243
|
source,
|
|
235
244
|
fileType: file.fileType,
|
|
236
245
|
});
|
|
237
|
-
const
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
246
|
+
const claim: NodeRewriteResolutionClaim = {
|
|
247
|
+
...pending,
|
|
248
|
+
status: "resolving",
|
|
249
|
+
claimId: `node-rewrite-claim-${nanoid()}`,
|
|
250
|
+
proposalId,
|
|
251
|
+
resolution: "accept",
|
|
252
|
+
};
|
|
253
|
+
const claimValue = claim as unknown as Record<string, unknown>;
|
|
254
|
+
const claimed = await compareAndSetAppState(
|
|
255
|
+
pendingKey,
|
|
256
|
+
pending,
|
|
257
|
+
claimValue,
|
|
258
|
+
);
|
|
259
|
+
if (!claimed) {
|
|
260
|
+
throw new Error(
|
|
261
|
+
"A newer regeneration request replaced this proposal before it could be accepted.",
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
let write;
|
|
266
|
+
try {
|
|
267
|
+
write = await writeInlineSourceFile({
|
|
268
|
+
designId: file.designId,
|
|
269
|
+
file,
|
|
270
|
+
content: rewrite.content,
|
|
271
|
+
expectedVersionHash: proposal.baseVersionHash,
|
|
272
|
+
});
|
|
273
|
+
} catch (error) {
|
|
274
|
+
const released = await compareAndSetAppState(
|
|
275
|
+
pendingKey,
|
|
276
|
+
claimValue,
|
|
277
|
+
pending,
|
|
278
|
+
);
|
|
279
|
+
if (!released) {
|
|
280
|
+
throw new Error(
|
|
281
|
+
"The design write failed and its regeneration reservation could not be restored.",
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
throw error;
|
|
285
|
+
}
|
|
286
|
+
const cleanupComplete = await clearProposalState(
|
|
287
|
+
proposalKey,
|
|
288
|
+
proposal,
|
|
289
|
+
claimValue,
|
|
290
|
+
);
|
|
244
291
|
|
|
245
292
|
return {
|
|
246
293
|
proposalId,
|
|
@@ -252,6 +299,7 @@ export default defineAction({
|
|
|
252
299
|
designId: file.designId,
|
|
253
300
|
fileId: file.id,
|
|
254
301
|
versionHash: write.versionHash,
|
|
302
|
+
cleanupComplete,
|
|
255
303
|
};
|
|
256
304
|
},
|
|
257
305
|
});
|
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
useActionMutation,
|
|
3
3
|
useActionQuery,
|
|
4
4
|
} from "@agent-native/core/client/hooks";
|
|
5
|
+
import { withBuilderUtmTrackingParams } from "@agent-native/core/shared";
|
|
5
6
|
import {
|
|
6
7
|
IconAlertTriangle,
|
|
7
8
|
IconApps,
|
|
@@ -315,7 +316,14 @@ export function FusionAppBanner({
|
|
|
315
316
|
</DropdownMenuTrigger>
|
|
316
317
|
<DropdownMenuContent align="end">
|
|
317
318
|
<DropdownMenuItem asChild className="cursor-pointer">
|
|
318
|
-
<a
|
|
319
|
+
<a
|
|
320
|
+
href={withBuilderUtmTrackingParams(editorUrl, {
|
|
321
|
+
campaign: "product",
|
|
322
|
+
content: "fusion_editor",
|
|
323
|
+
})}
|
|
324
|
+
target="_blank"
|
|
325
|
+
rel="noreferrer"
|
|
326
|
+
>
|
|
319
327
|
<IconExternalLink className="me-2 size-3.5" />
|
|
320
328
|
{
|
|
321
329
|
"Open in Builder" /* i18n-ignore fusion app banner, flag-gated feature */
|
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
useActionQuery,
|
|
4
4
|
} from "@agent-native/core/client/hooks";
|
|
5
5
|
import { useT } from "@agent-native/core/client/i18n";
|
|
6
|
+
import { withBuilderUtmTrackingParams } from "@agent-native/core/shared";
|
|
6
7
|
import { propNameToDataAttribute } from "@shared/component-model";
|
|
7
8
|
import {
|
|
8
9
|
IconArrowRight,
|
|
@@ -168,7 +169,10 @@ function MakeItRealCard({
|
|
|
168
169
|
`Generating ${migrateResult.branchName ?? "React app"}.`}
|
|
169
170
|
</p>
|
|
170
171
|
<a
|
|
171
|
-
href={migrateResult.url
|
|
172
|
+
href={withBuilderUtmTrackingParams(migrateResult.url, {
|
|
173
|
+
campaign: "product",
|
|
174
|
+
content: "design_migration",
|
|
175
|
+
})}
|
|
172
176
|
target="_blank"
|
|
173
177
|
rel="noopener noreferrer"
|
|
174
178
|
className="inline-flex h-6 shrink-0 items-center gap-1 rounded-md px-1.5 text-[10px] font-semibold text-[var(--design-editor-accent-color)] hover:bg-[var(--design-editor-panel-raised-bg)]"
|
|
@@ -1,12 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
callAction,
|
|
3
|
-
setClientAppState,
|
|
4
3
|
useActionMutation,
|
|
5
4
|
useChangeVersion,
|
|
6
5
|
} from "@agent-native/core/client/hooks";
|
|
7
6
|
import { useT } from "@agent-native/core/client/i18n";
|
|
8
7
|
import {
|
|
9
|
-
designRepromptPendingStateKey,
|
|
10
8
|
isNodeRewriteProposal,
|
|
11
9
|
type NodeHtmlPreviewBridgeMessage,
|
|
12
10
|
type NodeRewriteProposal,
|
|
@@ -426,7 +424,6 @@ export function NodeRewriteProposal({
|
|
|
426
424
|
if (!proposal || !instruction || refining || resolveMutation.isPending)
|
|
427
425
|
return;
|
|
428
426
|
const repromptId = crypto.randomUUID();
|
|
429
|
-
const pendingKey = designRepromptPendingStateKey(designId, fileId);
|
|
430
427
|
const pending = {
|
|
431
428
|
repromptId,
|
|
432
429
|
designId,
|
|
@@ -440,7 +437,7 @@ export function NodeRewriteProposal({
|
|
|
440
437
|
};
|
|
441
438
|
setRefining(true);
|
|
442
439
|
try {
|
|
443
|
-
await
|
|
440
|
+
await callAction("begin-node-rewrite-request", pending);
|
|
444
441
|
const submission = formatNodeRepromptSubmission({
|
|
445
442
|
...pending,
|
|
446
443
|
priorProposalId: proposal.proposalId,
|
|
@@ -10,10 +10,7 @@ import {
|
|
|
10
10
|
type ReviewThread,
|
|
11
11
|
} from "@agent-native/core/client/review";
|
|
12
12
|
import type { ReviewComment } from "@agent-native/core/review";
|
|
13
|
-
import {
|
|
14
|
-
designRepromptPendingStateKey,
|
|
15
|
-
type NodeRewriteTarget,
|
|
16
|
-
} from "@shared/node-rewrite";
|
|
13
|
+
import type { NodeRewriteTarget } from "@shared/node-rewrite";
|
|
17
14
|
import {
|
|
18
15
|
IconArrowUp,
|
|
19
16
|
IconChevronDown,
|
|
@@ -874,10 +871,9 @@ export function ReviewCanvasPins({
|
|
|
874
871
|
element = null;
|
|
875
872
|
}
|
|
876
873
|
}
|
|
877
|
-
const stateKey = designRepromptPendingStateKey(resourceId, targetId);
|
|
878
874
|
setAgentSubmitting(true);
|
|
879
875
|
try {
|
|
880
|
-
await
|
|
876
|
+
await callAction("begin-node-rewrite-request", pending);
|
|
881
877
|
const submission = formatNodeRepromptSubmission({
|
|
882
878
|
...pending,
|
|
883
879
|
subtreeHtml:
|
|
@@ -2,6 +2,7 @@ import { appApiPath } from "@agent-native/core/client/api-path";
|
|
|
2
2
|
import { useActionQuery } from "@agent-native/core/client/hooks";
|
|
3
3
|
import { useT } from "@agent-native/core/client/i18n";
|
|
4
4
|
import { openAgentSidebar } from "@agent-native/core/client/navigation";
|
|
5
|
+
import { withBuilderUtmTrackingParams } from "@agent-native/core/shared";
|
|
5
6
|
import {
|
|
6
7
|
useSetPageTitle,
|
|
7
8
|
useSetHeaderActions,
|
|
@@ -1128,7 +1129,14 @@ function BuilderIndexPreview({
|
|
|
1128
1129
|
<div className="flex items-center gap-2 border-t border-border pt-4">
|
|
1129
1130
|
{result.builderUrl ? (
|
|
1130
1131
|
<Button asChild className="cursor-pointer">
|
|
1131
|
-
<a
|
|
1132
|
+
<a
|
|
1133
|
+
href={withBuilderUtmTrackingParams(result.builderUrl, {
|
|
1134
|
+
campaign: "product",
|
|
1135
|
+
content: "design_system_intelligence",
|
|
1136
|
+
})}
|
|
1137
|
+
target="_blank"
|
|
1138
|
+
rel="noreferrer"
|
|
1139
|
+
>
|
|
1132
1140
|
<IconExternalLink className="size-4" />
|
|
1133
1141
|
{"Open in Builder" /* i18n-ignore Builder link action */}
|
|
1134
1142
|
</a>
|
|
@@ -15,6 +15,7 @@ export const MAX_NODE_REWRITE_PROPOSAL_BYTES = 256 * 1024;
|
|
|
15
15
|
export type NodeRewriteTarget = EditIntentTarget;
|
|
16
16
|
|
|
17
17
|
export interface PendingDesignReprompt {
|
|
18
|
+
status?: "pending";
|
|
18
19
|
repromptId: string;
|
|
19
20
|
designId: string;
|
|
20
21
|
fileId: string;
|
|
@@ -26,6 +27,16 @@ export interface PendingDesignReprompt {
|
|
|
26
27
|
priorRepromptId?: string;
|
|
27
28
|
}
|
|
28
29
|
|
|
30
|
+
export interface NodeRewriteResolutionClaim extends Omit<
|
|
31
|
+
PendingDesignReprompt,
|
|
32
|
+
"status"
|
|
33
|
+
> {
|
|
34
|
+
status: "resolving";
|
|
35
|
+
claimId: string;
|
|
36
|
+
proposalId: string;
|
|
37
|
+
resolution: "accept";
|
|
38
|
+
}
|
|
39
|
+
|
|
29
40
|
export interface NodeRewriteVariant {
|
|
30
41
|
html: string;
|
|
31
42
|
summary: string;
|
|
@@ -69,6 +80,7 @@ export function isPendingDesignReprompt(
|
|
|
69
80
|
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
70
81
|
const pending = value as Partial<PendingDesignReprompt>;
|
|
71
82
|
return (
|
|
83
|
+
(pending.status === undefined || pending.status === "pending") &&
|
|
72
84
|
typeof pending.repromptId === "string" &&
|
|
73
85
|
typeof pending.designId === "string" &&
|
|
74
86
|
typeof pending.fileId === "string" &&
|
|
@@ -79,6 +91,26 @@ export function isPendingDesignReprompt(
|
|
|
79
91
|
);
|
|
80
92
|
}
|
|
81
93
|
|
|
94
|
+
export function isNodeRewriteResolutionClaim(
|
|
95
|
+
value: unknown,
|
|
96
|
+
): value is NodeRewriteResolutionClaim {
|
|
97
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return false;
|
|
98
|
+
const claim = value as Partial<NodeRewriteResolutionClaim>;
|
|
99
|
+
return (
|
|
100
|
+
claim.status === "resolving" &&
|
|
101
|
+
typeof claim.claimId === "string" &&
|
|
102
|
+
typeof claim.proposalId === "string" &&
|
|
103
|
+
claim.resolution === "accept" &&
|
|
104
|
+
typeof claim.repromptId === "string" &&
|
|
105
|
+
typeof claim.designId === "string" &&
|
|
106
|
+
typeof claim.fileId === "string" &&
|
|
107
|
+
typeof claim.baseVersionHash === "string" &&
|
|
108
|
+
typeof claim.instruction === "string" &&
|
|
109
|
+
typeof claim.createdAt === "string" &&
|
|
110
|
+
Boolean(claim.target)
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
82
114
|
export interface NodeHtmlPreviewBridgeMessage {
|
|
83
115
|
type: "node-html-preview";
|
|
84
116
|
proposalId: string;
|
|
@@ -12,6 +12,7 @@ import { FeedbackButton } from "@agent-native/core/client/ui";
|
|
|
12
12
|
import {
|
|
13
13
|
IconArrowUp,
|
|
14
14
|
IconPlus,
|
|
15
|
+
IconLoader2,
|
|
15
16
|
IconMenu2,
|
|
16
17
|
IconX,
|
|
17
18
|
IconMessageCircle,
|
|
@@ -88,11 +89,9 @@ export function Sidebar() {
|
|
|
88
89
|
|
|
89
90
|
function handleSkip() {
|
|
90
91
|
setPopoverOpen(false);
|
|
91
|
-
const tempId = crypto.randomUUID().replace(/-/g, "").slice(0, 10);
|
|
92
|
-
navigate(`/forms/${tempId}`);
|
|
93
92
|
createForm.mutate(
|
|
94
93
|
{ title: t("sidebar.untitledForm") },
|
|
95
|
-
{ onSuccess: (form) => navigate(`/forms/${form.id}
|
|
94
|
+
{ onSuccess: (form) => navigate(`/forms/${form.id}`) },
|
|
96
95
|
);
|
|
97
96
|
}
|
|
98
97
|
|
|
@@ -171,7 +170,11 @@ export function Sidebar() {
|
|
|
171
170
|
size="sm"
|
|
172
171
|
className="min-h-10 px-2 text-xs text-muted-foreground active:scale-[0.96] transition-[background-color,color,transform]"
|
|
173
172
|
onClick={handleSkip}
|
|
173
|
+
disabled={createForm.isPending}
|
|
174
174
|
>
|
|
175
|
+
{createForm.isPending && (
|
|
176
|
+
<IconLoader2 className="h-3 w-3 animate-spin" />
|
|
177
|
+
)}
|
|
175
178
|
{t("sidebar.skipPrompt")}
|
|
176
179
|
</Button>
|
|
177
180
|
<span className="text-[11px] text-muted-foreground/70">
|
|
@@ -626,20 +626,15 @@ export function FormBuilderPage() {
|
|
|
626
626
|
</Tooltip>
|
|
627
627
|
)}
|
|
628
628
|
|
|
629
|
-
|
|
630
|
-
<
|
|
631
|
-
<
|
|
629
|
+
{form.status === "published" && (
|
|
630
|
+
<Tooltip>
|
|
631
|
+
<TooltipTrigger asChild>
|
|
632
632
|
<Button
|
|
633
633
|
variant="ghost"
|
|
634
634
|
size="icon"
|
|
635
635
|
className="h-10 w-10 active:scale-[0.96] motion-reduce:active:scale-100"
|
|
636
636
|
onClick={copyShareLink}
|
|
637
|
-
|
|
638
|
-
aria-label={
|
|
639
|
-
form.status === "published"
|
|
640
|
-
? t("builder.copyPublicFormLink")
|
|
641
|
-
: t("builder.publishBeforeCopyPublicFormLink")
|
|
642
|
-
}
|
|
637
|
+
aria-label={t("builder.copyPublicFormLink")}
|
|
643
638
|
>
|
|
644
639
|
<span className="relative inline-flex h-4 w-4 items-center justify-center">
|
|
645
640
|
<IconCopy
|
|
@@ -660,16 +655,14 @@ export function FormBuilderPage() {
|
|
|
660
655
|
/>
|
|
661
656
|
</span>
|
|
662
657
|
</Button>
|
|
663
|
-
</
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
{form.status === "published"
|
|
667
|
-
? copied
|
|
658
|
+
</TooltipTrigger>
|
|
659
|
+
<TooltipContent>
|
|
660
|
+
{copied
|
|
668
661
|
? t("builder.publicLinkCopied")
|
|
669
|
-
: t("builder.copyPublishedPublicLink")
|
|
670
|
-
|
|
671
|
-
</
|
|
672
|
-
|
|
662
|
+
: t("builder.copyPublishedPublicLink")}
|
|
663
|
+
</TooltipContent>
|
|
664
|
+
</Tooltip>
|
|
665
|
+
)}
|
|
673
666
|
|
|
674
667
|
<Tooltip>
|
|
675
668
|
<TooltipTrigger asChild>
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import { VisibilityBadge } from "@agent-native/toolkit/sharing";
|
|
8
8
|
import {
|
|
9
9
|
IconPlus,
|
|
10
|
+
IconLoader2,
|
|
10
11
|
IconDots,
|
|
11
12
|
IconTrash,
|
|
12
13
|
IconCopy,
|
|
@@ -100,11 +101,9 @@ export function FormsListPage() {
|
|
|
100
101
|
}, [forms]);
|
|
101
102
|
|
|
102
103
|
function handleCreate() {
|
|
103
|
-
const tempId = crypto.randomUUID().replace(/-/g, "").slice(0, 10);
|
|
104
|
-
navigate(`/forms/${tempId}`);
|
|
105
104
|
createForm.mutate(
|
|
106
105
|
{ title: t("forms.untitled") },
|
|
107
|
-
{ onSuccess: (form) => navigate(`/forms/${form.id}
|
|
106
|
+
{ onSuccess: (form) => navigate(`/forms/${form.id}`) },
|
|
108
107
|
);
|
|
109
108
|
}
|
|
110
109
|
|
|
@@ -114,16 +113,21 @@ export function FormsListPage() {
|
|
|
114
113
|
() => (
|
|
115
114
|
<Button
|
|
116
115
|
onClick={handleCreate}
|
|
116
|
+
disabled={createForm.isPending}
|
|
117
117
|
size="sm"
|
|
118
118
|
className="min-h-10 shrink-0 cursor-pointer active:scale-[0.96] transition-[background-color,box-shadow,transform]"
|
|
119
119
|
>
|
|
120
|
-
|
|
120
|
+
{createForm.isPending ? (
|
|
121
|
+
<IconLoader2 className="h-3.5 w-3.5 animate-spin" />
|
|
122
|
+
) : (
|
|
123
|
+
<IconPlus className="h-3.5 w-3.5" />
|
|
124
|
+
)}
|
|
121
125
|
<span className="hidden sm:inline">{t("forms.newForm")}</span>
|
|
122
126
|
<span className="sm:hidden">{t("forms.new")}</span>
|
|
123
127
|
</Button>
|
|
124
128
|
),
|
|
125
129
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
126
|
-
[],
|
|
130
|
+
[createForm.isPending],
|
|
127
131
|
);
|
|
128
132
|
useSetHeaderActions(headerActions);
|
|
129
133
|
|