diff --git a/frontend/editor/public/locales/en-US/translation.toml b/frontend/editor/public/locales/en-US/translation.toml index 2eb91dcc91..6fe9f9b485 100644 --- a/frontend/editor/public/locales/en-US/translation.toml +++ b/frontend/editor/public/locales/en-US/translation.toml @@ -8849,9 +8849,6 @@ labelsHeading = "Classification labels" noTools = "Enable at least one tool in the workflow first." saveFailed = "Couldn't save the pipeline. Please try again." -[portal.policies.wizard.output] -heading = "Output & run" - [portal.policies.wizard.output.filenameRule] autoNumber = "Auto-number" label = "Filename rule" @@ -8873,10 +8870,6 @@ upload = "Upload" [portal.policies.wizard.settings] heading = "Settings" -[portal.policies.wizard.sources] -heading = "Sources" -loading = "Loading sources…" - [portal.policies.wizard.tabs] ariaLabel = "Setup steps" settings = "Settings" diff --git a/frontend/editor/src/portal/components/policies/PolicySetupWizard.test.tsx b/frontend/editor/src/portal/components/policies/PolicySetupWizard.test.tsx index 77f54f311b..1772708a41 100644 --- a/frontend/editor/src/portal/components/policies/PolicySetupWizard.test.tsx +++ b/frontend/editor/src/portal/components/policies/PolicySetupWizard.test.tsx @@ -32,11 +32,6 @@ vi.mock("react-i18next", () => ({ initReactI18next: { type: "3rdParty", init: vi.fn() }, })); -const fetchSources = vi.fn(); -vi.mock("@portal/api/sources", () => ({ - fetchSources: () => fetchSources(), -})); - const fetchIntegrations = vi.fn(); vi.mock("@portal/api/integrations", () => ({ fetchIntegrations: () => fetchIntegrations(), @@ -89,7 +84,6 @@ async function submitWizard(saveLabel: string) { describe("PolicySetupWizard", () => { beforeEach(() => { - fetchSources.mockResolvedValue({ sources: [] }); fetchIntegrations.mockResolvedValue([]); }); diff --git a/frontend/editor/src/portal/components/policies/PolicySetupWizard.tsx b/frontend/editor/src/portal/components/policies/PolicySetupWizard.tsx index e457ab4ac7..1baabae2e1 100644 --- a/frontend/editor/src/portal/components/policies/PolicySetupWizard.tsx +++ b/frontend/editor/src/portal/components/policies/PolicySetupWizard.tsx @@ -1,11 +1,6 @@ -import { useMemo, useState, type ReactNode } from "react"; +import { useMemo, useState } from "react"; import { useTranslation } from "react-i18next"; -import CheckIcon from "@mui/icons-material/Check"; import TuneRoundedIcon from "@mui/icons-material/TuneRounded"; -import EditOutlinedIcon from "@mui/icons-material/EditOutlined"; -import FolderOutlinedIcon from "@mui/icons-material/FolderOutlined"; -import CloudOutlinedIcon from "@mui/icons-material/CloudOutlined"; -import StorageOutlinedIcon from "@mui/icons-material/StorageOutlined"; import { Banner, Button, @@ -34,7 +29,6 @@ import { type PolicyToolStep, } from "@app/policies/operations"; import { resolveRunOn } from "@app/policies/runOn"; -import { useSources } from "@portal/queries/sources"; import { fetchIntegrations } from "@portal/api/integrations"; import { errorMessage } from "@portal/api/http"; import { useAsync } from "@portal/hooks/useAsync"; @@ -46,21 +40,6 @@ import { PolicyPurviewConfig } from "@portal/components/policies/PolicyPurviewCo import { ClassificationLabelsSection } from "@portal/components/policies/ClassificationLabelsSection"; import "@portal/views/Policies.css"; -/** Outline icon for a source tile, keyed by the backend source `type`. */ -function sourceIcon(type: string): ReactNode { - const sx = { fontSize: "1.1rem" } as const; - switch (type) { - case "editor": - return ; - case "folder": - return ; - case "s3": - return ; - default: - return ; - } -} - interface PolicySetupWizardProps { /** The category being configured, or null when closed. */ entry: CatalogueEntry | null; @@ -280,36 +259,6 @@ function PolicySetupWizardBody({ const [fieldValues, setFieldValues] = useState(() => resolveFieldValues(entry), ); - // Real sources only; editor participation is its own flag, not an entry here. - const [sources, setSources] = useState(() => - (policy?.state.sources ?? []).filter((s) => s !== "editor"), - ); - // Whether the policy runs in the editor. Defaults on for a new policy (the common case); - // on edit it comes straight from the stored flag, never re-derived from the sources list. - const [runsOnEditor, setRunsOnEditor] = useState( - policy?.state.runsOnEditor ?? true, - ); - - const sourcesAsync = useSources(); - const availableSources = useMemo(() => { - const backendSources = (sourcesAsync.data?.sources ?? []).filter( - (s) => s.status !== "disabled", - ); - // The editor is always an available source. The backend now returns it as a - // virtual source too, so take that when present (avoids a duplicate tile) and - // otherwise fall back to a synthetic one; keep it first, selected by default. - const editorSource = backendSources.find((s) => s.id === "editor") ?? { - id: "editor", - name: t("portal.sources.types.editor.label"), - type: "editor", - status: "active" as const, - referenceCount: 0, - referencingPolicies: [], - config: [], - docsTotal: null, - }; - return [editorSource, ...backendSources.filter((s) => s.id !== "editor")]; - }, [sourcesAsync.data, t]); // Document-type scoping has no UI; preserve any saved scope on edit and // default new policies to all document types. const [scopeTypes] = useState(policy?.state.scopeTypes ?? []); @@ -381,18 +330,6 @@ function PolicySetupWizardBody({ ); } - function toggleSource(id: string) { - // The editor is not a real source: its tile toggles the runsOnEditor flag instead of - // adding "editor" to the sources list. - if (id === "editor") { - setRunsOnEditor((on) => !on); - return; - } - setSources((prev) => - prev.includes(id) ? prev.filter((s) => s !== id) : [...prev, id], - ); - } - /** The wizard's current state as a submit result: shared by Save and Customise. */ function collectResult(): PolicySetupResult { const steps: PipelineStep[] = enabledTools.map((tl) => @@ -400,9 +337,12 @@ function PolicySetupWizardBody({ ); return { required, - runsOnEditor, + // A template always runs in the editor. A pipeline takes exactly one input, and the simple + // wizard has no field to bind a stored source, so real sources never applied here; anyone + // wanting a folder or bucket source uses Customise, which drops into the full builder. + runsOnEditor: true, fieldValues, - sources, + sources: [], scopeTypes, reviewerEmail, outputMode, @@ -634,170 +574,112 @@ function PolicySetupWizardBody({ )} -

- {t("portal.policies.wizard.sources.heading")} -

- {sourcesAsync.loading && !sourcesAsync.data ? ( -

- {t("portal.policies.wizard.sources.loading")} -

- ) : ( - // The backend always returns the editor as a virtual source, so the - // loaded list is never empty - no "no sources" state exists. -
- {availableSources.map((src) => { - const on = - src.id === "editor" ? runsOnEditor : sources.includes(src.id); - return ( - - ); - })} -
- )} - -

- {t("portal.policies.wizard.output.heading")} -

- {runsOnEditor && ( - <> - - setRunOn(resolveRunOn(value, category.id))} + options={[ + { + value: "upload", + label: t("portal.policies.wizard.output.runOn.upload"), + }, + { + value: "export", + label: t("portal.policies.wizard.output.runOn.export"), + }, + ]} + /> + + + + setOutputNamePosition( + (value ?? "suffix") as + | "prefix" + | "suffix" + | "auto-number", + ) + } + options={[ + { + value: "prefix", + label: t( + "portal.policies.wizard.output.filenameRule.prefix", + ), + }, + { + value: "suffix", + label: t( + "portal.policies.wizard.output.filenameRule.suffix", + ), + }, + ...(outputMode === "new_file" + ? [ + { + value: "auto-number", + label: t( + "portal.policies.wizard.output.filenameRule.autoNumber", + ), + }, + ] + : []), + ]} + /> + {outputNamePosition !== "auto-number" && ( + - setRunOn(resolveRunOn(value, category.id)) - } - options={[ - { - value: "upload", - label: t("portal.policies.wizard.output.runOn.upload"), - }, - { - value: "export", - label: t("portal.policies.wizard.output.runOn.export"), - }, - ]} - /> - - - - setOutputNamePosition( - (value ?? "suffix") as - | "prefix" - | "suffix" - | "auto-number", - ) - } - options={[ - { - value: "prefix", - label: t( - "portal.policies.wizard.output.filenameRule.prefix", - ), - }, - { - value: "suffix", - label: t( - "portal.policies.wizard.output.filenameRule.suffix", - ), - }, - ...(outputMode === "new_file" - ? [ - { - value: "auto-number", - label: t( - "portal.policies.wizard.output.filenameRule.autoNumber", - ), - }, - ] - : []), - ]} - /> - {outputNamePosition !== "auto-number" && ( - setOutputName(e.target.value)} - /> + value={outputName} + placeholder={t( + "portal.policies.wizard.output.filenameRule.placeholder", )} -
- - - )} + onChange={(e) => setOutputName(e.target.value)} + /> + )} + + {/* TODO: reviewer user-picker goes here */} diff --git a/frontend/editor/src/portal/views/Policies.css b/frontend/editor/src/portal/views/Policies.css index d30244c821..b62976fbe9 100644 --- a/frontend/editor/src/portal/views/Policies.css +++ b/frontend/editor/src/portal/views/Policies.css @@ -281,26 +281,6 @@ margin-top: 0.75rem; } -/* Sources picker */ -/* Selectable source tiles: a vertical stack of full-width shared Buttons - (icon · name · check). Layout is the Button's own leftSection/label/ - rightSection — only the selected border/tint is added here. */ -.portal-policies__sources { - display: flex; - flex-direction: column; - gap: 0.5rem; -} - -.portal-policies__source--on { - border-color: var(--c-primary); -} - -.portal-policies__source-label { - display: inline-flex; - align-items: center; - gap: 0.5rem; -} - .portal-policies__link { border: none; background: none;