1
0
mirror of https://github.com/1Panel-dev/1Panel.git synced 2025-01-19 16:29:17 +08:00

feat: 增加 daemon.json 文件不存在或为空提示

This commit is contained in:
ssongliu 2023-02-01 16:15:31 +08:00 committed by ssongliu
parent d22b0a1368
commit b6e660a6cd
39 changed files with 641 additions and 430 deletions

View File

@ -1,6 +1,9 @@
package v1 package v1
import ( import (
"io/ioutil"
"os"
"github.com/1Panel-dev/1Panel/backend/app/api/v1/helper" "github.com/1Panel-dev/1Panel/backend/app/api/v1/helper"
"github.com/1Panel-dev/1Panel/backend/app/dto" "github.com/1Panel-dev/1Panel/backend/app/dto"
"github.com/1Panel-dev/1Panel/backend/constant" "github.com/1Panel-dev/1Panel/backend/constant"
@ -20,6 +23,26 @@ func (b *BaseApi) LoadDockerStatus(c *gin.Context) {
helper.SuccessWithData(c, status) helper.SuccessWithData(c, status)
} }
// @Tags Container Docker
// @Summary Load docker daemon.json
// @Description 获取 docker 配置信息(表单)
// @Produce json
// @Success 200 {object} string
// @Security ApiKeyAuth
// @Router /containers/daemonjson/file [get]
func (b *BaseApi) LoadDaemonJsonFile(c *gin.Context) {
if _, err := os.Stat(constant.DaemonJsonPath); err != nil {
helper.SuccessWithData(c, "daemon.json is not find in path")
return
}
content, err := ioutil.ReadFile(constant.DaemonJsonPath)
if err != nil {
helper.ErrorWithDetail(c, constant.CodeErrInternalServer, constant.ErrTypeInternalServer, err)
return
}
helper.SuccessWithData(c, string(content))
}
// @Tags Container Docker // @Tags Container Docker
// @Summary Load docker daemon.json // @Summary Load docker daemon.json
// @Description 获取 docker 配置信息 // @Description 获取 docker 配置信息

View File

@ -60,6 +60,7 @@ func (s *ContainerRouter) InitContainerRouter(Router *gin.RouterGroup) {
baRouter.POST("/volume", baseApi.CreateVolume) baRouter.POST("/volume", baseApi.CreateVolume)
baRouter.GET("/daemonjson", baseApi.LoadDaemonJson) baRouter.GET("/daemonjson", baseApi.LoadDaemonJson)
baRouter.GET("/daemonjson/file", baseApi.LoadDaemonJsonFile)
baRouter.GET("/docker/status", baseApi.LoadDockerStatus) baRouter.GET("/docker/status", baseApi.LoadDockerStatus)
baRouter.POST("/docker/operate", baseApi.OperateDocker) baRouter.POST("/docker/operate", baseApi.OperateDocker)
baRouter.POST("/daemonjson/update", baseApi.UpdateDaemonJson) baRouter.POST("/daemonjson/update", baseApi.UpdateDaemonJson)

View File

@ -881,17 +881,14 @@ var doc = `{
}, },
"/auth/status": { "/auth/status": {
"get": { "get": {
"description": "获取系统安全登录状态", "description": "判断是否为首次登录",
"tags": [ "tags": [
"Auth" "Auth"
], ],
"summary": "Load safety status", "summary": "Check is First login",
"responses": { "responses": {
"200": { "200": {
"description": "" "description": ""
},
"402": {
"description": ""
} }
} }
} }
@ -1637,6 +1634,31 @@ var doc = `{
} }
} }
}, },
"/containers/daemonjson/file": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取 docker 配置信息(表单)",
"produces": [
"application/json"
],
"tags": [
"Container Docker"
],
"summary": "Load docker daemon.json",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
}
},
"/containers/daemonjson/update": { "/containers/daemonjson/update": {
"post": { "post": {
"security": [ "security": [
@ -6230,6 +6252,25 @@ var doc = `{
} }
} }
}, },
"/settings/search/available": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取系统可用状态",
"tags": [
"System Setting"
],
"summary": "Load system available status",
"responses": {
"200": {
"description": ""
}
}
}
},
"/settings/snapshot": { "/settings/snapshot": {
"post": { "post": {
"security": [ "security": [
@ -10553,15 +10594,18 @@ var doc = `{
"model.App": { "model.App": {
"type": "object", "type": "object",
"properties": { "properties": {
"author": {
"type": "string"
},
"createdAt": { "createdAt": {
"type": "string" "type": "string"
}, },
"crossVersionUpdate": { "crossVersionUpdate": {
"type": "boolean" "type": "boolean"
}, },
"document": {
"type": "string"
},
"github": {
"type": "string"
},
"icon": { "icon": {
"type": "string" "type": "string"
}, },
@ -10583,9 +10627,6 @@ var doc = `{
"shortDesc": { "shortDesc": {
"type": "string" "type": "string"
}, },
"source": {
"type": "string"
},
"status": { "status": {
"type": "string" "type": "string"
}, },
@ -10594,6 +10635,9 @@ var doc = `{
}, },
"updatedAt": { "updatedAt": {
"type": "string" "type": "string"
},
"website": {
"type": "string"
} }
} }
}, },
@ -10981,8 +11025,20 @@ var doc = `{
"pageSize": { "pageSize": {
"type": "integer" "type": "integer"
}, },
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"type": { "type": {
"type": "string" "type": "string"
},
"unused": {
"type": "boolean"
},
"update": {
"type": "boolean"
} }
} }
}, },
@ -11852,15 +11908,18 @@ var doc = `{
"response.AppDTO": { "response.AppDTO": {
"type": "object", "type": "object",
"properties": { "properties": {
"author": {
"type": "string"
},
"createdAt": { "createdAt": {
"type": "string" "type": "string"
}, },
"crossVersionUpdate": { "crossVersionUpdate": {
"type": "boolean" "type": "boolean"
}, },
"document": {
"type": "string"
},
"github": {
"type": "string"
},
"icon": { "icon": {
"type": "string" "type": "string"
}, },
@ -11882,9 +11941,6 @@ var doc = `{
"shortDesc": { "shortDesc": {
"type": "string" "type": "string"
}, },
"source": {
"type": "string"
},
"status": { "status": {
"type": "string" "type": "string"
}, },
@ -11905,6 +11961,9 @@ var doc = `{
"items": { "items": {
"type": "string" "type": "string"
} }
},
"website": {
"type": "string"
} }
} }
}, },

View File

@ -867,17 +867,14 @@
}, },
"/auth/status": { "/auth/status": {
"get": { "get": {
"description": "获取系统安全登录状态", "description": "判断是否为首次登录",
"tags": [ "tags": [
"Auth" "Auth"
], ],
"summary": "Load safety status", "summary": "Check is First login",
"responses": { "responses": {
"200": { "200": {
"description": "" "description": ""
},
"402": {
"description": ""
} }
} }
} }
@ -1623,6 +1620,31 @@
} }
} }
}, },
"/containers/daemonjson/file": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取 docker 配置信息(表单)",
"produces": [
"application/json"
],
"tags": [
"Container Docker"
],
"summary": "Load docker daemon.json",
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "string"
}
}
}
}
},
"/containers/daemonjson/update": { "/containers/daemonjson/update": {
"post": { "post": {
"security": [ "security": [
@ -6216,6 +6238,25 @@
} }
} }
}, },
"/settings/search/available": {
"get": {
"security": [
{
"ApiKeyAuth": []
}
],
"description": "获取系统可用状态",
"tags": [
"System Setting"
],
"summary": "Load system available status",
"responses": {
"200": {
"description": ""
}
}
}
},
"/settings/snapshot": { "/settings/snapshot": {
"post": { "post": {
"security": [ "security": [
@ -10539,15 +10580,18 @@
"model.App": { "model.App": {
"type": "object", "type": "object",
"properties": { "properties": {
"author": {
"type": "string"
},
"createdAt": { "createdAt": {
"type": "string" "type": "string"
}, },
"crossVersionUpdate": { "crossVersionUpdate": {
"type": "boolean" "type": "boolean"
}, },
"document": {
"type": "string"
},
"github": {
"type": "string"
},
"icon": { "icon": {
"type": "string" "type": "string"
}, },
@ -10569,9 +10613,6 @@
"shortDesc": { "shortDesc": {
"type": "string" "type": "string"
}, },
"source": {
"type": "string"
},
"status": { "status": {
"type": "string" "type": "string"
}, },
@ -10580,6 +10621,9 @@
}, },
"updatedAt": { "updatedAt": {
"type": "string" "type": "string"
},
"website": {
"type": "string"
} }
} }
}, },
@ -10967,8 +11011,20 @@
"pageSize": { "pageSize": {
"type": "integer" "type": "integer"
}, },
"tags": {
"type": "array",
"items": {
"type": "string"
}
},
"type": { "type": {
"type": "string" "type": "string"
},
"unused": {
"type": "boolean"
},
"update": {
"type": "boolean"
} }
} }
}, },
@ -11838,15 +11894,18 @@
"response.AppDTO": { "response.AppDTO": {
"type": "object", "type": "object",
"properties": { "properties": {
"author": {
"type": "string"
},
"createdAt": { "createdAt": {
"type": "string" "type": "string"
}, },
"crossVersionUpdate": { "crossVersionUpdate": {
"type": "boolean" "type": "boolean"
}, },
"document": {
"type": "string"
},
"github": {
"type": "string"
},
"icon": { "icon": {
"type": "string" "type": "string"
}, },
@ -11868,9 +11927,6 @@
"shortDesc": { "shortDesc": {
"type": "string" "type": "string"
}, },
"source": {
"type": "string"
},
"status": { "status": {
"type": "string" "type": "string"
}, },
@ -11891,6 +11947,9 @@
"items": { "items": {
"type": "string" "type": "string"
} }
},
"website": {
"type": "string"
} }
} }
}, },

