diff --git a/apps/web/app/settings/workspace/use-workflow-creation.ts b/apps/web/app/settings/workspace/use-workflow-creation.ts index c870d566c7..bab300d3d3 100644 --- a/apps/web/app/settings/workspace/use-workflow-creation.ts +++ b/apps/web/app/settings/workspace/use-workflow-creation.ts @@ -12,6 +12,11 @@ import { type Workspace, } from "@/lib/types/http"; +// Seeded step definitions used whenever no template supplies default steps — +// the Custom option, and any template whose `default_steps` is absent or empty. +// These names are PERSISTED as the workflow's step names, so they deliberately +// stay English — translating them would write localized values into the +// database. export const DEFAULT_CUSTOM_STEPS: StepDefinition[] = [ { name: "Todo", position: 0, color: "bg-slate-500" }, { name: "In Progress", position: 1, color: "bg-blue-500" }, @@ -113,6 +118,7 @@ export function useWorkflowCreation({ const workflow: Workflow = { id: toWorkflowId(tempId), workspace_id: toWorkspaceId(workspace.id), + // Persisted workflow name; the fallback is data, not copy. name: newWorkflowName.trim() || template?.name || "New Workflow", description: template?.description, workflow_template_id: template?.id, diff --git a/apps/web/app/settings/workspace/workspace-workflows-client.tsx b/apps/web/app/settings/workspace/workspace-workflows-client.tsx index 0412d95137..de8b474a40 100644 --- a/apps/web/app/settings/workspace/workspace-workflows-client.tsx +++ b/apps/web/app/settings/workspace/workspace-workflows-client.tsx @@ -1,6 +1,8 @@ "use client"; import { useMemo, useRef, useState } from "react"; +import { useTranslation } from "react-i18next"; +import { t as translate } from "@/lib/i18n"; import Link from "@/components/routing/app-link"; import { useRouter } from "@/lib/routing/client-router"; import { IconGripVertical, IconArrowsShuffle } from "@tabler/icons-react"; @@ -100,8 +102,8 @@ function useWorkflowImportExport( setIsExportDialogOpen(true); } catch (error) { toast({ - title: "Failed to export workflows", - description: error instanceof Error ? error.message : "Request failed", + title: translate("workflows:failedToExportWorkflows"), + description: error instanceof Error ? error.message : translate("common:requestFailed"), variant: "error", }); } @@ -126,16 +128,18 @@ function useWorkflowImportExport( const created = result.created ?? []; const skipped = result.skipped ?? []; const parts: string[] = []; - if (created.length > 0) parts.push(`Created: ${created.join(", ")}`); - if (skipped.length > 0) parts.push(`Skipped (already exist): ${skipped.join(", ")}`); - toast({ title: "Import complete", description: parts.join(". ") }); + if (created.length > 0) + parts.push(translate("workflows:importCreated", { names: created.join(", ") })); + if (skipped.length > 0) + parts.push(translate("workflows:importSkipped", { names: skipped.join(", ") })); + toast({ title: translate("workflows:importCompleteTitle"), description: parts.join(". ") }); setIsImportDialogOpen(false); setImportYaml(""); if (created.length > 0) router.refresh(); } catch (error) { toast({ - title: "Failed to import workflows", - description: error instanceof Error ? error.message : "Invalid YAML", + title: translate("workflows:failedToImportWorkflows"), + description: error instanceof Error ? error.message : translate("workflows:invalidYaml"), variant: "error", }); } finally { @@ -405,12 +409,13 @@ function WorkflowList({ } function WorkflowDialogs({ page }: { page: ReturnType }) { + const { t } = useTranslation(); return ( <>

{workspace.name}

-

Manage workflows for this workspace.

+

+ {t("workflows:manageWorkflowsForThisWorkspace")} +

} - title="Workflows" - description="Create autonomous pipelines with automated transitions or manual workflows where you move tasks yourself" + title={t("workflows:workflows")} + description={t("workflows:workflowsSectionDescription")} action={ idMappings.current.get(id) ?? id); if (persistedOrder.some((id) => id.startsWith(TEMP_WORKFLOW_PREFIX))) { - throw new Error("Save workflows before ordering them"); + throw new Error(translate("workflows:saveWorkflowsBeforeOrdering")); } if (persistedOrder.length > 0) { await reorderWorkflowsAction(workspace.id, persistedOrder); diff --git a/apps/web/app/settings/workspace/workspace-workflows-dialogs.tsx b/apps/web/app/settings/workspace/workspace-workflows-dialogs.tsx index aa1afb4dc0..6ce802940c 100644 --- a/apps/web/app/settings/workspace/workspace-workflows-dialogs.tsx +++ b/apps/web/app/settings/workspace/workspace-workflows-dialogs.tsx @@ -1,5 +1,6 @@ "use client"; +import { useTranslation } from "react-i18next"; import { Button } from "@kandev/ui/button"; import { Label } from "@kandev/ui/label"; import { Input } from "@kandev/ui/input"; @@ -9,6 +10,9 @@ import { Textarea } from "@kandev/ui/textarea"; import { cn } from "@/lib/utils"; import type { WorkflowTemplate } from "@/lib/types/http"; +const YAML_PLACEHOLDER = + "version: 1\ntype: kandev_workflow\nworkflows:\n - name: My Workflow\n steps: [...]"; + type ImportWorkflowsDialogProps = { open: boolean; onOpenChange: (open: boolean) => void; @@ -30,15 +34,16 @@ export function ImportWorkflowsDialog({ onImport, importLoading, }: ImportWorkflowsDialogProps) { + const { t } = useTranslation(); return ( - Import Workflows + {t("workflows:importWorkflowsTitle")}
- +
- +