@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
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from "@agent-native/core/client/hooks";
|
|
7
7
|
import { useT } from "@agent-native/core/client/i18n";
|
|
8
8
|
import { openAgentSidebar } from "@agent-native/core/client/navigation";
|
|
9
|
+
import { withBuilderUtmTrackingParams } from "@agent-native/core/shared";
|
|
9
10
|
import {
|
|
10
11
|
IconWorld,
|
|
11
12
|
IconPalette,
|
|
@@ -921,7 +922,14 @@ function BuilderIndexPreview({
|
|
|
921
922
|
|
|
922
923
|
<div className="flex flex-wrap items-center gap-2 border-t border-border pt-3">
|
|
923
924
|
<Button size="sm" asChild className="cursor-pointer">
|
|
924
|
-
<a
|
|
925
|
+
<a
|
|
926
|
+
href={withBuilderUtmTrackingParams(result.builderUrl, {
|
|
927
|
+
campaign: "product",
|
|
928
|
+
content: "design_system_intelligence",
|
|
929
|
+
})}
|
|
930
|
+
target="_blank"
|
|
931
|
+
rel="noreferrer"
|
|
932
|
+
>
|
|
925
933
|
<IconExternalLink className="w-3.5 h-3.5" />
|
|
926
934
|
{t("designSystemSetup.openInBuilder")}
|
|
927
935
|
</a>
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "@agent-native/core/client/collab";
|
|
10
10
|
import { callAction } from "@agent-native/core/client/hooks";
|
|
11
11
|
import { isEmbedAuthActive } from "@agent-native/core/client/host";
|
|
12
|
+
import { useOrg } from "@agent-native/core/client/org";
|
|
12
13
|
import { nanoid } from "nanoid";
|
|
13
14
|
import {
|
|
14
15
|
createContext,
|
|
@@ -950,6 +951,7 @@ export const defaultSlideContent: Record<SlideLayout, string> = {
|
|
|
950
951
|
};
|
|
951
952
|
|
|
952
953
|
export function DeckProvider({ children }: { children: ReactNode }) {
|
|
954
|
+
const { data: org } = useOrg();
|
|
953
955
|
const [decks, setDecks] = useState<Deck[]>([]);
|
|
954
956
|
const [loading, setLoading] = useState(true);
|
|
955
957
|
const [loadError, setLoadError] = useState(false);
|
|
@@ -1269,6 +1271,22 @@ export function DeckProvider({ children }: { children: ReactNode }) {
|
|
|
1269
1271
|
});
|
|
1270
1272
|
}, [resetDeckBaseline]);
|
|
1271
1273
|
|
|
1274
|
+
// Switching orgs re-scopes list-decks server-side but leaves this context's
|
|
1275
|
+
// in-memory list untouched, so the previous org's decks linger. Reload when
|
|
1276
|
+
// the org id actually changes; skip the first observed id so we don't double
|
|
1277
|
+
// up on the mount fetch above.
|
|
1278
|
+
const lastOrgIdRef = useRef<string | null | undefined>(undefined);
|
|
1279
|
+
useEffect(() => {
|
|
1280
|
+
const orgId = org?.orgId ?? null;
|
|
1281
|
+
if (lastOrgIdRef.current === undefined) {
|
|
1282
|
+
lastOrgIdRef.current = orgId;
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
if (lastOrgIdRef.current === orgId) return;
|
|
1286
|
+
lastOrgIdRef.current = orgId;
|
|
1287
|
+
void reloadDecks();
|
|
1288
|
+
}, [org?.orgId, reloadDecks]);
|
|
1289
|
+
|
|
1272
1290
|
// Fallback polling for deck list + open-deck changes. SSE is the primary
|
|
1273
1291
|
// path; this catches agent/db writes that bypass it without hammering idle
|
|
1274
1292
|
// editor pages.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { IconPlus } from "@tabler/icons-react";
|
|
2
3
|
import { useState, type FormEvent } from "react";
|
|
3
4
|
|
|
@@ -17,17 +18,7 @@ import type { FieldConfig, FieldType } from "@/hooks/use-custom-fields";
|
|
|
17
18
|
import { FieldConfigControl } from "./editor/config/FieldConfigControl";
|
|
18
19
|
import { normalizedInitialConfig } from "./editor/config/utils";
|
|
19
20
|
import type { FieldDraft } from "./editor/types";
|
|
20
|
-
|
|
21
|
-
const FIELD_TYPE_OPTIONS: Array<{ value: FieldType; label: string }> = [
|
|
22
|
-
{ value: "text", label: "Text" },
|
|
23
|
-
{ value: "rich_text", label: "Rich text" },
|
|
24
|
-
{ value: "number", label: "Number" },
|
|
25
|
-
{ value: "percent", label: "Percent" },
|
|
26
|
-
{ value: "currency", label: "Currency" },
|
|
27
|
-
{ value: "single_select", label: "Single-select" },
|
|
28
|
-
{ value: "multi_select", label: "Multi-select" },
|
|
29
|
-
{ value: "date", label: "Date" },
|
|
30
|
-
];
|
|
21
|
+
import { FIELD_TYPE_LABEL_KEYS, FIELD_TYPE_VALUES } from "./field-types";
|
|
31
22
|
|
|
32
23
|
const FIELD_TYPES_WITH_CONFIG = new Set<FieldType>([
|
|
33
24
|
"currency",
|
|
@@ -44,6 +35,7 @@ export function FieldCreateBar({
|
|
|
44
35
|
busy: boolean;
|
|
45
36
|
onCreate: (draft: FieldDraft) => Promise<void>;
|
|
46
37
|
}) {
|
|
38
|
+
const t = useT();
|
|
47
39
|
const [title, setTitle] = useState("");
|
|
48
40
|
const [type, setType] = useState<FieldType>("text");
|
|
49
41
|
const [config, setConfig] = useState<FieldConfig>(
|
|
@@ -71,16 +63,18 @@ export function FieldCreateBar({
|
|
|
71
63
|
onSubmit={(event) => void handleSubmit(event)}
|
|
72
64
|
className="grid shrink-0 gap-3 rounded-lg border border-border bg-card p-3 md:grid-cols-[minmax(180px,1fr)_180px_auto] md:items-start"
|
|
73
65
|
>
|
|
74
|
-
<h2 className="text-sm font-medium md:col-span-3">
|
|
66
|
+
<h2 className="text-sm font-medium md:col-span-3">
|
|
67
|
+
{t("fields.createNewFieldHeading")}
|
|
68
|
+
</h2>
|
|
75
69
|
<div className="grid gap-2">
|
|
76
70
|
<Label htmlFor="new-field-title" className="sr-only">
|
|
77
|
-
|
|
71
|
+
{t("fields.fieldTitleLabel")}
|
|
78
72
|
</Label>
|
|
79
73
|
<Input
|
|
80
74
|
id="new-field-title"
|
|
81
75
|
value={title}
|
|
82
76
|
disabled={busy}
|
|
83
|
-
placeholder="
|
|
77
|
+
placeholder={t("fields.newFieldTitlePlaceholder")}
|
|
84
78
|
onChange={(event) => setTitle(event.currentTarget.value)}
|
|
85
79
|
/>
|
|
86
80
|
</div>
|
|
@@ -89,14 +83,14 @@ export function FieldCreateBar({
|
|
|
89
83
|
disabled={busy}
|
|
90
84
|
onValueChange={(value) => handleTypeChange(value as FieldType)}
|
|
91
85
|
>
|
|
92
|
-
<SelectTrigger aria-label="
|
|
86
|
+
<SelectTrigger aria-label={t("fields.fieldTypeAriaLabel")}>
|
|
93
87
|
<SelectValue />
|
|
94
88
|
</SelectTrigger>
|
|
95
89
|
<SelectContent>
|
|
96
90
|
<SelectGroup>
|
|
97
|
-
{
|
|
98
|
-
<SelectItem key={
|
|
99
|
-
{
|
|
91
|
+
{FIELD_TYPE_VALUES.map((value) => (
|
|
92
|
+
<SelectItem key={value} value={value}>
|
|
93
|
+
{t(FIELD_TYPE_LABEL_KEYS[value])}
|
|
100
94
|
</SelectItem>
|
|
101
95
|
))}
|
|
102
96
|
</SelectGroup>
|
|
@@ -104,7 +98,7 @@ export function FieldCreateBar({
|
|
|
104
98
|
</Select>
|
|
105
99
|
<Button type="submit" disabled={busy || title.trim().length === 0}>
|
|
106
100
|
<IconPlus className="size-4" />
|
|
107
|
-
|
|
101
|
+
{t("fields.createButton")}
|
|
108
102
|
</Button>
|
|
109
103
|
{FIELD_TYPES_WITH_CONFIG.has(type) ? (
|
|
110
104
|
<div className="md:col-span-3">
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { IconTrash } from "@tabler/icons-react";
|
|
2
3
|
|
|
3
4
|
import type { SortableItemRenderProps } from "@/components/dnd/SortableItem";
|
|
@@ -7,47 +8,48 @@ import { Badge } from "@/components/ui/badge";
|
|
|
7
8
|
import { Button } from "@/components/ui/button";
|
|
8
9
|
import type { FieldDefinition, FieldType } from "@/hooks/use-custom-fields";
|
|
9
10
|
|
|
10
|
-
|
|
11
|
-
text: "Text",
|
|
12
|
-
rich_text: "Rich text",
|
|
13
|
-
number: "Number",
|
|
14
|
-
percent: "Percent",
|
|
15
|
-
currency: "Currency",
|
|
16
|
-
single_select: "Single-select",
|
|
17
|
-
multi_select: "Multi-select",
|
|
18
|
-
date: "Date",
|
|
19
|
-
};
|
|
11
|
+
import { FIELD_TYPE_LABEL_KEYS } from "./field-types";
|
|
20
12
|
|
|
21
|
-
|
|
22
|
-
|
|
13
|
+
type Translate = ReturnType<typeof useT>;
|
|
14
|
+
|
|
15
|
+
function fieldTypeLabel(t: Translate, type: FieldType) {
|
|
16
|
+
const key = FIELD_TYPE_LABEL_KEYS[type];
|
|
17
|
+
return key ? t(key) : type;
|
|
23
18
|
}
|
|
24
19
|
|
|
25
|
-
function fieldDescription(field: FieldDefinition) {
|
|
26
|
-
if (field.type === "currency")
|
|
20
|
+
function fieldDescription(t: Translate, field: FieldDefinition) {
|
|
21
|
+
if (field.type === "currency") {
|
|
22
|
+
return t("fields.currencyDescription", { symbol: field.config.symbol });
|
|
23
|
+
}
|
|
27
24
|
if (field.type === "number") {
|
|
28
25
|
const parts: string[] = [];
|
|
29
|
-
parts.push(
|
|
30
|
-
|
|
26
|
+
parts.push(
|
|
27
|
+
t("fields.decimalsDescription", { count: field.config.precision ?? 0 }),
|
|
28
|
+
);
|
|
29
|
+
if (field.config.positiveOnly) parts.push(t("fields.positiveOnlySuffix"));
|
|
31
30
|
return parts.join(" · ");
|
|
32
31
|
}
|
|
33
32
|
if (field.type === "percent") {
|
|
34
|
-
return
|
|
33
|
+
return t("fields.decimalsDescription", {
|
|
34
|
+
count: field.config.precision ?? 0,
|
|
35
|
+
});
|
|
35
36
|
}
|
|
36
37
|
if (field.type === "single_select" || field.type === "multi_select") {
|
|
37
38
|
const options = "options" in field.config ? field.config.options : [];
|
|
38
|
-
return
|
|
39
|
+
return t("fields.optionsCountDescription", { count: options.length });
|
|
39
40
|
}
|
|
40
|
-
return fieldTypeLabel(field.type);
|
|
41
|
+
return fieldTypeLabel(t, field.type);
|
|
41
42
|
}
|
|
42
43
|
|
|
43
44
|
function FieldRowMetadata({ field }: { field: FieldDefinition }) {
|
|
45
|
+
const t = useT();
|
|
44
46
|
return (
|
|
45
47
|
<div className="flex min-w-0 flex-wrap items-center justify-end gap-1.5">
|
|
46
48
|
<Badge variant="secondary" className="px-1.5 py-0 text-xs font-normal">
|
|
47
|
-
{fieldTypeLabel(field.type)}
|
|
49
|
+
{fieldTypeLabel(t, field.type)}
|
|
48
50
|
</Badge>
|
|
49
51
|
<span className="truncate text-xs text-muted-foreground">
|
|
50
|
-
{fieldDescription(field)}
|
|
52
|
+
{fieldDescription(t, field)}
|
|
51
53
|
</span>
|
|
52
54
|
</div>
|
|
53
55
|
);
|
|
@@ -68,6 +70,7 @@ export function FieldListRow({
|
|
|
68
70
|
onOpenDetails,
|
|
69
71
|
onRequestDelete,
|
|
70
72
|
}: FieldListRowProps) {
|
|
73
|
+
const t = useT();
|
|
71
74
|
return (
|
|
72
75
|
<ListRow
|
|
73
76
|
sortable={sortable}
|
|
@@ -99,7 +102,9 @@ export function FieldListRow({
|
|
|
99
102
|
type="button"
|
|
100
103
|
variant="ghost"
|
|
101
104
|
size="icon"
|
|
102
|
-
aria-label={
|
|
105
|
+
aria-label={t("fields.deleteFieldAriaLabel", {
|
|
106
|
+
title: item.title,
|
|
107
|
+
})}
|
|
103
108
|
onPointerDown={(event) => event.stopPropagation()}
|
|
104
109
|
onClick={(event) => {
|
|
105
110
|
event.stopPropagation();
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { focusAgentChat } from "@agent-native/core/client/agent-chat";
|
|
2
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
3
|
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
3
4
|
import { toast } from "sonner";
|
|
4
5
|
|
|
@@ -37,6 +38,7 @@ export function FieldsList({
|
|
|
37
38
|
activeFieldId: string | null;
|
|
38
39
|
setActiveFieldId: (fieldId: string | null) => void;
|
|
39
40
|
}) {
|
|
41
|
+
const t = useT();
|
|
40
42
|
const { fields, isPending, isError, error } = useCustomFields();
|
|
41
43
|
const { fieldIds: visibleFieldIds } = useVisibleTaskFieldIds();
|
|
42
44
|
const updateVisibleTaskFields = useUpdateVisibleTaskFields();
|
|
@@ -79,9 +81,9 @@ export function FieldsList({
|
|
|
79
81
|
});
|
|
80
82
|
setActiveFieldId(created.id);
|
|
81
83
|
focusAgentChat();
|
|
82
|
-
toast.success("
|
|
84
|
+
toast.success(t("fields.createdToast"));
|
|
83
85
|
} catch (caught) {
|
|
84
|
-
toast.error((caught as Error)?.message ?? "
|
|
86
|
+
toast.error((caught as Error)?.message ?? t("fields.createError"));
|
|
85
87
|
throw caught;
|
|
86
88
|
}
|
|
87
89
|
}
|
|
@@ -94,10 +96,15 @@ export function FieldsList({
|
|
|
94
96
|
setPendingDelete(null);
|
|
95
97
|
if (activeFieldId === field.id) setActiveFieldId(null);
|
|
96
98
|
toast.success(
|
|
97
|
-
|
|
99
|
+
result.deletedValues
|
|
100
|
+
? t("fields.deletedWithValuesToast", {
|
|
101
|
+
title: field.title,
|
|
102
|
+
count: result.deletedValues,
|
|
103
|
+
})
|
|
104
|
+
: t("fields.deletedToast", { title: field.title }),
|
|
98
105
|
);
|
|
99
106
|
} catch (caught) {
|
|
100
|
-
toast.error((caught as Error)?.message ?? "
|
|
107
|
+
toast.error((caught as Error)?.message ?? t("fields.deleteError"));
|
|
101
108
|
}
|
|
102
109
|
}
|
|
103
110
|
|
|
@@ -122,7 +129,7 @@ export function FieldsList({
|
|
|
122
129
|
<div className="grid shrink-0 gap-3">
|
|
123
130
|
<FieldCreateBar busy={busy} onCreate={handleCreate} />
|
|
124
131
|
<ChipSelect
|
|
125
|
-
label="
|
|
132
|
+
label={t("fields.taskCardFieldsLabel")}
|
|
126
133
|
options={visibleFieldOptions}
|
|
127
134
|
selectedIds={visibleFieldIds}
|
|
128
135
|
onSelectedIdsChange={(fieldIds) =>
|
|
@@ -130,8 +137,8 @@ export function FieldsList({
|
|
|
130
137
|
}
|
|
131
138
|
disabled={busy || isPending || updateVisibleTaskFields.isPending}
|
|
132
139
|
limit={TASK_CARD_FIELD_LIMIT}
|
|
133
|
-
addButtonLabel="
|
|
134
|
-
emptyLabel="
|
|
140
|
+
addButtonLabel={t("fields.addFieldButtonLabel")}
|
|
141
|
+
emptyLabel={t("fields.noFieldsSelectedLabel")}
|
|
135
142
|
/>
|
|
136
143
|
</div>
|
|
137
144
|
|
|
@@ -140,22 +147,22 @@ export function FieldsList({
|
|
|
140
147
|
<FieldsListSkeleton />
|
|
141
148
|
) : isError ? (
|
|
142
149
|
<div
|
|
143
|
-
aria-label="
|
|
150
|
+
aria-label={t("fields.listAriaLabel")}
|
|
144
151
|
className="min-h-0 flex-1 overflow-y-auto overscroll-contain pr-1 outline-none"
|
|
145
152
|
>
|
|
146
153
|
<ListErrorMessage
|
|
147
154
|
error={error}
|
|
148
|
-
fallbackMessage="
|
|
155
|
+
fallbackMessage={t("fields.loadError")}
|
|
149
156
|
/>
|
|
150
157
|
</div>
|
|
151
158
|
) : orderedFields.length === 0 ? (
|
|
152
159
|
<div
|
|
153
|
-
aria-label="
|
|
160
|
+
aria-label={t("fields.listAriaLabel")}
|
|
154
161
|
className="min-h-0 flex-1 overflow-y-auto overscroll-contain pr-1 outline-none"
|
|
155
162
|
>
|
|
156
163
|
<ListEmptyState
|
|
157
|
-
heading="
|
|
158
|
-
description="
|
|
164
|
+
heading={t("fields.emptyHeading")}
|
|
165
|
+
description={t("fields.emptyDescription")}
|
|
159
166
|
/>
|
|
160
167
|
</div>
|
|
161
168
|
) : (
|
|
@@ -163,7 +170,7 @@ export function FieldsList({
|
|
|
163
170
|
<List
|
|
164
171
|
items={orderedFields}
|
|
165
172
|
selectionEnabled={false}
|
|
166
|
-
ariaLabel="
|
|
173
|
+
ariaLabel={t("fields.listAriaLabel")}
|
|
167
174
|
onReorder={handleReorder}
|
|
168
175
|
renderItem={({ item, sortable }) => (
|
|
169
176
|
<FieldListRow
|
|
@@ -198,18 +205,15 @@ export function FieldsList({
|
|
|
198
205
|
onOpenChange={(open) => {
|
|
199
206
|
if (!open) setPendingDelete(null);
|
|
200
207
|
}}
|
|
201
|
-
entityLabel="
|
|
208
|
+
entityLabel={t("fields.entitySingular")}
|
|
202
209
|
itemTitle={pendingDelete?.title ?? null}
|
|
203
210
|
pending={deleteField.isPending}
|
|
204
211
|
description={
|
|
205
|
-
pendingDelete
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
) : (
|
|
211
|
-
"This deletes the field and removes its values from every task."
|
|
212
|
-
)
|
|
212
|
+
pendingDelete
|
|
213
|
+
? t("fields.deleteFieldDescriptionWithTitle", {
|
|
214
|
+
title: pendingDelete.title,
|
|
215
|
+
})
|
|
216
|
+
: t("fields.deleteFieldDescription")
|
|
213
217
|
}
|
|
214
218
|
onConfirm={() => void handleDelete()}
|
|
215
219
|
/>
|
|
@@ -1,11 +1,14 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
+
|
|
1
3
|
import { Skeleton } from "@/components/ui/skeleton";
|
|
2
4
|
|
|
3
5
|
const SKELETON_ROW_COUNT = 3;
|
|
4
6
|
|
|
5
7
|
export function FieldsListSkeleton() {
|
|
8
|
+
const t = useT();
|
|
6
9
|
return (
|
|
7
10
|
<div
|
|
8
|
-
aria-label="
|
|
11
|
+
aria-label={t("fields.listAriaLabel")}
|
|
9
12
|
className="min-h-0 flex-1 overflow-y-auto overscroll-contain pr-1 outline-none"
|
|
10
13
|
>
|
|
11
14
|
<div className="grid gap-2">
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { useCallback } from "react";
|
|
2
3
|
import { useSearchParams } from "react-router";
|
|
3
4
|
|
|
@@ -5,6 +6,7 @@ import { FieldsList } from "@/components/custom-fields/FieldsList";
|
|
|
5
6
|
import { PageHeader } from "@/components/shared/PageHeader";
|
|
6
7
|
|
|
7
8
|
export function FieldsPage() {
|
|
9
|
+
const t = useT();
|
|
8
10
|
const [searchParams, setSearchParams] = useSearchParams();
|
|
9
11
|
const activeFieldId = searchParams.get("field");
|
|
10
12
|
|
|
@@ -29,8 +31,8 @@ export function FieldsPage() {
|
|
|
29
31
|
return (
|
|
30
32
|
<div className="mx-auto flex h-full min-h-0 w-full max-w-5xl flex-col gap-6 overflow-hidden p-4 md:p-6">
|
|
31
33
|
<PageHeader
|
|
32
|
-
title="
|
|
33
|
-
description="
|
|
34
|
+
title={t("fields.pageTitle")}
|
|
35
|
+
description={t("fields.pageDescription")}
|
|
34
36
|
/>
|
|
35
37
|
|
|
36
38
|
<FieldsList
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { useCallback } from "react";
|
|
2
3
|
import { toast } from "sonner";
|
|
3
4
|
|
|
@@ -19,10 +20,15 @@ export function FieldEditorSidebar({
|
|
|
19
20
|
disabled: boolean;
|
|
20
21
|
onClose: () => void;
|
|
21
22
|
}) {
|
|
23
|
+
const t = useT();
|
|
22
24
|
if (!field) return null;
|
|
23
25
|
|
|
24
26
|
return (
|
|
25
|
-
<SidePanel
|
|
27
|
+
<SidePanel
|
|
28
|
+
title={t("fieldEditor.panelTitle")}
|
|
29
|
+
closeLabel={t("fieldEditor.closeLabel")}
|
|
30
|
+
onClose={onClose}
|
|
31
|
+
>
|
|
26
32
|
<FieldEditorSidebarPanel field={field} disabled={disabled} />
|
|
27
33
|
</SidePanel>
|
|
28
34
|
);
|
|
@@ -35,6 +41,7 @@ function FieldEditorSidebarPanel({
|
|
|
35
41
|
field: FieldDefinition;
|
|
36
42
|
disabled: boolean;
|
|
37
43
|
}) {
|
|
44
|
+
const t = useT();
|
|
38
45
|
const updateField = useUpdateCustomField();
|
|
39
46
|
|
|
40
47
|
const saveUpdate = useCallback(
|
|
@@ -42,10 +49,12 @@ function FieldEditorSidebarPanel({
|
|
|
42
49
|
void updateField
|
|
43
50
|
.mutateAsync({ fieldId: field.id, ...payload })
|
|
44
51
|
.catch((caught) => {
|
|
45
|
-
toast.error(
|
|
52
|
+
toast.error(
|
|
53
|
+
(caught as Error)?.message ?? t("fieldEditor.updateError"),
|
|
54
|
+
);
|
|
46
55
|
});
|
|
47
56
|
},
|
|
48
|
-
[field.id, updateField],
|
|
57
|
+
[field.id, updateField, t],
|
|
49
58
|
);
|
|
50
59
|
|
|
51
60
|
return (
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
+
|
|
1
3
|
import { Input } from "@/components/ui/input";
|
|
2
4
|
import { Label } from "@/components/ui/label";
|
|
3
5
|
|
|
@@ -10,21 +12,22 @@ export function FieldTitleSection({
|
|
|
10
12
|
disabled?: boolean;
|
|
11
13
|
onChange: (title: string) => void;
|
|
12
14
|
}) {
|
|
15
|
+
const t = useT();
|
|
13
16
|
return (
|
|
14
17
|
<section className="grid gap-2 border-b border-border/70 px-3 py-3">
|
|
15
18
|
<div className="flex min-w-0 items-center justify-between gap-2">
|
|
16
19
|
<Label className="min-w-0 truncate text-[13px] font-medium">
|
|
17
|
-
|
|
20
|
+
{t("fieldEditor.titleLabel")}
|
|
18
21
|
</Label>
|
|
19
22
|
<span className="shrink-0 text-[11px] text-muted-foreground">
|
|
20
|
-
|
|
23
|
+
{t("fieldEditor.requiredLabel")}
|
|
21
24
|
</span>
|
|
22
25
|
</div>
|
|
23
26
|
<Input
|
|
24
27
|
value={title}
|
|
25
28
|
disabled={disabled}
|
|
26
29
|
onChange={(event) => onChange(event.currentTarget.value)}
|
|
27
|
-
aria-label="
|
|
30
|
+
aria-label={t("fieldEditor.editFieldTitleAriaLabel")}
|
|
28
31
|
className="h-9 text-[13px]"
|
|
29
32
|
/>
|
|
30
33
|
</section>
|
package/corpus/templates/tasks/app/components/custom-fields/editor/config/CurrencyConfigControl.tsx
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
+
|
|
1
3
|
import { Input } from "@/components/ui/input";
|
|
2
4
|
import { Label } from "@/components/ui/label";
|
|
3
5
|
|
|
@@ -12,10 +14,11 @@ export function CurrencyConfigControl({
|
|
|
12
14
|
onChange,
|
|
13
15
|
disabled = false,
|
|
14
16
|
}: FieldConfigControlProps) {
|
|
17
|
+
const t = useT();
|
|
15
18
|
return (
|
|
16
19
|
<div className="grid gap-3 sm:grid-cols-[96px_1fr]">
|
|
17
20
|
<div className="grid gap-2">
|
|
18
|
-
<Label>
|
|
21
|
+
<Label>{t("fieldEditor.symbolLabel")}</Label>
|
|
19
22
|
<Input
|
|
20
23
|
maxLength={8}
|
|
21
24
|
disabled={disabled}
|
|
@@ -29,7 +32,7 @@ export function CurrencyConfigControl({
|
|
|
29
32
|
/>
|
|
30
33
|
</div>
|
|
31
34
|
<div className="grid gap-2">
|
|
32
|
-
<Label>
|
|
35
|
+
<Label>{t("fieldEditor.precisionLabel")}</Label>
|
|
33
36
|
<Input
|
|
34
37
|
type="number"
|
|
35
38
|
min={0}
|
package/corpus/templates/tasks/app/components/custom-fields/editor/config/NumberConfigControl.tsx
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
+
|
|
1
3
|
import { Checkbox } from "@/components/ui/checkbox";
|
|
2
4
|
import { Input } from "@/components/ui/input";
|
|
3
5
|
import { Label } from "@/components/ui/label";
|
|
@@ -13,10 +15,11 @@ export function NumberConfigControl({
|
|
|
13
15
|
onChange,
|
|
14
16
|
disabled = false,
|
|
15
17
|
}: FieldConfigControlProps) {
|
|
18
|
+
const t = useT();
|
|
16
19
|
return (
|
|
17
20
|
<div className="grid gap-3">
|
|
18
21
|
<div className="grid gap-2">
|
|
19
|
-
<Label>
|
|
22
|
+
<Label>{t("fieldEditor.precisionLabel")}</Label>
|
|
20
23
|
<Input
|
|
21
24
|
type="number"
|
|
22
25
|
min={0}
|
|
@@ -44,7 +47,7 @@ export function NumberConfigControl({
|
|
|
44
47
|
})
|
|
45
48
|
}
|
|
46
49
|
/>
|
|
47
|
-
|
|
50
|
+
{t("fieldEditor.positiveOnlyLabel")}
|
|
48
51
|
</label>
|
|
49
52
|
</div>
|
|
50
53
|
</div>
|
package/corpus/templates/tasks/app/components/custom-fields/editor/config/PercentConfigControl.tsx
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
2
|
+
|
|
1
3
|
import { Input } from "@/components/ui/input";
|
|
2
4
|
import { Label } from "@/components/ui/label";
|
|
3
5
|
|
|
@@ -8,9 +10,10 @@ export function PercentConfigControl({
|
|
|
8
10
|
onChange,
|
|
9
11
|
disabled = false,
|
|
10
12
|
}: FieldConfigControlProps) {
|
|
13
|
+
const t = useT();
|
|
11
14
|
return (
|
|
12
15
|
<div className="grid gap-2">
|
|
13
|
-
<Label>
|
|
16
|
+
<Label>{t("fieldEditor.precisionLabel")}</Label>
|
|
14
17
|
<Input
|
|
15
18
|
type="number"
|
|
16
19
|
min={0}
|
package/corpus/templates/tasks/app/components/custom-fields/editor/config/SelectConfigControl.tsx
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { useT } from "@agent-native/core/client/i18n";
|
|
1
2
|
import { IconPlus, IconTrash } from "@tabler/icons-react";
|
|
2
3
|
|
|
3
4
|
import { Button } from "@/components/ui/button";
|
|
@@ -26,6 +27,7 @@ export function SelectConfigControl({
|
|
|
26
27
|
onChange,
|
|
27
28
|
disabled = false,
|
|
28
29
|
}: FieldConfigControlProps) {
|
|
30
|
+
const t = useT();
|
|
29
31
|
const options = optionsFromConfig(config);
|
|
30
32
|
|
|
31
33
|
function updateOption(
|
|
@@ -56,7 +58,7 @@ export function SelectConfigControl({
|
|
|
56
58
|
...options,
|
|
57
59
|
{
|
|
58
60
|
id: `opt_${crypto.randomUUID()}`,
|
|
59
|
-
name:
|
|
61
|
+
name: t("fieldEditor.newOptionName", { index: nextIndex }),
|
|
60
62
|
color: "gray",
|
|
61
63
|
sortOrder: options.length * 1000,
|
|
62
64
|
},
|
|
@@ -66,7 +68,7 @@ export function SelectConfigControl({
|
|
|
66
68
|
|
|
67
69
|
return (
|
|
68
70
|
<div className="grid gap-2">
|
|
69
|
-
<Label>
|
|
71
|
+
<Label>{t("fieldEditor.optionsLabel")}</Label>
|
|
70
72
|
<div className="grid gap-2">
|
|
71
73
|
{options.map((option, index) => (
|
|
72
74
|
<div
|
|
@@ -79,7 +81,9 @@ export function SelectConfigControl({
|
|
|
79
81
|
onChange={(event) =>
|
|
80
82
|
updateOption(index, { name: event.currentTarget.value })
|
|
81
83
|
}
|
|
82
|
-
aria-label={
|
|
84
|
+
aria-label={t("fieldEditor.optionNameAriaLabel", {
|
|
85
|
+
index: index + 1,
|
|
86
|
+
})}
|
|
83
87
|
/>
|
|
84
88
|
<Select
|
|
85
89
|
disabled={disabled}
|
|
@@ -88,7 +92,11 @@ export function SelectConfigControl({
|
|
|
88
92
|
updateOption(index, { color: value as SelectColorToken })
|
|
89
93
|
}
|
|
90
94
|
>
|
|
91
|
-
<SelectTrigger
|
|
95
|
+
<SelectTrigger
|
|
96
|
+
aria-label={t("fieldEditor.optionColorAriaLabel", {
|
|
97
|
+
name: option.name,
|
|
98
|
+
})}
|
|
99
|
+
>
|
|
92
100
|
<SelectValue />
|
|
93
101
|
</SelectTrigger>
|
|
94
102
|
<SelectContent>
|
|
@@ -99,7 +107,7 @@ export function SelectConfigControl({
|
|
|
99
107
|
<span
|
|
100
108
|
className={cn("size-2 rounded-full", color.className)}
|
|
101
109
|
/>
|
|
102
|
-
{color.
|
|
110
|
+
{t(color.labelKey)}
|
|
103
111
|
</span>
|
|
104
112
|
</SelectItem>
|
|
105
113
|
))}
|
|
@@ -112,7 +120,9 @@ export function SelectConfigControl({
|
|
|
112
120
|
size="icon"
|
|
113
121
|
disabled={disabled}
|
|
114
122
|
onClick={() => removeOption(index)}
|
|
115
|
-
aria-label={
|
|
123
|
+
aria-label={t("fieldEditor.removeOptionAriaLabel", {
|
|
124
|
+
name: option.name,
|
|
125
|
+
})}
|
|
116
126
|
>
|
|
117
127
|
<IconTrash className="size-4" />
|
|
118
128
|
</Button>
|
|
@@ -127,7 +137,7 @@ export function SelectConfigControl({
|
|
|
127
137
|
className="justify-self-start gap-2"
|
|
128
138
|
>
|
|
129
139
|
<IconPlus className="size-4" />
|
|
130
|
-
|
|
140
|
+
{t("fieldEditor.addOptionButton")}
|
|
131
141
|
</Button>
|
|
132
142
|
</div>
|
|
133
143
|
</div>
|