feat: 编排删除增加删除文件勾选 (#808)

pull/812/head
ssongliu 2023-04-27 12:44:18 +08:00 committed by GitHub
parent 5b68332b9a
commit b42cf32326
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 136 additions and 6 deletions

View File

@ -146,6 +146,7 @@ type ComposeOperation struct {
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`
Path string `json:"path" validate:"required"` Path string `json:"path" validate:"required"`
Operation string `json:"operation" validate:"required,oneof=start stop down"` Operation string `json:"operation" validate:"required,oneof=start stop down"`
WithFile bool `json:"withFile"`
} }
type ComposeUpdate struct { type ComposeUpdate struct {
Name string `json:"name" validate:"required"` Name string `json:"name" validate:"required"`

View File

@ -182,7 +182,9 @@ func (u *ContainerService) ComposeOperation(req dto.ComposeOperation) error {
global.LOG.Infof("docker-compose %s %s successful", req.Operation, req.Name) global.LOG.Infof("docker-compose %s %s successful", req.Operation, req.Name)
if req.Operation == "down" { if req.Operation == "down" {
_ = composeRepo.DeleteRecord(commonRepo.WithByName(req.Name)) _ = composeRepo.DeleteRecord(commonRepo.WithByName(req.Name))
_ = os.RemoveAll(strings.ReplaceAll(req.Path, "/docker-compose.yml", "")) if req.WithFile {
_ = os.RemoveAll(path.Dir(req.Path))
}
} }
return nil return nil

View File

@ -208,6 +208,7 @@ export namespace Container {
name: string; name: string;
operation: string; operation: string;
path: string; path: string;
withFile: boolean;
} }
export interface ComposeUpdate { export interface ComposeUpdate {
name: string; name: string;

View File

@ -546,6 +546,11 @@ const message = {
compose: 'Compose', compose: 'Compose',
fromChangeHelper: 'Switching the source will clear the current edited content. Do you want to continue?', fromChangeHelper: 'Switching the source will clear the current edited content. Do you want to continue?',
composePathHelper: 'Config file save path: {0}', composePathHelper: 'Config file save path: {0}',
composeHelper:
'The composition created through 1Panel editor or template will be saved in the {0}/docker/compose directory.',
deleteFile: 'Delete file',
deleteComposeHelper: 'Delete the corresponding composition file.',
deleteCompose: '" Delete this composition.',
apps: 'Apps', apps: 'Apps',
local: 'Local', local: 'Local',
createCompose: 'Create compose', createCompose: 'Create compose',

View File

@ -563,6 +563,10 @@ const message = {
compose: '', compose: '',
fromChangeHelper: '', fromChangeHelper: '',
composePathHelper: ': {0}', composePathHelper: ': {0}',
composeHelper: ' 1Panel {0}/docker/compose ',
deleteFile: '',
deleteComposeHelper: '',
deleteCompose: '" ',
apps: '', apps: '',
local: '', local: '',
createCompose: '', createCompose: '',

View File

@ -172,6 +172,7 @@ const acceptParams = (): void => {
form.from = 'edit'; form.from = 'edit';
form.path = ''; form.path = '';
form.file = ''; form.file = '';
form.template = null;
logInfo.value = ''; logInfo.value = '';
loadTemplates(); loadTemplates();
loadPath(); loadPath();

View File

@ -0,0 +1,90 @@
<template>
<el-dialog
v-model="dialogVisiable"
:title="$t('commons.button.delete') + ' - ' + composeName"
width="30%"
:close-on-click-modal="false"
>
<el-form ref="deleteForm" v-loading="loading">
<el-form-item>
<el-checkbox v-model="deleteFile" :label="$t('container.deleteFile')" />
<span class="input-help">
{{ $t('container.deleteComposeHelper') }}
</span>
</el-form-item>
<el-form-item>
<div>
<span style="font-size: 12px">{{ $t('database.delete') }}</span>
<span style="font-size: 12px; color: red; font-weight: 500">{{ composeName }}</span>
<span style="font-size: 12px">{{ $t('container.deleteCompose') }}</span>
</div>
<el-input v-model="deleteInfo" :placeholder="composeName"></el-input>
</el-form-item>
</el-form>
<template #footer>
<span class="dialog-footer">
<el-button @click="dialogVisiable = false" :disabled="loading">
{{ $t('commons.button.cancel') }}
</el-button>
<el-button type="primary" @click="submit" :disabled="deleteInfo != composeName || loading">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import { FormInstance } from 'element-plus';
import { ref } from 'vue';
import i18n from '@/lang';
import { MsgSuccess } from '@/utils/message';
import { composeOperator } from '@/api/modules/container';
let dialogVisiable = ref(false);
let loading = ref(false);
let deleteInfo = ref('');
const deleteFile = ref();
const composeName = ref();
const composePath = ref();
const deleteForm = ref<FormInstance>();
interface DialogProps {
name: string;
path: string;
}
const emit = defineEmits<{ (e: 'search'): void }>();
const acceptParams = async (prop: DialogProps) => {
deleteFile.value = false;
composeName.value = prop.name;
composePath.value = prop.path;
deleteInfo.value = '';
dialogVisiable.value = true;
};
const submit = async () => {
loading.value = true;
let params = {
name: composeName.value,
path: composePath.value,
operation: 'down',
withFile: deleteFile.value,
};
await composeOperator(params)
.then(() => {
loading.value = false;
emit('search');
MsgSuccess(i18n.global.t('commons.msg.deleteSuccess'));
dialogVisiable.value = false;
})
.catch(() => {
loading.value = false;
});
};
defineExpose({
acceptParams,
});
</script>

View File

@ -10,6 +10,20 @@
</el-card> </el-card>
<LayoutContent v-if="!isOnDetail" :title="$t('container.compose')" :class="{ mask: dockerStatus != 'Running' }"> <LayoutContent v-if="!isOnDetail" :title="$t('container.compose')" :class="{ mask: dockerStatus != 'Running' }">
<template #prompt>
<el-alert type="info" :closable="false">
<template #default>
<span>
<span>{{ $t('container.composeHelper', [baseDir]) }}</span>
<el-button type="primary" link @click="toFolder">
<el-icon>
<FolderOpened />
</el-icon>
</el-button>
</span>
</template>
</el-alert>
</template>
<template #toolbar> <template #toolbar>
<el-row> <el-row>
<el-col :span="16"> <el-col :span="16">
@ -72,6 +86,7 @@
<EditDialog ref="dialogEditRef" /> <EditDialog ref="dialogEditRef" />
<CreateDialog @search="search" ref="dialogRef" /> <CreateDialog @search="search" ref="dialogRef" />
<DeleteDialog @search="search" ref="dialogDelRef" />
</div> </div>
</template> </template>
@ -83,12 +98,13 @@ import { reactive, onMounted, ref } from 'vue';
import LayoutContent from '@/layout/layout-content.vue'; import LayoutContent from '@/layout/layout-content.vue';
import EditDialog from '@/views/container/compose/edit/index.vue'; import EditDialog from '@/views/container/compose/edit/index.vue';
import CreateDialog from '@/views/container/compose/create/index.vue'; import CreateDialog from '@/views/container/compose/create/index.vue';
import DeleteDialog from '@/views/container/compose/delete/index.vue';
import ComposeDetial from '@/views/container/compose/detail/index.vue'; import ComposeDetial from '@/views/container/compose/detail/index.vue';
import { composeOperator, loadDockerStatus, searchCompose } from '@/api/modules/container'; import { loadDockerStatus, searchCompose } from '@/api/modules/container';
import i18n from '@/lang'; import i18n from '@/lang';
import { Container } from '@/api/interface/container'; import { Container } from '@/api/interface/container';
import { useDeleteData } from '@/hooks/use-delete-data';
import { LoadFile } from '@/api/modules/files'; import { LoadFile } from '@/api/modules/files';
import { loadBaseDir } from '@/api/modules/setting';
import router from '@/routers'; import router from '@/routers';
const data = ref(); const data = ref();
@ -96,6 +112,7 @@ const selects = ref<any>([]);
const loading = ref(false); const loading = ref(false);
const isOnDetail = ref(false); const isOnDetail = ref(false);
const baseDir = ref();
const paginationConfig = reactive({ const paginationConfig = reactive({
currentPage: 1, currentPage: 1,
@ -124,6 +141,15 @@ const goSetting = async () => {
router.push({ name: 'ContainerSetting' }); router.push({ name: 'ContainerSetting' });
}; };
const toFolder = async () => {
router.push({ path: '/hosts/files', query: { path: baseDir.value + '/docker/compose' } });
};
const loadPath = async () => {
const pathRes = await loadBaseDir();
baseDir.value = pathRes.data;
};
const search = async () => { const search = async () => {
let params = { let params = {
info: searchName.value, info: searchName.value,
@ -163,14 +189,13 @@ const onOpenDialog = async () => {
dialogRef.value!.acceptParams(); dialogRef.value!.acceptParams();
}; };
const dialogDelRef = ref();
const onDelete = async (row: Container.ComposeInfo) => { const onDelete = async (row: Container.ComposeInfo) => {
const param = { const param = {
name: row.name, name: row.name,
path: row.path, path: row.path,
operation: 'down',
}; };
await useDeleteData(composeOperator, param, 'commons.msg.delete'); dialogDelRef.value.acceptParams(param);
search();
}; };
const dialogEditRef = ref(); const dialogEditRef = ref();
@ -205,6 +230,7 @@ const buttons = [
}, },
]; ];
onMounted(() => { onMounted(() => {
loadPath();
loadStatus(); loadStatus();
}); });
</script> </script>