mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2024-11-29 05:49:07 +08:00
fix: 应用删除增加强制删除选项
This commit is contained in:
parent
1a06571bec
commit
a6239a7359
@ -39,6 +39,8 @@ type AppInstalledOperate struct {
|
||||
BackupId uint `json:"backupId"`
|
||||
DetailId uint `json:"detailId"`
|
||||
Operate constant.AppOperate `json:"operate" validate:"required"`
|
||||
ForceDelete bool `json:"forceDelete"`
|
||||
DeleteBackup bool `json:"deleteBackup"`
|
||||
}
|
||||
|
||||
type PortUpdate struct {
|
||||
|
@ -143,7 +143,7 @@ func (a AppInstallService) Operate(req request.AppInstalledOperate) error {
|
||||
install.Status = constant.Running
|
||||
case constant.Delete:
|
||||
tx, ctx := getTxAndContext()
|
||||
if err := deleteAppInstall(ctx, install); err != nil {
|
||||
if err := deleteAppInstall(ctx, install, req.ForceDelete, req.DeleteBackup); err != nil {
|
||||
tx.Rollback()
|
||||
return err
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ func createLink(ctx context.Context, app model.App, appInstall *model.AppInstall
|
||||
return nil
|
||||
}
|
||||
|
||||
func deleteAppInstall(ctx context.Context, install model.AppInstall) error {
|
||||
func deleteAppInstall(ctx context.Context, install model.AppInstall, forceDelete bool, deleteBackup bool) error {
|
||||
op := files.NewFileOp()
|
||||
appDir := install.GetPath()
|
||||
dir, _ := os.Stat(appDir)
|
||||
@ -169,13 +169,13 @@ func deleteAppInstall(ctx context.Context, install model.AppInstall) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if err := appInstallRepo.Delete(ctx, install); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := deleteLink(ctx, &install); err != nil {
|
||||
if err := deleteLink(ctx, &install); err != nil && !forceDelete {
|
||||
return err
|
||||
}
|
||||
if deleteBackup {
|
||||
backups, _ := appInstallBackupRepo.GetBy(appInstallBackupRepo.WithAppInstallID(install.ID))
|
||||
for _, backup := range backups {
|
||||
_ = op.DeleteDir(backup.Path)
|
||||
@ -183,6 +183,7 @@ func deleteAppInstall(ctx context.Context, install model.AppInstall) error {
|
||||
if err := appInstallBackupRepo.Delete(ctx, appInstallBackupRepo.WithAppInstallID(install.ID)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -263,7 +263,7 @@ func (w WebsiteService) DeleteWebsite(req request.WebsiteDelete) error {
|
||||
return err
|
||||
}
|
||||
if !reflect.DeepEqual(model.AppInstall{}, appInstall) {
|
||||
if err := deleteAppInstall(ctx, appInstall); err != nil {
|
||||
if err := deleteAppInstall(ctx, appInstall, req.ForceDelete, true); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
@ -108,6 +108,8 @@ export namespace App {
|
||||
operate: string;
|
||||
backupId?: number;
|
||||
detailId?: number;
|
||||
forceDelete?: boolean;
|
||||
deleteBackup?: boolean;
|
||||
}
|
||||
|
||||
export interface AppInstalledSearch {
|
||||
|
@ -789,6 +789,10 @@ export default {
|
||||
database: '数据库',
|
||||
defaultConfig: '默认配置',
|
||||
defaultConfigHelper: '已恢复为默认配置,保存后生效',
|
||||
forceDelete: '强制删除',
|
||||
forceDeleteHelper: '强制删除,会忽略删除过程中碰到的问题,最终删除元数据',
|
||||
deleteBackup: '删除备份',
|
||||
deleteBackupHelper: '同时删除应用备份',
|
||||
},
|
||||
website: {
|
||||
website: '网站',
|
||||
|
105
frontend/src/views/app-store/installed/delete/index.vue
Normal file
105
frontend/src/views/app-store/installed/delete/index.vue
Normal file
@ -0,0 +1,105 @@
|
||||
<template>
|
||||
<el-dialog
|
||||
v-model="open"
|
||||
:title="$t('commons.button.delete') + ' - ' + appInstallName"
|
||||
width="30%"
|
||||
:close-on-click-modal="false"
|
||||
:before-close="handleClose"
|
||||
>
|
||||
<el-form ref="deleteForm" label-position="left">
|
||||
<el-form-item>
|
||||
<el-checkbox v-model="deleteReq.forceDelete" :label="$t('app.forceDelete')" />
|
||||
</el-form-item>
|
||||
<div class="helper">
|
||||
<span class="input-help">
|
||||
{{ $t('app.forceDeleteHelper') }}
|
||||
</span>
|
||||
</div>
|
||||
<el-form-item>
|
||||
<el-checkbox v-model="deleteReq.deleteBackup" :label="$t('app.deleteBackup')" />
|
||||
</el-form-item>
|
||||
<div class="helper">
|
||||
<span class="input-help">
|
||||
{{ $t('app.deleteBackupHelper') }}
|
||||
</span>
|
||||
</div>
|
||||
<br />
|
||||
<span v-html="deleteHelper"></span>
|
||||
<el-form-item>
|
||||
<el-input v-model="deleteInfo" :placeholder="appInstallName" />
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="handleClose" :loading="loading">
|
||||
{{ $t('commons.button.cancel') }}
|
||||
</el-button>
|
||||
<el-button type="primary" @click="submit" :loading="loading" :disabled="deleteInfo != appInstallName">
|
||||
{{ $t('commons.button.confirm') }}
|
||||
</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
</template>
|
||||
<script lang="ts" setup>
|
||||
import { ElMessage, FormInstance } from 'element-plus';
|
||||
import { ref } from 'vue';
|
||||
import { App } from '@/api/interface/app';
|
||||
import { InstalledOp } from '@/api/modules/app';
|
||||
import i18n from '@/lang';
|
||||
|
||||
let deleteReq = ref({
|
||||
operate: 'delete',
|
||||
installId: 0,
|
||||
deleteBackup: false,
|
||||
forceDelete: false,
|
||||
});
|
||||
let open = ref(false);
|
||||
let loading = ref(false);
|
||||
let deleteHelper = ref('');
|
||||
let deleteInfo = ref('');
|
||||
let appInstallName = ref('');
|
||||
|
||||
const deleteForm = ref<FormInstance>();
|
||||
const em = defineEmits(['close']);
|
||||
|
||||
const handleClose = () => {
|
||||
open.value = false;
|
||||
em('close', open);
|
||||
};
|
||||
|
||||
const acceptParams = async (app: App.AppInstalled) => {
|
||||
deleteReq.value = {
|
||||
operate: 'delete',
|
||||
installId: 0,
|
||||
deleteBackup: false,
|
||||
forceDelete: false,
|
||||
};
|
||||
deleteReq.value.installId = app.id;
|
||||
deleteHelper.value = i18n.global.t('website.deleteConfirmHelper', [app.name]);
|
||||
appInstallName.value = app.name;
|
||||
open.value = true;
|
||||
};
|
||||
|
||||
const submit = async () => {
|
||||
loading.value = true;
|
||||
InstalledOp(deleteReq.value)
|
||||
.then(() => {
|
||||
handleClose();
|
||||
ElMessage.success(i18n.global.t('commons.msg.deleteSuccess'));
|
||||
})
|
||||
.finally(() => {
|
||||
loading.value = false;
|
||||
});
|
||||
};
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss">
|
||||
.helper {
|
||||
margin-top: -20px;
|
||||
}
|
||||
</style>
|
@ -109,6 +109,7 @@
|
||||
</el-dialog>
|
||||
<Backups ref="backupRef" @close="search"></Backups>
|
||||
<AppResources ref="checkRef"></AppResources>
|
||||
<AppDelete ref="deleteRef" @close="search"></AppDelete>
|
||||
</el-card>
|
||||
</template>
|
||||
|
||||
@ -127,8 +128,9 @@ import i18n from '@/lang';
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import Backups from './backups.vue';
|
||||
import AppResources from './check/index.vue';
|
||||
import AppDelete from './delete/index.vue';
|
||||
import { App } from '@/api/interface/app';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
// import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
import Status from '@/components/status/index.vue';
|
||||
|
||||
let data = ref<any>();
|
||||
@ -148,6 +150,7 @@ let operateReq = reactive({
|
||||
let versions = ref<App.VersionDetail[]>();
|
||||
const backupRef = ref();
|
||||
const checkRef = ref();
|
||||
const deleteRef = ref();
|
||||
let searchName = ref('');
|
||||
|
||||
const sync = () => {
|
||||
@ -192,8 +195,10 @@ const openOperate = (row: any, op: string) => {
|
||||
if (res.data && res.data.length > 0) {
|
||||
checkRef.value.acceptParams({ items: items });
|
||||
} else {
|
||||
await useDeleteData(InstalledOp, operateReq, 'app.deleteWarn');
|
||||
search();
|
||||
deleteRef.value.acceptParams(row);
|
||||
|
||||
// await useDeleteData(InstalledOp, operateReq, 'app.deleteWarn');
|
||||
// search();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
Loading…
Reference in New Issue
Block a user