feat: 容器批量操作增加详情显示 (#2201)

pull/2207/head
ssongliu 2023-09-06 17:14:16 +08:00 committed by GitHub
parent df5a1b3e40
commit ae515b079c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 107 additions and 68 deletions

View File

@ -611,7 +611,7 @@ var AddDatabases = &gormigrate.Migration{
if err := tx.Create(&model.Database{ if err := tx.Create(&model.Database{
AppInstallID: redisInfo.ID, AppInstallID: redisInfo.ID,
Name: redisInfo.Name, Name: redisInfo.Name,
Type: "mariadb", Type: "redis",
Version: redisInfo.Version, Version: redisInfo.Version,
From: "local", From: "local",
Address: redisInfo.ServiceName, Address: redisInfo.ServiceName,
@ -627,7 +627,7 @@ var AddDatabases = &gormigrate.Migration{
if err := tx.Create(&model.Database{ if err := tx.Create(&model.Database{
AppInstallID: pgInfo.ID, AppInstallID: pgInfo.ID,
Name: pgInfo.Name, Name: pgInfo.Name,
Type: "mariadb", Type: "postgresql",
Version: pgInfo.Version, Version: pgInfo.Version,
From: "local", From: "local",
Address: pgInfo.ServiceName, Address: pgInfo.ServiceName,
@ -643,7 +643,7 @@ var AddDatabases = &gormigrate.Migration{
if err := tx.Create(&model.Database{ if err := tx.Create(&model.Database{
AppInstallID: mongodbInfo.ID, AppInstallID: mongodbInfo.ID,
Name: mongodbInfo.Name, Name: mongodbInfo.Name,
Type: "mariadb", Type: "mongodb",
Version: mongodbInfo.Version, Version: mongodbInfo.Version,
From: "local", From: "local",
Address: mongodbInfo.ServiceName, Address: mongodbInfo.ServiceName,
@ -659,7 +659,7 @@ var AddDatabases = &gormigrate.Migration{
if err := tx.Create(&model.Database{ if err := tx.Create(&model.Database{
AppInstallID: memcachedInfo.ID, AppInstallID: memcachedInfo.ID,
Name: memcachedInfo.Name, Name: memcachedInfo.Name,
Type: "mariadb", Type: "memcached",
Version: memcachedInfo.Version, Version: memcachedInfo.Version,
From: "local", From: "local",
Address: memcachedInfo.ServiceName, Address: memcachedInfo.ServiceName,

View File

@ -470,9 +470,9 @@ const message = {
updateContaienrHelper: updateContaienrHelper:
'Container editing requires rebuilding the container. Any data that has not been persisted will be lost. Do you want to continue?', 'Container editing requires rebuilding the container. Any data that has not been persisted will be lost. Do you want to continue?',
containerList: 'Container list', containerList: 'Container list',
operatorHelper: '{0} will be performed on the selected container. Do you want to continue?', operatorHelper: '{0} will be performed on the following container, Do you want to continue?',
operatorAppHelper: operatorAppHelper:
'There is a container from the App store. The {0} operation may affect the normal use of this service. Are you sure?', 'The {0} operation will be performed on the following containers, some of which are from the App Store. This operation may affect the normal use of the service, Do you want to continue?',
start: 'Start', start: 'Start',
stop: 'Stop', stop: 'Stop',
restart: 'Restart', restart: 'Restart',

View File

@ -459,8 +459,9 @@ const message = {
edit: '', edit: '',
updateContaienrHelper: '', updateContaienrHelper: '',
containerList: '', containerList: '',
operatorHelper: ' {0} ', operatorHelper: ' {0} ',
operatorAppHelper: '{0} 使', operatorAppHelper:
' {0} 使',
start: '', start: '',
stop: '', stop: '',
restart: '', restart: '',

View File

@ -459,8 +459,9 @@ const message = {
edit: '', edit: '',
updateContaienrHelper: '', updateContaienrHelper: '',
containerList: '', containerList: '',
operatorHelper: ' {0} ', operatorHelper: ' {0} ',
operatorAppHelper: '{0} 使', operatorAppHelper:
' {0} 使',
start: '', start: '',
stop: '', stop: '',
restart: '', restart: '',

View File

@ -245,6 +245,7 @@ html {
// search // search
.search-button { .search-button {
float: right; float: right;
margin-right: 10px;
.el-input__wrapper { .el-input__wrapper {
border-radius: 50px; border-radius: 50px;
} }

View File

@ -106,6 +106,7 @@
<ContainerLogDialog ref="dialogContainerLogRef" /> <ContainerLogDialog ref="dialogContainerLogRef" />
<MonitorDialog ref="dialogMonitorRef" /> <MonitorDialog ref="dialogMonitorRef" />
<TerminalDialog ref="dialogTerminalRef" /> <TerminalDialog ref="dialogTerminalRef" />
<HandleDialog @search="search" ref="handleRef" />
</template> </template>
</LayoutContent> </LayoutContent>
</div> </div>
@ -117,10 +118,11 @@ import Tooltip from '@/components/tooltip/index.vue';
import MonitorDialog from '@/views/container/container/monitor/index.vue'; import MonitorDialog from '@/views/container/container/monitor/index.vue';
import ContainerLogDialog from '@/views/container/container/log/index.vue'; import ContainerLogDialog from '@/views/container/container/log/index.vue';
import TerminalDialog from '@/views/container/container/terminal/index.vue'; import TerminalDialog from '@/views/container/container/terminal/index.vue';
import HandleDialog from '@/views/container/container/handle/index.vue';
import CodemirrorDialog from '@/components/codemirror-dialog/index.vue'; import CodemirrorDialog from '@/components/codemirror-dialog/index.vue';
import Status from '@/components/status/index.vue'; import Status from '@/components/status/index.vue';
import { dateFormat } from '@/utils/util'; import { dateFormat } from '@/utils/util';
import { composeOperator, containerOperator, inspect, searchContainer } from '@/api/modules/container'; import { composeOperator, inspect, searchContainer } from '@/api/modules/container';
import { ElMessageBox } from 'element-plus'; import { ElMessageBox } from 'element-plus';
import i18n from '@/lang'; import i18n from '@/lang';
import { Container } from '@/api/interface/container'; import { Container } from '@/api/interface/container';
@ -131,6 +133,9 @@ const composePath = ref();
const filters = ref(); const filters = ref();
const createdBy = ref(); const createdBy = ref();
const dialogContainerLogRef = ref();
const handleRef = ref();
const emit = defineEmits<{ (e: 'back'): void }>(); const emit = defineEmits<{ (e: 'back'): void }>();
interface DialogProps { interface DialogProps {
createdBy: string; createdBy: string;
@ -228,35 +233,14 @@ const checkStatus = (operation: string) => {
const onOperate = async (operation: string) => { const onOperate = async (operation: string) => {
let msg = i18n.global.t('container.operatorHelper', [i18n.global.t('container.' + operation)]); let msg = i18n.global.t('container.operatorHelper', [i18n.global.t('container.' + operation)]);
let containers = [];
for (const item of selects.value) { for (const item of selects.value) {
containers.push(item.name);
if (item.isFromApp) { if (item.isFromApp) {
msg = i18n.global.t('container.operatorAppHelper', [i18n.global.t('container.' + operation)]); msg = i18n.global.t('container.operatorAppHelper', [i18n.global.t('container.' + operation)]);
break;
} }
} }
ElMessageBox.confirm(msg, i18n.global.t('container.' + operation), { handleRef.value.acceptParams({ containers: containers, operation: operation, msg: msg });
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
type: 'info',
}).then(() => {
let ps = [];
for (const item of selects.value) {
const param = {
name: item.name,
operation: operation,
newName: '',
};
ps.push(containerOperator(param));
}
Promise.all(ps)
.then(() => {
search();
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {
search();
});
});
}; };
const onComposeOperate = async (operation: string) => { const onComposeOperate = async (operation: string) => {
@ -302,8 +286,6 @@ const onTerminal = (row: any) => {
dialogTerminalRef.value!.acceptParams({ containerID: row.containerID, container: row.name }); dialogTerminalRef.value!.acceptParams({ containerID: row.containerID, container: row.name });
}; };
const dialogContainerLogRef = ref();
const buttons = [ const buttons = [
{ {
label: i18n.global.t('file.terminal'), label: i18n.global.t('file.terminal'),

View File

@ -0,0 +1,77 @@
<template>
<el-dialog v-model="open" :title="$t('app.delete')" width="30%" :close-on-click-modal="false">
<div>
<span class="lineClass" style="color: red">{{ msg }}</span>
<ul>
<li class="lineClass" v-for="(row, index) in containers" :key="index">{{ row }}</li>
</ul>
</div>
<template #footer>
<span class="dialog-footer">
<el-button @click="open = false" :disabled="loading">
{{ $t('commons.button.cancel') }}
</el-button>
<el-button type="primary" @click="onConfirm" v-loading="loading">
{{ $t('commons.button.confirm') }}
</el-button>
</span>
</template>
</el-dialog>
</template>
<script lang="ts" setup>
import i18n from '@/lang';
import { ref } from 'vue';
import { containerOperator } from '@/api/modules/container';
import { MsgSuccess } from '@/utils/message';
const open = ref(false);
const containers = ref();
const msg = ref();
const operation = ref();
const loading = ref(false);
const em = defineEmits(['search']);
interface DialogProps {
containers: Array<string>;
operation: string;
msg: string;
}
const acceptParams = (props: DialogProps) => {
containers.value = props.containers;
operation.value = props.operation;
msg.value = props.msg;
open.value = true;
};
const onConfirm = () => {
const pros = [];
for (const item of containers.value) {
pros.push(containerOperator({ name: item, operation: operation.value, newName: '' }));
}
loading.value = true;
Promise.all(pros)
.then(() => {
open.value = false;
loading.value = false;
em('search');
MsgSuccess(i18n.global.t('commons.msg.deleteSuccess'));
})
.finally(() => {
open.value = false;
loading.value = false;
em('search');
});
};
defineExpose({
acceptParams,
});
</script>
<style scoped>
.lineClass {
line-height: 25px;
}
</style>

View File

@ -179,6 +179,7 @@
<TerminalDialog ref="dialogTerminalRef" /> <TerminalDialog ref="dialogTerminalRef" />
<PortJumpDialog ref="dialogPortJumpRef" /> <PortJumpDialog ref="dialogPortJumpRef" />
<HandleDialog @search="search" ref="handleRef" />
</div> </div>
</template> </template>
@ -192,23 +193,22 @@ import UpgraeDialog from '@/views/container/container/upgrade/index.vue';
import MonitorDialog from '@/views/container/container/monitor/index.vue'; import MonitorDialog from '@/views/container/container/monitor/index.vue';
import ContainerLogDialog from '@/views/container/container/log/index.vue'; import ContainerLogDialog from '@/views/container/container/log/index.vue';
import TerminalDialog from '@/views/container/container/terminal/index.vue'; import TerminalDialog from '@/views/container/container/terminal/index.vue';
import HandleDialog from '@/views/container/container/handle/index.vue';
import CodemirrorDialog from '@/components/codemirror-dialog/index.vue'; import CodemirrorDialog from '@/components/codemirror-dialog/index.vue';
import PortJumpDialog from '@/components/port-jump/index.vue'; import PortJumpDialog from '@/components/port-jump/index.vue';
import Status from '@/components/status/index.vue'; import Status from '@/components/status/index.vue';
import { reactive, onMounted, ref, computed } from 'vue'; import { reactive, onMounted, ref, computed } from 'vue';
import { import {
containerListStats, containerListStats,
containerOperator,
inspect, inspect,
loadContainerInfo, loadContainerInfo,
loadDockerStatus, loadDockerStatus,
searchContainer, searchContainer,
} from '@/api/modules/container'; } from '@/api/modules/container';
import { Container } from '@/api/interface/container'; import { Container } from '@/api/interface/container';
import { ElMessageBox } from 'element-plus';
import i18n from '@/lang'; import i18n from '@/lang';
import router from '@/routers'; import router from '@/routers';
import { MsgSuccess, MsgWarning } from '@/utils/message'; import { MsgWarning } from '@/utils/message';
import { GlobalStore } from '@/store'; import { GlobalStore } from '@/store';
const globalStore = GlobalStore(); const globalStore = GlobalStore();
@ -229,6 +229,7 @@ const paginationConfig = reactive({
const searchName = ref(); const searchName = ref();
const dialogUpgradeRef = ref(); const dialogUpgradeRef = ref();
const dialogPortJumpRef = ref(); const dialogPortJumpRef = ref();
const handleRef = ref();
const dockerStatus = ref('Running'); const dockerStatus = ref('Running');
const loadStatus = async () => { const loadStatus = async () => {
@ -415,38 +416,14 @@ const checkStatus = (operation: string, row: Container.ContainerInfo | null) =>
const onOperate = async (operation: string, row: Container.ContainerInfo | null) => { const onOperate = async (operation: string, row: Container.ContainerInfo | null) => {
let opList = row ? [row] : selects.value; let opList = row ? [row] : selects.value;
let msg = i18n.global.t('container.operatorHelper', [i18n.global.t('container.' + operation)]); let msg = i18n.global.t('container.operatorHelper', [i18n.global.t('container.' + operation)]);
let containers = [];
for (const item of opList) { for (const item of opList) {
containers.push(item.name);
if (item.isFromApp) { if (item.isFromApp) {
msg = i18n.global.t('container.operatorAppHelper', [i18n.global.t('container.' + operation)]); msg = i18n.global.t('container.operatorAppHelper', [i18n.global.t('container.' + operation)]);
break;
} }
} }
ElMessageBox.confirm(msg, i18n.global.t('container.' + operation), { handleRef.value.acceptParams({ containers: containers, operation: operation, msg: msg });
confirmButtonText: i18n.global.t('commons.button.confirm'),
cancelButtonText: i18n.global.t('commons.button.cancel'),
type: 'info',
}).then(() => {
let ps = [];
for (const item of opList) {
const param = {
name: item.name,
operation: operation,
newName: '',
};
ps.push(containerOperator(param));
}
loading.value = true;
Promise.all(ps)
.then(() => {
loading.value = false;
search();
MsgSuccess(i18n.global.t('commons.msg.operationSuccess'));
})
.catch(() => {
loading.value = false;
search();
});
});
}; };
const buttons = [ const buttons = [

View File

@ -2,7 +2,7 @@
<el-dialog v-model="dialogVisiable" :title="$t('container.containerPrune')" :destroy-on-close="true" width="30%"> <el-dialog v-model="dialogVisiable" :title="$t('container.containerPrune')" :destroy-on-close="true" width="30%">
<div> <div>
<ul class="help-ul"> <ul class="help-ul">
<li lineClass style="color: red">{{ $t('container.containerPruneHelper1') }}</li> <li class="lineClass" style="color: red">{{ $t('container.containerPruneHelper1') }}</li>
<li class="lineClass">{{ $t('container.containerPruneHelper2') }}</li> <li class="lineClass">{{ $t('container.containerPruneHelper2') }}</li>
<li class="lineClass">{{ $t('container.containerPruneHelper3') }}</li> <li class="lineClass">{{ $t('container.containerPruneHelper3') }}</li>
</ul> </ul>