mirror of
https://github.com/langbot-app/LangBot.git
synced 2025-11-25 19:37:36 +08:00
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:
@@ -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 && (
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -39,6 +39,7 @@ const enUS = {
|
||||
deleteSuccess: 'Deleted successfully',
|
||||
deleteError: 'Delete failed: ',
|
||||
addRound: 'Add Round',
|
||||
copy: 'Copy',
|
||||
copySuccess: 'Copy Successfully',
|
||||
test: 'Test',
|
||||
forgotPassword: 'Forgot Password?',
|
||||
@@ -440,6 +441,7 @@ const enUS = {
|
||||
createError: 'Creation failed: ',
|
||||
saveSuccess: 'Saved successfully',
|
||||
saveError: 'Save failed: ',
|
||||
copySuffix: ' Copy',
|
||||
deleteConfirmation:
|
||||
'Are you sure you want to delete this pipeline? Bots bound to this pipeline will not work.',
|
||||
defaultPipelineCannotDelete: 'Default pipeline cannot be deleted',
|
||||
|
||||
@@ -40,6 +40,7 @@ const jaJP = {
|
||||
deleteSuccess: '削除に成功しました',
|
||||
deleteError: '削除に失敗しました:',
|
||||
addRound: 'ラウンドを追加',
|
||||
copy: 'コピー',
|
||||
copySuccess: 'コピーに成功しました',
|
||||
test: 'テスト',
|
||||
forgotPassword: 'パスワードを忘れた?',
|
||||
@@ -443,6 +444,7 @@ const jaJP = {
|
||||
createError: '作成に失敗しました:',
|
||||
saveSuccess: '保存に成功しました',
|
||||
saveError: '保存に失敗しました:',
|
||||
copySuffix: ' Copy',
|
||||
deleteConfirmation:
|
||||
'本当にこのパイプラインを削除しますか?このパイプラインに紐付けられたボットは動作しなくなります。',
|
||||
defaultPipelineCannotDelete: 'デフォルトパイプラインは削除できません',
|
||||
|
||||
@@ -39,6 +39,7 @@ const zhHans = {
|
||||
deleteSuccess: '删除成功',
|
||||
deleteError: '删除失败:',
|
||||
addRound: '添加回合',
|
||||
copy: '复制',
|
||||
copySuccess: '复制成功',
|
||||
test: '测试',
|
||||
forgotPassword: '忘记密码?',
|
||||
@@ -423,6 +424,7 @@ const zhHans = {
|
||||
createError: '创建失败:',
|
||||
saveSuccess: '保存成功',
|
||||
saveError: '保存失败:',
|
||||
copySuffix: ' Copy',
|
||||
deleteConfirmation:
|
||||
'你确定要删除这个流水线吗?已绑定此流水线的机器人将无法使用。',
|
||||
defaultPipelineCannotDelete: '默认流水线不可删除',
|
||||
|
||||
@@ -39,6 +39,7 @@ const zhHant = {
|
||||
deleteSuccess: '刪除成功',
|
||||
deleteError: '刪除失敗:',
|
||||
addRound: '新增回合',
|
||||
copy: '複製',
|
||||
copySuccess: '複製成功',
|
||||
test: '測試',
|
||||
forgotPassword: '忘記密碼?',
|
||||
@@ -421,6 +422,7 @@ const zhHant = {
|
||||
createError: '建立失敗:',
|
||||
saveSuccess: '儲存成功',
|
||||
saveError: '儲存失敗:',
|
||||
copySuffix: ' Copy',
|
||||
deleteConfirmation:
|
||||
'您確定要刪除這個流程線嗎?已綁定此流程線的機器人將無法使用。',
|
||||
defaultPipelineCannotDelete: '預設流程線不可刪除',
|
||||
|
||||
Reference in New Issue
Block a user