diff --git a/web/src/lib/components/schema/AddStepButton.svelte b/web/src/lib/components/schema/AddStepButton.svelte
index fba6712..474c8b8 100644
--- a/web/src/lib/components/schema/AddStepButton.svelte
+++ b/web/src/lib/components/schema/AddStepButton.svelte
@@ -1,123 +1,21 @@
-
-
- {#if open}
-
- {/if}
+
+
diff --git a/web/src/lib/components/schema/SchemaToolView.svelte b/web/src/lib/components/schema/SchemaToolView.svelte
index 4e584fd..9d09321 100644
--- a/web/src/lib/components/schema/SchemaToolView.svelte
+++ b/web/src/lib/components/schema/SchemaToolView.svelte
@@ -2,6 +2,7 @@
import AddStepButton from "./AddStepButton.svelte";
import SchemaFields from "./SchemaFields.svelte";
import SchemaPreview from "./SchemaPreview.svelte";
+ import ToolPickerButton from "./ToolPickerButton.svelte";
import StepCard from "$lib/components/display/StepCard.svelte";
import { hasTransparency } from "$lib/core/analyze";
import { debounce } from "$lib/core/debounce";
@@ -23,6 +24,7 @@
import { t } from "$lib/i18n/t";
import {
createChain,
+ createStep,
insertStep,
loadChain,
moveStep,
@@ -246,6 +248,20 @@
steps = steps.with(index, { ...step, collapsed: !step.collapsed });
}
+ // Замена инструмента на месте: ключ и свёрнутость шага сохраняются,
+ // параметры — дефолты нового инструмента, вход пересчитывается при прогоне.
+ function replaceStepTool(index: number, toolId: string) {
+ const step = steps[index];
+ const next = createStep(toolId);
+ if (!step || !next) return;
+ touchedFor(step.key).clear();
+ steps = steps.with(index, {
+ ...next,
+ key: step.key,
+ collapsed: step.collapsed,
+ });
+ }
+
function onStepDrop(e: DragEvent, to: number) {
e.preventDefault();
if (dragFrom !== null) steps = moveStep(steps, dragFrom, to);
@@ -483,6 +499,13 @@
ondrop={(e) => onStepDrop(e, i)}
ondragend={() => (dragFrom = null)}
>
+ {#snippet tools()}
+
replaceStepTool(i, id)}
+ />
+ {/snippet}
+ import Icon from "$lib/components/ui/Icon.svelte";
+ import { pageTitle } from "$lib/i18n/schema-tool-strings";
+ import { chainablePages } from "$lib/pipeline.svelte";
+ import type { Page } from "$lib/registry";
+ import { Plus, Repeat } from "@lucide/svelte";
+
+ interface Props {
+ label: string;
+ iconOnly?: boolean;
+ onadd: (toolId: string) => void;
+ }
+ let { label, iconOnly = false, onadd }: Props = $props();
+
+ const pages = chainablePages();
+
+ let open = $state(false);
+ let root = $state(null);
+
+ function choose(page: Page) {
+ onadd(page.steps[0].id);
+ open = false;
+ }
+
+ $effect(() => {
+ if (!open) return;
+ function onPointerDown(e: PointerEvent) {
+ if (!root?.contains(e.target as Node)) open = false;
+ }
+ function onKey(e: KeyboardEvent) {
+ if (e.key === "Escape") open = false;
+ }
+ window.addEventListener("pointerdown", onPointerDown);
+ window.addEventListener("keydown", onKey);
+ return () => {
+ window.removeEventListener("pointerdown", onPointerDown);
+ window.removeEventListener("keydown", onKey);
+ };
+ });
+
+
+
+
+ {#if open}
+
+ {/if}
+
+
+
diff --git a/web/src/lib/i18n/en.ts b/web/src/lib/i18n/en.ts
index 0ec7d21..e07cda7 100644
--- a/web/src/lib/i18n/en.ts
+++ b/web/src/lib/i18n/en.ts
@@ -49,6 +49,7 @@ export const en: Dict = {
},
chain: {
addStep: "Add step",
+ changeTool: "Change tool",
collapseStep: "Collapse step",
expandStep: "Expand step",
inputLegend: "Input",
diff --git a/web/src/lib/i18n/ru.ts b/web/src/lib/i18n/ru.ts
index cf22467..a292b27 100644
--- a/web/src/lib/i18n/ru.ts
+++ b/web/src/lib/i18n/ru.ts
@@ -50,6 +50,7 @@ export const ru: Dict = {
},
chain: {
addStep: "Добавить шаг",
+ changeTool: "Поменять инструмент",
collapseStep: "Свернуть шаг",
expandStep: "Развернуть шаг",
inputLegend: "Вход",