View File

@ -1447,12 +1447,14 @@ definitions:
type: object type: object
model.App: model.App:
properties: properties:
author:
type: string
createdAt: createdAt:
type: string type: string
crossVersionUpdate: crossVersionUpdate:
type: boolean type: boolean
document:
type: string
github:
type: string
icon: icon:
type: string type: string
id: id:
@ -1467,14 +1469,14 @@ definitions:
type: string type: string
shortDesc: shortDesc:
type: string type: string
source:
type: string
status: status:
type: string type: string
type: type:
type: string type: string
updatedAt: updatedAt:
type: string type: string
website:
type: string
type: object type: object
model.AppInstall: model.AppInstall:
properties: properties:
@ -1727,8 +1729,16 @@ definitions:
type: integer type: integer
pageSize: pageSize:
type: integer type: integer
tags:
items:
type: string
type: array
type: type:
type: string type: string
unused:
type: boolean
update:
type: boolean
required: required:
- page - page
- pageSize - pageSize
@ -2314,12 +2324,14 @@ definitions:
type: object type: object
response.AppDTO: response.AppDTO:
properties: properties:
author:
type: string
createdAt: createdAt:
type: string type: string
crossVersionUpdate: crossVersionUpdate:
type: boolean type: boolean
document:
type: string
github:
type: string
icon: icon:
type: string type: string
id: id:
@ -2334,8 +2346,6 @@ definitions:
type: string type: string
shortDesc: shortDesc:
type: string type: string
source:
type: string
status: status:
type: string type: string
tags: tags:
@ -2350,6 +2360,8 @@ definitions:
items: items:
type: string type: string
type: array type: array
website:
type: string
type: object type: object
response.AppDetailDTO: response.AppDetailDTO:
properties: properties:
@ -3125,13 +3137,11 @@ paths:
- Auth - Auth
/auth/status: /auth/status:
get: get:
description: 获取系统安全登录状态 description: 判断是否为首次登录
responses: responses:
"200": "200":
description: "" description: ""
"402": summary: Check is First login
description: ""
summary: Load safety status
tags: tags:
- Auth - Auth
/backups: /backups:
@ -3605,6 +3615,21 @@ paths:
summary: Load docker daemon.json summary: Load docker daemon.json
tags: tags:
- Container Docker - Container Docker
/containers/daemonjson/file:
get:
description: 获取 docker 配置信息(表单)
produces:
- application/json
responses:
"200":
description: OK
schema:
type: string
security:
- ApiKeyAuth: []
summary: Load docker daemon.json
tags:
- Container Docker
/containers/daemonjson/update: /containers/daemonjson/update:
post: post:
consumes: consumes:
@ -6529,6 +6554,17 @@ paths:
summary: Load system setting info summary: Load system setting info
tags: tags:
- System Setting - System Setting
/settings/search/available:
get:
description: 获取系统可用状态
responses:
"200":
description: ""
security:
- ApiKeyAuth: []
summary: Load system available status
tags:
- System Setting
/settings/snapshot: /settings/snapshot:
post: post:
consumes: consumes:

View File

