mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-10-09 15:06:37 +08:00
feat: add terminal for runtimes (#8758)
This commit is contained in:
parent
6d8d6f05f1
commit
41b2dd82f0
8 changed files with 188 additions and 1 deletions
|
@ -552,7 +552,7 @@ func operateSupervisorCtl(operate, name, group, includeDir, containerName string
|
|||
err error
|
||||
)
|
||||
if containerName != "" {
|
||||
cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(2 * time.Second))
|
||||
cmdMgr := cmd.NewCommandMgr(cmd.WithTimeout(30 * time.Second))
|
||||
output, err = cmdMgr.RunWithStdoutBashCf("docker exec %s supervisorctl %s", containerName, strings.Join(processNames, " "))
|
||||
} else {
|
||||
var out []byte
|
||||
|
|
85
frontend/src/views/website/runtime/components/terminal.vue
Normal file
85
frontend/src/views/website/runtime/components/terminal.vue
Normal file
|
@ -0,0 +1,85 @@
|
|||
<template>
|
||||
<DrawerPro
|
||||
v-model="terminalVisible"
|
||||
:header="$t('menu.terminal')"
|
||||
@close="handleClose"
|
||||
:resource="title"
|
||||
size="large"
|
||||
>
|
||||
<template #content>
|
||||
<el-form ref="formRef" :model="form" label-position="top">
|
||||
<el-button v-if="!terminalOpen" @click="initTerm(formRef)">
|
||||
{{ $t('commons.button.conn') }}
|
||||
</el-button>
|
||||
<el-button v-else @click="onClose()">{{ $t('commons.button.disConn') }}</el-button>
|
||||
<Terminal
|
||||
style="height: calc(100vh - 200px); margin-top: 18px"
|
||||
ref="terminalRef"
|
||||
v-if="terminalOpen"
|
||||
></Terminal>
|
||||
</el-form>
|
||||
</template>
|
||||
</DrawerPro>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import { reactive, ref, nextTick } from 'vue';
|
||||
import { ElForm, FormInstance } from 'element-plus';
|
||||
import Terminal from '@/components/terminal/index.vue';
|
||||
|
||||
const title = ref();
|
||||
const terminalVisible = ref(false);
|
||||
const terminalOpen = ref(false);
|
||||
const form = reactive({
|
||||
isCustom: false,
|
||||
command: '',
|
||||
user: '',
|
||||
containerID: '',
|
||||
});
|
||||
const formRef = ref();
|
||||
const terminalRef = ref<InstanceType<typeof Terminal> | null>(null);
|
||||
|
||||
interface DialogProps {
|
||||
containerID: string;
|
||||
container: string;
|
||||
}
|
||||
const acceptParams = async (params: DialogProps): Promise<void> => {
|
||||
terminalVisible.value = true;
|
||||
form.containerID = params.containerID;
|
||||
title.value = params.container;
|
||||
form.isCustom = false;
|
||||
form.user = '';
|
||||
form.command = '/bin/bash';
|
||||
terminalOpen.value = false;
|
||||
initTerm(formRef.value);
|
||||
};
|
||||
|
||||
const initTerm = (formEl: FormInstance | undefined) => {
|
||||
if (!formEl) return;
|
||||
formEl.validate(async (valid) => {
|
||||
if (!valid) return;
|
||||
terminalOpen.value = true;
|
||||
await nextTick();
|
||||
terminalRef.value!.acceptParams({
|
||||
endpoint: '/api/v2/containers/exec',
|
||||
args: `source=container&containerid=${form.containerID}&user=${form.user}&command=${form.command}`,
|
||||
error: '',
|
||||
initCmd: '',
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const onClose = () => {
|
||||
terminalRef.value?.onClose();
|
||||
terminalOpen.value = false;
|
||||
};
|
||||
|
||||
function handleClose() {
|
||||
onClose();
|
||||
terminalVisible.value = false;
|
||||
}
|
||||
|
||||
defineExpose({
|
||||
acceptParams,
|
||||
});
|
||||
</script>
|
|
@ -78,6 +78,7 @@
|
|||
<ComposeLogs ref="composeLogRef" />
|
||||
<PortJumpDialog ref="dialogPortJumpRef" />
|
||||
<AppResources ref="checkRef" @close="search" />
|
||||
<Terminal ref="terminalRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -98,6 +99,7 @@ import { ElMessageBox } from 'element-plus';
|
|||
import { GlobalStore } from '@/store';
|
||||
import RuntimeStatus from '@/views/website/runtime/components/runtime-status.vue';
|
||||
import PortJump from '@/views/website/runtime/components/port-jump.vue';
|
||||
import Terminal from '@/views/website/runtime/components/terminal.vue';
|
||||
import { disabledButton } from '@/utils/runtime';
|
||||
|
||||
const loading = ref(false);
|
||||
|
@ -107,6 +109,7 @@ const deleteRef = ref();
|
|||
const dialogPortJumpRef = ref();
|
||||
const composeLogRef = ref();
|
||||
const checkRef = ref();
|
||||
const terminalRef = ref();
|
||||
|
||||
const globalStore = GlobalStore();
|
||||
const mobile = computed(() => {
|
||||
|
@ -162,6 +165,15 @@ const buttons = [
|
|||
return disabledButton(row, 'edit');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('menu.terminal'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
openTerminal(row);
|
||||
},
|
||||
disabled: function (row: Runtime.Runtime) {
|
||||
return disabledButton(row, 'config');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
|
@ -207,6 +219,11 @@ const openDelete = (row: Runtime.Runtime) => {
|
|||
});
|
||||
};
|
||||
|
||||
const openTerminal = (row: Runtime.Runtime) => {
|
||||
const container = row.params['CONTAINER_NAME'];
|
||||
terminalRef.value.acceptParams({ containerID: container, container: container });
|
||||
};
|
||||
|
||||
const openLog = (row: any) => {
|
||||
composeLogRef.value.acceptParams({ compose: row.path + '/docker-compose.yml', resource: row.name });
|
||||
};
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
<ComposeLogs ref="composeLogRef" />
|
||||
<PortJumpDialog ref="dialogPortJumpRef" />
|
||||
<AppResources ref="checkRef" @close="search" />
|
||||
<Terminal ref="terminalRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -97,6 +98,7 @@ import AppResources from '@/views/website/runtime/php/check/index.vue';
|
|||
import { ElMessageBox } from 'element-plus';
|
||||
import RuntimeStatus from '@/views/website/runtime/components/runtime-status.vue';
|
||||
import PortJump from '@/views/website/runtime/components/port-jump.vue';
|
||||
import Terminal from '@/views/website/runtime/components/terminal.vue';
|
||||
import { disabledButton } from '@/utils/runtime';
|
||||
import { GlobalStore } from '@/store';
|
||||
const globalStore = GlobalStore();
|
||||
|
@ -111,6 +113,7 @@ const deleteRef = ref();
|
|||
const dialogPortJumpRef = ref();
|
||||
const composeLogRef = ref();
|
||||
const checkRef = ref();
|
||||
const terminalRef = ref();
|
||||
|
||||
const paginationConfig = reactive({
|
||||
cacheSizeKey: 'runtime-page-size',
|
||||
|
@ -161,6 +164,15 @@ const buttons = [
|
|||
return disabledButton(row, 'edit');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('menu.terminal'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
openTerminal(row);
|
||||
},
|
||||
disabled: function (row: Runtime.Runtime) {
|
||||
return disabledButton(row, 'config');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
|
@ -214,6 +226,11 @@ const goDashboard = async (port: any, protocol: string) => {
|
|||
dialogPortJumpRef.value.acceptParams({ port: port, protocol: protocol });
|
||||
};
|
||||
|
||||
const openTerminal = (row: Runtime.Runtime) => {
|
||||
const container = row.params['CONTAINER_NAME'];
|
||||
terminalRef.value.acceptParams({ containerID: container, container: container });
|
||||
};
|
||||
|
||||
const operateRuntime = async (operate: string, ID: number) => {
|
||||
try {
|
||||
const action = await ElMessageBox.confirm(
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
<ComposeLogs ref="composeLogRef" />
|
||||
<PortJumpDialog ref="dialogPortJumpRef" />
|
||||
<AppResources ref="checkRef" @close="search" />
|
||||
<Terminal ref="terminalRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -97,6 +98,7 @@ import AppResources from '@/views/website/runtime/php/check/index.vue';
|
|||
import { ElMessageBox } from 'element-plus';
|
||||
import RuntimeStatus from '@/views/website/runtime/components/runtime-status.vue';
|
||||
import PortJump from '@/views/website/runtime/components/port-jump.vue';
|
||||
import Terminal from '@/views/website/runtime/components/terminal.vue';
|
||||
import { disabledButton } from '@/utils/runtime';
|
||||
import { GlobalStore } from '@/store';
|
||||
const globalStore = GlobalStore();
|
||||
|
@ -111,6 +113,7 @@ const deleteRef = ref();
|
|||
const dialogPortJumpRef = ref();
|
||||
const composeLogRef = ref();
|
||||
const checkRef = ref();
|
||||
const terminalRef = ref();
|
||||
|
||||
const paginationConfig = reactive({
|
||||
cacheSizeKey: 'runtime-page-size',
|
||||
|
@ -161,6 +164,15 @@ const buttons = [
|
|||
return disabledButton(row, 'edit');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('menu.terminal'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
openTerminal(row);
|
||||
},
|
||||
disabled: function (row: Runtime.Runtime) {
|
||||
return disabledButton(row, 'config');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
|
@ -210,6 +222,11 @@ const openLog = (row: any) => {
|
|||
composeLogRef.value.acceptParams({ compose: row.path + '/docker-compose.yml', resource: row.name });
|
||||
};
|
||||
|
||||
const openTerminal = (row: Runtime.Runtime) => {
|
||||
const container = row.params['CONTAINER_NAME'];
|
||||
terminalRef.value.acceptParams({ containerID: container, container: container });
|
||||
};
|
||||
|
||||
const goDashboard = async (port: any, protocol: string) => {
|
||||
dialogPortJumpRef.value.acceptParams({ port: port, protocol: protocol });
|
||||
};
|
||||
|
|
|
@ -79,6 +79,7 @@
|
|||
<PortJumpDialog ref="dialogPortJumpRef" />
|
||||
<Modules ref="moduleRef" />
|
||||
<AppResources ref="checkRef" @close="search" />
|
||||
<Terminal ref="terminalRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -99,6 +100,7 @@ import AppResources from '@/views/website/runtime/php/check/index.vue';
|
|||
import { ElMessageBox } from 'element-plus';
|
||||
import RuntimeStatus from '@/views/website/runtime/components/runtime-status.vue';
|
||||
import PortJump from '@/views/website/runtime/components/port-jump.vue';
|
||||
import Terminal from '@/views/website/runtime/components/terminal.vue';
|
||||
import { disabledButton } from '@/utils/runtime';
|
||||
import { GlobalStore } from '@/store';
|
||||
const globalStore = GlobalStore();
|
||||
|
@ -114,6 +116,7 @@ const dialogPortJumpRef = ref();
|
|||
const composeLogRef = ref();
|
||||
const moduleRef = ref();
|
||||
const checkRef = ref();
|
||||
const terminalRef = ref();
|
||||
|
||||
const paginationConfig = reactive({
|
||||
cacheSizeKey: 'runtime-page-size',
|
||||
|
@ -173,6 +176,15 @@ const buttons = [
|
|||
return disabledButton(row, 'edit');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('menu.terminal'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
openTerminal(row);
|
||||
},
|
||||
disabled: function (row: Runtime.Runtime) {
|
||||
return disabledButton(row, 'config');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
|
@ -230,6 +242,11 @@ const goDashboard = async (port: any, protocol: string) => {
|
|||
dialogPortJumpRef.value.acceptParams({ port: port, protocol: protocol });
|
||||
};
|
||||
|
||||
const openTerminal = (row: Runtime.Runtime) => {
|
||||
const container = row.params['CONTAINER_NAME'];
|
||||
terminalRef.value.acceptParams({ containerID: container, container: container });
|
||||
};
|
||||
|
||||
const operateRuntime = async (operate: string, ID: number) => {
|
||||
try {
|
||||
const action = await ElMessageBox.confirm(
|
||||
|
|
|
@ -103,6 +103,7 @@
|
|||
<ComposeLogs ref="composeLogRef" :highlightDiff="200" />
|
||||
<Config ref="configRef" />
|
||||
<Supervisor ref="supervisorRef" />
|
||||
<Terminal ref="terminalRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -125,6 +126,7 @@ import ComposeLogs from '@/components/log/compose/index.vue';
|
|||
import Config from '@/views/website/runtime/php/config/index.vue';
|
||||
import Supervisor from '@/views/website/runtime/php/supervisor/index.vue';
|
||||
import RuntimeStatus from '@/views/website/runtime/components/runtime-status.vue';
|
||||
import Terminal from '@/views/website/runtime/components/terminal.vue';
|
||||
import { disabledButton } from '@/utils/runtime';
|
||||
import { GlobalStore } from '@/store';
|
||||
const globalStore = GlobalStore();
|
||||
|
@ -155,6 +157,7 @@ const items = ref<Runtime.RuntimeDTO[]>([]);
|
|||
const composeLogRef = ref();
|
||||
const configRef = ref();
|
||||
const supervisorRef = ref();
|
||||
const terminalRef = ref();
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
|
@ -220,6 +223,15 @@ const buttons = [
|
|||
return disabledButton(row, 'config');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('menu.terminal'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
openTerminal(row);
|
||||
},
|
||||
disabled: function (row: Runtime.Runtime) {
|
||||
return disabledButton(row, 'config');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
|
@ -258,6 +270,11 @@ const openSupervisor = (row: Runtime.Runtime) => {
|
|||
supervisorRef.value.acceptParams(row.id);
|
||||
};
|
||||
|
||||
const openTerminal = (row: Runtime.Runtime) => {
|
||||
const container = row.params['CONTAINER_NAME'];
|
||||
terminalRef.value.acceptParams({ containerID: container, container: container });
|
||||
};
|
||||
|
||||
const openLog = (row: Runtime.RuntimeDTO) => {
|
||||
if (row.status == 'Running') {
|
||||
composeLogRef.value.acceptParams({ compose: row.path + '/docker-compose.yml', resource: row.name });
|
||||
|
|
|
@ -78,6 +78,7 @@
|
|||
<ComposeLogs ref="composeLogRef" />
|
||||
<PortJumpDialog ref="dialogPortJumpRef" />
|
||||
<AppResources ref="checkRef" @close="search" />
|
||||
<Terminal ref="terminalRef" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
@ -97,6 +98,7 @@ import AppResources from '@/views/website/runtime/php/check/index.vue';
|
|||
import { ElMessageBox } from 'element-plus';
|
||||
import RuntimeStatus from '@/views/website/runtime/components/runtime-status.vue';
|
||||
import PortJump from '@/views/website/runtime/components/port-jump.vue';
|
||||
import Terminal from '@/views/website/runtime/components/terminal.vue';
|
||||
import { disabledButton } from '@/utils/runtime';
|
||||
import { GlobalStore } from '@/store';
|
||||
const globalStore = GlobalStore();
|
||||
|
@ -111,6 +113,7 @@ const deleteRef = ref();
|
|||
const dialogPortJumpRef = ref();
|
||||
const composeLogRef = ref();
|
||||
const checkRef = ref();
|
||||
const terminalRef = ref();
|
||||
|
||||
const paginationConfig = reactive({
|
||||
cacheSizeKey: 'runtime-page-size',
|
||||
|
@ -161,6 +164,15 @@ const buttons = [
|
|||
return disabledButton(row, 'edit');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('menu.terminal'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
openTerminal(row);
|
||||
},
|
||||
disabled: function (row: Runtime.Runtime) {
|
||||
return disabledButton(row, 'config');
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
click: function (row: Runtime.Runtime) {
|
||||
|
@ -214,6 +226,11 @@ const goDashboard = async (port: any, protocol: string) => {
|
|||
dialogPortJumpRef.value.acceptParams({ port: port, protocol: protocol });
|
||||
};
|
||||
|
||||
const openTerminal = (row: Runtime.Runtime) => {
|
||||
const container = row.params['CONTAINER_NAME'];
|
||||
terminalRef.value.acceptParams({ containerID: container, container: container });
|
||||
};
|
||||
|
||||
const operateRuntime = async (operate: string, ID: number) => {
|
||||
try {
|
||||
const action = await ElMessageBox.confirm(
|
||||
|
|
Loading…
Add table
Reference in a new issue