Add pipeline copy button to duplicate existing configurations (#1767)

* Initial plan

* Add copy button to pipeline configuration page

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* Add i18n support for copy suffix and address code review feedback

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* Show new pipeline name in copy toast and close dialog after copy

Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>

* perf: tool list style in extension tab

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: RockChinQ <45992437+RockChinQ@users.noreply.github.com>
Co-authored-by: Junyan Qin <rockchinq@gmail.com>
This commit is contained in:
Copilot
2025-11-08 14:03:41 +08:00
committed by GitHub
parent 3edae3e678
commit 8d7976190d
6 changed files with 55 additions and 6 deletions

View File

@@ -286,8 +286,8 @@ export default function PipelineExtension({
variant="outline"
className="flex items-center gap-1 mt-1"
>
<Wrench className="h-3 w-3 text-white" />
<span className="text-xs text-white">
<Wrench className="h-3 w-3 text-black dark:text-white" />
<span className="text-xs text-black dark:text-white">
{t('pipelines.extensions.toolCount', {
count: server.runtime_info.tool_count || 0,
})}
@@ -416,14 +416,17 @@ export default function PipelineExtension({
</div>
{server.runtime_info &&
server.runtime_info.status === 'connected' && (
<div className="flex items-center gap-1 mt-1">
<Wrench className="h-3 w-3 text-muted-foreground" />
<span className="text-xs text-muted-foreground">
<Badge
variant="outline"
className="flex items-center gap-1 mt-1"
>
<Wrench className="h-3 w-3 text-black dark:text-white" />
<span className="text-xs text-black dark:text-white">
{t('pipelines.extensions.toolCount', {
count: server.runtime_info.tool_count || 0,
})}
</span>
</div>
</Badge>
)}
</div>
{!server.enable && (

View File

@@ -346,6 +346,32 @@ export default function PipelineFormComponent({
}
};
const handleCopy = () => {
if (pipelineId) {
let newPipelineName = '';
httpClient
.getPipeline(pipelineId)
.then((resp) => {
const originalPipeline = resp.pipeline;
newPipelineName = `${originalPipeline.name}${t('pipelines.copySuffix')}`;
const newPipeline: Pipeline = {
name: newPipelineName,
description: originalPipeline.description,
config: originalPipeline.config,
};
return httpClient.createPipeline(newPipeline);
})
.then(() => {
onFinish();
toast.success(`${t('common.copySuccess')}: ${newPipelineName}`);
onCancel();
})
.catch((err) => {
toast.error(t('pipelines.createError') + err.message);
});
}
};
return (
<>
<div className="!max-w-[70vw] max-w-6xl h-full p-0 flex flex-col bg-white dark:bg-black">
@@ -478,6 +504,18 @@ export default function PipelineFormComponent({
{t('pipelines.defaultPipelineCannotDelete')}
</div>
)}
{isEditMode && (
<Button
type="button"
variant="default"
onClick={handleCopy}
className="bg-green-600 hover:bg-green-700 text-white"
>
{t('common.copy')}
</Button>
)}
<Button type="submit" form="pipeline-form">
{isEditMode ? t('common.save') : t('common.submit')}
</Button>