@ -130,6 +130,9 @@ export const dockerOperate = (params: Container.DockerOperate) => {
export const loadDaemonJson = () => { export const loadDaemonJson = () => {
return http.get<Container.DaemonJsonConf>(`/containers/daemonjson`); return http.get<Container.DaemonJsonConf>(`/containers/daemonjson`);
}; };
export const loadDaemonJsonFile = () => {
return http.get<string>(`/containers/daemonjson/file`);
};
export const loadDockerStatus = () => { export const loadDockerStatus = () => {
return http.get<string>(`/containers/docker/status`); return http.get<string>(`/containers/docker/status`);
}; };

View File

@ -17,7 +17,7 @@
placeholder="None data" placeholder="None data"
:indent-with-tab="true" :indent-with-tab="true"
:tabSize="4" :tabSize="4"
style="margin-top: 10px; height: calc(100vh - 350px)" style="margin-top: 10px; height: calc(100vh - 375px)"
:lineWrapping="true" :lineWrapping="true"
:matchBrackets="true" :matchBrackets="true"
theme="cobalt" theme="cobalt"

View File

@ -3,12 +3,12 @@ export default {
true: 'true', true: 'true',
false: 'false', false: 'false',
button: { button: {
create: 'Create', create: 'Create ',
add: 'Add', add: 'Add ',
save: 'Save', save: 'Save ',
set: 'Reset', set: 'Reset',
sync: 'Sync', sync: 'Sync ',
delete: 'Delete', delete: 'Delete ',
edit: 'Edit', edit: 'Edit',
enable: 'Enable', enable: 'Enable',
disable: 'Disable', disable: 'Disable',

View File

@ -79,7 +79,7 @@ export default {
infoTitle: '提示', infoTitle: '提示',
notRecords: '当前任务未产生执行记录', notRecords: '当前任务未产生执行记录',
sureLogOut: '您是否确认退出登录?', sureLogOut: '您是否确认退出登录?',
createSuccess: '建成功', createSuccess: '建成功',
updateSuccess: '更新成功', updateSuccess: '更新成功',
uploadSuccess: '上传成功', uploadSuccess: '上传成功',
operate: '操作', operate: '操作',
@ -245,7 +245,7 @@ export default {
database: { database: {
delete: '删除操作无法回滚请输入 "', delete: '删除操作无法回滚请输入 "',
deleteHelper: '" 删除此数据库', deleteHelper: '" 删除此数据库',
create: '建数据库', create: '建数据库',
noMysql: '当前未检测到 {0} 数据库请进入应用商店点击安装', noMysql: '当前未检测到 {0} 数据库请进入应用商店点击安装',
mysqlBadStatus: '当前 mysql 应用状态异常请在', mysqlBadStatus: '当前 mysql 应用状态异常请在',
adjust: '中查看原因或修改配置', adjust: '中查看原因或修改配置',
@ -269,7 +269,6 @@ export default {
portSetting: '端口', portSetting: '端口',
portHelper: '该端口为容器对外暴露端口修改需要单独保存并且重启容器', portHelper: '该端口为容器对外暴露端口修改需要单独保存并且重启容器',
baseSetting: '基础设置',
confChange: '配置修改', confChange: '配置修改',
unSupportType: '不支持当前文件类型', unSupportType: '不支持当前文件类型',
@ -746,7 +745,7 @@ export default {
snapshot: '快照', snapshot: '快照',
recoverDetail: '恢复详情', recoverDetail: '恢复详情',
createSnapshot: '建快照', createSnapshot: '建快照',
recover: '恢复', recover: '恢复',
noRecoverRecord: '暂无恢复记录', noRecoverRecord: '暂无恢复记录',
lastRecoverAt: '上次恢复时间', lastRecoverAt: '上次恢复时间',
@ -890,7 +889,7 @@ export default {
remark: '备注', remark: '备注',
group: '分组', group: '分组',
groupSetting: '分组管理', groupSetting: '分组管理',
createGroup: '建分组', createGroup: '建分组',
app: '应用', app: '应用',
appNew: '新装应用', appNew: '新装应用',
appInstalled: '已装应用', appInstalled: '已装应用',
@ -923,7 +922,7 @@ export default {
check: '查看', check: '查看',
acmeAccountManage: 'Acme 账户', acmeAccountManage: 'Acme 账户',
email: '邮箱', email: '邮箱',
addAccount: '建账户', addAccount: '建账户',
acmeAccount: 'Acme 账户', acmeAccount: 'Acme 账户',
provider: '验证方式', provider: '验证方式',
dnsCommon: '手动解析', dnsCommon: '手动解析',
@ -1052,7 +1051,7 @@ export default {
saveAndReload: '保存并重载', saveAndReload: '保存并重载',
}, },
ssl: { ssl: {
create: '建证书', create: '建证书',
provider: '类型', provider: '类型',
manualCreate: '手动创建', manualCreate: '手动创建',
acmeAccount: 'Acme 账号', acmeAccount: 'Acme 账号',
@ -1072,7 +1071,7 @@ export default {
autoRenewHelper: '距离到期时间7天自动续签', autoRenewHelper: '距离到期时间7天自动续签',
renewSuccess: '续签成功', renewSuccess: '续签成功',
renewWebsite: '该证书已经和以下网站关联续签会同步应用到这些网站', renewWebsite: '该证书已经和以下网站关联续签会同步应用到这些网站',
createAcme: '建账户', createAcme: '建账户',
}, },
firewall: { firewall: {
ccDeny: 'CC 防护', ccDeny: 'CC 防护',

View File

@ -100,7 +100,7 @@ const showBack = computed(() => {
} }
.content-container__toolbar { .content-container__toolbar {
margin-top: 30px; margin-top: 20px;
} }
.content-container_form { .content-container_form {

View File

@ -35,7 +35,7 @@
</el-row> </el-row>
</el-card> </el-card>
</div> </div>
<el-card style="margin-top: 20px"> <el-card style="margin-top: 40px">
<LayoutContent :header="$t('container.containerList')" back-name="Compose" :reload="true"> <LayoutContent :header="$t('container.containerList')" back-name="Compose" :reload="true">
<ComplexTable <ComplexTable
:pagination-config="paginationConfig" :pagination-config="paginationConfig"
@ -99,7 +99,7 @@
show-overflow-tooltip show-overflow-tooltip
/> />
<fu-table-operations <fu-table-operations
width="200px" width="220"
:ellipsis="10" :ellipsis="10"
:buttons="buttons" :buttons="buttons"
:label="$t('commons.table.operate')" :label="$t('commons.table.operate')"

View File

@ -10,13 +10,13 @@
<LayoutContent v-loading="loading" :title="$t('container.image')" :class="{ mask: dockerStatus != 'Running' }"> <LayoutContent v-loading="loading" :title="$t('container.image')" :class="{ mask: dockerStatus != 'Running' }">
<template #toolbar> <template #toolbar>
<el-button @click="onOpenPull"> <el-button type="primary" plain @click="onOpenPull">
{{ $t('container.imagePull') }} {{ $t('container.imagePull') }}
</el-button> </el-button>
<el-button @click="onOpenload"> <el-button type="primary" plain @click="onOpenload">
{{ $t('container.importImage') }} {{ $t('container.importImage') }}
</el-button> </el-button>
<el-button @click="onOpenBuild"> <el-button type="primary" plain @click="onOpenBuild">
{{ $t('container.build') }} {{ $t('container.build') }}
</el-button> </el-button>
</template> </template>

View File

@ -7,7 +7,7 @@
size="50%" size="50%"
> >
<template #header> <template #header>
<DrawerHeader :header="$t('container.imagePull')" :back="handleClose" /> <DrawerHeader :header="$t('container.imagePull')" :back="onCloseLog" />
</template> </template>
<el-row type="flex" justify="center"> <el-row type="flex" justify="center">
<el-col :span="22"> <el-col :span="22">
@ -106,13 +106,8 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
buttonDisabled.value = false; buttonDisabled.value = false;
logInfo.value = ''; logInfo.value = '';
}; };
const emit = defineEmits<{ (e: 'search'): void }>(); const emit = defineEmits<{ (e: 'search'): void }>();
const handleClose = () => {
drawerVisiable.value = false;
};
type FormInstance = InstanceType<typeof ElForm>; type FormInstance = InstanceType<typeof ElForm>;
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>();
@ -150,6 +145,7 @@ const onCloseLog = async () => {
emit('search'); emit('search');
clearInterval(Number(timer)); clearInterval(Number(timer));
timer = null; timer = null;
drawerVisiable.value = false;
}; };
function loadDetailInfo(id: number) { function loadDetailInfo(id: number) {

View File

@ -1,13 +1,13 @@
<template> <template>
<el-drawer <el-drawer
v-model="drawerVisiable" v-model="drawerVisiable"
@close="onCloseLog"
:destroy-on-close="true" :destroy-on-close="true"
@close="onCloseLog"
:close-on-click-modal="false" :close-on-click-modal="false"
size="50%" size="50%"
> >
<template #header> <template #header>
<DrawerHeader :header="$t('container.imagePush')" :back="handleClose" /> <DrawerHeader :header="$t('container.imagePush')" :back="onCloseLog" />
</template> </template>
<el-row type="flex" justify="center"> <el-row type="flex" justify="center">
<el-col :span="22"> <el-col :span="22">
@ -116,10 +116,6 @@ const acceptParams = async (params: DialogProps): Promise<void> => {
}; };
const emit = defineEmits<{ (e: 'search'): void }>(); const emit = defineEmits<{ (e: 'search'): void }>();
const handleClose = () => {
drawerVisiable.value = false;
};
type FormInstance = InstanceType<typeof ElForm>; type FormInstance = InstanceType<typeof ElForm>;
const formRef = ref<FormInstance>(); const formRef = ref<FormInstance>();
@ -154,6 +150,7 @@ const onCloseLog = async () => {
emit('search'); emit('search');
clearInterval(Number(timer)); clearInterval(Number(timer));
timer = null; timer = null;
drawerVisiable.value = false;
}; };
function loadDetailInfo(id: number) { function loadDetailInfo(id: number) {

View File

@ -17,7 +17,7 @@
<el-button type="primary" @click="onCreate()"> <el-button type="primary" @click="onCreate()">
{{ $t('container.createNetwork') }} {{ $t('container.createNetwork') }}
</el-button> </el-button>
<el-button plain :disabled="selects.length === 0" @click="batchDelete(null)"> <el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
{{ $t('commons.button.delete') }} {{ $t('commons.button.delete') }}
</el-button> </el-button>
</template> </template>

View File

@ -13,7 +13,7 @@
<el-button type="primary" @click="onOpenDialog('create')"> <el-button type="primary" @click="onOpenDialog('create')">
{{ $t('container.createRepo') }} {{ $t('container.createRepo') }}
</el-button> </el-button>
<el-button plain :disabled="selects.length === 0" @click="onBatchDelete(null)"> <el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }} {{ $t('commons.button.delete') }}
</el-button> </el-button>
</template> </template>

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<div class="app-content" style="margin-top: 20px"> <div class="app-content" style="margin-top: 30px">
<el-card class="app-card"> <el-card class="app-card">
<el-row :gutter="20"> <el-row :gutter="20">
<el-col :lg="3" :xl="2"> <el-col :lg="3" :xl="2">
@ -49,7 +49,7 @@
</el-card> </el-card>
</div> </div>
<LayoutContent v-loading="loading" :title="$t('container.setting')" :divider="true"> <LayoutContent v-loading="loading" style="margin-top: 30px" :title="$t('container.setting')" :divider="true">
<template #main> <template #main>
<el-radio-group v-model="confShowType" @change="changeMode"> <el-radio-group v-model="confShowType" @change="changeMode">
<el-radio-button label="base">{{ $t('database.baseConf') }}</el-radio-button> <el-radio-button label="base">{{ $t('database.baseConf') }}</el-radio-button>
@ -58,7 +58,7 @@
<el-row style="margin-top: 20px" v-if="confShowType === 'base'"> <el-row style="margin-top: 20px" v-if="confShowType === 'base'">
<el-col :span="1"><br /></el-col> <el-col :span="1"><br /></el-col>
<el-col :span="10"> <el-col :span="10">
<el-form :model="form" ref="formRef" label-width="120px"> <el-form :model="form" label-position="left" ref="formRef" label-width="120px">
<el-form-item :label="$t('container.mirrors')" prop="mirrors"> <el-form-item :label="$t('container.mirrors')" prop="mirrors">
<el-input <el-input
type="textarea" type="textarea"
@ -98,10 +98,10 @@
<div v-if="confShowType === 'all'"> <div v-if="confShowType === 'all'">
<codemirror <codemirror
:autofocus="true" :autofocus="true"
placeholder="None data" placeholder="# The Docker configuration file does not exist or is empty (/etc/docker/daemon.json)"
:indent-with-tab="true" :indent-with-tab="true"
:tabSize="4" :tabSize="4"
style="margin-top: 10px; height: calc(100vh - 380px)" style="margin-top: 10px; height: calc(100vh - 430px)"
:lineWrapping="true" :lineWrapping="true"
:matchBrackets="true" :matchBrackets="true"
theme="cobalt" theme="cobalt"
@ -128,13 +128,18 @@ import { Codemirror } from 'vue-codemirror';
import LayoutContent from '@/layout/layout-content.vue'; import LayoutContent from '@/layout/layout-content.vue';
import { javascript } from '@codemirror/lang-javascript'; import { javascript } from '@codemirror/lang-javascript';
import { oneDark } from '@codemirror/theme-one-dark'; import { oneDark } from '@codemirror/theme-one-dark';
import { LoadFile } from '@/api/modules/files';
import ConfirmDialog from '@/components/confirm-dialog/index.vue'; import ConfirmDialog from '@/components/confirm-dialog/index.vue';
import i18n from '@/lang'; import i18n from '@/lang';
import { dockerOperate, loadDaemonJson, updateDaemonJson, updateDaemonJsonByfile } from '@/api/modules/container'; import {
dockerOperate,
loadDaemonJson,
loadDaemonJsonFile,
updateDaemonJson,
updateDaemonJsonByfile,
} from '@/api/modules/container';
const loading = ref(false); const loading = ref(false);
const showDaemonJsonAlert = ref(false);
const extensions = [javascript(), oneDark]; const extensions = [javascript(), oneDark];
const confShowType = ref('base'); const confShowType = ref('base');
@ -224,14 +229,20 @@ const onSubmitSave = async () => {
}; };
const loadDockerConf = async () => { const loadDockerConf = async () => {
const res = await LoadFile({ path: '/etc/docker/daemon.json' }); const res = await loadDaemonJsonFile();
dockerConf.value = res.data; if (res.data === 'daemon.json is not find in path') {
console.log(res.data);
showDaemonJsonAlert.value = true;
} else {
dockerConf.value = res.data;
}
}; };
const changeMode = async () => { const changeMode = async () => {
if (confShowType.value === 'all') { if (confShowType.value === 'all') {
loadDockerConf(); loadDockerConf();
} else { } else {
showDaemonJsonAlert.value = false;
search(); search();
} }
}; };

View File

@ -17,7 +17,7 @@
<el-button type="primary" @click="onOpenDialog('create')"> <el-button type="primary" @click="onOpenDialog('create')">
{{ $t('container.createComposeTemplate') }} {{ $t('container.createComposeTemplate') }}
</el-button> </el-button>
<el-button plain :disabled="selects.length === 0" @click="onBatchDelete(null)"> <el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }} {{ $t('commons.button.delete') }}
</el-button> </el-button>
</template> </template>

View File

@ -13,7 +13,7 @@
<el-button type="primary" @click="onCreate()"> <el-button type="primary" @click="onCreate()">
{{ $t('container.createVolume') }} {{ $t('container.createVolume') }}
</el-button> </el-button>
<el-button plain :disabled="selects.length === 0" @click="batchDelete(null)"> <el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
{{ $t('commons.button.delete') }} {{ $t('commons.button.delete') }}
</el-button> </el-button>
</template> </template>

View File

@ -13,7 +13,7 @@
<el-button type="primary" @click="onOpenDialog('create')"> <el-button type="primary" @click="onOpenDialog('create')">
{{ $t('commons.button.create') }}{{ $t('cronjob.cronTask') }} {{ $t('commons.button.create') }}{{ $t('cronjob.cronTask') }}
</el-button> </el-button>
<el-button plain :disabled="selects.length === 0" @click="onBatchDelete(null)"> <el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }} {{ $t('commons.button.delete') }}
</el-button> </el-button>
</template> </template>

View File

@ -3,130 +3,148 @@
<template #header> <template #header>
<DrawerHeader :header="$t('cronjob.cronTask')" :back="handleClose" /> <DrawerHeader :header="$t('cronjob.cronTask')" :back="handleClose" />
</template> </template>
<el-form ref="formRef" :model="dialogData.rowData" label-position="left" :rules="rules" label-width="120px"> <el-form ref="formRef" label-position="top" :model="dialogData.rowData" :rules="rules" label-width="120px">
<el-form-item :label="$t('cronjob.taskType')" prop="type"> <el-row type="flex" justify="center">
<el-select style="width: 100%" v-model="dialogData.rowData!.type"> <el-col :span="22">
<el-option value="shell" :label="$t('cronjob.shell')" /> <el-form-item :label="$t('cronjob.taskType')" prop="type">
<el-option value="website" :label="$t('cronjob.website')" /> <el-select style="width: 100%" v-model="dialogData.rowData!.type">
<el-option value="database" :label="$t('cronjob.database')" /> <el-option value="shell" :label="$t('cronjob.shell')" />
<el-option value="directory" :label="$t('cronjob.directory')" /> <el-option value="website" :label="$t('cronjob.website')" />
<el-option value="curl" :label="$t('cronjob.curl') + ' URL'" /> <el-option value="database" :label="$t('cronjob.database')" />
</el-select> <el-option value="directory" :label="$t('cronjob.directory')" />
</el-form-item> <el-option value="curl" :label="$t('cronjob.curl') + ' URL'" />
</el-select>
</el-form-item>
<el-form-item :label="$t('cronjob.taskName')" prop="name"> <el-form-item :label="$t('cronjob.taskName')" prop="name">
<el-input style="width: 100%" clearable v-model.trim="dialogData.rowData!.name" /> <el-input style="width: 100%" clearable v-model.trim="dialogData.rowData!.name" />
</el-form-item> </el-form-item>
<el-form-item :label="$t('cronjob.cronSpec')" prop="spec"> <el-form-item :label="$t('cronjob.cronSpec')" prop="spec">
<el-select style="width: 20%" v-model="dialogData.rowData!.specType"> <el-select style="width: 20%" v-model="dialogData.rowData!.specType">
<el-option v-for="item in specOptions" :key="item.label" :value="item.value" :label="item.label" /> <el-option
</el-select> v-for="item in specOptions"
<el-select :key="item.label"
v-if="dialogData.rowData!.specType === 'perWeek'" :value="item.value"
style="width: 12%; margin-left: 20px" :label="item.label"
v-model="dialogData.rowData!.week" />
> </el-select>
<el-option v-for="item in weekOptions" :key="item.label" :value="item.value" :label="item.label" /> <el-select
</el-select> v-if="dialogData.rowData!.specType === 'perWeek'"
<el-input style="width: 12%; margin-left: 20px"
v-if="dialogData.rowData!.specType === 'perMonth' || dialogData.rowData!.specType === 'perNDay'" v-model="dialogData.rowData!.week"
style="width: 20%; margin-left: 20px" >
v-model.number="dialogData.rowData!.day" <el-option
> v-for="item in weekOptions"
<template #append>{{ $t('cronjob.day') }}</template> :key="item.label"
</el-input> :value="item.value"
<el-input :label="item.label"
v-if="dialogData.rowData!.specType !== 'perHour' && dialogData.rowData!.specType !== 'perNMinute'" />
style="width: 20%; margin-left: 20px" </el-select>
v-model.number="dialogData.rowData!.hour" <el-input
> v-if="dialogData.rowData!.specType === 'perMonth' || dialogData.rowData!.specType === 'perNDay'"
<template #append>{{ $t('cronjob.hour') }}</template> style="width: 20%; margin-left: 20px"
</el-input> v-model.number="dialogData.rowData!.day"
<el-input style="width: 20%; margin-left: 20px" v-model.number="dialogData.rowData!.minute"> >
<template #append>{{ $t('cronjob.minute') }}</template> <template #append>{{ $t('cronjob.day') }}</template>
</el-input> </el-input>
</el-form-item> <el-input
v-if="dialogData.rowData!.specType !== 'perHour' && dialogData.rowData!.specType !== 'perNMinute'"
style="width: 20%; margin-left: 20px"
v-model.number="dialogData.rowData!.hour"
>
<template #append>{{ $t('cronjob.hour') }}</template>
</el-input>
<el-input style="width: 20%; margin-left: 20px" v-model.number="dialogData.rowData!.minute">
<template #append>{{ $t('cronjob.minute') }}</template>
</el-input>
</el-form-item>
<el-form-item v-if="hasScript()" :label="$t('cronjob.shellContent')" prop="script"> <el-form-item v-if="hasScript()" :label="$t('cronjob.shellContent')" prop="script">
<el-input <el-input
style="width: 100%" style="width: 100%"
clearable clearable
type="textarea" type="textarea"
:autosize="{ minRows: 3, maxRows: 6 }" :autosize="{ minRows: 3, maxRows: 6 }"
v-model="dialogData.rowData!.script" v-model="dialogData.rowData!.script"
/>
</el-form-item>
<el-form-item v-if="dialogData.rowData!.type === 'website'" :label="$t('cronjob.website')" prop="website">
<el-select style="width: 100%" v-model="dialogData.rowData!.website">
<el-option v-for="item in websiteOptions" :key="item" :value="item" :label="item" />
</el-select>
</el-form-item>
<div v-if="dialogData.rowData!.type === 'database'">
<el-form-item :label="$t('cronjob.database')" prop="dbName">
<el-select style="width: 100%" clearable v-model="dialogData.rowData!.dbName">
<el-option v-for="item in mysqlInfo.dbNames" :key="item" :label="item" :value="item" />
</el-select>
</el-form-item>
</div>
<el-form-item
v-if="dialogData.rowData!.type === 'directory'"
:label="$t('cronjob.sourceDir')"
prop="sourceDir"
>
<el-input style="width: 100%" disabled v-model="dialogData.rowData!.sourceDir">
<template #append>
<FileList @choose="loadDir" :dir="true"></FileList>
</template>
</el-input>
</el-form-item>
<div v-if="isBackup()">
<el-form-item :label="$t('cronjob.target')" prop="targetDirID">
<el-select style="width: 100%" v-model="dialogData.rowData!.targetDirID">
<el-option
v-for="item in backupOptions"
:key="item.label"
:value="item.value"
:label="item.label"
/> />
</el-select> </el-form-item>
</el-form-item>
<el-form-item v-if="dialogData.rowData!.targetDirID !== localDirID">
<el-checkbox v-model="dialogData.rowData!.keepLocal">
{{ $t('cronjob.saveLocal') }}
</el-checkbox>
</el-form-item>
<el-form-item :label="$t('cronjob.retainCopies')" prop="retainCopies">
<el-input-number
:min="1"
:max="30"
v-model.number="dialogData.rowData!.retainCopies"
></el-input-number>
</el-form-item>
</div>
<el-form-item v-if="dialogData.rowData!.type === 'curl'" :label="$t('cronjob.url')" prop="url"> <el-form-item
<el-input style="width: 100%" clearable v-model.trim="dialogData.rowData!.url" /> v-if="dialogData.rowData!.type === 'website'"
</el-form-item> :label="$t('cronjob.website')"
prop="website"
>
<el-select style="width: 100%" v-model="dialogData.rowData!.website">
<el-option v-for="item in websiteOptions" :key="item" :value="item" :label="item" />
</el-select>
</el-form-item>
<el-form-item <div v-if="dialogData.rowData!.type === 'database'">
v-if="dialogData.rowData!.type === 'website' || dialogData.rowData!.type === 'directory'" <el-form-item :label="$t('cronjob.database')" prop="dbName">
:label="$t('cronjob.exclusionRules')" <el-select style="width: 100%" clearable v-model="dialogData.rowData!.dbName">
prop="exclusionRules" <el-option v-for="item in mysqlInfo.dbNames" :key="item" :label="item" :value="item" />
> </el-select>
<el-input </el-form-item>
style="width: 100%" </div>
type="textarea"
:placeholder="$t('cronjob.rulesHelper')" <el-form-item
:autosize="{ minRows: 3, maxRows: 6 }" v-if="dialogData.rowData!.type === 'directory'"
clearable :label="$t('cronjob.sourceDir')"
v-model="dialogData.rowData!.exclusionRules" prop="sourceDir"
/> >
</el-form-item> <el-input style="width: 100%" disabled v-model="dialogData.rowData!.sourceDir">
<template #append>
<FileList @choose="loadDir" :dir="true"></FileList>
</template>
</el-input>
</el-form-item>
<div v-if="isBackup()">
<el-form-item :label="$t('cronjob.target')" prop="targetDirID">
<el-select style="width: 100%" v-model="dialogData.rowData!.targetDirID">
<el-option
v-for="item in backupOptions"
:key="item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item v-if="dialogData.rowData!.targetDirID !== localDirID">
<el-checkbox v-model="dialogData.rowData!.keepLocal">
{{ $t('cronjob.saveLocal') }}
</el-checkbox>
</el-form-item>
<el-form-item :label="$t('cronjob.retainCopies')" prop="retainCopies">
<el-input-number
:min="1"
:max="30"
v-model.number="dialogData.rowData!.retainCopies"
></el-input-number>
</el-form-item>
</div>
<el-form-item v-if="dialogData.rowData!.type === 'curl'" :label="$t('cronjob.url')" prop="url">
<el-input style="width: 100%" clearable v-model.trim="dialogData.rowData!.url" />
</el-form-item>
<el-form-item
v-if="dialogData.rowData!.type === 'website' || dialogData.rowData!.type === 'directory'"
:label="$t('cronjob.exclusionRules')"
prop="exclusionRules"
>
<el-input
style="width: 100%"
type="textarea"
:placeholder="$t('cronjob.rulesHelper')"
:autosize="{ minRows: 3, maxRows: 6 }"
clearable
v-model="dialogData.rowData!.exclusionRules"
/>
</el-form-item>
</el-col>
</el-row>
</el-form> </el-form>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">

View File

@ -2,16 +2,14 @@
<div> <div>
<el-drawer v-model="backupVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%"> <el-drawer v-model="backupVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
<template #header> <template #header>
<div class="card-header"> <DrawerHeader :header="$t('database.backup')" :resource="dbName" :back="handleClose" />
<span>{{ $t('database.backup') }} - {{ dbName }}</span>
</div>
</template> </template>
<ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" @search="search" :data="data"> <ComplexTable :pagination-config="paginationConfig" v-model:selects="selects" @search="search" :data="data">
<template #toolbar> <template #toolbar>
<el-button type="primary" @click="onBackup()"> <el-button type="primary" @click="onBackup()">
{{ $t('database.backup') }} {{ $t('database.backup') }}
</el-button> </el-button>
<el-button type="danger" plain :disabled="selects.length === 0" @click="onBatchDelete(null)"> <el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }} {{ $t('commons.button.delete') }}
</el-button> </el-button>
</template> </template>
@ -64,6 +62,9 @@ const acceptParams = (params: DialogProps): void => {
backupVisiable.value = true; backupVisiable.value = true;
search(); search();
}; };
const handleClose = () => {
backupVisiable.value = false;
};
const search = async () => { const search = async () => {
let params = { let params = {

View File

@ -1,43 +1,45 @@
<template> <template>
<el-drawer v-model="createVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%"> <el-drawer v-model="createVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
<template #header> <template #header>
<div class="card-header"> <DrawerHeader :header="$t('database.create')" :back="handleClose" />
<span>{{ $t('database.create') }}</span>
</div>
</template> </template>
<el-form ref="formRef" :model="form" :rules="rules" label-width="80px"> <el-form ref="formRef" label-position="top" :model="form" :rules="rules" label-width="80px">
<el-form-item :label="$t('commons.table.name')" prop="name"> <el-row type="flex" justify="center">
<el-input clearable v-model.trim="form.name"> <el-col :span="22">
<template #append> <el-form-item :label="$t('commons.table.name')" prop="name">
<el-select v-model="form.format" style="width: 80px"> <el-input clearable v-model.trim="form.name">
<el-option label="utf8mb4" value="utf8mb4" /> <template #append>
<el-option label="utf-8" value="utf8" /> <el-select v-model="form.format" style="width: 120px">
<el-option label="gbk" value="gbk" /> <el-option label="utf8mb4" value="utf8mb4" />
<el-option label="big5" value="big5" /> <el-option label="utf-8" value="utf8" />
</el-select> <el-option label="gbk" value="gbk" />
</template> <el-option label="big5" value="big5" />
</el-input> </el-select>
</el-form-item> </template>
<el-form-item :label="$t('commons.login.username')" prop="username"> </el-input>
<el-input clearable v-model.trim="form.username" /> </el-form-item>
</el-form-item> <el-form-item :label="$t('commons.login.username')" prop="username">
<el-form-item :label="$t('commons.login.password')" prop="password"> <el-input clearable v-model.trim="form.username" />
<el-input type="password" clearable show-password v-model.trim="form.password" /> </el-form-item>
</el-form-item> <el-form-item :label="$t('commons.login.password')" prop="password">
<el-input type="password" clearable show-password v-model.trim="form.password" />
</el-form-item>
<el-form-item :label="$t('database.permission')" prop="permission"> <el-form-item :label="$t('database.permission')" prop="permission">
<el-select v-model="form.permission"> <el-select v-model="form.permission">
<el-option value="localhost" :label="$t('database.permissionLocal')" /> <el-option value="localhost" :label="$t('database.permissionLocal')" />
<el-option value="%" :label="$t('database.permissionAll')" /> <el-option value="%" :label="$t('database.permissionAll')" />
<el-option value="ip" :label="$t('database.permissionForIP')" /> <el-option value="ip" :label="$t('database.permissionForIP')" />
</el-select> </el-select>
</el-form-item> </el-form-item>
<el-form-item v-if="form.permission === 'ip'" prop="permissionIPs"> <el-form-item v-if="form.permission === 'ip'" prop="permissionIPs">
<el-input clearable v-model="form.permissionIPs" /> <el-input clearable v-model="form.permissionIPs" />
</el-form-item> </el-form-item>
<el-form-item :label="$t('commons.table.description')" prop="description"> <el-form-item :label="$t('commons.table.description')" prop="description">
<el-input type="textarea" clearable v-model="form.description" /> <el-input type="textarea" clearable v-model="form.description" />
</el-form-item> </el-form-item>
</el-col>
</el-row>
</el-form> </el-form>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">
@ -92,6 +94,9 @@ const acceptParams = (params: DialogProps): void => {
form.description = ''; form.description = '';
createVisiable.value = true; createVisiable.value = true;
}; };
const handleClose = () => {
createVisiable.value = false;
};
const emit = defineEmits<{ (e: 'search'): void }>(); const emit = defineEmits<{ (e: 'search'): void }>();
const onSubmit = async (formEl: FormInstance | undefined) => { const onSubmit = async (formEl: FormInstance | undefined) => {

View File

@ -1,6 +1,6 @@
<template> <template>
<div v-loading="loading"> <div v-loading="loading">
<LayoutContent :title="'Mysql ' + $t('menu.database')"> <LayoutContent :title="'Mysql ' + $t('menu.database')" :class="{ mask: mysqlStatus != 'Running' }">
<template #app> <template #app>
<AppStatus <AppStatus
:app-key="'mysql'" :app-key="'mysql'"
@ -82,15 +82,17 @@
fix fix
/> />
</ComplexTable> </ComplexTable>
<el-card
width="30%"
v-if="mysqlStatus != 'Running' && !isOnSetting && mysqlIsExist && !loading"
class="mask-prompt"
>
<span style="font-size: 14px">{{ $t('commons.service.serviceNotStarted', ['Mysql']) }}</span>
</el-card>
</template> </template>
</LayoutContent> </LayoutContent>
<el-card
width="30%"
v-if="mysqlStatus != 'Running' && !isOnSetting && mysqlIsExist && !loading"
class="mask-prompt"
>
<span style="font-size: 14px">{{ $t('commons.service.serviceNotStarted', ['Mysql']) }}</span>
</el-card>
<Setting ref="settingRef" style="margin-top: 20px" /> <Setting ref="settingRef" style="margin-top: 20px" />
<el-dialog v-model="changeVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="30%"> <el-dialog v-model="changeVisiable" :destroy-on-close="true" :close-on-click-modal="false" width="30%">
<template #header> <template #header>

View File

@ -1,6 +1,6 @@
<template> <template>
<div v-show="onSetting"> <div v-show="onSetting">
<LayoutContent :title="$t('nginx.nginxConfig')" :reload="true"> <LayoutContent :title="'Mysql ' + $t('database.setting')" :reload="true">
<template #buttons> <template #buttons>
<el-button type="primary" :plain="activeName !== 'conf'" @click="changeTab('conf')"> <el-button type="primary" :plain="activeName !== 'conf'" @click="changeTab('conf')">
{{ $t('database.confChange') }} {{ $t('database.confChange') }}
@ -33,7 +33,7 @@
placeholder="None data" placeholder="None data"
:indent-with-tab="true" :indent-with-tab="true"
:tabSize="4" :tabSize="4"
style="margin-top: 10px; height: calc(100vh - 360px)" style="margin-top: 10px; height: calc(100vh - 375px)"
:lineWrapping="true" :lineWrapping="true"
:matchBrackets="true" :matchBrackets="true"
theme="cobalt" theme="cobalt"

View File

@ -1,12 +1,12 @@
<template> <template>
<div v-loading="loading"> <div v-loading="loading">
<span style="float: left">{{ $t('database.longQueryTime') }}</span> <span style="float: left; line-height: 30px">{{ $t('database.longQueryTime') }}</span>
<div style="margin-left: 5px; float: left"> <div style="margin-left: 5px; float: left">
<el-input type="number" v-model.number="variables.long_query_time"> <el-input type="number" v-model.number="variables.long_query_time">
<template #append>{{ $t('database.second') }}</template> <template #append>{{ $t('database.second') }}</template>
</el-input> </el-input>
</div> </div>
<span style="float: left; margin-left: 20px">{{ $t('database.isOn') }}</span> <span style="float: left; margin-left: 20px; line-height: 30px">{{ $t('database.isOn') }}</span>
<el-switch <el-switch
style="margin-left: 5px; float: left" style="margin-left: 5px; float: left"
v-model="variables.slow_query_log" v-model="variables.slow_query_log"
@ -25,7 +25,7 @@
placeholder="None data" placeholder="None data"
:indent-with-tab="true" :indent-with-tab="true"
:tabSize="4" :tabSize="4"
style="margin-top: 10px; height: calc(100vh - 370px)" style="margin-top: 10px; height: calc(100vh - 392px)"
:lineWrapping="true" :lineWrapping="true"
:matchBrackets="true" :matchBrackets="true"
theme="cobalt" theme="cobalt"

View File

@ -2,9 +2,7 @@
<div> <div>
<el-drawer v-model="upVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%"> <el-drawer v-model="upVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
<template #header> <template #header>
<div class="card-header"> <DrawerHeader :header="$t('commons.button.import')" :back="handleClose" />
<span>{{ $t('commons.button.import') }}</span>
</div>
</template> </template>
<el-upload <el-upload
ref="uploadRef" ref="uploadRef"
@ -31,7 +29,6 @@
<template #toolbar> <template #toolbar>
<el-button <el-button
style="margin-left: 10px" style="margin-left: 10px"
type="danger"
plain plain
:disabled="selects.length === 0" :disabled="selects.length === 0"
@click="onBatchDelete(null)" @click="onBatchDelete(null)"

View File

@ -1,6 +1,7 @@
<template> <template>
<div v-loading="loading"> <div v-loading="loading">
<AppStatus <AppStatus
:class="{ mask: redisStatus != 'Running' }"
:app-key="'redis'" :app-key="'redis'"
style="margin-top: 20px" style="margin-top: 20px"
@before="onBefore" @before="onBefore"
@ -8,18 +9,26 @@
@is-exist="checkExist" @is-exist="checkExist"
></AppStatus> ></AppStatus>
<LayoutContent v-show="!isOnSetting && redisIsExist" :title="'Redis ' + $t('menu.database')"> <LayoutContent
v-show="!isOnSetting && redisIsExist"
:title="'Redis ' + $t('menu.database')"
:class="{ mask: redisStatus != 'Running' }"
>
<template #toolbar v-if="!isOnSetting && redisIsExist"> <template #toolbar v-if="!isOnSetting && redisIsExist">
<el-button type="primary" plain @click="goDashboard" icon="Position">Redis-Commander</el-button> <el-button type="primary" plain @click="goDashboard" icon="Position">Redis-Commander</el-button>
<el-button plain @click="onChangePassword"> <el-button type="primary" plain @click="onChangePassword">
{{ $t('database.changePassword') }} {{ $t('database.changePassword') }}
</el-button> </el-button>
</template> </template>
<template #main> <template #main>
<Terminal :key="isRefresh" style="margin-top: 10px" ref="terminalRef" /> <Terminal :key="isRefresh" ref="terminalRef" />
</template> </template>
</LayoutContent> </LayoutContent>
<el-card width="30%" v-if="redisStatus != 'Running' && !isOnSetting && redisIsExist" class="mask-prompt">
<span style="font-size: 14px">{{ $t('commons.service.serviceNotStarted', ['Redis']) }}</span>
</el-card>
<Setting ref="settingRef" style="margin-top: 30px" /> <Setting ref="settingRef" style="margin-top: 30px" />
<Password ref="passwordRef" @check-exist="initTerminal" @close-terminal="closeTerminal(true)" /> <Password ref="passwordRef" @check-exist="initTerminal" @close-terminal="closeTerminal(true)" />
<el-dialog <el-dialog

View File

@ -1,6 +1,6 @@
<template> <template>
<div v-show="settingShow"> <div v-show="settingShow">
<LayoutContent :title="$t('nginx.nginxConfig')" :reload="true"> <LayoutContent :title="'Redis' + $t('database.setting')" :reload="true">
<template #buttons> <template #buttons>
<el-button type="primary" :plain="activeName !== 'conf'" @click="changeTab('conf')"> <el-button type="primary" :plain="activeName !== 'conf'" @click="changeTab('conf')">
{{ $t('database.confChange') }} {{ $t('database.confChange') }}
@ -40,7 +40,7 @@
placeholder="None data" placeholder="None data"
:indent-with-tab="true" :indent-with-tab="true"
:tabSize="4" :tabSize="4"
style="margin-top: 10px; height: calc(100vh - 370px)" style="margin-top: 10px; height: calc(100vh - 380px)"
:lineWrapping="true" :lineWrapping="true"
:matchBrackets="true" :matchBrackets="true"
theme="cobalt" theme="cobalt"

View File

@ -87,7 +87,7 @@
> >
<template #toolbar> <template #toolbar>
<el-button type="primary" @click="onBackup">{{ $t('setting.backup') }}</el-button> <el-button type="primary" @click="onBackup">{{ $t('setting.backup') }}</el-button>
<el-button type="danger" plain :disabled="selects.length === 0" @click="onBatchDelete(null)"> <el-button type="primary" plain :disabled="selects.length === 0" @click="onBatchDelete(null)">
{{ $t('commons.button.delete') }} {{ $t('commons.button.delete') }}
</el-button> </el-button>
</template> </template>

View File

@ -3,7 +3,7 @@
<el-row> <el-row>
<el-col :span="1"><br /></el-col> <el-col :span="1"><br /></el-col>
<el-col :span="12"> <el-col :span="12">
<table style="margin-top: 20px; width: 100%" class="myTable"> <table style="width: 100%" class="myTable">
<tr> <tr>
<td>uptime_in_days</td> <td>uptime_in_days</td>
<td>{{ redisStatus!.uptime_in_days }}</td> <td>{{ redisStatus!.uptime_in_days }}</td>

View File

@ -1,6 +1,6 @@
<template> <template>
<div v-show="terminalShow" style="height: 100%"> <div v-show="terminalShow" style="height: 100%">
<div style="height: calc(100vh - 360px)" :id="'terminal-exec'"></div> <div style="height: calc(100vh - 370px)" :id="'terminal-exec'"></div>
</div> </div>
</template> </template>

View File

@ -3,7 +3,7 @@
<RouterButton <RouterButton
:buttons="[ :buttons="[
{ {
label: i18n.global.t('menu.monitor'), label: i18n.global.t('menu.home'),
path: '/home/index', path: '/home/index',
}, },
]" ]"

View File

@ -5,7 +5,7 @@
<el-button type="primary" @click="onCreate()"> <el-button type="primary" @click="onCreate()">
{{ $t('commons.button.create') }}{{ $t('terminal.quickCommand') }} {{ $t('commons.button.create') }}{{ $t('terminal.quickCommand') }}
</el-button> </el-button>
<el-button plain :disabled="selects.length === 0" @click="batchDelete(null)"> <el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
{{ $t('commons.button.delete') }} {{ $t('commons.button.delete') }}
</el-button> </el-button>
</template> </template>
@ -28,7 +28,7 @@
</ComplexTable> </ComplexTable>
</template> </template>
</LayoutContent> </LayoutContent>
<el-drawer v-model="cmdVisiable" size="50%"> <el-drawer v-model="cmdVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
<template #header> <template #header>
<DrawerHeader <DrawerHeader
:header="$t('commons.button.' + operate) + $t('terminal.quickCommand')" :header="$t('commons.button.' + operate) + $t('terminal.quickCommand')"

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<el-drawer v-model="dialogVisiable" size="50%"> <el-drawer v-model="dialogVisiable" :destroy-on-close="true" :close-on-click-modal="false" size="50%">
<template #header> <template #header>
<DrawerHeader :header="$t('terminal.addHost')" :back="handleClose" /> <DrawerHeader :header="$t('terminal.addHost')" :back="handleClose" />
</template> </template>

View File

@ -1,6 +1,6 @@
<template> <template>
<div> <div>
<LayoutContent :title="$t('setting.backup')" :divider="true"> <LayoutContent :title="$t('setting.backup')">
<template #main> <template #main>
<el-form label-position="left" label-width="130px" :v-key="reflash"> <el-form label-position="left" label-width="130px" :v-key="reflash">
<el-row :gutter="20"> <el-row :gutter="20">

View File

@ -3,99 +3,118 @@
<template #header> <template #header>
<DrawerHeader :header="title + $t('setting.backupAccount')" :back="handleClose" /> <DrawerHeader :header="title + $t('setting.backupAccount')" :back="handleClose" />
</template> </template>
<el-form ref="formRef" v-loading="loading" :model="dialogData.rowData" label-width="120px"> <el-form ref="formRef" v-loading="loading" label-position="top" :model="dialogData.rowData" label-width="120px">
<el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect"> <el-row type="flex" justify="center">
<span>{{ dialogData.rowData!.type }}</span> <el-col :span="22">
</el-form-item> <el-form-item :label="$t('commons.table.type')" prop="type" :rules="Rules.requiredSelect">
<el-form-item <div style="margin-left: 10px">
v-if="dialogData.rowData!.type === 'LOCAL'" <el-tag>{{ dialogData.rowData!.type }}</el-tag>
:label="$t('setting.currentPath')" </div>
prop="varsJson['dir']" </el-form-item>
:rules="Rules.requiredInput" <el-form-item
> v-if="dialogData.rowData!.type === 'LOCAL'"
<el-input disabled v-model="dialogData.rowData!.varsJson['dir']"> :label="$t('setting.currentPath')"
<template #append> prop="varsJson['dir']"
<FileList @choose="loadDir" :dir="true"></FileList> :rules="Rules.requiredInput"
</template> >
</el-input> <el-input disabled v-model="dialogData.rowData!.varsJson['dir']">
</el-form-item> <template #append>
<el-form-item <FileList @choose="loadDir" :dir="true"></FileList>
v-if="hasBucket(dialogData.rowData!.type)" </template>
label="Access Key ID" </el-input>
prop="accessKey" </el-form-item>
:rules="Rules.requiredInput" <el-form-item
> v-if="hasBucket(dialogData.rowData!.type)"
<el-input v-model.trim="dialogData.rowData!.accessKey" /> label="Access Key ID"
</el-form-item> prop="accessKey"
<el-form-item :rules="Rules.requiredInput"
v-if="hasBucket(dialogData.rowData!.type)" >
label="Secret Key" <el-input v-model.trim="dialogData.rowData!.accessKey" />
prop="credential" </el-form-item>
:rules="Rules.requiredInput" <el-form-item
> v-if="hasBucket(dialogData.rowData!.type)"
<el-input show-password clearable v-model.trim="dialogData.rowData!.credential" /> label="Secret Key"
</el-form-item> prop="credential"
<el-form-item :rules="Rules.requiredInput"
v-if="dialogData.rowData!.type === 'S3'" >
label="Region" <el-input show-password clearable v-model.trim="dialogData.rowData!.credential" />
prop="varsJson.region" </el-form-item>
:rules="Rules.requiredInput" <el-form-item
> v-if="dialogData.rowData!.type === 'S3'"
<el-input v-model.trim="dialogData.rowData!.varsJson['region']" /> label="Region"
</el-form-item> prop="varsJson.region"
<el-form-item :rules="Rules.requiredInput"
v-if="hasBucket(dialogData.rowData!.type) && dialogData.rowData!.type !== 'MINIO'" >
label="Endpoint" <el-input v-model.trim="dialogData.rowData!.varsJson['region']" />
prop="varsJson.endpoint" </el-form-item>
:rules="Rules.requiredInput" <el-form-item
> v-if="hasBucket(dialogData.rowData!.type) && dialogData.rowData!.type !== 'MINIO'"
<el-input v-model.trim="dialogData.rowData!.varsJson['endpoint']" /> label="Endpoint"
</el-form-item> prop="varsJson.endpoint"
<el-form-item :rules="Rules.requiredInput"
v-if="dialogData.rowData!.type === 'MINIO'" >
label="Endpoint" <el-input v-model.trim="dialogData.rowData!.varsJson['endpoint']" />
prop="varsJson.endpointItem" </el-form-item>
:rules="Rules.requiredInput" <el-form-item
> v-if="dialogData.rowData!.type === 'MINIO'"
<el-input v-model="dialogData.rowData!.varsJson['endpointItem']"> label="Endpoint"
<template #prepend> prop="varsJson.endpointItem"
<el-select v-model.trim="endpoints" style="width: 80px"> :rules="Rules.requiredInput"
<el-option label="http" value="http" /> >
<el-option label="https" value="https" /> <el-input v-model="dialogData.rowData!.varsJson['endpointItem']">
<template #prepend>
<el-select v-model.trim="endpoints" style="width: 80px">
<el-option label="http" value="http" />
<el-option label="https" value="https" />
</el-select>
</template>
</el-input>
</el-form-item>
<el-form-item
v-if="dialogData.rowData!.type !== '' && hasBucket(dialogData.rowData!.type)"
label="Bucket"
prop="bucket"
:rules="Rules.requiredSelect"
>
<el-select style="width: 80%" v-model="dialogData.rowData!.bucket">
<el-option v-for="item in buckets" :key="item" :value="item" />
</el-select> </el-select>
</template> <el-button style="width: 20%" plain @click="getBuckets">
</el-input> {{ $t('setting.loadBucket') }}
</el-form-item> </el-button>
<el-form-item </el-form-item>
v-if="dialogData.rowData!.type !== '' && hasBucket(dialogData.rowData!.type)" <div v-if="dialogData.rowData!.type === 'SFTP'">
label="Bucket" <el-form-item
prop="bucket" :label="$t('setting.address')"
:rules="Rules.requiredSelect" prop="varsJson.address"
> :rules="Rules.requiredInput"
<el-select style="width: 80%" v-model="dialogData.rowData!.bucket"> >
<el-option v-for="item in buckets" :key="item" :value="item" /> <el-input v-model.trim="dialogData.rowData!.varsJson['address']" />
</el-select> </el-form-item>
<el-button style="width: 20%" plain @click="getBuckets"> <el-form-item :label="$t('setting.port')" prop="varsJson.port" :rules="[Rules.number]">
{{ $t('setting.loadBucket') }} <el-input-number
</el-button> :min="0"
</el-form-item> :max="65535"
<div v-if="dialogData.rowData!.type === 'SFTP'"> v-model.number="dialogData.rowData!.varsJson['port']"
<el-form-item :label="$t('setting.address')" prop="varsJson.address" :rules="Rules.requiredInput"> />
<el-input v-model.trim="dialogData.rowData!.varsJson['address']" /> </el-form-item>
</el-form-item> <el-form-item :label="$t('setting.username')" prop="accessKey" :rules="[Rules.requiredInput]">
<el-form-item :label="$t('setting.port')" prop="varsJson.port" :rules="[Rules.number]"> <el-input v-model="dialogData.rowData!.accessKey" />
<el-input-number :min="0" :max="65535" v-model.number="dialogData.rowData!.varsJson['port']" /> </el-form-item>
</el-form-item> <el-form-item :label="$t('setting.password')" prop="credential" :rules="[Rules.requiredInput]">
<el-form-item :label="$t('setting.username')" prop="accessKey" :rules="[Rules.requiredInput]"> <el-input
<el-input v-model="dialogData.rowData!.accessKey" /> type="password"
</el-form-item> clearable
<el-form-item :label="$t('setting.password')" prop="credential" :rules="[Rules.requiredInput]"> show-password
<el-input type="password" clearable show-password v-model="dialogData.rowData!.credential" /> v-model="dialogData.rowData!.credential"
</el-form-item> />
<el-form-item :label="$t('setting.path')" prop="bucket"> </el-form-item>
<el-input v-model="dialogData.rowData!.bucket" /> <el-form-item :label="$t('setting.path')" prop="bucket">
</el-form-item> <el-input v-model="dialogData.rowData!.bucket" />
</div> </el-form-item>
</div>
</el-col>
</el-row>
</el-form> </el-form>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">

View File

@ -31,36 +31,6 @@
</template> </template>
</el-input> </el-input>
</el-form-item> </el-form-item>
<!-- <el-form-item :label="$t('setting.panelPort')" :rules="Rules.port" prop="serverPort">
<el-input clearable v-model.number="form.serverPort">
<template #append>
<el-button
@click="onSavePort(panelFormRef, 'ServerPort', form.serverPort)"
icon="Collection"
>
{{ $t('commons.button.save') }}
</el-button>
</template>
</el-input>
</el-form-item> -->
<el-form-item :label="$t('setting.theme')" :rules="Rules.requiredSelect" prop="theme">
<el-radio-group
@change="onSave(panelFormRef, 'Theme', form.theme)"
v-model="form.theme"
>
<el-radio-button label="light">
<el-icon><Sunny /></el-icon>
{{ $t('setting.light') }}
</el-radio-button>
<el-radio-button label="dark">
<el-icon><Moon /></el-icon>
{{ $t('setting.dark') }}
</el-radio-button>
</el-radio-group>
</el-form-item>
<el-form-item :label="$t('setting.language')" :rules="Rules.requiredSelect" prop="language"> <el-form-item :label="$t('setting.language')" :rules="Rules.requiredSelect" prop="language">
<el-radio-group <el-radio-group
style="width: 100%" style="width: 100%"
@ -70,11 +40,6 @@
<el-radio label="zh">中文</el-radio> <el-radio label="zh">中文</el-radio>
<el-radio label="en">English</el-radio> <el-radio label="en">English</el-radio>
</el-radio-group> </el-radio-group>
<div>
<span class="input-help">
{{ $t('setting.languageHelper') }}
</span>
</div>
</el-form-item> </el-form-item>
<el-form-item <el-form-item

View File

@ -1,6 +1,14 @@
<template> <template>
<div> <div>
<LayoutContent v-loading="loading" v-if="!isRecordShow" :title="$t('setting.snapshot')" :divider="true"> <LayoutContent v-loading="loading" v-if="!isRecordShow" :title="$t('setting.snapshot')">
<template #toolbar>
<el-button type="primary" @click="onCreate()">
{{ $t('setting.createSnapshot') }}
</el-button>
<el-button type="primary" plain :disabled="selects.length === 0" @click="batchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</template>
<template #main> <template #main>
<ComplexTable <ComplexTable
:pagination-config="paginationConfig" :pagination-config="paginationConfig"
@ -9,14 +17,6 @@
style="margin-top: 20px" style="margin-top: 20px"
@search="search" @search="search"
> >
<template #toolbar>
<el-button type="primary" icon="Plus" @click="onCreate()">
{{ $t('setting.createSnapshot') }}
</el-button>
<el-button type="danger" plain :disabled="selects.length === 0" @click="batchDelete(null)">
{{ $t('commons.button.delete') }}
</el-button>
</template>
<el-table-column type="selection" fix /> <el-table-column type="selection" fix />
<el-table-column <el-table-column
show-overflow-tooltip show-overflow-tooltip
@ -72,20 +72,31 @@
<template #header> <template #header>
<DrawerHeader :header="$t('setting.createSnapshot')" :back="handleClose" /> <DrawerHeader :header="$t('setting.createSnapshot')" :back="handleClose" />
</template> </template>
<el-form v-loading="loading" ref="snapRef" label-width="100px" :model="snapInfo" :rules="rules"> <el-form
<el-form-item :label="$t('cronjob.target')" prop="from"> v-loading="loading"
<el-select v-model="snapInfo.from" clearable> label-position="top"
<el-option ref="snapRef"
v-for="item in backupOptions" label-width="100px"
:key="item.label" :model="snapInfo"
:value="item.value" :rules="rules"
:label="item.label" >
/> <el-row type="flex" justify="center">
</el-select> <el-col :span="22">
</el-form-item> <el-form-item :label="$t('cronjob.target')" prop="from">
<el-form-item :label="$t('commons.table.description')" prop="description"> <el-select v-model="snapInfo.from" clearable>
<el-input type="textarea" clearable v-model="snapInfo.description" /> <el-option
</el-form-item> v-for="item in backupOptions"
:key="item.label"
:value="item.value"
:label="item.label"
/>
</el-select>
</el-form-item>
<el-form-item :label="$t('commons.table.description')" prop="description">
<el-input type="textarea" clearable v-model="snapInfo.description" />
</el-form-item>
</el-col>
</el-row>
</el-form> </el-form>
<template #footer> <template #footer>
<span class="dialog-footer"> <span class="dialog-footer">