mirror of
https://github.com/1Panel-dev/1Panel.git
synced 2025-01-19 08:19:15 +08:00
feat: Merge code from dev (#7726)
This commit is contained in:
parent
bb250557a2
commit
b90a90c0c8
@ -7,24 +7,23 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
|
||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
|
||||||
"github.com/docker/docker/api/types/image"
|
|
||||||
|
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
"github.com/1Panel-dev/1Panel/agent/app/dto"
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/model"
|
"github.com/1Panel-dev/1Panel/agent/app/model"
|
||||||
|
"github.com/1Panel-dev/1Panel/agent/app/repo"
|
||||||
"github.com/1Panel-dev/1Panel/agent/app/task"
|
"github.com/1Panel-dev/1Panel/agent/app/task"
|
||||||
"github.com/1Panel-dev/1Panel/agent/buserr"
|
"github.com/1Panel-dev/1Panel/agent/buserr"
|
||||||
"github.com/1Panel-dev/1Panel/agent/constant"
|
"github.com/1Panel-dev/1Panel/agent/constant"
|
||||||
"github.com/1Panel-dev/1Panel/agent/i18n"
|
"github.com/1Panel-dev/1Panel/agent/i18n"
|
||||||
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
"github.com/1Panel-dev/1Panel/agent/utils/docker"
|
||||||
"github.com/docker/docker/api/types"
|
"github.com/docker/docker/api/types"
|
||||||
|
"github.com/docker/docker/api/types/container"
|
||||||
|
"github.com/docker/docker/api/types/image"
|
||||||
"github.com/docker/docker/api/types/registry"
|
"github.com/docker/docker/api/types/registry"
|
||||||
"github.com/docker/docker/pkg/archive"
|
"github.com/docker/docker/pkg/archive"
|
||||||
"github.com/docker/docker/pkg/homedir"
|
"github.com/docker/docker/pkg/homedir"
|
||||||
@ -419,6 +418,9 @@ func (u *ImageService) ImageRemove(req dto.BatchDelete) (dto.ContainerPruneRepor
|
|||||||
}
|
}
|
||||||
return report, buserr.WithDetail(constant.ErrInUsed, id, nil)
|
return report, buserr.WithDetail(constant.ErrInUsed, id, nil)
|
||||||
}
|
}
|
||||||
|
if strings.Contains(err.Error(), "image has dependent") {
|
||||||
|
return report, buserr.New(constant.ErrObjectBeDependent)
|
||||||
|
}
|
||||||
return report, err
|
return report, err
|
||||||
}
|
}
|
||||||
report.DeletedNumber++
|
report.DeletedNumber++
|
||||||
|
@ -105,6 +105,7 @@ var (
|
|||||||
var (
|
var (
|
||||||
ErrInUsed = "ErrInUsed"
|
ErrInUsed = "ErrInUsed"
|
||||||
ErrObjectInUsed = "ErrObjectInUsed"
|
ErrObjectInUsed = "ErrObjectInUsed"
|
||||||
|
ErrObjectBeDependent = "ErrObjectBeDependent"
|
||||||
ErrPortRules = "ErrPortRules"
|
ErrPortRules = "ErrPortRules"
|
||||||
ErrPgImagePull = "ErrPgImagePull"
|
ErrPgImagePull = "ErrPgImagePull"
|
||||||
)
|
)
|
||||||
|
@ -157,6 +157,7 @@ ErrTypeOfRedis: "The recovery file type does not match the current persistence m
|
|||||||
#container
|
#container
|
||||||
ErrInUsed: "{{ .detail }} is in use and cannot be deleted"
|
ErrInUsed: "{{ .detail }} is in use and cannot be deleted"
|
||||||
ErrObjectInUsed: "This object is in use and cannot be deleted"
|
ErrObjectInUsed: "This object is in use and cannot be deleted"
|
||||||
|
ErrObjectBeDependent: "This image is dependent on other images and can't be deleted"
|
||||||
ErrPortRules: "The number of ports does not match, please re-enter!"
|
ErrPortRules: "The number of ports does not match, please re-enter!"
|
||||||
ErrPgImagePull: "Image pull timeout. Please configure image acceleration or manually pull the postgres:16.0-alpine image and try again"
|
ErrPgImagePull: "Image pull timeout. Please configure image acceleration or manually pull the postgres:16.0-alpine image and try again"
|
||||||
|
|
||||||
|
@ -158,6 +158,7 @@ ErrTypeOfRedis: "恢復文件類型與當前持久化方式不符,請修改後
|
|||||||
#container
|
#container
|
||||||
ErrInUsed: "{{ .detail }} 正被使用,無法刪除"
|
ErrInUsed: "{{ .detail }} 正被使用,無法刪除"
|
||||||
ErrObjectInUsed: "該對象正被使用,無法刪除"
|
ErrObjectInUsed: "該對象正被使用,無法刪除"
|
||||||
|
ErrObjectBeDependent: "該鏡像依賴於其他鏡像,無法刪除"
|
||||||
ErrPortRules: "端口數目不匹配,請重新輸入!"
|
ErrPortRules: "端口數目不匹配,請重新輸入!"
|
||||||
ErrPgImagePull: "鏡像拉取超時,請配置鏡像加速或手動拉取 postgres:16.0-alpine 鏡像後重試"
|
ErrPgImagePull: "鏡像拉取超時,請配置鏡像加速或手動拉取 postgres:16.0-alpine 鏡像後重試"
|
||||||
|
|
||||||
|
@ -156,8 +156,9 @@ ErrTypeOfRedis: "恢复文件类型与当前持久化方式不符,请修改后
|
|||||||
#container
|
#container
|
||||||
ErrInUsed: "{{ .detail }} 正被使用,无法删除"
|
ErrInUsed: "{{ .detail }} 正被使用,无法删除"
|
||||||
ErrObjectInUsed: "该对象正被使用,无法删除"
|
ErrObjectInUsed: "该对象正被使用,无法删除"
|
||||||
|
ErrObjectBeDependent: "该镜像依赖于其他镜像,无法删除"
|
||||||
ErrPortRules: "端口数目不匹配,请重新输入!"
|
ErrPortRules: "端口数目不匹配,请重新输入!"
|
||||||
ErrPgImagePull: "镜像拉取超时,请配置镜像加速或手动拉取 postgres:16.0-alpine 镜像后重试"
|
ErrPgImagePull: "镜像拉取超时,请配置镜像加速或手动拉取 {{ .name }} 镜像后重试"
|
||||||
|
|
||||||
#runtime
|
#runtime
|
||||||
ErrDirNotFound: "build 文件夹不存在!请检查文件完整性!"
|
ErrDirNotFound: "build 文件夹不存在!请检查文件完整性!"
|
||||||
|
@ -25,12 +25,12 @@ func (f *Firewall) Name() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (f *Firewall) Status() (bool, error) {
|
func (f *Firewall) Status() (bool, error) {
|
||||||
stdout, _ := cmd.Exec("firewall-cmd --state")
|
stdout, _ := cmd.Exec("LANGUAGE=en_US:en firewall-cmd --state")
|
||||||
return stdout == "running\n", nil
|
return stdout == "running\n", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Firewall) Version() (string, error) {
|
func (f *Firewall) Version() (string, error) {
|
||||||
stdout, err := cmd.Exec("firewall-cmd --version")
|
stdout, err := cmd.Exec("LANGUAGE=en_US:en firewall-cmd --version")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("load the firewall version failed, err: %s", stdout)
|
return "", fmt.Errorf("load the firewall version failed, err: %s", stdout)
|
||||||
}
|
}
|
||||||
|
@ -17,9 +17,9 @@ type Ufw struct {
|
|||||||
func NewUfw() (*Ufw, error) {
|
func NewUfw() (*Ufw, error) {
|
||||||
var ufw Ufw
|
var ufw Ufw
|
||||||
if cmd.HasNoPasswordSudo() {
|
if cmd.HasNoPasswordSudo() {
|
||||||
ufw.CmdStr = "sudo ufw"
|
ufw.CmdStr = "LANGUAGE=en_US:en sudo ufw"
|
||||||
} else {
|
} else {
|
||||||
ufw.CmdStr = "ufw"
|
ufw.CmdStr = "LANGUAGE=en_US:en ufw"
|
||||||
}
|
}
|
||||||
return &ufw, nil
|
return &ufw, nil
|
||||||
}
|
}
|
||||||
|
@ -306,7 +306,7 @@ func loadImageTag() (string, error) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
if _, err := client.ImagePull(ctx, itemTag, image.PullOptions{}); err != nil {
|
if _, err := client.ImagePull(ctx, itemTag, image.PullOptions{}); err != nil {
|
||||||
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
|
if errors.Is(ctx.Err(), context.DeadlineExceeded) {
|
||||||
return itemTag, buserr.New(constant.ErrPgImagePull)
|
return itemTag, buserr.WithName(constant.ErrPgImagePull, itemTag)
|
||||||
}
|
}
|
||||||
global.LOG.Errorf("image %s pull failed, err: %v", itemTag, err)
|
global.LOG.Errorf("image %s pull failed, err: %v", itemTag, err)
|
||||||
return itemTag, fmt.Errorf("image %s pull failed, err: %v", itemTag, err)
|
return itemTag, fmt.Errorf("image %s pull failed, err: %v", itemTag, err)
|
||||||
|
@ -20,10 +20,7 @@
|
|||||||
"prettier": "prettier --write ."
|
"prettier": "prettier --write ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/lang-html": "^6.4.9",
|
|
||||||
"@codemirror/lang-javascript": "^6.2.2",
|
|
||||||
"@codemirror/lang-json": "^6.0.1",
|
"@codemirror/lang-json": "^6.0.1",
|
||||||
"@codemirror/lang-php": "^6.0.1",
|
|
||||||
"@codemirror/language": "^6.10.2",
|
"@codemirror/language": "^6.10.2",
|
||||||
"@codemirror/legacy-modes": "^6.4.0",
|
"@codemirror/legacy-modes": "^6.4.0",
|
||||||
"@codemirror/theme-one-dark": "^6.1.2",
|
"@codemirror/theme-one-dark": "^6.1.2",
|
||||||
|
@ -134,7 +134,6 @@ const onCheck = async (key: any, name: any) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const onOperate = async (operation: string) => {
|
const onOperate = async (operation: string) => {
|
||||||
em('update:maskShow', false);
|
|
||||||
operateReq.operate = operation;
|
operateReq.operate = operation;
|
||||||
ElMessageBox.confirm(
|
ElMessageBox.confirm(
|
||||||
i18n.global.t('app.operatorHelper', [i18n.global.t('app.' + operation)]),
|
i18n.global.t('app.operatorHelper', [i18n.global.t('app.' + operation)]),
|
||||||
@ -144,8 +143,7 @@ const onOperate = async (operation: string) => {
|
|||||||
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
cancelButtonText: i18n.global.t('commons.button.cancel'),
|
||||||
type: 'info',
|
type: 'info',
|
||||||
},
|
},
|
||||||
)
|
).then(() => {
|
||||||
.then(() => {
|
|
||||||
em('update:maskShow', true);
|
em('update:maskShow', true);
|
||||||
em('update:loading', true);
|
em('update:loading', true);
|
||||||
em('before');
|
em('before');
|
||||||
@ -159,9 +157,6 @@ const onOperate = async (operation: string) => {
|
|||||||
.catch(() => {
|
.catch(() => {
|
||||||
em('update:loading', false);
|
em('update:loading', false);
|
||||||
});
|
});
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
em('update:maskShow', true);
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -130,7 +130,6 @@ const taskLogRef = ref();
|
|||||||
|
|
||||||
const data = ref();
|
const data = ref();
|
||||||
const paginationConfig = reactive({
|
const paginationConfig = reactive({
|
||||||
cacheSizeKey: 'backup-page-size',
|
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
|
@ -8,13 +8,13 @@
|
|||||||
import { CSSProperties } from 'vue';
|
import { CSSProperties } from 'vue';
|
||||||
import { basicSetup, EditorView } from 'codemirror';
|
import { basicSetup, EditorView } from 'codemirror';
|
||||||
import { EditorState } from '@codemirror/state';
|
import { EditorState } from '@codemirror/state';
|
||||||
import { javascript } from '@codemirror/lang-javascript';
|
|
||||||
import { oneDark } from '@codemirror/theme-one-dark';
|
import { oneDark } from '@codemirror/theme-one-dark';
|
||||||
import { StreamLanguage } from '@codemirror/language';
|
import { StreamLanguage } from '@codemirror/language';
|
||||||
import { nginx } from './nginx';
|
import { nginx } from './nginx';
|
||||||
import { yaml } from '@codemirror/legacy-modes/mode/yaml';
|
import { yaml } from '@codemirror/legacy-modes/mode/yaml';
|
||||||
import { shell } from '@codemirror/legacy-modes/mode/shell';
|
import { shell } from '@codemirror/legacy-modes/mode/shell';
|
||||||
import { dockerFile } from '@codemirror/legacy-modes/mode/dockerfile';
|
import { dockerFile } from '@codemirror/legacy-modes/mode/dockerfile';
|
||||||
|
import { javascript } from '@codemirror/legacy-modes/mode/javascript';
|
||||||
import { placeholder } from '@codemirror/view';
|
import { placeholder } from '@codemirror/view';
|
||||||
import { json } from '@codemirror/lang-json';
|
import { json } from '@codemirror/lang-json';
|
||||||
|
|
||||||
@ -94,7 +94,7 @@ const initCodeMirror = () => {
|
|||||||
extensions.push(StreamLanguage.define(dockerFile));
|
extensions.push(StreamLanguage.define(dockerFile));
|
||||||
break;
|
break;
|
||||||
case 'javascript':
|
case 'javascript':
|
||||||
extensions.push(javascript());
|
extensions.push(StreamLanguage.define(javascript));
|
||||||
break;
|
break;
|
||||||
case 'nginx':
|
case 'nginx':
|
||||||
extensions.push(StreamLanguage.define(nginx));
|
extensions.push(StreamLanguage.define(nginx));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<el-button v-if="type == 'icon'" link @click="copyText(content)" icon="DocumentCopy" class="ml-1.5"></el-button>
|
<el-button v-if="type == 'icon'" link @click="copyText(content)" icon="DocumentCopy" class="ml-1.5"></el-button>
|
||||||
<el-button type="primary" @click="copyText(content)" v-else>{{ $t('commons.button.copy') }}</el-button>
|
<el-button @click="copyText(content)" v-else>{{ $t('commons.button.copy') }}</el-button>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
|
@ -153,7 +153,6 @@ const open = ref();
|
|||||||
const data = ref();
|
const data = ref();
|
||||||
const title = ref();
|
const title = ref();
|
||||||
const paginationConfig = reactive({
|
const paginationConfig = reactive({
|
||||||
cacheSizeKey: 'upload-page-size',
|
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
|
@ -224,6 +224,19 @@ const checkDBName = (rule: any, value: any, callback: any) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const checkComposeName = (rule: any, value: any, callback: any) => {
|
||||||
|
if (value === '' || typeof value === 'undefined' || value == null) {
|
||||||
|
callback(new Error(i18n.global.t('commons.rule.composeName')));
|
||||||
|
} else {
|
||||||
|
const reg = /^[a-z0-9]{1}[a-z0-9_-]{0,256}$/;
|
||||||
|
if (!reg.test(value) && value !== '') {
|
||||||
|
callback(new Error(i18n.global.t('commons.rule.composeName')));
|
||||||
|
} else {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const checkImageName = (rule: any, value: any, callback: any) => {
|
const checkImageName = (rule: any, value: any, callback: any) => {
|
||||||
if (value === '' || typeof value === 'undefined' || value == null) {
|
if (value === '' || typeof value === 'undefined' || value == null) {
|
||||||
callback(new Error(i18n.global.t('commons.rule.imageName')));
|
callback(new Error(i18n.global.t('commons.rule.imageName')));
|
||||||
@ -568,6 +581,7 @@ interface CommonRule {
|
|||||||
simplePassword: FormItemRule;
|
simplePassword: FormItemRule;
|
||||||
dbName: FormItemRule;
|
dbName: FormItemRule;
|
||||||
imageName: FormItemRule;
|
imageName: FormItemRule;
|
||||||
|
composeName: FormItemRule;
|
||||||
volumeName: FormItemRule;
|
volumeName: FormItemRule;
|
||||||
linuxName: FormItemRule;
|
linuxName: FormItemRule;
|
||||||
password: FormItemRule;
|
password: FormItemRule;
|
||||||
@ -643,6 +657,11 @@ export const Rules: CommonRule = {
|
|||||||
validator: checkDBName,
|
validator: checkDBName,
|
||||||
trigger: 'blur',
|
trigger: 'blur',
|
||||||
},
|
},
|
||||||
|
composeName: {
|
||||||
|
required: true,
|
||||||
|
validator: checkComposeName,
|
||||||
|
trigger: 'blur',
|
||||||
|
},
|
||||||
imageName: {
|
imageName: {
|
||||||
required: true,
|
required: true,
|
||||||
validator: checkImageName,
|
validator: checkImageName,
|
||||||
|
@ -201,6 +201,8 @@ const message = {
|
|||||||
simpleName: 'Supports non-underscore starting, English, numbers, _, length 3-30',
|
simpleName: 'Supports non-underscore starting, English, numbers, _, length 3-30',
|
||||||
simplePassword: 'Supports non-underscore starting, English, numbers, _, length 1-30',
|
simplePassword: 'Supports non-underscore starting, English, numbers, _, length 1-30',
|
||||||
dbName: 'Supports non-special character starting, including English, Chinese, numbers, .-_, with a length of 1-64',
|
dbName: 'Supports non-special character starting, including English, Chinese, numbers, .-_, with a length of 1-64',
|
||||||
|
composeName:
|
||||||
|
'Supports non-special characters at the beginning, lowercase letters, numbers, - and _, length 1-256',
|
||||||
imageName: 'Support English, numbers, :@/.-_, length 1-256',
|
imageName: 'Support English, numbers, :@/.-_, length 1-256',
|
||||||
volumeName: 'Support English, numbers, .-_, length 2-30',
|
volumeName: 'Support English, numbers, .-_, length 2-30',
|
||||||
supervisorName: 'Supports non-special characters starting with English, numbers, - and _, length 1-128',
|
supervisorName: 'Supports non-special characters starting with English, numbers, - and _, length 1-128',
|
||||||
@ -949,6 +951,14 @@ const message = {
|
|||||||
retainCopiesUnit: ' copies (View)',
|
retainCopiesUnit: ' copies (View)',
|
||||||
cronSpecRule: 'The execution period format in line {0} is incorrect. Please check and try again!',
|
cronSpecRule: 'The execution period format in line {0} is incorrect. Please check and try again!',
|
||||||
cronSpecRule2: 'Execution period format is incorrect, please check and try again!',
|
cronSpecRule2: 'Execution period format is incorrect, please check and try again!',
|
||||||
|
perMonthHelper: 'Execute on the {0} day of every month at {1}:{2}',
|
||||||
|
perWeekHelper: 'Execute every week on {0} at {1}:{2}',
|
||||||
|
perDayHelper: 'Execute every day at {0}:{1}',
|
||||||
|
perHourHelper: 'Execute every hour at {0} minutes',
|
||||||
|
perNDayHelper: 'Execute every {0} days at {1}:{2}',
|
||||||
|
perNHourHelper: 'Execute every {0} hours at {1}',
|
||||||
|
perNMinuteHelper: 'Execute every {0} minutes',
|
||||||
|
perNSecondHelper: 'Execute every {0} seconds',
|
||||||
perMonth: 'Every monthly',
|
perMonth: 'Every monthly',
|
||||||
perWeek: 'Every week',
|
perWeek: 'Every week',
|
||||||
perHour: 'Every hour',
|
perHour: 'Every hour',
|
||||||
@ -957,8 +967,6 @@ const message = {
|
|||||||
perNHour: 'Every N hours',
|
perNHour: 'Every N hours',
|
||||||
perNMinute: 'Every N minutes',
|
perNMinute: 'Every N minutes',
|
||||||
perNSecond: 'Every N seconds',
|
perNSecond: 'Every N seconds',
|
||||||
per: 'Every ',
|
|
||||||
handle: 'Handle',
|
|
||||||
day: 'Day',
|
day: 'Day',
|
||||||
monday: 'Monday',
|
monday: 'Monday',
|
||||||
tuesday: 'Tuesday',
|
tuesday: 'Tuesday',
|
||||||
|
@ -200,6 +200,7 @@ const message = {
|
|||||||
simpleName: '支持非底線開頭,英文、數字、_,長度3-30',
|
simpleName: '支持非底線開頭,英文、數字、_,長度3-30',
|
||||||
simplePassword: '支持非底線開頭,英文、數字、_,長度1-30',
|
simplePassword: '支持非底線開頭,英文、數字、_,長度1-30',
|
||||||
dbName: '支持非特殊字符開頭,英文、中文、數字、.-_,長度1-64',
|
dbName: '支持非特殊字符開頭,英文、中文、數字、.-_,長度1-64',
|
||||||
|
composeName: '支持非特殊字符開頭,小寫英文、數字、-和_,長度1-256',
|
||||||
imageName: '支持英文、數字、:@/.-_,長度1-256',
|
imageName: '支持英文、數字、:@/.-_,長度1-256',
|
||||||
volumeName: '支持英文、數字、.-和_,長度2-30',
|
volumeName: '支持英文、數字、.-和_,長度2-30',
|
||||||
supervisorName: '支援非特殊字元開頭,英文、數字、-和_,長度1-128',
|
supervisorName: '支援非特殊字元開頭,英文、數字、-和_,長度1-128',
|
||||||
@ -902,6 +903,14 @@ const message = {
|
|||||||
retainCopiesUnit: ' 份 (查看)',
|
retainCopiesUnit: ' 份 (查看)',
|
||||||
cronSpecRule: '第 {0} 行中執行週期格式錯誤,請檢查後重試!',
|
cronSpecRule: '第 {0} 行中執行週期格式錯誤,請檢查後重試!',
|
||||||
cronSpecRule2: '執行週期格式錯誤,請檢查後重試!',
|
cronSpecRule2: '執行週期格式錯誤,請檢查後重試!',
|
||||||
|
perMonthHelper: '每月 {0} 日 {1}:{2} 執行',
|
||||||
|
perWeekHelper: '每週 {0} {1}:{2} 執行',
|
||||||
|
perDayHelper: '每日 {0}:{1} 執行',
|
||||||
|
perHourHelper: '每小時 {0}分 執行',
|
||||||
|
perNDayHelper: '每 {0} 日 {1}:{2} 執行',
|
||||||
|
perNHourHelper: '每 {0}小時 {1}分 執行',
|
||||||
|
perNMinuteHelper: '每 {0}分 執行',
|
||||||
|
perNSecondHelper: '每 {0}秒 執行',
|
||||||
perMonth: '每月',
|
perMonth: '每月',
|
||||||
perWeek: '每周',
|
perWeek: '每周',
|
||||||
perHour: '每小時',
|
perHour: '每小時',
|
||||||
@ -910,8 +919,6 @@ const message = {
|
|||||||
perNHour: '每 N 時',
|
perNHour: '每 N 時',
|
||||||
perNMinute: '每 N 分鐘',
|
perNMinute: '每 N 分鐘',
|
||||||
perNSecond: '每 N 秒',
|
perNSecond: '每 N 秒',
|
||||||
per: '每',
|
|
||||||
handle: '執行',
|
|
||||||
day: '日',
|
day: '日',
|
||||||
monday: '周一',
|
monday: '周一',
|
||||||
tuesday: '周二',
|
tuesday: '周二',
|
||||||
|
@ -200,6 +200,7 @@ const message = {
|
|||||||
simpleName: '支持非下划线开头,英文、数字、_,长度3-30',
|
simpleName: '支持非下划线开头,英文、数字、_,长度3-30',
|
||||||
simplePassword: '支持非下划线开头,英文、数字、_,长度1-30',
|
simplePassword: '支持非下划线开头,英文、数字、_,长度1-30',
|
||||||
dbName: '支持非特殊字符开头,英文、中文、数字、.-_,长度1-64',
|
dbName: '支持非特殊字符开头,英文、中文、数字、.-_,长度1-64',
|
||||||
|
composeName: '支持非特殊字符开头,小写英文、数字、-和_,长度1-256',
|
||||||
imageName: '支持英文、数字、:@/.-_,长度1-256',
|
imageName: '支持英文、数字、:@/.-_,长度1-256',
|
||||||
volumeName: '支持英文、数字、.-和_,长度2-30',
|
volumeName: '支持英文、数字、.-和_,长度2-30',
|
||||||
supervisorName: '支持非特殊字符开头,英文、数字、-和_,长度1-128',
|
supervisorName: '支持非特殊字符开头,英文、数字、-和_,长度1-128',
|
||||||
@ -902,6 +903,14 @@ const message = {
|
|||||||
retainCopiesUnit: ' 份 (查看)',
|
retainCopiesUnit: ' 份 (查看)',
|
||||||
cronSpecRule: '第 {0} 行中执行周期格式错误,请检查后重试!',
|
cronSpecRule: '第 {0} 行中执行周期格式错误,请检查后重试!',
|
||||||
cronSpecRule2: '执行周期格式错误,请检查后重试!',
|
cronSpecRule2: '执行周期格式错误,请检查后重试!',
|
||||||
|
perMonthHelper: '每月 {0} 日 {1}:{2} 执行',
|
||||||
|
perWeekHelper: '每周 {0} {1}:{2} 执行',
|
||||||
|
perDayHelper: '每日 {0}:{1} 执行',
|
||||||
|
perHourHelper: '每小时 {0}分 执行',
|
||||||
|
perNDayHelper: '每 {0} 日 {1}:{2} 执行',
|
||||||
|
perNHourHelper: '每 {0}小时 {1}分 执行',
|
||||||
|
perNMinuteHelper: '每 {0}分 执行',
|
||||||
|
perNSecondHelper: '每 {0}秒 执行',
|
||||||
perMonth: '每月',
|
perMonth: '每月',
|
||||||
perWeek: '每周',
|
perWeek: '每周',
|
||||||
perHour: '每小时',
|
perHour: '每小时',
|
||||||
@ -910,8 +919,6 @@ const message = {
|
|||||||
perNHour: '每 N 时',
|
perNHour: '每 N 时',
|
||||||
perNMinute: '每 N 分钟',
|
perNMinute: '每 N 分钟',
|
||||||
perNSecond: '每 N 秒',
|
perNSecond: '每 N 秒',
|
||||||
per: '每',
|
|
||||||
handle: '执行',
|
|
||||||
day: '日',
|
day: '日',
|
||||||
monday: '周一',
|
monday: '周一',
|
||||||
tuesday: '周二',
|
tuesday: '周二',
|
||||||
|
@ -98,7 +98,7 @@ const form = reactive({
|
|||||||
envFileContent: `env_file:\n - 1panel.env`,
|
envFileContent: `env_file:\n - 1panel.env`,
|
||||||
});
|
});
|
||||||
const rules = reactive({
|
const rules = reactive({
|
||||||
name: [Rules.requiredInput, Rules.imageName],
|
name: [Rules.requiredInput, Rules.composeName],
|
||||||
path: [Rules.requiredInput],
|
path: [Rules.requiredInput],
|
||||||
template: [Rules.requiredSelect],
|
template: [Rules.requiredSelect],
|
||||||
});
|
});
|
||||||
|
@ -373,7 +373,7 @@
|
|||||||
/>
|
/>
|
||||||
<fu-table-operations
|
<fu-table-operations
|
||||||
fix
|
fix
|
||||||
width="180px"
|
width="200px"
|
||||||
:ellipsis="2"
|
:ellipsis="2"
|
||||||
:buttons="buttons"
|
:buttons="buttons"
|
||||||
:label="$t('commons.table.operate')"
|
:label="$t('commons.table.operate')"
|
||||||
|
@ -517,18 +517,17 @@ const search = async () => {
|
|||||||
form.cmd = res.data.cmd || [];
|
form.cmd = res.data.cmd || [];
|
||||||
for (const item of form.cmd) {
|
for (const item of form.cmd) {
|
||||||
if (item.indexOf(' ') !== -1) {
|
if (item.indexOf(' ') !== -1) {
|
||||||
itemCmd += `"${item.replaceAll('"', '\\"')}" `;
|
itemCmd += `"${escapeQuotes(item)}" `;
|
||||||
} else {
|
} else {
|
||||||
itemCmd += item + ' ';
|
itemCmd += item + ' ';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
form.cmdStr = itemCmd.trimEnd();
|
form.cmdStr = itemCmd.trimEnd();
|
||||||
|
|
||||||
let itemEntrypoint = '';
|
let itemEntrypoint = '';
|
||||||
form.entrypoint = res.data.entrypoint || [];
|
form.entrypoint = res.data.entrypoint || [];
|
||||||
for (const item of form.entrypoint) {
|
for (const item of form.entrypoint) {
|
||||||
if (item.indexOf(' ') !== -1) {
|
if (item.indexOf(' ') !== -1) {
|
||||||
itemEntrypoint += `"${item.replaceAll('"', '\\"')}" `;
|
itemEntrypoint += `"${escapeQuotes(item)}" `;
|
||||||
} else {
|
} else {
|
||||||
itemEntrypoint += item + ' ';
|
itemEntrypoint += item + ' ';
|
||||||
}
|
}
|
||||||
@ -656,14 +655,14 @@ const onSubmit = async (formEl: FormInstance | undefined) => {
|
|||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
form.cmd = [];
|
form.cmd = [];
|
||||||
if (form.cmdStr) {
|
if (form.cmdStr) {
|
||||||
let itemCmd = splitWithQuotes(form.cmdStr);
|
let itemCmd = splitStringIgnoringQuotes(form.cmdStr);
|
||||||
for (const item of itemCmd) {
|
for (const item of itemCmd) {
|
||||||
form.cmd.push(item.replace(/(?<!\\)"/g, '').replaceAll('\\"', '"'));
|
form.cmd.push(item.replace(/(?<!\\)"/g, '').replaceAll('\\"', '"'));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
form.entrypoint = [];
|
form.entrypoint = [];
|
||||||
if (form.entrypointStr) {
|
if (form.entrypointStr) {
|
||||||
let itemEntrypoint = splitWithQuotes(form.entrypointStr);
|
let itemEntrypoint = splitStringIgnoringQuotes(form.entrypointStr);
|
||||||
for (const item of itemEntrypoint) {
|
for (const item of itemEntrypoint) {
|
||||||
form.entrypoint.push(item.replace(/(?<!\\)"/g, '').replaceAll('\\"', '"'));
|
form.entrypoint.push(item.replace(/(?<!\\)"/g, '').replaceAll('\\"', '"'));
|
||||||
}
|
}
|
||||||
@ -778,15 +777,25 @@ const isFromApp = (rowData: Container.ContainerHelper) => {
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
const splitWithQuotes = (str) => {
|
const escapeQuotes = (input) => {
|
||||||
str = str.replace(/\\"/g, '<quota>');
|
return input.replace(/(?<!\\)"/g, '\\"');
|
||||||
const regex = /(?=(?:[^'"]|['"][^'"]*['"])*$)\s+/g;
|
};
|
||||||
let parts = str.split(regex).filter(Boolean);
|
|
||||||
let returnList = [];
|
const splitStringIgnoringQuotes = (input) => {
|
||||||
for (const item of parts) {
|
input = input.replace(/\\"/g, '<quota>');
|
||||||
returnList.push(item.replaceAll('<quota>', '\\"'));
|
const regex = /"([^"]*)"|(\S+)/g;
|
||||||
|
const result = [];
|
||||||
|
let match;
|
||||||
|
|
||||||
|
while ((match = regex.exec(input)) !== null) {
|
||||||
|
if (match[1]) {
|
||||||
|
result.push(match[1].replaceAll('<quota>', '\\"'));
|
||||||
|
} else if (match[2]) {
|
||||||
|
result.push(match[2].replaceAll('<quota>', '\\"'));
|
||||||
}
|
}
|
||||||
return returnList;
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
};
|
};
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
@ -67,7 +67,6 @@ const loading = ref();
|
|||||||
|
|
||||||
const data = ref();
|
const data = ref();
|
||||||
const paginationConfig = reactive({
|
const paginationConfig = reactive({
|
||||||
cacheSizeKey: 'backup-cronjob-page-size',
|
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
|
@ -166,50 +166,26 @@ export function transSpecToObj(spec: string) {
|
|||||||
|
|
||||||
export function transSpecToStr(spec: string): string {
|
export function transSpecToStr(spec: string): string {
|
||||||
const specObj = transSpecToObj(spec);
|
const specObj = transSpecToObj(spec);
|
||||||
let str = '';
|
|
||||||
if (specObj.specType.indexOf('N') === -1 || specObj.specType === 'perWeek') {
|
|
||||||
str += i18n.global.t('cronjob.' + specObj.specType) + ' ';
|
|
||||||
} else {
|
|
||||||
str += i18n.global.t('cronjob.per') + ' ';
|
|
||||||
}
|
|
||||||
switch (specObj.specType) {
|
switch (specObj.specType) {
|
||||||
case 'perMonth':
|
case 'perMonth':
|
||||||
str +=
|
return i18n.global.t('cronjob.perMonthHelper', [specObj.day, specObj.hour, loadZero(specObj.minute)]);
|
||||||
specObj.day +
|
|
||||||
i18n.global.t('cronjob.day') +
|
|
||||||
' ' +
|
|
||||||
loadZero(specObj.hour) +
|
|
||||||
':' +
|
|
||||||
loadZero(specObj.minute);
|
|
||||||
break;
|
|
||||||
case 'perWeek':
|
case 'perWeek':
|
||||||
str += loadWeek(specObj.week) + ' ' + loadZero(specObj.hour) + ':' + loadZero(specObj.minute);
|
return i18n.global.t('cronjob.perWeekHelper', [
|
||||||
break;
|
loadWeek(specObj.week),
|
||||||
|
specObj.hour,
|
||||||
|
loadZero(specObj.minute),
|
||||||
|
]);
|
||||||
case 'perDay':
|
case 'perDay':
|
||||||
str += loadZero(specObj.hour) + ':' + loadZero(specObj.minute);
|
return i18n.global.t('cronjob.perDayHelper', [specObj.hour, loadZero(specObj.minute)]);
|
||||||
break;
|
|
||||||
case 'perNDay':
|
|
||||||
str +=
|
|
||||||
specObj.day +
|
|
||||||
i18n.global.t('commons.units.day') +
|
|
||||||
', ' +
|
|
||||||
loadZero(specObj.hour) +
|
|
||||||
':' +
|
|
||||||
loadZero(specObj.minute);
|
|
||||||
break;
|
|
||||||
case 'perNHour':
|
|
||||||
str += specObj.hour + i18n.global.t('commons.units.hour') + ', ' + loadZero(specObj.minute);
|
|
||||||
break;
|
|
||||||
case 'perHour':
|
case 'perHour':
|
||||||
str += loadZero(specObj.minute);
|
return i18n.global.t('cronjob.perHourHelper', [loadZero(specObj.minute)]);
|
||||||
break;
|
case 'perNDay':
|
||||||
|
return i18n.global.t('cronjob.perNDayHelper', [specObj.day, specObj.hour, loadZero(specObj.minute)]);
|
||||||
|
case 'perNHour':
|
||||||
|
return i18n.global.t('cronjob.perNHourHelper', [specObj.hour, loadZero(specObj.minute)]);
|
||||||
case 'perNMinute':
|
case 'perNMinute':
|
||||||
str += loadZero(specObj.minute) + i18n.global.t('commons.units.minute');
|
return i18n.global.t('cronjob.perNMinuteHelper', [loadZero(specObj.minute)]);
|
||||||
break;
|
|
||||||
case 'perNSecond':
|
case 'perNSecond':
|
||||||
str += loadZero(specObj.second) + i18n.global.t('commons.units.second');
|
return i18n.global.t('cronjob.perNSecondHelper', [loadZero(specObj.second)]);
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return str + ' ' + i18n.global.t('cronjob.handle');
|
|
||||||
}
|
}
|
||||||
|
@ -102,7 +102,7 @@ const bindRef = ref();
|
|||||||
|
|
||||||
const data = ref();
|
const data = ref();
|
||||||
const paginationConfig = reactive({
|
const paginationConfig = reactive({
|
||||||
cacheSizeKey: 'backup-page-size',
|
cacheSizeKey: 'license-page-size',
|
||||||
currentPage: 1,
|
currentPage: 1,
|
||||||
pageSize: 10,
|
pageSize: 10,
|
||||||
total: 0,
|
total: 0,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user