mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-18 22:22:59 +08:00
feat: 增加 inspect 详情显示
This commit is contained in:
parent
39f9de0b00
commit
9962c6c4a8
@ -1,8 +1,6 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/1Panel-dev/1Panel/app/api/v1/helper"
|
||||
"github.com/1Panel-dev/1Panel/app/dto"
|
||||
"github.com/1Panel-dev/1Panel/constant"
|
||||
@ -49,13 +47,18 @@ func (b *BaseApi) ContainerOperation(c *gin.Context) {
|
||||
helper.SuccessWithData(c, nil)
|
||||
}
|
||||
|
||||
func (b *BaseApi) ContainerDetail(c *gin.Context) {
|
||||
id, ok := c.Params.Get("id")
|
||||
if !ok {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, errors.New("error id in path"))
|
||||
func (b *BaseApi) Inspect(c *gin.Context) {
|
||||
var req dto.InspectReq
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
result, err := containerService.ContainerInspect(id)
|
||||
if err := global.VALID.Struct(req); err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrBadRequest, constant.ErrTypeInvalidParams, err)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := containerService.Inspect(req)
|
||||
if err != nil {
|
||||
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
|
||||
return
|
||||
|
@ -7,6 +7,11 @@ type PageContainer struct {
|
||||
Status string `json:"status" validate:"required,oneof=all running"`
|
||||
}
|
||||
|
||||
type InspectReq struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type ContainerInfo struct {
|
||||
ContainerID string `json:"containerID"`
|
||||
Name string `json:"name"`
|
||||
|
@ -27,7 +27,7 @@ type IContainerService interface {
|
||||
PageVolume(req dto.PageInfo) (int64, interface{}, error)
|
||||
ContainerOperation(req dto.ContainerOperation) error
|
||||
ContainerLogs(param dto.ContainerLog) (string, error)
|
||||
ContainerInspect(id string) (string, error)
|
||||
Inspect(req dto.InspectReq) (string, error)
|
||||
DeleteNetwork(req dto.BatchDelete) error
|
||||
CreateNetwork(req dto.NetworkCreat) error
|
||||
DeleteVolume(req dto.BatchDelete) error
|
||||
@ -77,6 +77,30 @@ func (u *ContainerService) Page(req dto.PageContainer) (int64, interface{}, erro
|
||||
return int64(total), backDatas, nil
|
||||
}
|
||||
|
||||
func (u *ContainerService) Inspect(req dto.InspectReq) (string, error) {
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
var inspectInfo interface{}
|
||||
switch req.Type {
|
||||
case "container":
|
||||
inspectInfo, err = client.ContainerInspect(context.Background(), req.ID)
|
||||
case "network":
|
||||
inspectInfo, err = client.NetworkInspect(context.TODO(), req.ID, types.NetworkInspectOptions{})
|
||||
case "volume":
|
||||
inspectInfo, err = client.VolumeInspect(context.TODO(), req.ID)
|
||||
}
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bytes, err := json.Marshal(inspectInfo)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(bytes), nil
|
||||
}
|
||||
|
||||
func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error {
|
||||
var err error
|
||||
ctx := context.Background()
|
||||
@ -105,22 +129,6 @@ func (u *ContainerService) ContainerOperation(req dto.ContainerOperation) error
|
||||
return err
|
||||
}
|
||||
|
||||
func (u *ContainerService) ContainerInspect(id string) (string, error) {
|
||||
client, err := docker.NewDockerClient()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
inspect, err := client.ContainerInspect(context.Background(), id)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
bytes, err := json.Marshal(inspect)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(bytes), err
|
||||
}
|
||||
|
||||
func (u *ContainerService) ContainerLogs(req dto.ContainerLog) (string, error) {
|
||||
var (
|
||||
options types.ContainerLogsOptions
|
||||
|
@ -21,7 +21,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) {
|
||||
baseApi := v1.ApiGroupApp.BaseApi
|
||||
{
|
||||
baRouter.POST("/search", baseApi.SearchContainer)
|
||||
baRouter.GET("/detail/:id", baseApi.ContainerDetail)
|
||||
baRouter.POST("/inspect", baseApi.Inspect)
|
||||
withRecordRouter.POST("operate", baseApi.ContainerOperation)
|
||||
withRecordRouter.POST("/log", baseApi.ContainerLogs)
|
||||
|
||||
|
@ -16,6 +16,10 @@ export namespace Container {
|
||||
containerID: string;
|
||||
mode: string;
|
||||
}
|
||||
export interface ContainerInspect {
|
||||
id: string;
|
||||
type: string;
|
||||
}
|
||||
|
||||
export interface ImageInfo {
|
||||
id: string;
|
||||
|
@ -14,8 +14,8 @@ export const ContainerOperator = (params: Container.ContainerOperate) => {
|
||||
return http.post(`/containers/operate`, params);
|
||||
};
|
||||
|
||||
export const getContainerInspect = (containerID: string) => {
|
||||
return http.get<string>(`/containers/detail/${containerID}`);
|
||||
export const inspect = (params: Container.ContainerInspect) => {
|
||||
return http.post<string>(`/containers/inspect`, params);
|
||||
};
|
||||
|
||||
// image
|
||||
|
@ -37,7 +37,11 @@
|
||||
min-width="100"
|
||||
prop="name"
|
||||
fix
|
||||
/>
|
||||
>
|
||||
<template #default="{ row }">
|
||||
<el-link @click="onInspect(row.containerID)" type="primary">{{ row.name }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:label="$t('container.image')"
|
||||
show-overflow-tooltip
|
||||
@ -165,7 +169,7 @@ import { oneDark } from '@codemirror/theme-one-dark';
|
||||
import { reactive, onMounted, ref } from 'vue';
|
||||
import { dateFromat, dateFromatForName } from '@/utils/util';
|
||||
import { Rules } from '@/global/form-rules';
|
||||
import { ContainerOperator, getContainerInspect, getContainerLog, getContainerPage } from '@/api/modules/container';
|
||||
import { ContainerOperator, inspect, getContainerLog, getContainerPage } from '@/api/modules/container';
|
||||
import { Container } from '@/api/interface/container';
|
||||
import { ElForm, ElMessage, ElMessageBox, FormInstance } from 'element-plus';
|
||||
import i18n from '@/lang';
|
||||
@ -244,11 +248,12 @@ const onCreate = async () => {
|
||||
dialogCreateRef.value!.acceptParams();
|
||||
};
|
||||
|
||||
const onDetail = async (row: Container.ContainerInfo) => {
|
||||
const res = await getContainerInspect(row.containerID);
|
||||
const onInspect = async (id: string) => {
|
||||
const res = await inspect({ id: id, type: 'container' });
|
||||
detailInfo.value = JSON.stringify(JSON.parse(res.data), null, 2);
|
||||
detailVisiable.value = true;
|
||||
};
|
||||
|
||||
const onLog = async (row: Container.ContainerInfo) => {
|
||||
logSearch.container = row.name;
|
||||
logSearch.containerID = row.containerID;
|
||||
@ -371,12 +376,6 @@ const buttons = [
|
||||
onLog(row);
|
||||
},
|
||||
},
|
||||
{
|
||||
label: i18n.global.t('commons.button.view'),
|
||||
click: (row: Container.ContainerInfo) => {
|
||||
onDetail(row);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
onMounted(() => {
|
||||
|
@ -11,13 +11,11 @@
|
||||
</el-button>
|
||||
</template>
|
||||
<el-table-column type="selection" fix />
|
||||
<el-table-column
|
||||
:label="$t('commons.table.name')"
|
||||
show-overflow-tooltip
|
||||
min-width="80"
|
||||
prop="name"
|
||||
fix
|
||||
/>
|
||||
<el-table-column :label="$t('commons.table.name')" show-overflow-tooltip min-width="80" prop="name" fix>
|
||||
<template #default="{ row }">
|
||||
<el-link @click="onInspect(row.id)" type="primary">{{ row.name }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column :label="$t('container.driver')" show-overflow-tooltip min-width="40" prop="driver" />
|
||||
<el-table-column :label="$t('container.attachable')" min-width="40" prop="attachable" fix>
|
||||
<template #default="{ row }">
|
||||
@ -46,6 +44,33 @@
|
||||
</ComplexTable>
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="detailVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="70%">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>{{ $t('commons.button.view') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<codemirror
|
||||
:autofocus="true"
|
||||
placeholder="None data"
|
||||
:indent-with-tab="true"
|
||||
:tabSize="4"
|
||||
style="max-height: 500px"
|
||||
:lineWrapping="true"
|
||||
:matchBrackets="true"
|
||||
theme="cobalt"
|
||||
:styleActiveLine="true"
|
||||
:extensions="extensions"
|
||||
v-model="detailInfo"
|
||||
:readOnly="true"
|
||||
/>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="detailVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<CreateDialog @search="search" ref="dialogCreateRef" />
|
||||
</div>
|
||||
</template>
|
||||
@ -53,13 +78,20 @@
|
||||
<script lang="ts" setup>
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import CreateDialog from '@/views/container/network/create/index.vue';
|
||||
import { Codemirror } from 'vue-codemirror';
|
||||
import { javascript } from '@codemirror/lang-javascript';
|
||||
import { oneDark } from '@codemirror/theme-one-dark';
|
||||
import { reactive, onMounted, ref } from 'vue';
|
||||
import { dateFromat } from '@/utils/util';
|
||||
import { deleteNetwork, getNetworkPage } from '@/api/modules/container';
|
||||
import { deleteNetwork, getNetworkPage, inspect } from '@/api/modules/container';
|
||||
import { Container } from '@/api/interface/container';
|
||||
import i18n from '@/lang';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
|
||||
const detailVisiable = ref<boolean>(false);
|
||||
const detailInfo = ref();
|
||||
const extensions = [javascript(), oneDark];
|
||||
|
||||
const data = ref();
|
||||
const selects = ref<any>([]);
|
||||
const paginationConfig = reactive({
|
||||
@ -103,6 +135,12 @@ const batchDelete = async (row: Container.NetworkInfo | null) => {
|
||||
search();
|
||||
};
|
||||
|
||||
const onInspect = async (id: string) => {
|
||||
const res = await inspect({ id: id, type: 'network' });
|
||||
detailInfo.value = JSON.stringify(JSON.parse(res.data), null, 2);
|
||||
detailVisiable.value = true;
|
||||
};
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: i18n.global.t('commons.button.delete'),
|
||||
|
@ -11,13 +11,11 @@
|
||||
</el-button>
|
||||
</template>
|
||||
<el-table-column type="selection" fix />
|
||||
<el-table-column
|
||||
:label="$t('commons.table.name')"
|
||||
show-overflow-tooltip
|
||||
min-width="80"
|
||||
prop="name"
|
||||
fix
|
||||
/>
|
||||
<el-table-column :label="$t('commons.table.name')" show-overflow-tooltip min-width="80" prop="name" fix>
|
||||
<template #default="{ row }">
|
||||
<el-link @click="onInspect(row.name)" type="primary">{{ row.name }}</el-link>
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column
|
||||
:label="$t('container.mountpoint')"
|
||||
show-overflow-tooltip
|
||||
@ -35,6 +33,33 @@
|
||||
</ComplexTable>
|
||||
</el-card>
|
||||
|
||||
<el-dialog v-model="detailVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="70%">
|
||||
<template #header>
|
||||
<div class="card-header">
|
||||
<span>{{ $t('commons.button.view') }}</span>
|
||||
</div>
|
||||
</template>
|
||||
<codemirror
|
||||
:autofocus="true"
|
||||
placeholder="None data"
|
||||
:indent-with-tab="true"
|
||||
:tabSize="4"
|
||||
style="max-height: 500px"
|
||||
:lineWrapping="true"
|
||||
:matchBrackets="true"
|
||||
theme="cobalt"
|
||||
:styleActiveLine="true"
|
||||
:extensions="extensions"
|
||||
v-model="detailInfo"
|
||||
:readOnly="true"
|
||||
/>
|
||||
<template #footer>
|
||||
<span class="dialog-footer">
|
||||
<el-button @click="detailVisiable = false">{{ $t('commons.button.cancel') }}</el-button>
|
||||
</span>
|
||||
</template>
|
||||
</el-dialog>
|
||||
|
||||
<CreateDialog @search="search" ref="dialogCreateRef" />
|
||||
</div>
|
||||
</template>
|
||||
@ -42,13 +67,20 @@
|
||||
<script lang="ts" setup>
|
||||
import ComplexTable from '@/components/complex-table/index.vue';
|
||||
import CreateDialog from '@/views/container/volume/create/index.vue';
|
||||
import { Codemirror } from 'vue-codemirror';
|
||||
import { javascript } from '@codemirror/lang-javascript';
|
||||
import { oneDark } from '@codemirror/theme-one-dark';
|
||||
import { reactive, onMounted, ref } from 'vue';
|
||||
import { dateFromat } from '@/utils/util';
|
||||
import { deleteVolume, getVolumePage } from '@/api/modules/container';
|
||||
import { deleteVolume, getVolumePage, inspect } from '@/api/modules/container';
|
||||
import { Container } from '@/api/interface/container';
|
||||
import i18n from '@/lang';
|
||||
import { useDeleteData } from '@/hooks/use-delete-data';
|
||||
|
||||
const detailVisiable = ref<boolean>(false);
|
||||
const detailInfo = ref();
|
||||
const extensions = [javascript(), oneDark];
|
||||
|
||||
const data = ref();
|
||||
const selects = ref<any>([]);
|
||||
const paginationConfig = reactive({
|
||||
@ -79,6 +111,12 @@ const search = async () => {
|
||||
});
|
||||
};
|
||||
|
||||
const onInspect = async (id: string) => {
|
||||
const res = await inspect({ id: id, type: 'volume' });
|
||||
detailInfo.value = JSON.stringify(JSON.parse(res.data), null, 2);
|
||||
detailVisiable.value = true;
|
||||
};
|
||||
|
||||
const batchDelete = async (row: Container.VolumeInfo | null) => {
|
||||
let ids: Array<string> = [];
|
||||
if (row === null) {
|
||||
|
Loading…
Reference in New Issue
Block a user