Compare commits

..

88 Commits

Author SHA1 Message Date
吴小白
86ce758adb feat: 更新 action node 版本 2022-11-17 21:56:54 +08:00
Jiangjie.Bai
582a84178d Merge pull request #2187 from jumpserver/dev
v2.28.0
2022-11-17 17:44:19 +08:00
“huailei000”
73de782756 fix: 修复绑定企业微信弹窗时input样式遮挡问题 2022-11-17 16:55:11 +08:00
Jiangjie.Bai
9b9f7c936c Merge pull request #2184 from jumpserver/dev
v2.28.0-rc5
2022-11-17 14:18:15 +08:00
jiangweidong
55100e64a1 perf: 翻译用户的[邮件]改为[邮箱] 2022-11-17 14:16:00 +08:00
jiangweidong
6d74959b64 perf: 翻译用户的[邮件]改为[邮箱] 2022-11-17 14:16:00 +08:00
Jiangjie.Bai
2a6100957f Merge pull request #2182 from jumpserver/dev
v2.28.0-rc4
2022-11-16 21:08:55 +08:00
feng626
6a3f6f8914 Merge pull request #2180 from jumpserver/pr@dev@ticket_expire_time
pef: ticket expire time
2022-11-15 17:34:08 +08:00
“huailei000”
704ae0b294 fix: 修复改密计划详情中列表和资产树添加资产到节点时table会获取url中参数问题 2022-11-15 17:11:40 +08:00
feng
9bf4597d8d pef: ticket expire time 2022-11-15 16:54:45 +08:00
Jiangjie.Bai
16606d6a27 Merge pull request #2176 from jumpserver/dev
v2.28.0-rc2
2022-11-14 10:01:05 +08:00
jiangweidong
bb1d19610e perf: 优化操作日志界面显示随主题变化 2022-11-14 09:47:12 +08:00
老广
ca871b16c4 Revert "perf: 优化刷新页面方法,避免刷新时页面出现空白"
This reverts commit a514e88b78.
2022-11-11 19:39:14 +08:00
Jiangjie.Bai
0a612f50e6 Merge pull request #2164 from jumpserver/dev
v2.28.0-rc1
2022-11-10 17:45:47 +08:00
“huailei000”
d566adb644 fix: 修复账号信息更新消息订阅从新进入页面状态没有改变问题 2022-11-10 17:43:28 +08:00
jiangweidong
242f958428 feat: 云资产同步支持选择IP类型 2022-11-10 17:42:14 +08:00
“huailei000”
f97d46814d perf: update yarn.lock 2022-11-08 15:28:11 +08:00
Jiangjie.Bai
5cc501f5af perf: 优化优先使用系统设置中的 rdp_resolution 配置 2022-11-07 18:47:29 +08:00
jiangweidong
31fd0ecde0 feat: 显示部分资源的批量删除操作按钮 2022-11-04 14:34:14 +08:00
jiangweidong
9d6ac3907a feat: 重构操作日志 (#2088)
* feat: 操作日志重构-支持查看变更资源信息

* feat: 修改界面

* feat: 优化操作日志详情界面

* feat: 修改显示样式
2022-11-04 14:33:02 +08:00
jiangweidong
784bd16e87 feat: 支持纳管 clickhouse[Web Terminal] (#2112) 2022-11-04 14:31:54 +08:00
jiangweidong
4a11ea2c57 feat: 云同步支持金山云 (#2125) 2022-11-04 14:31:20 +08:00
Jiangjie.Bai
4a2ffc754f fix: 修复创建第三方用户时 need_update_password 默认为 true 的问题 2022-11-01 16:38:06 +08:00
吴小白
d31929eb33 perf: 优化构建 2022-10-24 09:51:15 +08:00
Jiangjie.Bai
fe36fa9390 Merge pull request #2117 from jumpserver/dev
v2.27.0-rc4
2022-10-18 21:02:10 +08:00
“huailei000”
a97de8afb4 perf: 重置element-ui的message组件,防止重复点击重复弹出提示 2022-10-18 20:59:39 +08:00
Jiangjie.Bai
ba109900ec Merge pull request #2113 from jumpserver/dev
v2.27.0-rc3
2022-10-18 11:20:57 +08:00
“huailei000”
f8649457d6 perf: 优化页面布局 2022-10-18 10:34:18 +08:00
“huailei000”
8863693541 fix: 修复平台列表修复克隆名称带空格不能创建问题 2022-10-18 10:29:15 +08:00
“huailei000”
c2cbd3f5b0 fix: 修复切换组织下拉框icon图标颜色不明显 2022-10-17 16:32:07 +08:00
“huailei000”
0b84b96afb fix: 修复终端设置-创建录像存储设置默认存储字段不生效问题 2022-10-17 14:50:43 +08:00
Jiangjie.Bai
ec7768267f Merge pull request #2105 from jumpserver/dev
v2.27.0-rc2
2022-10-14 11:01:32 +08:00
吴小白
4aefb6779f fix: 修正错误的构建参数 2022-10-14 10:52:14 +08:00
吴小白
06fd007c62 Revert "revert: 还原 dockerfile"
This reverts commit 6f4e029537.
2022-10-14 10:52:14 +08:00
ibuler
6f4e029537 revert: 还原 dockerfile 2022-10-14 10:29:27 +08:00
Jiangjie.Bai
cc58b374ab Merge pull request #2101 from jumpserver/dev
v2.27.0-rc1
2022-10-13 17:44:53 +08:00
“huailei000”
07f35dbbb2 fix: jQuery undefined 2022-10-13 17:41:08 +08:00
Jiangjie.Bai
04ffbb8fd6 Merge pull request #2097 from jumpserver/dev
v2.27.0-rc1
2022-10-13 15:14:40 +08:00
“huailei000”
12a501d559 perf: update jquery 2022-10-13 11:20:29 +08:00
feng626
7dcd4490ba Merge pull request #2093 from jumpserver/pr@dev@task_log
fix: 修复任务列表无法查看日志信息bug
2022-10-13 10:54:48 +08:00
feng626
dd1ac7c7f8 fix: 修复任务列表无法查看日志信息bug 2022-10-13 10:50:53 +08:00
“huailei000”
471910e0b8 pref: 作业中心任务详情添加查看输出快捷键 2022-10-12 19:13:08 +08:00
“huailei000”
a514e88b78 perf: 优化刷新页面方法,避免刷新时页面出现空白 2022-10-11 16:21:02 +08:00
Jiangjie.Bai
b79fefdee8 feat: 命令过滤器支持关联节点; 2022-10-09 19:02:17 +08:00
Jiangjie.Bai
d2b3025709 perf: 优化用户创建默认勾选登录后需要修改密码 2022-10-09 16:57:02 +08:00
吴小白
386e2417e3 Merge pull request #2075 from YonezawaYukar/dev
fix: 修正 Dockerfile
2022-10-08 09:38:21 +08:00
米泽由香里
fd57b37cea Update Dockerfile
修改一处错误
RUN重复两次 导致无法正常build
2022-10-04 03:28:10 +08:00
吴小白
a6222f87d2 fix: 编译时修改版本 2022-09-30 10:08:14 +08:00
吴小白
5cd4e5b40b perf: 使用 yarn 构建 2022-09-30 10:08:14 +08:00
吴小白
eb3d9089e0 perf: 构建时使用缓存 2022-09-30 10:08:14 +08:00
jiangweidong
56c22cffe6 perf: 优化短信配置错误提示不友好问题 2022-09-26 14:53:03 +08:00
“huailei000”
fe1e26957a fix: 修复全局组织下更新、删除:用户、端点、端点规则、组织权限 2022-09-26 14:52:16 +08:00
“huailei000”
bc366947f0 fix: 实例同步列表不显示多选框;设置云同步详情页面的菜单高亮显示;云同步进入详情不主动激活detail页卡 2022-09-26 14:51:06 +08:00
“huailei000”
86150cc571 fix: 修复账号信息内容更新不及时问题 2022-09-26 14:49:56 +08:00
Jiangjie.Bai
f11fc947af feat: 修改 Endpoint 的创建页面; 修改 Oracle 数据库创建不包含版本号字段 2022-09-22 19:24:15 +08:00
Jiangjie.Bai
49880f6739 Merge pull request #2059 from jumpserver/dev
v2.26.0
2022-09-15 17:49:44 +08:00
“huailei000”
82faf0f99e perf: 资产详情-授权用户没有数据时显示暂无数据 2022-09-15 17:48:41 +08:00
Jiangjie.Bai
e6f98d58c4 Merge pull request #2057 from jumpserver/dev
v2.26.0-rc4
2022-09-15 16:18:03 +08:00
“huailei000”
3536a94976 fix: 修复全局组织下命令过滤不能创建 2022-09-15 15:59:53 +08:00
“huailei000”
45276010e0 fix: 创建数据库端口设置为必填项 2022-09-15 15:34:00 +08:00
“huailei000”
2e47f42366 fix: 修复批量命令列表可点击链接颜色 2022-09-15 15:33:41 +08:00
“huailei000”
dd6e9a1512 fix: 修复批量命令列表可点击链接颜色 2022-09-15 15:33:41 +08:00
Jiangjie.Bai
fd1f16d43c Merge pull request #2050 from jumpserver/dev
v2.26.0-rc2
2022-09-13 17:41:39 +08:00
feng626
24931a9f5a perf: 工单新增相关过滤 2022-09-13 15:33:22 +08:00
ibuler
f51924bf1d perf: 优化密码加密,如果没有key就不加密了 2022-09-13 15:32:53 +08:00
“huailei000”
f82257edb8 fix: 修复创建、更新用户后点击邀请用户接口404问题 2022-09-13 15:31:53 +08:00
jiangweidong
286e9894c0 perf: 屏蔽--secure参数,目前redis-cli版本为6.0,暂时用不到 2022-09-13 11:50:06 +08:00
Jiangjie.Bai
968b2415b1 Merge pull request #2043 from jumpserver/dev
v2.26.0-rc1
2022-09-08 15:46:44 +08:00
“huailei000”
e0f6fb305d perf: cas用户属性映射不能为空,至少设置username 2022-09-08 15:46:08 +08:00
jiangweidong
e0fd33f376 fix: 修复数据库创建页面有多个mongdob的问题 (#2041) 2022-09-08 15:16:54 +08:00
jiangweidong
7ad86062b4 perf: 支持连接开启ssl且自签证书的Redis/MongoDB (#2039)
* perf: 支持连接开启ssl且自签证书的Redis/MongoDB

* 修改字段文案

* 修改字段名称

* 修改变量名
2022-09-07 16:09:07 +08:00
“huailei000”
1fce7561db fix: 修复用户首次登录页面翻译 2022-09-06 19:38:49 +08:00
“huailei000”
3b17235b6e fix: 批量更新不请求接口 2022-09-06 19:06:14 +08:00
jiangweidong
52c9b9503b feat: 支持MFA可配置华为云平台短信对接 2022-09-06 17:33:42 +08:00
Jiangjie.Bai
48a2b20320 Merge pull request #2025 from jumpserver/pr@dev@feat_cloud_support_ctyun_private
feat: 云同步支持同步天翼私有云平台资产
2022-09-06 17:31:01 +08:00
Jiangjie.Bai
e6cc8cd2e8 Merge branch 'dev' into pr@dev@feat_cloud_support_ctyun_private 2022-09-06 17:30:47 +08:00
jiangweidong
3a183ddf53 feat: 支持OAuth2协议自定义注销功能 2022-09-06 17:27:11 +08:00
jiangweidong
7eb77487d1 feat: feat: 支持连接开启了ssl的Redis数据库 2022-09-06 16:55:37 +08:00
jiangweidong
a5da581317 feat: 云同步支持资产同步腾讯云(轻量应用服务器) 2022-09-06 16:19:58 +08:00
“huailei000”
6bda9a372e fix: moment.js 插件升级修复官方漏洞 2022-09-05 13:55:52 +08:00
jiangweidong
a8de087137 feat: 云同步支持同步天翼私有云平台资产 2022-09-02 17:37:27 +08:00
jiangweidong
34d9790a04 feat: MongoDB支持连接SSL类型 2022-08-24 15:00:56 +08:00
“huailei000”
5bfe2497fd fix: 修复新建用户个人信息确认后跳转路由还会返回个人信息确认页问题 2022-08-24 14:48:08 +08:00
jiangweidong
e16a775037 feat: 改密计划支持MongoDB改密 2022-08-24 14:47:46 +08:00
“huailei000”
42fab92237 fix: 调整按钮大小 2022-08-19 16:24:29 +08:00
Jiangjie.Bai
e2eac83615 fix: 修复上传json文件上传问题 2022-08-19 13:36:22 +08:00
“huailei000”
04465a1da3 fix: 修复LDAP用户导入失败弹出提示 2022-08-19 11:05:31 +08:00
“huailei000”
2adb1ee980 fix: 升级lodash 2022-08-19 11:04:43 +08:00
83 changed files with 6222 additions and 3679 deletions

View File

@@ -39,7 +39,7 @@ jobs:
steps:
- uses: actions/checkout@v2
- name: Build it and upload
uses: jumpserver/action-build-upload-assets@node10
uses: jumpserver/action-build-upload-assets@node14.16
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:

View File

@@ -1,23 +1,26 @@
FROM node:10 as stage-build
FROM node:14.16 as stage-build
ARG TARGETARCH
ARG NPM_REGISTRY="https://registry.npmmirror.com"
ENV NPM_REGISTY=$NPM_REGISTRY
ARG SASS_BINARY_SITE="https://npmmirror.com/mirrors/node-sass"
ENV SASS_BINARY_SITE=$SASS_BINARY_SITE
WORKDIR /data
RUN npm config set sass_binary_site=${SASS_BINARY_SITE}
RUN npm config set registry ${NPM_REGISTRY}
RUN yarn config set registry ${NPM_REGISTRY}
COPY package.json yarn.lock /data/
RUN yarn install
RUN npm rebuild node-sass
RUN set -ex \
&& npm config set registry ${NPM_REGISTRY} \
&& yarn config set registry ${NPM_REGISTRY} \
&& yarn config set cache-folder /root/.cache/yarn/lina
ADD package.json yarn.lock /data
RUN --mount=type=cache,target=/root/.cache/yarn \
yarn install
ARG VERSION
ENV VERSION=$VERSION
ADD . /data
RUN cd utils && bash -xieu build.sh build
RUN --mount=type=cache,target=/root/.cache/yarn \
sed -i "s@Version <strong>.*</strong>@Version <strong>${VERSION}</strong>@g" src/layout/components/Footer/index.vue \
&& yarn build
FROM nginx:alpine
COPY --from=stage-build /data/release/lina /opt/lina
COPY --from=stage-build /data/lina /opt/lina
COPY nginx.conf /etc/nginx/conf.d/default.conf

View File

@@ -7,6 +7,7 @@
"scripts": {
"dev": "vue-cli-service serve",
"serve": "vue-cli-service serve",
"build": "vue-cli-service build",
"build:prod": "vue-cli-service build",
"build:stage": "vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
@@ -32,13 +33,13 @@
"element-ui": "2.13.2",
"eslint-plugin-html": "^6.0.0",
"install": "^0.13.0",
"jquery": "^3.5.0",
"jquery": "^3.6.1",
"js-cookie": "2.2.0",
"jsencrypt": "^3.2.1",
"krry-transfer": "^1.7.3",
"less": "^3.10.3",
"less-loader": "^5.0.0",
"lodash": "^4.17.15",
"lodash": "^4.17.21",
"lodash.clonedeep": "^4.5.0",
"lodash.frompairs": "^4.0.1",
"lodash.get": "^4.4.2",
@@ -50,8 +51,8 @@
"lodash.set": "^4.3.2",
"lodash.topairs": "^4.3.0",
"lodash.values": "^4.3.0",
"moment": "^2.29.1",
"moment-parseformat": "^3.0.0",
"moment": "^2.29.4",
"moment-parseformat": "^4.0.0",
"normalize.css": "7.0.0",
"npm": "^7.8.0",
"nprogress": "0.2.0",

View File

@@ -247,6 +247,15 @@ td .el-button.el-button--mini {
border-top-color: #676a6c;
}
.text-link {
color: info!important;
}
.text-link:hover {
color: info!important;
filter: opacity(65%)!important;
}
.text-danger {
color: danger;
}

View File

@@ -45,3 +45,20 @@ export const JsonRequired = {
}
}
}
export const JsonRequiredUserNameMapped = {
required: true,
trigger: 'change',
validator: (rule, value, callback) => {
try {
JSON.parse(value)
const hasUserName = _.map(JSON.parse(value), (value) => value)
if (!hasUserName.includes('username')) {
callback(new Error(i18n.t('common.requiredHasUserNameMapped')))
}
callback()
} catch (e) {
callback(new Error(i18n.t('common.InvalidJson')))
}
}
}

View File

@@ -50,7 +50,7 @@ export default {
const reader = new FileReader()
reader.onload = function() {
let result = this.result
if (vm.toFormat === 'object') {
if (vm.toFormat === 'object' && vm.fileName.endsWith('.json')) {
result = JSON.parse(result)
}
vm.$emit('input', result)

View File

@@ -0,0 +1,61 @@
<template>
<el-row :gutter="10">
<div v-if="isAllEmpty()" style="text-align: center">
{{ this.$t('common.NoContent') }}
</div>
<div v-else>
<el-col :span="rightEmpty() ? 24 : 12">
<div v-if="!leftEmpty()">
<el-tag type="primary" effect="dark" :closable="false" style="width: 100%;">{{ row.leftTitle }}</el-tag>
<div v-for="(value, key, index) in row.left" :key="index">
<el-tag type="primary"><strong>{{ key }}: </strong>{{ value }}</el-tag>
</div>
</div>
</el-col>
<el-col :span="leftEmpty() ? 24 : 12">
<div v-if="!rightEmpty()">
<el-tag type="primary" effect="dark" :closable="false" style="width: 100%;">{{ row.rightTitle }}</el-tag>
<div v-for="(value, key, index) in row.right" :key="index">
<el-tag type="primary"><strong>{{ key }}: </strong>{{ value }}</el-tag>
</div>
</div>
</el-col>
</div>
</el-row>
</template>
<script>
export default {
name: 'TwoTabFormatter',
props: {
row: {
type: Object,
default: () => ({})
}
},
methods: {
isEmpty(content) {
return !content || JSON.stringify(content) === '{}'
},
leftEmpty() {
return this.isEmpty(this.row.left)
},
rightEmpty() {
return this.isEmpty(this.row.right)
},
isAllEmpty() {
return this.leftEmpty() && this.rightEmpty()
}
}
}
</script>
<style scoped>
.el-tag{
width: 100%;
white-space: normal;
height:auto;
}
</style>

View File

@@ -12,6 +12,7 @@ import DialogDetailFormatter from './DialogDetailFormatter'
import EditableInputFormatter from './EditableInputFormatter'
import StatusFormatter from './StatusFormatter'
import TagsFormatter from './TagsFormatter'
import TwoTabFormatter from './TwoTabFormatter'
export default {
DetailFormatter,
@@ -27,7 +28,8 @@ export default {
ArrayFormatter,
EditableInputFormatter,
StatusFormatter,
TagsFormatter
TagsFormatter,
TwoTabFormatter
}
export {
@@ -44,5 +46,6 @@ export {
ArrayFormatter,
EditableInputFormatter,
StatusFormatter,
TagsFormatter
TagsFormatter,
TwoTabFormatter
}

View File

@@ -55,19 +55,19 @@
</el-col>
</el-row>
<el-row :gutter="24" style="margin: 0 auto;">
<el-col :md="24 - smsWidth" :sm="24">
<el-input v-model="SecretKey" :show-password="showPassword" :placeholder="HelpText" style="margin-bottom: 20px;" />
</el-col>
<el-col v-if="Select === 'sms'" :md="smsWidth" :sm="24">
<el-button
size="mini"
type="primary"
style="line-height:20px; float: right;"
:disabled="smsBtndisabled"
@click="sendChallengeCode"
>
{{ smsBtnText }}
</el-button>
<el-col :md="24" :sm="24" style="display: flex; margin-bottom: 20px;">
<el-input v-model="SecretKey" :show-password="showPassword" :placeholder="HelpText" />
<span v-if="Select === 'sms'" style="margin: -1px 0 0 20px;">
<el-button
size="mini"
type="primary"
style="line-height:20px; float: right;"
:disabled="smsBtndisabled"
@click="sendChallengeCode"
>
{{ smsBtnText }}
</el-button>
</span>
</el-col>
</el-row>
<el-row :gutter="24" style="margin: 0 auto;">

View File

@@ -47,6 +47,7 @@
"sqlserver": "SQLServer",
"redis": "Redis",
"mongodb": "MongoDB",
"clickhouse": "ClickHouse",
"k8s": "kubernetes"
},
"applicationsCategory": {
@@ -244,7 +245,9 @@
"View": "View",
"LoginIP": "Login IP",
"LoginCity": "Login city",
"LoginDate": "Login date"
"LoginDate": "Login date",
"BeforeChange": "Before change",
"AfterChange": "After change"
},
"auth": {
"LoginRequiredMsg": "You account has logout, Please login again",
@@ -254,6 +257,7 @@
"ReLoginErr": "Login time has exceeded 5 minutes, please login again"
},
"common": {
"NoContent": "No content",
"NeedAddAppsOrSystemUserErrMsg": "Please add apps or system user",
"VerificationCodeSent": "The verification code has been sent",
"SendVerificationCode": "Send verification code",
@@ -267,6 +271,12 @@
"IPLoginLimit": "IP login limit",
"Setting": "Setting",
"Certificate": "Certificate",
"CACertificate": "CA Certificate",
"ClientCertificate": "Client certificate",
"CertificateKey": "Certificate key file",
"AllowInvalidCert": "Allow invalid cert",
"UseSSL": "Use SSL/TLS",
"SecretKey": "Secret key",
"Scope": "Type",
"Builtin": "Builtin",
"DateCreated": "Date created",
@@ -408,6 +418,7 @@
"disableSelected": "Disable selected",
"disableSuccessMsg": "Disable success",
"fieldRequiredError": "This field is required",
"requiredHasUserNameMapped": "The mapping of the username field must be included, such as {'uid': 'username'}",
"getErrorMsg": "Get failed",
"fileType": "File type",
"Status": "Status",
@@ -424,6 +435,7 @@
"downloadImportTemplateMsg": "Download import template",
"downloadUpdateTemplateMsg": "Download update template",
"onlyCSVFilesTips": "Only csv supported",
"ImportFail": "Import fail",
"updateSuccessMsg": "Update success, total: {count}",
"dragUploadFileInfo": "Drag file here or click here to upload",
"uploadCsvLth10MHelpText": "csv/xlsx files with a size less than 10M",
@@ -771,7 +783,7 @@
"OperateLog": "Operation Logs",
"PasswordChangeLog": "Password Update Logs",
"Perms": "Permissions",
"PersonalInformationImprovement": "PersonalInformationImprovement",
"PersonalInformationImprovement": "Personal information improvement",
"PlatformCreate": "Platform create",
"PlatformDetail": "Platform detail",
"PlatformList": "Platforms",
@@ -925,6 +937,9 @@
"SMS": "SMS",
"AlibabaCloud": "Alibaba cloud",
"TencentCloud": "Tencent cloud",
"HuaweiCloud": "Huawei cloud",
"SignChannelNum": "Signature Channel Number",
"AppEndpoint": "App access address",
"CMPP2": "CMPP v2.0",
"VerifySignTmpl": "Verification code template",
"Radius": "Radius",
@@ -1139,6 +1154,10 @@
"reply": "Reply",
"status": "Status",
"title": "Title",
"RelevantApp": "App",
"RelevantAsset": "Asset",
"RelevantCommand": "Command",
"RelevantSystemUser": "System user",
"type": "Type",
"user": "User",
"Status": "Status",
@@ -1407,9 +1426,11 @@
"IPNetworkSegment": "Ip Network Segment",
"Aliyun": "Ali Cloud",
"Qcloud": "Tencent Cloud",
"QcloudLighthouse": "Tencent Cloud(Lighthouse)",
"QingyunPrivatecloud": "Qingyun Private Cloud",
"HuaweiPrivatecloud": "Huawei Private Cloud",
"OpenStack": "OpenStack",
"CTYunPrivate": "CTYun Private Cloud",
"GCP": "Google Cloud Platform",
"FC": "Fusion Compute",
"LAN": "LAN",
@@ -1418,6 +1439,7 @@
"HuaweiCloud": "Huawei Cloud",
"BaiduCloud": "Baidu Cloud",
"JDCloud": "JD Cloud",
"KingSoftCloud": "KingSoft Cloud",
"Azure":"Azure(China)",
"Azure_Int": "Azure(International)",
"HostnameStrategy": "Used to produce the asset hostname. For example, 1. Instance name (instanceDemo)2. Instance name and Partial IP (instanceDemo-250.1)",

View File

@@ -52,6 +52,7 @@
"sqlserver": "SQLServer",
"redis": "Redis",
"mongodb": "MongoDB",
"clickhouse": "ClickHouse",
"k8s": "Kubernetes"
},
"applicationsCategory": {
@@ -249,7 +250,9 @@
"SystemUserName": "システムユーザー名",
"LoginIP": "ログインIP",
"LoginCity": "ログイン都市",
"LoginDate": "ログイン日"
"LoginDate": "ログイン日",
"BeforeChange": "変更前",
"AfterChange": "変更後"
},
"auth": {
"LoginRequiredMsg": "アカウントが終了しました。ログインし直してください",
@@ -259,6 +262,7 @@
"ReLoginErr": "ログイン時間が 5 分を超えました。もう一度ログインしてください"
},
"common": {
"NoContent": "まだ内容がない",
"NeedAddAppsOrSystemUserErrMsg": "アプリケーションまたはシステムユーザーを追加してください",
"VerificationCodeSent": "検証コードが送信されました",
"SendVerificationCode": "認証コードの送信",
@@ -272,6 +276,12 @@
"IPLoginLimit": "IPログイン制限",
"Setting": "設定",
"Certificate": "証明書",
"CACertificate": "CA 証明書",
"ClientCertificate": "クライアント証明書",
"CertificateKey": "証明書秘密鍵ファイル",
"AllowInvalidCert": "証明書チェックを無視する",
"UseSSL": "使う SSL/TLS",
"SecretKey": "鍵",
"Scope": "カテゴリ",
"Builtin": "内蔵",
"DateCreated": "作成日",
@@ -417,6 +427,7 @@
"disableSelected": "選択した無効",
"disableSuccessMsg": "成功を無効にする",
"fieldRequiredError": "このフィールドは必須項目です",
"requiredHasUserNameMapped": "usernameフィールドのマッピングを含める必要があります, {'uid':'username'}など",
"getErrorMsg": "の取得に失敗しました",
"MFAErrorMsg": "MFAエラーです。チェックしてください",
"Total": "合計",
@@ -435,6 +446,7 @@
"downloadImportTemplateMsg": "作成テンプレートのダウンロード",
"downloadUpdateTemplateMsg": "更新テンプレートのダウンロード",
"onlyCSVFilesTips": "Csvファイルのインポートのみサポート",
"ImportFail": "インポートに失敗しました",
"updateSuccessMsg": "更新のインポートに成功しました。合計:{count}",
"uploadCsvLth10MHelpText": "Csv/xlsxのみアップロードでき、10m以下です",
"dragUploadFileInfo": "ここにファイルをドラッグするか、ここをクリックしてアップロードしてください",
@@ -944,6 +956,9 @@
"Feature": "機能",
"AlibabaCloud": "Alibaba cloud",
"TencentCloud": "テンセント雲",
"HuaweiCloud": "ファーウェイ雲",
"SignChannelNum": "サインパス番号",
"AppEndpoint": "アクセスアドレスを適用する",
"CMPP2": "CMPP v2.0",
"Radius": "Radius",
"VerifySignTmpl": "認証コードメールテンプレート",
@@ -1171,6 +1186,10 @@
"reply": "返信",
"status": "ステータス",
"title": "タイトル",
"RelevantApp": "するアプリケーション",
"RelevantAsset": "する資産",
"RelevantCommand": "するコマンド",
"RelevantSystemUser": "するシステムユーザー",
"action": "アクション",
"type": "タイプ",
"user": "ユーザー",
@@ -1240,7 +1259,7 @@
"DatePasswordLastUpdated": "パスワード最終更新日",
"DatePasswordUpdated": "パスワード更新日",
"DescribeOfGuide": "詳細については、をクリックしてください。",
"Email": "メール",
"Email": "ポスト",
"Phone": "携帯番号",
"WeCom": "企業wechat",
"DingTalk": "ホッチキス",
@@ -1450,9 +1469,11 @@
"IPNetworkSegment": "IPネットワークセグメント",
"Aliyun": "Alibaba cloud",
"Qcloud": "テンセント雲",
"QcloudLighthouse": "テンセント雲(軽量アプリケーションサーバー)",
"QingyunPrivatecloud": "青雲プライベートクラウド",
"HuaweiPrivatecloud": "ファーウェイプライベートクラウド",
"OpenStack": "OpenStack",
"CTYunPrivate": "天翼プライベート・クラウド",
"GCP": "Googleクラウド",
"FC": "Fusion Compute",
"LAN": "ローカルエリアネットワーク",
@@ -1461,6 +1482,7 @@
"HuaweiCloud": "ファーウェイ雲",
"BaiduCloud": "百度雲",
"JDCloud": "京東雲",
"KingSoftCloud": "金山雲",
"Azure": "Azure(中国)",
"Azure_Int": "Azure (国際)",
"HostnameStrategy": "資産を生成するためにホスト名。例: 1. インスタンス名 (instanceDemo) 2.インスタンス名と一部IP (下位2桁) (instanceDemo-250.1)",

View File

@@ -52,6 +52,7 @@
"sqlserver": "SQLServer",
"redis": "Redis",
"mongodb": "MongoDB",
"clickhouse": "ClickHouse",
"k8s": "Kubernetes"
},
"applicationsCategory": {
@@ -249,7 +250,9 @@
"SystemUserName": "系统用户名",
"LoginIP": "登录IP",
"LoginCity": "登录城市",
"LoginDate": "登录日期"
"LoginDate": "登录日期",
"BeforeChange": "变更前",
"AfterChange": "变更后"
},
"auth": {
"LoginRequiredMsg": "账号已退出,请重新登录",
@@ -259,6 +262,7 @@
"ReLoginErr": "登录时长已超过 5 分钟,请重新登录"
},
"common": {
"NoContent": "暂无内容",
"NeedAddAppsOrSystemUserErrMsg": "需要添加应用或系统用户",
"VerificationCodeSent": "验证码已发送",
"SendVerificationCode": "发送验证码",
@@ -272,6 +276,12 @@
"IPLoginLimit": "IP 登录限制",
"Setting": "设置",
"Certificate": "证书",
"CACertificate": "CA 证书",
"ClientCertificate": "客户端证书",
"CertificateKey": "证书秘钥文件",
"AllowInvalidCert": "忽略证书检查",
"UseSSL": "使用 SSL/TLS",
"SecretKey": "密钥",
"Scope": "类别",
"Builtin": "内置",
"DateCreated": "创建日期",
@@ -417,6 +427,7 @@
"disableSelected": "禁用所选",
"disableSuccessMsg": "禁用成功",
"fieldRequiredError": "这个字段是必填项",
"requiredHasUserNameMapped": "必须包含 username 字段的映射,如 { 'uid': 'username' }",
"getErrorMsg": "获取失败",
"MFAErrorMsg": "MFA错误请检查",
"Total": "总共",
@@ -435,6 +446,7 @@
"downloadImportTemplateMsg": "下载创建模板",
"downloadUpdateTemplateMsg": "下载更新模板",
"onlyCSVFilesTips": "仅支持csv文件导入",
"ImportFail": "导入失败",
"updateSuccessMsg": "导入更新成功,总共:{count}",
"uploadCsvLth10MHelpText": "只能上传 csv/xlsx, 且不超过 10M",
"dragUploadFileInfo": "将文件拖到此处,或点击此处上传",
@@ -945,6 +957,9 @@
"Feature": "功能",
"AlibabaCloud": "阿里云",
"TencentCloud": "腾讯云",
"HuaweiCloud": "华为云",
"SignChannelNum": "签名通道号",
"AppEndpoint": "应用接入地址",
"CMPP2": "CMPP v2.0",
"Radius": "Radius",
"VerifySignTmpl": "验证码短信模板",
@@ -1172,6 +1187,10 @@
"reply": "回复",
"status": "状态",
"title": "标题",
"RelevantApp": "应用",
"RelevantAsset": "资产",
"RelevantCommand": "命令",
"RelevantSystemUser": "系统用户",
"action": "动作",
"type": "类型",
"user": "用户",
@@ -1241,7 +1260,7 @@
"DatePasswordLastUpdated": "最后更新密码日期",
"DatePasswordUpdated": "密码更新日期",
"DescribeOfGuide": "欢迎使用JumpServer堡垒机系统获取更多信息请点击",
"Email": "邮",
"Email": "邮",
"Phone": "手机号",
"WeCom": "企业微信",
"DingTalk": "钉钉",
@@ -1451,8 +1470,10 @@
"IPNetworkSegment": "IP网段",
"Aliyun": "阿里云",
"Qcloud": "腾讯云",
"QcloudLighthouse": "腾讯云(轻量应用服务器)",
"QingyunPrivatecloud": "青云私有云",
"HuaweiPrivatecloud": "华为私有云",
"CTYunPrivate": "天翼私有云",
"OpenStack": "OpenStack",
"GCP": "谷歌云",
"FC": "Fusion Compute",
@@ -1462,6 +1483,7 @@
"HuaweiCloud": "华为云",
"BaiduCloud": "百度云",
"JDCloud": "京东云",
"KingSoftCloud": "金山云",
"Azure":"Azure(中国)",
"Azure_Int": "Azure(国际)",
"HostnameStrategy": "用于生成资产主机名。例如1. 实例名称 (instanceDemo)2. 实例名称和部分IP(后两位) (instanceDemo-250.1)",

View File

@@ -233,6 +233,10 @@ export default {
encryptedFields: {
type: Array,
default: () => ['password', 'token', 'private_key']
},
needGetObjectDetail: {
type: Boolean,
default: true
}
},
data() {
@@ -312,7 +316,7 @@ export default {
},
async getFormValue() {
const cloneFrom = this.$route.query['clone_from']
if (!this.isUpdateMethod() && !cloneFrom) {
if ((!this.isUpdateMethod() && !cloneFrom) || !this.needGetObjectDetail) {
return Object.assign(this.form, this.initial)
}
let object = this.object
@@ -322,9 +326,9 @@ export default {
const url = `${curUrl}${cloneFrom}/${query ? ('?' + query) : ''}`
object = await this.getObjectDetail(url)
if (object['name']) {
object.name = this.$t('common.cloneFrom') + ' ' + object.name
object.name = this.$t('common.cloneFrom') + object.name
} else if (object['hostname']) {
object.hostname = this.$t('common.cloneFrom') + ' ' + object.hostname
object.hostname = this.$t('common.cloneFrom') + object.hostname
}
} else {
object = await this.getObjectDetail(this.iUrl)

View File

@@ -97,6 +97,7 @@ export default {
getDefaultFormSetting() {
const vm = this
return {
needGetObjectDetail: false,
submitMethod: () => 'patch',
cleanFormValue: (value) => {
const filterValue = {}

View File

@@ -177,7 +177,7 @@ export default {
}
&>>> .el-input__icon {
color: #606266;
color: #606266!important;
}
}

View File

@@ -12,7 +12,7 @@ export default {
<style scoped>
.wrapper-content {
padding: 20px 25px 40px;
padding: 20px 25px 10px;
}
.wrapper-content >>> .el-alert {

View File

@@ -43,6 +43,10 @@ export default {
</script>
<style scoped>
.page {
height: calc(100vh - 55px - 41px);
overflow: auto;
}
@media print {
.disabled-when-print{
display: none;

View File

@@ -46,7 +46,6 @@ Vue.use(require('vue-moment'), {
moment
})
// logger
import VueLogger from 'vuejs-logger'
import loggerOptions from './utils/logger'
Vue.use(VueLogger, loggerOptions)
@@ -55,14 +54,14 @@ import ECharts from 'vue-echarts'
Vue.component('echarts', ECharts)
import service from '@/utils/request'
Vue.prototype.$axios = service
// lodash
// import _ from 'lodash'
window._ = require('lodash')
// Vue.set(Vue.prototype, '_', _)
// if the table component cannot access `this.$axios`, it cannot send request
Vue.prototype.$axios = service
import { Message } from '@/utils/Message'
Vue.prototype.$message = Message
// 注册全局事件总线
Vue.prototype.$eventBus = new Vue()
new Vue({

View File

@@ -15,6 +15,16 @@ export default [
permissions: []
}
},
{
path: '/ops/ansible/task/:id/log/',
component: () => import('@/views/ops/CeleryTaskLog'),
name: 'AnsibleTaskLog',
hidden: true,
meta: {
title: i18n.t('route.CeleryTaskLog'),
permissions: []
}
},
{
path: '/ops/task/task/:id/log/',
component: () => import('@/views/ops/CeleryTaskLog'),

View File

@@ -1,6 +1,8 @@
import empty from '@/layout/empty'
import i18n from '@/i18n/i18n'
const activateMenu = '/console/assets/assets'
export default [
{
path: 'cloud',
@@ -20,7 +22,7 @@ export default [
hidden: true,
meta: {
title: i18n.t('xpack.Cloud.CloudSync'),
activeMenu: '/console/assets/assets'
activeMenu: activateMenu
}
},
{
@@ -71,6 +73,7 @@ export default [
hidden: true,
meta: {
title: i18n.t('xpack.Cloud.AccountDetail'),
activeMenu: activateMenu,
permissions: ['xpack.view_account']
}
}
@@ -121,7 +124,8 @@ export default [
name: 'SyncInstanceTaskDetail',
hidden: true,
meta: {
title: i18n.t('xpack.Cloud.SyncInstanceTaskDetail')
title: i18n.t('xpack.Cloud.SyncInstanceTaskDetail'),
activeMenu: activateMenu
}
}
]

View File

@@ -72,6 +72,9 @@ const mutations = {
},
ADD_WORKBENCH_ORGS(state, org) {
state.workbenchOrgs.push(org)
},
SET_IS_FIRST_LOGIN(state, flag) {
state.profile.is_first_login = flag
}
}
@@ -140,6 +143,9 @@ const actions = {
const usingOrgs = mapper[viewName] || state.consoleOrgs
Vue.$log.debug('Set using orgs: ', viewName, usingOrgs)
commit('SET_USING_ORGS', usingOrgs)
},
ifFirstLogin({ commit }, flag) {
commit('SET_IS_FIRST_LOGIN', flag)
}
}

View File

@@ -182,6 +182,9 @@ input[type=file] {
.el-col.el-col-sm-24 .ibox {
margin-bottom: 10px;
&:last-child {
margin-bottom: 0;
}
}
.el-pagination {

20
src/utils/Message.js Normal file
View File

@@ -0,0 +1,20 @@
// 重置message防止重复点击重复弹出message弹框
import { Message as elMessage } from 'element-ui'
let messageDom = null
const Message = (options) => {
// 判断弹窗是否已存在, 若存在则关闭
if (messageDom) messageDom.close()
messageDom = elMessage(options)
}
const typeArray = ['success', 'error', 'warning', 'info']
typeArray.forEach(type => {
Message[type] = options => {
if (typeof options === 'string') options = { message: options }
options.type = type
return Message(options)
}
})
export { Message }

View File

@@ -302,3 +302,8 @@ export function groupedDropdownToCascader(group) {
export { BASE_URL }
export function openWindow(url, name = '', iWidth = 900, iHeight = 600) {
var iTop = (window.screen.height - 30 - iHeight) / 2
var iLeft = (window.screen.width - 10 - iWidth) / 2
window.open(url, name, 'height=' + iHeight + ',width=' + iWidth + ',top=' + iTop + ',left=' + iLeft)
}

View File

@@ -37,10 +37,13 @@ export function encryptPassword(password) {
if (!password) {
return ''
}
let rsaPublicKeyText = getCookie('jms_public_key')
if (!rsaPublicKeyText) {
return password
}
const aesKey = (Math.random() + 1).toString(36).substring(2)
// public key 是 base64 存储的
const rsaPublicKeyText = getCookie('jms_public_key')
.replaceAll('"', '')
rsaPublicKeyText = rsaPublicKeyText.replaceAll('"', '')
const rsaPublicKey = atob(rsaPublicKeyText)
const keyCipher = rsaEncrypt(aesKey, rsaPublicKey)
const passwordCipher = aesEncrypt(password, aesKey)

View File

@@ -1,8 +1,10 @@
import store from '@/store'
import { constantRoutes } from '@/router'
import { openWindow } from './common'
export function openTaskPage(taskId) {
window.open(`/#/ops/celery/task/${taskId}/log/`, '', 'width=900,height=600')
export function openTaskPage(taskId, taskType) {
taskType = taskType || 'celery'
openWindow(`/#/ops/${taskType}/task/${taskId}/log/?type=${taskType}`)
}
export function checkPermission(permsRequired, permsAll) {

View File

@@ -1,4 +1,4 @@
import $ from 'jquery'
import $ from 'jquery/dist/jquery.min.js'
window.$ = $
window.jQuery = $
export default $

View File

@@ -3,7 +3,8 @@ import i18n from '@/i18n/i18n'
import { getTokenFromCookie } from '@/utils/auth'
import { getErrorResponseMsg } from '@/utils/common'
import { refreshSessionIdAge } from '@/api/users'
import { Message, MessageBox } from 'element-ui'
import { MessageBox } from 'element-ui'
import { Message } from '@/utils/Message'
import store from '@/store'
import axiosRetry from 'axios-retry'
import router from '@/router'

View File

@@ -3,7 +3,7 @@ import store from '@/store'
import router, { resetRouter } from '@/router'
import Vue from 'vue'
import VueCookie from 'vue-cookie'
import { Message } from 'element-ui'
import { Message } from '@/utils/Message'
import orgUtil from '@/utils/org'
import orgs from '@/api/orgs'
import { getPropView, isViewHasOrgs } from '@/utils/jms'

View File

@@ -39,6 +39,9 @@ export function changeElementColor(themeColors) {
.el-link.el-link--${key}:after {
border-color: ${value}!important;
}
.el-tag--dark.el-tag--${key} {
background-color: ${value} !important;
}
`
}
}

View File

@@ -78,7 +78,6 @@ export default {
hasRefresh: true,
hasExport: false,
hasImport: false,
hasMoreActions: false,
createRoute: () => {
return {
name: 'AccountBackupPlanCreate'

View File

@@ -123,7 +123,6 @@ export default {
hasRefresh: true,
hasExport: false,
hasImport: false,
hasMoreActions: false,
searchConfig: {
getUrlQuery: false
},

View File

@@ -74,6 +74,9 @@ export default {
hasExport: false,
hasImport: false,
hasCreate: false,
searchConfig: {
getUrlQuery: false
},
hasMoreActions: false
},
assetRelationConfig: {

View File

@@ -107,7 +107,6 @@ export default {
hasRefresh: true,
hasExport: false,
hasImport: false,
hasMoreActions: false,
createRoute: () => {
return {
name: 'AssetChangeAuthPlanCreate'

View File

@@ -84,8 +84,7 @@ export default {
createRoute: 'AssetAclCreate',
hasRefresh: true,
hasExport: false,
hasImport: false,
hasMoreActions: false
hasImport: false
}
}
}

View File

@@ -5,6 +5,9 @@
<script>
import { GenericCreateUpdatePage } from '@/layout/components'
import { getDatabaseTypeFieldsMap } from '@/views/applications/DatabaseApp/const'
import { UploadKey } from '@/components'
import { Required } from '@/components/DataForm/rules'
export default {
components: {
GenericCreateUpdatePage
@@ -36,6 +39,32 @@ export default {
fieldsMeta: {
host: {
type: 'input'
},
port: {
rules: [Required]
},
use_ssl: {
label: this.$t('common.UseSSL'),
component: 'el-switch'
},
allow_invalid_cert: {
label: this.$t('common.AllowInvalidCert'),
hidden: (form) => { return !form.use_ssl }
},
ca_cert: {
label: this.$t('common.CACertificate'),
hidden: (form) => { return !form.use_ssl },
component: UploadKey
},
client_cert: {
label: this.$t('common.ClientCertificate'),
hidden: (form) => { return !form.use_ssl },
component: UploadKey
},
cert_key: {
label: this.$t('common.CertificateKey'),
hidden: (form) => { return !form.use_ssl },
component: UploadKey
}
}
}

View File

@@ -1,10 +1,14 @@
import { ORACLE } from '../const'
import { MONGODB, REDIS } from '../const'
export function getDatabaseTypeFieldsMap(type) {
const baseParams = ['host', 'port', 'database']
const tlsParams = ['use_ssl', 'ca_cert']
switch (type) {
case ORACLE:
return ['host', 'port', 'database', 'version']
case REDIS:
return baseParams.concat(tlsParams.concat(['client_cert', 'cert_key']))
case MONGODB:
return baseParams.concat(tlsParams.concat(['cert_key', 'allow_invalid_cert']))
default:
return ['host', 'port', 'database']
return baseParams
}
}

View File

@@ -52,6 +52,7 @@ export const DATABASE_CATEGORY = 'db'
export const SQLSERVER = 'sqlserver'
export const REDIS = 'redis'
export const MONGODB = 'mongodb'
export const CLICKHOUSE = 'clickhouse'
export const DATABASE = [
{
@@ -89,27 +90,37 @@ export const DATABASE = [
type: 'primary',
category: DATABASE_CATEGORY,
has: hasLicence
}
]
export const KV_DATABASE = [
{
name: REDIS,
title: i18n.t(`applications.applicationsType.${REDIS}`),
type: 'primary',
category: DATABASE_CATEGORY,
has: true,
group: i18n.t('applications.NoSQLProtocol')
},
{
name: MONGODB,
title: i18n.t(`applications.applicationsType.${MONGODB}`),
name: CLICKHOUSE,
title: i18n.t(`applications.applicationsType.${CLICKHOUSE}`),
type: 'primary',
category: DATABASE_CATEGORY
category: DATABASE_CATEGORY,
has: hasLicence
}
]
export const AppPlanDatabase = DATABASE
const MONGODB_ITEM = {
name: MONGODB,
title: i18n.t(`applications.applicationsType.${MONGODB}`),
type: 'primary',
category: DATABASE_CATEGORY,
group: i18n.t('applications.NoSQLProtocol')
}
const REDIS_ITEM = {
name: REDIS,
title: i18n.t(`applications.applicationsType.${REDIS}`),
type: 'primary',
category: DATABASE_CATEGORY,
has: true
}
export const KV_DATABASE = [
MONGODB_ITEM, REDIS_ITEM
]
export const AppPlanDatabase = [...DATABASE, MONGODB_ITEM]
export const KUBERNETES = 'k8s'
export const CLOUD_CATEGORY = 'cloud'

View File

@@ -1,18 +1,40 @@
<template>
<IBox :fa="icon" :type="type" :title="title" v-bind="$attrs">
<table style="width: 100%;table-layout:fixed;" class="CardTable">
<tr v-for="obj of iObjects" :key="obj.value" class="item">
<td style="overflow: hidden;text-overflow: ellipsis;white-space: nowrap;">
<el-tooltip style="margin: 4px;" effect="dark" :content="obj.label" placement="left">
<el-link class="detail" @click="goDetail(obj)">{{ obj.label }}</el-link>
</el-tooltip>
</td>
<td>
<el-button size="mini" type="primary" style="float: right" @click="buttonClickCallback(obj)">
{{ buttonTitle }}
</el-button>
</td>
</tr>
<IBox
:fa="icon"
:type="type"
:title="title"
v-bind="$attrs"
>
<table class="card-table">
<div v-if="iObjects.length > 0" v-cloak>
<tr v-for="obj of iObjects" :key="obj.value" class="item">
<td>
<el-tooltip
style="margin: 4px;"
effect="dark"
:content="obj.label"
placement="left"
>
<el-link class="detail" @click="goDetail(obj)">
{{ obj.label }}
</el-link>
</el-tooltip>
</td>
<td>
<el-button
size="mini"
type="primary"
style="float: right"
@click="buttonClickCallback(obj)"
>
{{ buttonTitle }}
</el-button>
</td>
</tr>
</div>
<div v-else v-cloak style="text-align: center;">
{{ $t('common.NoData') }}
</div>
</table>
</IBox>
</template>
@@ -71,9 +93,9 @@ export default {
methods: {
async loadObjects() {
const data = await this.$axios.get(this.url)
data.forEach((v) => {
for (const v of data) {
v['label'] = v['name']
})
}
this.objects = data
},
goDetail(obj) {
@@ -84,18 +106,26 @@ export default {
</script>
<style lang="scss" scoped>
.card-table {
width: 100%;
table-layout:fixed;
}
[v-cloak]{
display: none!important;
}
b, strong {
font-weight: 700;
font-size: 13px;
}
tr td {
line-height: 1.42857;
padding: 8px;
vertical-align: top;
display: inline;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
tr.item {
border-bottom: 1px solid #e7eaec;
padding: 8px;

View File

@@ -88,7 +88,10 @@ export default {
},
headerActions: {
hasLeftActions: false,
hasRightActions: false
hasRightActions: false,
searchConfig: {
getUrlQuery: false
}
}
}
},

View File

@@ -22,7 +22,7 @@ export default {
const accountProviderAttrs = ACCOUNT_PROVIDER_ATTRS_MAP[accountProvider]
function setFieldAttrs() {
const fieldsObject = {}
const updateNotRequiredFields = ['access_key_secret', 'client_secret', 'password', 'sc_password', 'oc_password']
const updateNotRequiredFields = ['access_key_secret', 'client_secret', 'password', 'sc_password', 'oc_password', 'cert_file', 'key_file']
for (const item of accountProviderAttrs?.attrs) {
fieldsObject[item] = {
rules: updateNotRequiredFields.includes(item) && vm.$route.params.id ? [] : [Required]
@@ -61,6 +61,20 @@ export default {
toFormat: 'object'
}
},
cert_file: {
label: this.$t('common.Certificate'),
component: UploadKey,
el: {
toFormat: 'object'
}
},
key_file: {
label: this.$t('common.SecretKey'),
component: UploadKey,
el: {
toFormat: 'object'
}
},
password: {
rules: this.$route.params.id ? [] : [Required]
}
@@ -91,13 +105,17 @@ export default {
const attrs = values.attrs
for (const item of encryptedFields) {
const value = attrs[item]
if (value) {
attrs[item] = encryptPassword(value)
if (!value) {
continue
}
attrs[item] = encryptPassword(value)
}
const toListFields = ['ip_group']
for (const item of toListFields) {
let value = attrs[item]
if (!value) {
continue
}
value = value?.split(',') || []
value = value.filter((value, index) => { if (value) return true })
attrs[item] = value

View File

@@ -4,7 +4,7 @@
<script type="text/jsx">
import GenericListTable from '@/layout/components/GenericListTable'
import { ACCOUNT_PROVIDER_ATTRS_MAP, aliyun, aws_china, aws_international, huaweicloud, qcloud, azure, azure_international, vmware, nutanix, qingcloud_private, huaweicloud_private, openstack, gcp, baiducloud, jdcloud, fc, lan } from '../const'
import { ACCOUNT_PROVIDER_ATTRS_MAP, aliyun, aws_china, aws_international, huaweicloud, qcloud, qcloud_lighthouse, azure, azure_international, vmware, nutanix, qingcloud_private, huaweicloud_private, ctyun_private, openstack, gcp, baiducloud, jdcloud, kingsoftcloud, fc, lan } from '../const'
export default {
name: 'AccountList',
@@ -82,6 +82,10 @@ export default {
type: 'primary',
can: true
},
{
name: qcloud_lighthouse,
title: ACCOUNT_PROVIDER_ATTRS_MAP[qcloud_lighthouse].title
},
{
name: huaweicloud,
title: ACCOUNT_PROVIDER_ATTRS_MAP[huaweicloud].title
@@ -94,6 +98,10 @@ export default {
name: jdcloud,
title: ACCOUNT_PROVIDER_ATTRS_MAP[jdcloud].title
},
{
name: kingsoftcloud,
title: ACCOUNT_PROVIDER_ATTRS_MAP[kingsoftcloud].title
},
{
name: aws_china,
title: ACCOUNT_PROVIDER_ATTRS_MAP[aws_china].title
@@ -127,6 +135,10 @@ export default {
name: huaweicloud_private,
title: ACCOUNT_PROVIDER_ATTRS_MAP[huaweicloud_private].title
},
{
name: ctyun_private,
title: ACCOUNT_PROVIDER_ATTRS_MAP[ctyun_private].title
},
{
name: openstack,
title: ACCOUNT_PROVIDER_ATTRS_MAP[openstack].title

View File

@@ -24,7 +24,7 @@ export default {
fields: [
[this.$t('common.Basic'), ['name']],
[this.$t('xpack.Cloud.CloudSource'), ['account', 'regions']],
[this.$t('xpack.Cloud.SaveSetting'), ['hostname_strategy', 'node', 'unix_admin_user', 'windows_admin_user', 'protocols', 'ip_network_segment_group', 'is_always_update']],
[this.$t('xpack.Cloud.SaveSetting'), ['hostname_strategy', 'node', 'unix_admin_user', 'windows_admin_user', 'protocols', 'ip_network_segment_group', 'sync_ip_type', 'is_always_update']],
[this.$t('xpack.Timer'), ['is_periodic', 'crontab', 'interval']],
[this.$t('common.Other'), ['comment']]
],
@@ -92,6 +92,7 @@ export default {
component: Select2,
el: {
multiple: true,
allowCreate: true,
value: [],
ajax: {
url: '/api/v1/xpack/cloud/regions/',

View File

@@ -38,6 +38,7 @@ export default {
},
tableConfig: {
url: `/api/v1/xpack/cloud/sync-instance-tasks/${this.object.id}/instances/`,
hasSelection: false,
columns: [
'instance_id',
{

View File

@@ -58,10 +58,7 @@ export default {
formatter: DetailFormatter,
formatterArgs: {
permissions: 'xpack.view_syncinstancedetail',
route: 'SyncInstanceTaskDetail',
routeQuery: {
activeTab: 'detail'
}
route: 'SyncInstanceTaskDetail'
}
},
history_count: {

View File

@@ -1,21 +1,25 @@
import i18n from '@/i18n/i18n'
export const gcp = 'gcp'
export const aliyun = 'aliyun'
export const baiducloud = 'baiducloud'
export const jdcloud = 'jdcloud'
export const kingsoftcloud = 'kingsoftcloud'
export const aws_international = 'aws_international'
export const aws_china = 'aws_china'
export const huaweicloud = 'huaweicloud'
export const qcloud = 'qcloud'
export const qcloud_lighthouse = 'qcloud_lighthouse'
export const azure = 'azure'
export const azure_international = 'azure_international'
export const vmware = 'vmware'
export const nutanix = 'nutanix'
export const qingcloud_private = 'qingcloud_private'
export const huaweicloud_private = 'huaweicloud_private'
export const ctyun_private = 'ctyun_private'
export const openstack = 'openstack'
export const gcp = 'gcp'
export const nutanix = 'nutanix'
export const vmware = 'vmware'
export const fc = 'fc'
export const baiducloud = 'baiducloud'
export const jdcloud = 'jdcloud'
export const lan = 'lan'
export const ACCOUNT_PROVIDER_ATTRS_MAP = {
@@ -49,11 +53,21 @@ export const ACCOUNT_PROVIDER_ATTRS_MAP = {
title: i18n.t('xpack.Cloud.JDCloud'),
attrs: ['access_key_id', 'access_key_secret']
},
[kingsoftcloud]: {
name: kingsoftcloud,
title: i18n.t('xpack.Cloud.KingSoftCloud'),
attrs: ['access_key_id', 'access_key_secret']
},
[qcloud]: {
name: qcloud,
title: i18n.t('xpack.Cloud.Qcloud'),
attrs: ['access_key_id', 'access_key_secret']
},
[qcloud_lighthouse]: {
name: qcloud_lighthouse,
title: i18n.t('xpack.Cloud.QcloudLighthouse'),
attrs: ['access_key_id', 'access_key_secret']
},
[azure]: {
name: azure,
title: i18n.t('xpack.Cloud.Azure'),
@@ -64,6 +78,11 @@ export const ACCOUNT_PROVIDER_ATTRS_MAP = {
title: i18n.t('xpack.Cloud.Azure_Int'),
attrs: ['client_id', 'client_secret', 'tenant_id', 'subscription_id']
},
[gcp]: {
name: gcp,
title: i18n.t('xpack.Cloud.GCP'),
attrs: ['service_account_key']
},
[vmware]: {
name: vmware,
title: 'VMware',
@@ -89,16 +108,16 @@ export const ACCOUNT_PROVIDER_ATTRS_MAP = {
title: i18n.t('xpack.Cloud.OpenStack'),
attrs: ['auth_url', 'user_domain_name', 'username', 'password']
},
[gcp]: {
name: gcp,
title: i18n.t('xpack.Cloud.GCP'),
attrs: ['service_account_key']
},
[fc]: {
name: fc,
title: i18n.t('xpack.Cloud.FC'),
attrs: ['api_endpoint', 'username', 'password']
},
[ctyun_private]: {
name: ctyun_private,
title: i18n.t('xpack.Cloud.CTYunPrivate'),
attrs: ['access_key_id', 'access_key_secret', 'api_endpoint', 'cert_file', 'key_file']
},
[lan]: {
name: lan,
title: i18n.t('xpack.Cloud.LAN'),

View File

@@ -15,7 +15,7 @@ export default {
},
fields: [
[this.$t('common.Basic'), ['name']],
[this.$t('common.Correlation'), ['users', 'user_groups', 'assets', 'applications', 'system_users']],
[this.$t('common.Correlation'), ['users', 'user_groups', 'nodes', 'assets', 'applications', 'system_users']],
[this.$t('common.Other'), ['is_active', 'comment']]
],
fieldsMeta: {
@@ -36,6 +36,17 @@ export default {
url: '/api/v1/users/groups/'
}
},
nodes: {
el: {
value: [],
ajax: {
url: '/api/v1/assets/nodes/',
transformOption: (item) => {
return { label: item.full_value, value: item.id }
}
}
}
},
assets: {
type: 'assetSelect',
component: AssetSelect,

View File

@@ -80,11 +80,7 @@ export default {
hasImport: false,
hasRefresh: true,
hasSearch: true,
hasMoreActions: false,
createRoute: 'CommandFilterCreate',
canCreate: () => {
return this.$hasPerm('assets.add_commandfilter')
}
createRoute: 'CommandFilterCreate'
}
}
},

View File

@@ -42,7 +42,6 @@ export default {
}
},
headerActions: {
hasMoreActions: false,
createRoute: 'DomainCreate'
},
notice: this.$t('assets.DomainHelpMessage')

View File

@@ -27,7 +27,6 @@ export default {
}
},
headerActions: {
hasMoreActions: false,
createRoute: 'LabelCreate'
}
}

View File

@@ -49,6 +49,7 @@ export default {
case 'sqlserver':
case 'redis':
case 'mongodb':
case 'clickhouse':
return Database
case 'k8s':
return K8S

View File

@@ -42,7 +42,7 @@ export default {
vm.relationDialog.tableConfig.url = setUrlParam(vm.relationDialog.tableConfig.url, 'commandexecution', row.id)
vm.relationDialog.show = true
}
return <el-link onClick={onClick}>{ cellValue.length }</el-link>
return <el-link class='text-link' onClick={onClick}>{ cellValue.length }</el-link>
}
},
command: {
@@ -67,7 +67,7 @@ export default {
formatter: (row) => {
const label = this.$t('audits.View')
const route = { to: { name: 'CeleryTaskLog', params: { id: row.id }}}
return <router-link {...{ attrs: route }} target='_blank'>{ label }</router-link>
return <router-link class='text-link' {...{ attrs: route }} target='_blank'>{ label }</router-link>
}
},
date_start: {
@@ -138,5 +138,4 @@ export default {
</script>
<style>
</style>

View File

@@ -1,23 +1,48 @@
<template>
<GenericListPage :table-config="tableConfig" :header-actions="headerActions" />
<div>
<GenericListPage
v-loading="loading"
:table-config="tableConfig"
:header-actions="headerActions"
/>
<el-dialog
:title="this.$t('route.OperateLog')"
:visible.sync="logDetailVisible"
width="70%"
>
<TwoTabFormatter :row="rowObj" />
</el-dialog>
</div>
</template>
<script>
import GenericListPage from '@/layout/components/GenericListPage'
import { getDaysAgo, getDaysFuture } from '@/utils/common'
import TwoTabFormatter from '@/components/TableFormatters/TwoTabFormatter'
import { ActionsFormatter } from '@/components/TableFormatters'
export default {
components: {
GenericListPage
GenericListPage,
TwoTabFormatter
},
data() {
const vm = this
const now = new Date()
const dateFrom = getDaysAgo(7, now).toISOString()
const dateTo = getDaysFuture(1, now).toISOString()
return {
rowObj: {
left: '',
right: '',
leftTitle: vm.$t('audits.BeforeChange'),
rightTitle: vm.$t('audits.AfterChange')
},
logDetailVisible: false,
loading: false,
tableConfig: {
url: '/api/v1/audits/operate-logs/',
columns: ['user', 'action_display', 'resource_type_display', 'resource', 'remote_addr', 'datetime'],
columns: ['user', 'action_display', 'resource_type_display', 'resource', 'remote_addr', 'datetime', 'actions'],
columnsMeta: {
user: {
showOverflowTooltip: true
@@ -36,7 +61,38 @@ export default {
width: '140px'
},
action_display: {
width: '90px'
width: '70px'
},
actions: {
width: '70px',
formatter: ActionsFormatter,
formatterArgs: {
hasUpdate: false,
canUpdate: false,
hasDelete: false,
canDelete: false,
hasClone: false,
canClone: false,
extraActions: [
{
name: 'View',
title: this.$t('common.View'),
type: 'primary',
callback: ({ row }) => {
vm.loading = true
vm.$axios.get(
`/api/v1/audits/operate-logs/${row.id}/?type=action_detail`,
).then(res => {
vm.rowObj.left = res.before
vm.rowObj.right = res.after
vm.logDetailVisible = true
}).finally(() => {
vm.loading = false
})
}
}
]
}
}
},
extraQuery: {

View File

@@ -6,6 +6,7 @@
import ListTable from '@/components/ListTable'
import { ActionsFormatter } from '@/components/TableFormatters'
import { toSafeLocalDateStr } from '@/utils/common'
import { openTaskPage } from '@/utils/jms'
export default {
name: 'AdhocExecutionHistory',
@@ -86,6 +87,14 @@ export default {
callback: function({ row, tableData }) {
return this.$router.push({ name: 'HistoryExecutionDetail', params: { id: row.id }})
}
},
{
name: 'log',
title: this.$t('ops.output'),
type: 'info',
callback: function({ row }) {
openTaskPage(row.id, 'ansible')
}
}
]
}

View File

@@ -15,7 +15,6 @@ import DetailCard from '@/components/DetailCard'
import { toSafeLocalDateStr } from '@/utils/common'
import RunInfoCard from '../../RunInfoCard'
import { toLastFailureDisplay, toLastSucessDisplay } from '../business'
import { openTaskPage } from '@/utils/jms'
export default {
name: 'HistoryExecutionDetail',
@@ -72,17 +71,6 @@ export default {
{
key: this.$t('ops.isSuccess'),
value: this.object.is_success
},
{
key: this.$t('ops.output'),
value: this.object.id,
formatter: function(row, value) {
const onClick = function() {
openTaskPage(value, 'ansible')
}
const title = this.$t('common.View')
return <a onClick={onClick} >{ title }</a>
}
}
]
}

View File

@@ -108,7 +108,7 @@ export default {
openTaskPage(value, 'ansible')
}
const title = this.$t('common.View')
return <a onClick={onClick} >{ title }</a>
return <a class='text-link' onClick={onClick} >{ title }</a>
}
}
]

View File

@@ -6,6 +6,7 @@
import ListTable from '@/components/ListTable'
import { DetailFormatter } from '@/components/TableFormatters'
import { toSafeLocalDateStr } from '@/utils/common'
import { openTaskPage } from '@/utils/jms'
export default {
name: 'TaskHistory',
@@ -95,6 +96,14 @@ export default {
callback: function({ row, tableData }) {
return this.$router.push({ name: 'HistoryExecutionDetail', params: { id: row.id }})
}
},
{
name: 'log',
title: this.$t('ops.output'),
type: 'info',
callback: function({ row }) {
openTaskPage(row.id, 'ansible')
}
}
]
}

View File

@@ -78,6 +78,7 @@ export default {
},
onPerformSuccess() {
this.$message.success(this.$t('common.updateSuccessMsg'))
this.$store.dispatch('users/ifFirstLogin', false)
setTimeout(() => this.$router.push({ name: 'ProfileInfo' }), 100)
},
submitMethod() {

View File

@@ -160,7 +160,7 @@ export default {
attrs: {
disabled: true,
name: 'site_msg',
model: this.object.receive_backends.indexOf('site_msg') !== -1
model: this.object?.receive_backends.indexOf('site_msg') !== -1
},
callbacks: {
change: this.updateUserReceiveBackends
@@ -171,7 +171,7 @@ export default {
type: 'switcher',
attrs: {
name: 'email',
model: this.object.receive_backends.indexOf('email') !== -1
model: this.object?.receive_backends.indexOf('email') !== -1
},
callbacks: {
change: this.updateUserReceiveBackends
@@ -182,7 +182,7 @@ export default {
type: 'switcher',
attrs: {
name: 'wecom',
model: this.object.receive_backends.indexOf('wecom') !== -1
model: this.object?.receive_backends.indexOf('wecom') !== -1
},
has: this.$store.getters.publicSettings.AUTH_WECOM,
callbacks: {
@@ -194,7 +194,7 @@ export default {
type: 'switcher',
attrs: {
name: 'dingtalk',
model: this.object.receive_backends.indexOf('dingtalk') !== -1
model: this.object?.receive_backends.indexOf('dingtalk') !== -1
},
has: this.$store.getters.publicSettings.AUTH_DINGTALK,
callbacks: {
@@ -206,7 +206,7 @@ export default {
type: 'switcher',
attrs: {
name: 'feishu',
model: this.object.receive_backends.indexOf('feishu') !== -1
model: this.object?.receive_backends.indexOf('feishu') !== -1
},
has: this.$store.getters.publicSettings.AUTH_FEISHU,
callbacks: {
@@ -306,6 +306,7 @@ export default {
{ 'receive_backends': this.getReceiveBackendList() }
).then(res => {
this.$message.success(this.$t('common.updateSuccessMsg'))
this.$store.dispatch('users/getProfile', true)
}).catch(err => {
this.$message.error(this.$t('common.updateErrorMsg' + ' ' + err))
})

View File

@@ -8,7 +8,7 @@
<script>
import BaseAuth from './Base'
import { JsonRequired } from '@/components/DataForm/rules'
import { JsonRequiredUserNameMapped } from '@/components/DataForm/rules'
import { JsonEditor } from '@/components/FormFields'
export default {
@@ -25,16 +25,14 @@ export default {
'AUTH_CAS', 'CAS_SERVER_URL', 'CAS_ROOT_PROXIED_AS', 'CAS_VERSION'
]],
[this.$t('common.Other'), [
'CAS_LOGOUT_COMPLETELY', 'CAS_USERNAME_ATTRIBUTE',
'CAS_APPLY_ATTRIBUTES_TO_USER', 'CAS_RENAME_ATTRIBUTES',
'CAS_CREATE_USER'
'CAS_LOGOUT_COMPLETELY', 'CAS_RENAME_ATTRIBUTES', 'CAS_CREATE_USER'
]]
],
fieldsMeta: {
CAS_RENAME_ATTRIBUTES: {
component: JsonEditor,
label: this.$t('setting.authUserAttrMap'),
rules: [JsonRequired]
rules: [JsonRequiredUserNameMapped]
}
},
submitMethod: () => 'patch',
@@ -43,9 +41,18 @@ export default {
return obj
},
cleanFormValue(data) {
if (data['CAS_RENAME_ATTRIBUTES']) {
data['CAS_RENAME_ATTRIBUTES'] = JSON.parse(data['CAS_RENAME_ATTRIBUTES'])
let userNameAttribute = ''
const renameAttributes = JSON.parse(data['CAS_RENAME_ATTRIBUTES'])
if (renameAttributes) {
data['CAS_RENAME_ATTRIBUTES'] = renameAttributes
}
for (const key in renameAttributes) {
if (renameAttributes[key] === 'username') {
userNameAttribute = key
}
}
data['CAS_USERNAME_ATTRIBUTE'] = userNameAttribute
data['CAS_APPLY_ATTRIBUTES_TO_USER'] = true
return data
}
}

View File

@@ -36,9 +36,11 @@ export default {
'AUTH_OAUTH2_SCOPE',
'AUTH_OAUTH2_PROVIDER_AUTHORIZATION_ENDPOINT',
'AUTH_OAUTH2_ACCESS_TOKEN_ENDPOINT',
'AUTH_OAUTH2_PROVIDER_USERINFO_ENDPOINT'
'AUTH_OAUTH2_PROVIDER_USERINFO_ENDPOINT',
'AUTH_OAUTH2_PROVIDER_END_SESSION_ENDPOINT'
]],
[this.$t('common.Other'), [
'AUTH_OAUTH2_LOGOUT_COMPLETELY',
'AUTH_OAUTH2_ALWAYS_UPDATE_USER',
'AUTH_OAUTH2_USER_ATTR_MAP'
]]

View File

@@ -28,6 +28,7 @@
import ListTable from '@/components/ListTable'
import Dialog from '@/components/Dialog'
import { importLdapUser, refreshLdapUserCache, startLdapUserCache } from '@/api/settings'
import { getErrorResponseMsg } from '@/utils/common'
export default {
name: 'ImportDialog',
@@ -103,7 +104,12 @@ export default {
importLdapUser(data).then(res => {
this.$message.success(res.msg)
// eslint-disable-next-line no-return-assign
}).finally(() => this.dialogLdapUserImportLoginStatus = false)
}).catch(error => {
const errorMessage = getErrorResponseMsg(error) || this.$t('common.imExport.ImportFail')
this.$message.error(errorMessage)
}).finally(() => {
this.dialogLdapUserImportLoginStatus = false
})
}
},
importAllUserClick() {

View File

@@ -60,6 +60,7 @@ export default {
actions: {
prop: 'id',
formatterArgs: {
canUpdate: this.$hasPerm('orgs.change_organization'),
canDelete: function({ row }) {
return !row.is_default && vm.$hasPerm('orgs.delete_organization')
},

View File

@@ -47,7 +47,8 @@ export default {
this.$t('setting.Perm'),
[
'PERM_SINGLE_ASSET_TO_UNGROUP_NODE',
'TICKET_AUTHORIZE_DEFAULT_TIME'
'TICKET_AUTHORIZE_DEFAULT_TIME',
'TICKET_AUTHORIZE_DEFAULT_TIME_UNIT'
]
]
],

View File

@@ -12,7 +12,7 @@
v-on="$listeners"
@confirm="onConfirm()"
>
<GenericCreateUpdateForm v-bind="iConfig" @submitSuccess="submitSuccess" />
<GenericCreateUpdateForm ref="form" v-bind="iConfig" @submitSuccess="submitSuccess" />
</Dialog>
</div>
</template>
@@ -52,6 +52,16 @@ export default {
submitSuccess(res) {
this.$emit('input', !!res[this.enableField])
this.visible = false
},
testPerformError(error) {
const data = error.response.data
for (const key of Object.keys(data)) {
let value = data[key]
if (value instanceof Array) {
value = value.join(';')
}
this.$refs.form.$refs.form.setFieldError(key, value)
}
}
}
}

View File

@@ -1,5 +1,5 @@
<template>
<BaseSMS :title="$t('setting.CMPP2')" :config="$data" />
<BaseSMS ref="baseSms" :title="$t('setting.CMPP2')" :config="$data" />
</template>
<script>
@@ -28,8 +28,9 @@ export default {
value
).then(res => {
vm.$message.success(res['msg'])
}).catch(() => {
}).catch((error) => {
vm.$log.error('err occur')
vm.$refs.baseSms.testPerformError(error)
}).finally(() => { btn.loading = false })
}
}

View File

@@ -1,5 +1,5 @@
<template>
<BaseSMS :title="$t('setting.AlibabaCloud')" :config="$data" />
<BaseSMS ref="baseSms" :title="$t('setting.AlibabaCloud')" :config="$data" />
</template>
<script>
@@ -28,8 +28,9 @@ export default {
value
).then(res => {
vm.$message.success(res['msg'])
}).catch(() => {
}).catch((error) => {
vm.$log.error('err occur')
vm.$refs.baseSms.testPerformError(error)
}).finally(() => { btn.loading = false })
}
}

View File

@@ -0,0 +1,88 @@
<template>
<BaseSMS ref="baseSms" :title="$t('setting.HuaweiCloud')" :config="$data" />
</template>
<script>
import BaseSMS from './Base'
import { UpdateToken } from '@/components/FormFields'
export default {
name: 'SMSHuawei',
components: {
BaseSMS
},
data() {
const vm = this
return {
url: `/api/v1/settings/setting/?category=huawei`,
hasDetailInMsg: false,
visible: false,
moreButtons: [
{
title: this.$t('common.Test'),
loading: false,
callback: function(value, form, btn) {
btn.loading = true
vm.$axios.post(
`/api/v1/settings/sms/huawei/testing/`,
value
).then(res => {
vm.$message.success(res['msg'])
}).catch((error) => {
vm.$log.error('err occur')
vm.$refs.baseSms.testPerformError(error)
}).finally(() => { btn.loading = false })
}
}
],
fields: [
[
this.$t('common.BasicInfo'),
[
'HUAWEI_APP_KEY', 'HUAWEI_APP_SECRET', 'HUAWEI_SMS_ENDPOINT'
]
],
[
this.$t('setting.VerifySignTmpl'),
[
'HUAWEI_SIGN_CHANNEL_NUM', 'HUAWEI_VERIFY_SIGN_NAME', 'HUAWEI_VERIFY_TEMPLATE_CODE'
]
],
[
this.$t('common.Other'),
[
'SMS_TEST_PHONE'
]
]
],
fieldsMeta: {
HUAWEI_VERIFY_SIGN_TMPL: {
fields: ['SIGN_NAME', 'TEMPLATE_CODE'],
fieldsMeta: {
}
},
HUAWEI_APP_SECRET: {
component: UpdateToken
},
HUAWEI_SIGN_CHANNEL_NUM: {
label: this.$t('setting.SignChannelNum')
},
HUAWEI_SMS_ENDPOINT: {
label: this.$t('setting.AppEndpoint')
}
},
submitMethod() {
return 'put'
}
}
},
computed: {
},
methods: {
}
}
</script>
<style scoped>
</style>

View File

@@ -1,5 +1,5 @@
<template>
<BaseSMS :title="$t('setting.TencentCloud')" :config="$data" />
<BaseSMS ref="baseSms" :title="$t('setting.TencentCloud')" :config="$data" />
</template>
<script>
@@ -28,8 +28,9 @@ export default {
value
).then(res => {
vm.$message.success(res['msg'])
}).catch(() => {
}).catch((error) => {
vm.$log.error('err occur')
vm.$refs.baseSms.testPerformError(error)
}).finally(() => { btn.loading = false })
}
}

View File

@@ -6,6 +6,7 @@
import GenericCreateUpdatePage from '@/layout/components/GenericCreateUpdatePage'
import SMSAlibaba from './SMSAlibaba'
import SMSTencent from './SMSTencent'
import SMSHuawei from './SMSHuawei'
import CMPP2 from './CMPP2'
export default {
@@ -24,7 +25,7 @@ export default {
],
[
this.$t('setting.SMSProvider'), [
'ALIYUN', 'QCLOUD', 'CMPP2'
'ALIYUN', 'QCLOUD', 'HUAWEICLOUD', 'CMPP2'
]
]
],
@@ -43,6 +44,13 @@ export default {
return form['SMS_BACKEND'] !== 'tencent'
}
},
HUAWEICLOUD: {
label: this.$t('setting.HuaweiCloud'),
component: SMSHuawei,
hidden: (form) => {
return form['SMS_BACKEND'] !== 'huawei'
}
},
CMPP2: {
label: this.$t('setting.CMPP2'),
component: CMPP2,

View File

@@ -37,6 +37,12 @@ export default {
[
'TERMINAL_MAGNUS_ENABLED'
]
],
[
`Web ${comp}(Luna)`,
[
'TERMINAL_GRAPHICAL_RESOLUTION'
]
]
],
fieldsMeta: {

View File

@@ -23,13 +23,15 @@ export default {
this.$t('applications.port'),
[
'http_port', 'https_port', 'ssh_port', 'rdp_port',
'mysql_port', 'mariadb_port', 'postgresql_port', 'redis_port',
'oracle_11g_port', 'oracle_12c_port'
'magnus_listen_port_range'
]
],
[this.$t('common.Other'), ['comment']]
],
fieldsMeta: {
magnus_listen_port_range: {
disabled: true
}
},
hasDetailInMsg: false
}

View File

@@ -20,17 +20,15 @@ export default {
url: '/api/v1/terminal/endpoints/',
columns: [
'name', 'host',
'http_port', 'https_port', 'ssh_port',
'rdp_port', 'mysql_port', 'mariadb_port',
'postgresql_port', 'redis_port',
'oracle_11g_port', 'oracle_12c_port',
'http_port', 'https_port', 'ssh_port', 'rdp_port',
'magnus_listen_port_range',
'date_created', 'comment', 'actions'
],
columnsShow: {
min: ['name', 'actions'],
default: [
'name', 'host', 'actions',
'http_port', 'https_port', 'ssh_port', 'rdp_port'
'http_port', 'https_port', 'ssh_port', 'rdp_port', 'magnus_listen_port_range'
]
},
columnsMeta: {
@@ -39,9 +37,10 @@ export default {
},
actions: {
formatterArgs: {
canUpdate: this.$hasPerm('terminal.change_endpoint'),
updateRoute: 'EndpointUpdate',
cloneRoute: 'EndpointCreate',
canDelete: ({ row }) => row.id !== '00000000-0000-0000-0000-000000000001'
canDelete: ({ row }) => row.id !== '00000000-0000-0000-0000-000000000001' && this.$hasPerm('terminal.delete_endpoint')
}
}
}

View File

@@ -38,6 +38,7 @@ export default {
},
actions: {
formatterArgs: {
canUpdate: this.$hasPerm('terminal.change_endpointrule'),
updateRoute: 'EndpointRuleUpdate',
cloneRoute: 'EndpointRuleCreate'
}

View File

@@ -27,7 +27,8 @@ export default {
initial: {
type: storageType,
endpoint_suffix: 'core.chinacloudapi.cn',
protocol: 'http'
protocol: 'http',
is_default: true
},
getUrl() {
const params = this.$route.params

View File

@@ -1,27 +1,38 @@
<template>
<Page v-bind="$attrs">
<IBox>
<div>
<el-form ref="testForm" label-width="20%" :model="testData" :rules="testRules">
<el-form-item :label="$t('setting.basicTools')">
<el-radio-group v-model="testData.tool_type" @change="changeToolType">
<el-radio v-for="t in tools" :key="t" :label="t" />
</el-radio-group>
</el-form-item>
<el-form-item :label="$t('setting.destinationIP')" prop="dest_addr">
<el-input v-model="testData.dest_addr" :placeholder="$t('setting.destinationIP')" />
</el-form-item>
<el-form-item v-if="testData.tool_type=='Telnet'" :label="$t('setting.testPort')" prop="port_num">
<el-input v-model="testData.port_num" :placeholder="$t('setting.testPort')" />
</el-form-item>
<el-form-item>
<el-button type="primary" :loading="isTesting" @click="submitTest">{{ $t('setting.testTools') }}</el-button>
</el-form-item>
<el-form-item>
<el-input v-model="testResp" type="textarea" :readonly="true" :rows="8" :placeholder="$t('setting.testHelpText')" />
</el-form-item>
</el-form>
</div>
<el-form ref="testForm" label-width="20%" :model="testData" :rules="testRules">
<el-form-item :label="$t('setting.basicTools')">
<el-radio-group v-model="testData.tool_type" @change="changeToolType">
<el-radio v-for="t in tools" :key="t" :label="t" />
</el-radio-group>
</el-form-item>
<el-form-item :label="$t('setting.destinationIP')" prop="dest_addr">
<el-input v-model="testData.dest_addr" :placeholder="$t('setting.destinationIP')" />
</el-form-item>
<el-form-item v-if="testData.tool_type=='Telnet'" :label="$t('setting.testPort')" prop="port_num">
<el-input v-model="testData.port_num" :placeholder="$t('setting.testPort')" />
</el-form-item>
<el-form-item>
<el-button
type="primary"
size="small"
:loading="isTesting"
@click="submitTest"
>
{{ $t('setting.testTools') }}
</el-button>
</el-form-item>
<el-form-item>
<el-input
v-model="testResp"
type="textarea"
:readonly="true"
:rows="8"
:placeholder="$t('setting.testHelpText')"
/>
</el-form-item>
</el-form>
</IBox>
</Page>
</template>
@@ -95,20 +106,19 @@ export default {
}
</script>
<style scoped>
.el-form ::v-deep .el-form-item {
margin-bottom: 12px;
}
.el-form ::v-deep .el-form-item__content {
width: 75%;
}
.el-form ::v-deep .el-form-item__label {
padding: 0 30px 0 0;
}
.el-form ::v-deep .el-form-item__error {
<style lang="scss" scoped>
.el-form {
&>>> .el-form-item {
margin-bottom: 12px;
}
&>>> .el-form-item__content {
width: 75%;
}
&>>> .el-form-item__label {
padding: 0 30px 0 0;
}
&>>> .el-form-item__error {
position: inherit;
}
}
</style>

View File

@@ -141,7 +141,7 @@ export default {
valueLabel: this.$t('tickets.Pending')
}
},
exclude: ['state'],
exclude: ['state', 'id', 'title'],
options: [
{
value: 'state',
@@ -162,6 +162,30 @@ export default {
label: this.$t('tickets.Rejected')
}
]
},
{
value: 'id',
label: 'ID'
},
{
value: 'title',
label: this.$t('tickets.title')
},
{
value: 'relevant_app',
label: this.$t('tickets.RelevantApp')
},
{
value: 'relevant_asset',
label: this.$t('tickets.RelevantAsset')
},
{
value: 'relevant_system_user',
label: this.$t('tickets.RelevantCommand')
},
{
value: 'relevant_command',
label: this.$t('tickets.RelevantSystemUser')
}
]
},

View File

@@ -25,8 +25,10 @@ export default {
data() {
const vm = this
const now = new Date()
const TicketAuthorizeDefaultTime = store.getters.publicSettings['TICKET_AUTHORIZE_DEFAULT_TIME']
const date_expired = getDaysFuture(TicketAuthorizeDefaultTime, new Date()).toISOString()
const time = store.getters.publicSettings['TICKET_AUTHORIZE_DEFAULT_TIME']
const unit = store.getters.publicSettings['TICKET_AUTHORIZE_DEFAULT_TIME_UNIT']
const dividend = unit === 'hour' ? 24 : 1
const date_expired = getDaysFuture(time / dividend, new Date()).toISOString()
const date_start = now.toISOString()
let apply_category_type = []

View File

@@ -17,8 +17,10 @@ export default {
data() {
const now = new Date()
const TicketAuthorizeDefaultTime = store.getters.publicSettings['TICKET_AUTHORIZE_DEFAULT_TIME']
const date_expired = getDaysFuture(TicketAuthorizeDefaultTime, new Date()).toISOString()
const time = store.getters.publicSettings['TICKET_AUTHORIZE_DEFAULT_TIME']
const unit = store.getters.publicSettings['TICKET_AUTHORIZE_DEFAULT_TIME_UNIT']
const dividend = unit === 'hour' ? 24 : 1
const date_expired = getDaysFuture(time / dividend, new Date()).toISOString()
const date_start = now.toISOString()
return {
// 工单创建 隐藏提示信息中的跳转连接

View File

@@ -14,7 +14,9 @@ export default {
},
data() {
return {
initial: {},
initial: {
need_update_password: true
},
user: {
'can_public_key_auth': false
},
@@ -169,6 +171,9 @@ export default {
if (value.update_password !== undefined) {
delete value.update_password
}
if (value.source !== 'local') {
delete value.need_update_password
}
return value
}
}

View File

@@ -115,6 +115,7 @@ export default {
actions: {
formatterArgs: {
hasDelete: hasDelete,
canUpdate: this.$hasPerm('users.change_user'),
extraActions: [
{
title: this.$t('users.Remove'),

View File

@@ -42,7 +42,8 @@ export default {
InviteLoading: false,
formConfig: {
url: '/api/v1/users/users/invite/',
method: 'post',
getUrl: () => '/api/v1/users/users/invite/',
submitMethod: () => 'post',
hasReset: false,
hasSaveContinue: false,
createSuccessMsg: this.$t('users.InviteSuccess'),

8861
yarn.lock

File diff suppressed because it is too large Load Diff