mirror of
https://github.com/jumpserver/lina.git
synced 2026-01-14 03:46:26 +00:00
Compare commits
101 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2732050e61 | ||
|
|
4e904add32 | ||
|
|
b85ed8405e | ||
|
|
e827deef35 | ||
|
|
3c2c2ca302 | ||
|
|
453ca578b5 | ||
|
|
aa622ff812 | ||
|
|
171ceeef3a | ||
|
|
754e861294 | ||
|
|
e7b37d43f2 | ||
|
|
fd749ef211 | ||
|
|
5667c39bcb | ||
|
|
982ce90a9a | ||
|
|
86ce758adb | ||
|
|
582a84178d | ||
|
|
73de782756 | ||
|
|
9b9f7c936c | ||
|
|
55100e64a1 | ||
|
|
6d74959b64 | ||
|
|
2a6100957f | ||
|
|
6a3f6f8914 | ||
|
|
704ae0b294 | ||
|
|
9bf4597d8d | ||
|
|
16606d6a27 | ||
|
|
bb1d19610e | ||
|
|
ca871b16c4 | ||
|
|
0a612f50e6 | ||
|
|
d566adb644 | ||
|
|
242f958428 | ||
|
|
f97d46814d | ||
|
|
5cc501f5af | ||
|
|
31fd0ecde0 | ||
|
|
9d6ac3907a | ||
|
|
784bd16e87 | ||
|
|
4a11ea2c57 | ||
|
|
4a2ffc754f | ||
|
|
d31929eb33 | ||
|
|
fe36fa9390 | ||
|
|
a97de8afb4 | ||
|
|
ba109900ec | ||
|
|
f8649457d6 | ||
|
|
8863693541 | ||
|
|
c2cbd3f5b0 | ||
|
|
0b84b96afb | ||
|
|
ec7768267f | ||
|
|
4aefb6779f | ||
|
|
06fd007c62 | ||
|
|
6f4e029537 | ||
|
|
cc58b374ab | ||
|
|
07f35dbbb2 | ||
|
|
04ffbb8fd6 | ||
|
|
12a501d559 | ||
|
|
7dcd4490ba | ||
|
|
dd1ac7c7f8 | ||
|
|
471910e0b8 | ||
|
|
a514e88b78 | ||
|
|
b79fefdee8 | ||
|
|
d2b3025709 | ||
|
|
386e2417e3 | ||
|
|
fd57b37cea | ||
|
|
a6222f87d2 | ||
|
|
5cd4e5b40b | ||
|
|
eb3d9089e0 | ||
|
|
56c22cffe6 | ||
|
|
fe1e26957a | ||
|
|
bc366947f0 | ||
|
|
86150cc571 | ||
|
|
f11fc947af | ||
|
|
49880f6739 | ||
|
|
82faf0f99e | ||
|
|
e6f98d58c4 | ||
|
|
3536a94976 | ||
|
|
45276010e0 | ||
|
|
2e47f42366 | ||
|
|
dd6e9a1512 | ||
|
|
fd1f16d43c | ||
|
|
24931a9f5a | ||
|
|
f51924bf1d | ||
|
|
f82257edb8 | ||
|
|
286e9894c0 | ||
|
|
968b2415b1 | ||
|
|
e0f6fb305d | ||
|
|
e0fd33f376 | ||
|
|
7ad86062b4 | ||
|
|
1fce7561db | ||
|
|
3b17235b6e | ||
|
|
52c9b9503b | ||
|
|
48a2b20320 | ||
|
|
e6cc8cd2e8 | ||
|
|
3a183ddf53 | ||
|
|
7eb77487d1 | ||
|
|
a5da581317 | ||
|
|
6bda9a372e | ||
|
|
a8de087137 | ||
|
|
34d9790a04 | ||
|
|
5bfe2497fd | ||
|
|
e16a775037 | ||
|
|
42fab92237 | ||
|
|
e2eac83615 | ||
|
|
04465a1da3 | ||
|
|
2adb1ee980 |
2
.github/workflows/release-drafter.yml
vendored
2
.github/workflows/release-drafter.yml
vendored
@@ -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:
|
||||
|
||||
25
Dockerfile
25
Dockerfile
@@ -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
|
||||
|
||||
@@ -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,7 +33,7 @@
|
||||
"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",
|
||||
@@ -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",
|
||||
@@ -62,6 +63,7 @@
|
||||
"vue-echarts": "^5.0.0-beta.0",
|
||||
"vue-i18n": "^8.15.5",
|
||||
"vue-json-editor": "^1.4.3",
|
||||
"vue-markdown": "^2.2.4",
|
||||
"vue-moment": "^4.1.0",
|
||||
"vue-password-strength-meter": "^1.7.2",
|
||||
"vue-router": "3.0.6",
|
||||
@@ -91,6 +93,7 @@
|
||||
"eslint": "^5.15.3",
|
||||
"eslint-plugin-vue": "5.2.2",
|
||||
"eslint-plugin-vue-i18n": "^0.3.0",
|
||||
"github-markdown-css": "^5.2.0",
|
||||
"html-webpack-plugin": "3.2.0",
|
||||
"husky": "^4.2.3",
|
||||
"less-loader": "^5.0.0",
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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')))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
37
src/components/MarkDown/index.vue
Normal file
37
src/components/MarkDown/index.vue
Normal file
@@ -0,0 +1,37 @@
|
||||
<template>
|
||||
<div class="markdown-body">
|
||||
<VueMarkdown :source="value" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import VueMarkdown from 'vue-markdown'
|
||||
import 'github-markdown-css/github-markdown-light.css'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
VueMarkdown
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: ''
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang='scss' scoped>
|
||||
.markdown-body * {
|
||||
padding: 10px;
|
||||
background-color: #f3f3f3;
|
||||
color: #1a1a1a;
|
||||
font-size: 13px;
|
||||
//& >>> .table * {
|
||||
// background-color: #f3f3f3;
|
||||
//}
|
||||
}
|
||||
</style>
|
||||
61
src/components/TableFormatters/TwoTabFormatter.vue
Normal file
61
src/components/TableFormatters/TwoTabFormatter.vue
Normal 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>
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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;">
|
||||
|
||||
@@ -28,3 +28,4 @@ export { default as AssetRelationCard } from './AssetRelationCard'
|
||||
export { default as UserConfirmDialog } from './UserConfirmDialog'
|
||||
export { default as Announcement } from './Announcement'
|
||||
export { default as CronTab } from './CronTab'
|
||||
export { default as MarkDown } from './MarkDown'
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
},
|
||||
"acl": {
|
||||
"name": "Name",
|
||||
"ip_group_help_text": "The format is a comma-separated string, * means match all. Example: 192.168.10.1, 192.168.1.0/24, 10.1.1.1-10.1.1.20, 2001:db8:2de::e13, 2001:db8:1a:1110::/64",
|
||||
"username": "Username",
|
||||
"ip_group": "IP group",
|
||||
"action": "Action",
|
||||
@@ -47,6 +48,7 @@
|
||||
"sqlserver": "SQLServer",
|
||||
"redis": "Redis",
|
||||
"mongodb": "MongoDB",
|
||||
"clickhouse": "ClickHouse",
|
||||
"k8s": "kubernetes"
|
||||
},
|
||||
"applicationsCategory": {
|
||||
@@ -244,7 +246,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 +258,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 +272,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 +419,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",
|
||||
@@ -772,7 +784,7 @@
|
||||
"OperateLog": "Operation Logs",
|
||||
"PasswordChangeLog": "Password Update Logs",
|
||||
"Perms": "Permissions",
|
||||
"PersonalInformationImprovement": "PersonalInformationImprovement",
|
||||
"PersonalInformationImprovement": "Personal information improvement",
|
||||
"PlatformCreate": "Platform create",
|
||||
"PlatformDetail": "Platform detail",
|
||||
"PlatformList": "Platforms",
|
||||
@@ -926,6 +938,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",
|
||||
@@ -1140,6 +1155,10 @@
|
||||
"reply": "Reply",
|
||||
"status": "Status",
|
||||
"title": "Title",
|
||||
"RelevantApp": "App",
|
||||
"RelevantAsset": "Asset",
|
||||
"RelevantCommand": "Command",
|
||||
"RelevantSystemUser": "System user",
|
||||
"type": "Type",
|
||||
"user": "User",
|
||||
"Status": "Status",
|
||||
@@ -1408,9 +1427,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",
|
||||
@@ -1419,6 +1440,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)",
|
||||
|
||||
@@ -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": "合計",
|
||||
@@ -945,6 +956,9 @@
|
||||
"Feature": "機能",
|
||||
"AlibabaCloud": "Alibaba cloud",
|
||||
"TencentCloud": "テンセント雲",
|
||||
"HuaweiCloud": "ファーウェイ雲",
|
||||
"SignChannelNum": "サインパス番号",
|
||||
"AppEndpoint": "アクセスアドレスを適用する",
|
||||
"CMPP2": "CMPP v2.0",
|
||||
"Radius": "Radius",
|
||||
"VerifySignTmpl": "認証コードメールテンプレート",
|
||||
@@ -1172,6 +1186,10 @@
|
||||
"reply": "返信",
|
||||
"status": "ステータス",
|
||||
"title": "タイトル",
|
||||
"RelevantApp": "するアプリケーション",
|
||||
"RelevantAsset": "する資産",
|
||||
"RelevantCommand": "するコマンド",
|
||||
"RelevantSystemUser": "するシステムユーザー",
|
||||
"action": "アクション",
|
||||
"type": "タイプ",
|
||||
"user": "ユーザー",
|
||||
@@ -1241,7 +1259,7 @@
|
||||
"DatePasswordLastUpdated": "パスワード最終更新日",
|
||||
"DatePasswordUpdated": "パスワード更新日",
|
||||
"DescribeOfGuide": "詳細については、をクリックしてください。",
|
||||
"Email": "メール",
|
||||
"Email": "ポスト",
|
||||
"Phone": "携帯番号",
|
||||
"WeCom": "企業wechat",
|
||||
"DingTalk": "ホッチキス",
|
||||
@@ -1451,9 +1469,11 @@
|
||||
"IPNetworkSegment": "IPネットワークセグメント",
|
||||
"Aliyun": "Alibaba cloud",
|
||||
"Qcloud": "テンセント雲",
|
||||
"QcloudLighthouse": "テンセント雲(軽量アプリケーションサーバー)",
|
||||
"QingyunPrivatecloud": "青雲プライベートクラウド",
|
||||
"HuaweiPrivatecloud": "ファーウェイプライベートクラウド",
|
||||
"OpenStack": "OpenStack",
|
||||
"CTYunPrivate": "天翼プライベート・クラウド",
|
||||
"GCP": "Googleクラウド",
|
||||
"FC": "Fusion Compute",
|
||||
"LAN": "ローカルエリアネットワーク",
|
||||
@@ -1462,6 +1482,7 @@
|
||||
"HuaweiCloud": "ファーウェイ雲",
|
||||
"BaiduCloud": "百度雲",
|
||||
"JDCloud": "京東雲",
|
||||
"KingSoftCloud": "金山雲",
|
||||
"Azure": "Azure(中国)",
|
||||
"Azure_Int": "Azure (国際)",
|
||||
"HostnameStrategy": "資産を生成するためにホスト名。例: 1. インスタンス名 (instanceDemo) 2.インスタンス名と一部IP (下位2桁) (instanceDemo-250.1)",
|
||||
|
||||
@@ -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": "总共",
|
||||
@@ -946,6 +957,9 @@
|
||||
"Feature": "功能",
|
||||
"AlibabaCloud": "阿里云",
|
||||
"TencentCloud": "腾讯云",
|
||||
"HuaweiCloud": "华为云",
|
||||
"SignChannelNum": "签名通道号",
|
||||
"AppEndpoint": "应用接入地址",
|
||||
"CMPP2": "CMPP v2.0",
|
||||
"Radius": "Radius",
|
||||
"VerifySignTmpl": "验证码短信模板",
|
||||
@@ -1173,6 +1187,10 @@
|
||||
"reply": "回复",
|
||||
"status": "状态",
|
||||
"title": "标题",
|
||||
"RelevantApp": "应用",
|
||||
"RelevantAsset": "资产",
|
||||
"RelevantCommand": "命令",
|
||||
"RelevantSystemUser": "系统用户",
|
||||
"action": "动作",
|
||||
"type": "类型",
|
||||
"user": "用户",
|
||||
@@ -1242,7 +1260,7 @@
|
||||
"DatePasswordLastUpdated": "最后更新密码日期",
|
||||
"DatePasswordUpdated": "密码更新日期",
|
||||
"DescribeOfGuide": "欢迎使用JumpServer堡垒机系统,获取更多信息请点击",
|
||||
"Email": "邮件",
|
||||
"Email": "邮箱",
|
||||
"Phone": "手机号",
|
||||
"WeCom": "企业微信",
|
||||
"DingTalk": "钉钉",
|
||||
@@ -1452,8 +1470,10 @@
|
||||
"IPNetworkSegment": "IP网段",
|
||||
"Aliyun": "阿里云",
|
||||
"Qcloud": "腾讯云",
|
||||
"QcloudLighthouse": "腾讯云(轻量应用服务器)",
|
||||
"QingyunPrivatecloud": "青云私有云",
|
||||
"HuaweiPrivatecloud": "华为私有云",
|
||||
"CTYunPrivate": "天翼私有云",
|
||||
"OpenStack": "OpenStack",
|
||||
"GCP": "谷歌云",
|
||||
"FC": "Fusion Compute",
|
||||
@@ -1463,6 +1483,7 @@
|
||||
"HuaweiCloud": "华为云",
|
||||
"BaiduCloud": "百度云",
|
||||
"JDCloud": "京东云",
|
||||
"KingSoftCloud": "金山云",
|
||||
"Azure":"Azure(中国)",
|
||||
"Azure_Int": "Azure(国际)",
|
||||
"HostnameStrategy": "用于生成资产主机名。例如:1. 实例名称 (instanceDemo);2. 实例名称和部分IP(后两位) (instanceDemo-250.1)",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -97,6 +97,7 @@ export default {
|
||||
getDefaultFormSetting() {
|
||||
const vm = this
|
||||
return {
|
||||
needGetObjectDetail: false,
|
||||
submitMethod: () => 'patch',
|
||||
cleanFormValue: (value) => {
|
||||
const filterValue = {}
|
||||
|
||||
@@ -177,7 +177,7 @@ export default {
|
||||
}
|
||||
|
||||
&>>> .el-input__icon {
|
||||
color: #606266;
|
||||
color: #606266!important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ export default {
|
||||
|
||||
<style scoped>
|
||||
.wrapper-content {
|
||||
padding: 20px 25px 40px;
|
||||
padding: 20px 25px 10px;
|
||||
}
|
||||
|
||||
.wrapper-content >>> .el-alert {
|
||||
|
||||
@@ -43,6 +43,10 @@ export default {
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.page {
|
||||
height: calc(100vh - 55px - 41px);
|
||||
overflow: auto;
|
||||
}
|
||||
@media print {
|
||||
.disabled-when-print{
|
||||
display: none;
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
20
src/utils/Message.js
Normal 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 }
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
|
||||
2
src/utils/jquery-vendor.js
vendored
2
src/utils/jquery-vendor.js
vendored
@@ -1,4 +1,4 @@
|
||||
import $ from 'jquery'
|
||||
import $ from 'jquery/dist/jquery.min.js'
|
||||
window.$ = $
|
||||
window.jQuery = $
|
||||
export default $
|
||||
|
||||
@@ -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'
|
||||
@@ -13,7 +14,7 @@ import { DEFAULT_ORG_ID } from '@/utils/org'
|
||||
const service = axios.create({
|
||||
baseURL: process.env.VUE_APP_BASE_API, // url = base url + request url
|
||||
// withCredentials: true, // send cookies when cross-domain requests
|
||||
timeout: 60 * 1000 // request timeout
|
||||
timeout: 2 * 60 * 1000 // request timeout
|
||||
})
|
||||
|
||||
function beforeRequestAddToken(config) {
|
||||
|
||||
@@ -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'
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,7 +78,6 @@ export default {
|
||||
hasRefresh: true,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasMoreActions: false,
|
||||
createRoute: () => {
|
||||
return {
|
||||
name: 'AccountBackupPlanCreate'
|
||||
|
||||
@@ -123,7 +123,6 @@ export default {
|
||||
hasRefresh: true,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasMoreActions: false,
|
||||
searchConfig: {
|
||||
getUrlQuery: false
|
||||
},
|
||||
|
||||
@@ -74,6 +74,9 @@ export default {
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasCreate: false,
|
||||
searchConfig: {
|
||||
getUrlQuery: false
|
||||
},
|
||||
hasMoreActions: false
|
||||
},
|
||||
assetRelationConfig: {
|
||||
|
||||
@@ -107,7 +107,6 @@ export default {
|
||||
hasRefresh: true,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasMoreActions: false,
|
||||
createRoute: () => {
|
||||
return {
|
||||
name: 'AssetChangeAuthPlanCreate'
|
||||
|
||||
@@ -84,8 +84,7 @@ export default {
|
||||
createRoute: 'AssetAclCreate',
|
||||
hasRefresh: true,
|
||||
hasExport: false,
|
||||
hasImport: false,
|
||||
hasMoreActions: false
|
||||
hasImport: false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,64 +52,82 @@ export const DATABASE_CATEGORY = 'db'
|
||||
export const SQLSERVER = 'sqlserver'
|
||||
export const REDIS = 'redis'
|
||||
export const MONGODB = 'mongodb'
|
||||
export const CLICKHOUSE = 'clickhouse'
|
||||
|
||||
const MYSQL_ITEM = {
|
||||
name: MYSQL,
|
||||
title: i18n.t(`applications.applicationsType.${MYSQL}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: true,
|
||||
group: i18n.t('applications.RDBProtocol')
|
||||
}
|
||||
|
||||
const MARIADB_ITEM = {
|
||||
name: MARIADB,
|
||||
title: i18n.t(`applications.applicationsType.${MARIADB}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: true
|
||||
}
|
||||
|
||||
const ORACLE_ITEM = {
|
||||
name: ORACLE,
|
||||
title: i18n.t(`applications.applicationsType.${ORACLE}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: hasLicence
|
||||
}
|
||||
|
||||
const POSTGRESQL_ITEM = {
|
||||
name: POSTGRESQL,
|
||||
title: i18n.t(`applications.applicationsType.${POSTGRESQL}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: hasLicence
|
||||
}
|
||||
|
||||
const SQLSERVER_ITEM = {
|
||||
name: SQLSERVER,
|
||||
title: i18n.t(`applications.applicationsType.${SQLSERVER}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: hasLicence
|
||||
}
|
||||
|
||||
const CLICKHOUSE_ITEM = {
|
||||
name: CLICKHOUSE,
|
||||
title: i18n.t(`applications.applicationsType.${CLICKHOUSE}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: hasLicence
|
||||
}
|
||||
|
||||
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 DATABASE = [
|
||||
{
|
||||
name: MYSQL,
|
||||
title: i18n.t(`applications.applicationsType.${MYSQL}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: true,
|
||||
group: i18n.t('applications.RDBProtocol')
|
||||
},
|
||||
{
|
||||
name: MARIADB,
|
||||
title: i18n.t(`applications.applicationsType.${MARIADB}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: true
|
||||
},
|
||||
{
|
||||
name: ORACLE,
|
||||
title: i18n.t(`applications.applicationsType.${ORACLE}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: hasLicence
|
||||
},
|
||||
{
|
||||
name: POSTGRESQL,
|
||||
title: i18n.t(`applications.applicationsType.${POSTGRESQL}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: hasLicence
|
||||
},
|
||||
{
|
||||
name: SQLSERVER,
|
||||
title: i18n.t(`applications.applicationsType.${SQLSERVER}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY,
|
||||
has: hasLicence
|
||||
}
|
||||
MYSQL_ITEM, MARIADB_ITEM, ORACLE_ITEM, POSTGRESQL_ITEM, SQLSERVER_ITEM, CLICKHOUSE_ITEM
|
||||
]
|
||||
|
||||
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}`),
|
||||
type: 'primary',
|
||||
category: DATABASE_CATEGORY
|
||||
}
|
||||
MONGODB_ITEM, REDIS_ITEM
|
||||
]
|
||||
|
||||
export const AppPlanDatabase = DATABASE
|
||||
export const AppPlanDatabase = [MYSQL_ITEM, MARIADB_ITEM, ORACLE_ITEM, POSTGRESQL_ITEM, SQLSERVER_ITEM, MONGODB_ITEM]
|
||||
|
||||
export const KUBERNETES = 'k8s'
|
||||
export const CLOUD_CATEGORY = 'cloud'
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -88,7 +88,10 @@ export default {
|
||||
},
|
||||
headerActions: {
|
||||
hasLeftActions: false,
|
||||
hasRightActions: false
|
||||
hasRightActions: false,
|
||||
searchConfig: {
|
||||
getUrlQuery: false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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]
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/',
|
||||
|
||||
@@ -38,6 +38,7 @@ export default {
|
||||
},
|
||||
tableConfig: {
|
||||
url: `/api/v1/xpack/cloud/sync-instance-tasks/${this.object.id}/instances/`,
|
||||
hasSelection: false,
|
||||
columns: [
|
||||
'instance_id',
|
||||
{
|
||||
|
||||
@@ -58,10 +58,7 @@ export default {
|
||||
formatter: DetailFormatter,
|
||||
formatterArgs: {
|
||||
permissions: 'xpack.view_syncinstancedetail',
|
||||
route: 'SyncInstanceTaskDetail',
|
||||
routeQuery: {
|
||||
activeTab: 'detail'
|
||||
}
|
||||
route: 'SyncInstanceTaskDetail'
|
||||
}
|
||||
},
|
||||
history_count: {
|
||||
|
||||
@@ -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'),
|
||||
|
||||
@@ -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,
|
||||
@@ -63,7 +74,7 @@ export default {
|
||||
el: {
|
||||
value: [],
|
||||
ajax: {
|
||||
url: `/api/v1/assets/system-users/?protocol__in=ssh,telnet,mysql,postgresql,mariadb,oracle,sqlserver,k8s`,
|
||||
url: `/api/v1/assets/system-users/?protocol__in=ssh,telnet,mysql,postgresql,mariadb,oracle,sqlserver,k8s,redis,mongodb,clickhouse`,
|
||||
transformOption: (item) => {
|
||||
if (this.$route.query.type === 'k8s') {
|
||||
return { label: item.name, value: item.id }
|
||||
|
||||
@@ -75,7 +75,7 @@ export default {
|
||||
icon: 'fa-info-circle',
|
||||
title: this.$t('assets.SystemUser'),
|
||||
objectsAjax: {
|
||||
url: `/api/v1/assets/system-users/?protocol__in=ssh,telnet,mysql,postgresql,mariadb,oracle,sqlserver,k8s`,
|
||||
url: `/api/v1/assets/system-users/?protocol__in=ssh,telnet,mysql,postgresql,mariadb,oracle,sqlserver,k8s,redis,mongodb,clickhouse`,
|
||||
transformOption: (item) => defaultTransformOption(item, 'username')
|
||||
},
|
||||
hasObjectsId: this.object.system_users,
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -42,7 +42,6 @@ export default {
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasMoreActions: false,
|
||||
createRoute: 'DomainCreate'
|
||||
},
|
||||
notice: this.$t('assets.DomainHelpMessage')
|
||||
|
||||
@@ -27,7 +27,6 @@ export default {
|
||||
}
|
||||
},
|
||||
headerActions: {
|
||||
hasMoreActions: false,
|
||||
createRoute: 'LabelCreate'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@ export default {
|
||||
case 'sqlserver':
|
||||
case 'redis':
|
||||
case 'mongodb':
|
||||
case 'clickhouse':
|
||||
return Database
|
||||
case 'k8s':
|
||||
return K8S
|
||||
|
||||
@@ -23,14 +23,14 @@ export default {
|
||||
url: '/api/v1/assets/system-users/?type=common',
|
||||
columns: [
|
||||
'name', 'username', 'username_same_with_user', 'protocol', 'login_mode',
|
||||
'assets_amount', 'applications_amount', 'priority',
|
||||
'priority',
|
||||
'created_by', 'date_created', 'date_updated', 'comment', 'org_name', 'actions'
|
||||
],
|
||||
columnsShow: {
|
||||
min: ['name', 'actions'],
|
||||
default: [
|
||||
'name', 'username', 'protocol', 'login_mode', 'assets_amount',
|
||||
'applications_amount', 'comment', 'actions'
|
||||
'name', 'username', 'protocol', 'login_mode',
|
||||
'comment', 'actions'
|
||||
]
|
||||
},
|
||||
columnsMeta: {
|
||||
@@ -49,12 +49,6 @@ export default {
|
||||
login_mode: {
|
||||
width: '120px'
|
||||
},
|
||||
assets_amount: {
|
||||
width: '80px'
|
||||
},
|
||||
applications_amount: {
|
||||
width: '80px'
|
||||
},
|
||||
actions: {
|
||||
formatterArgs: {
|
||||
onUpdate: ({ row }) => {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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))
|
||||
})
|
||||
|
||||
@@ -25,17 +25,6 @@ export default {
|
||||
]
|
||||
]
|
||||
],
|
||||
fieldsMeta: {
|
||||
FORGOT_PASSWORD_URL: {
|
||||
on: {
|
||||
change([value], updateForm) {
|
||||
if (value && !value.startsWith('http')) {
|
||||
updateForm({ FORGOT_PASSWORD_URL: 'http://' + value })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
submitMethod() {
|
||||
return 'patch'
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ export default {
|
||||
[
|
||||
this.$t('common.BasicInfo'),
|
||||
[
|
||||
'AUTH_FEISHU', 'FEISHU_APP_ID', 'FEISHU_APP_SECRET'
|
||||
'AUTH_FEISHU', 'FEISHU_APP_ID', 'FEISHU_APP_SECRET', 'FEISHU_VERSION'
|
||||
]
|
||||
]
|
||||
],
|
||||
|
||||
@@ -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'
|
||||
]]
|
||||
|
||||
@@ -32,6 +32,7 @@ export default {
|
||||
'AUTH_OPENID_PROVIDER_TOKEN_ENDPOINT', 'AUTH_OPENID_PROVIDER_JWKS_ENDPOINT',
|
||||
'AUTH_OPENID_PROVIDER_USERINFO_ENDPOINT', 'AUTH_OPENID_PROVIDER_END_SESSION_ENDPOINT',
|
||||
'AUTH_OPENID_PROVIDER_SIGNATURE_ALG', 'AUTH_OPENID_PROVIDER_SIGNATURE_KEY',
|
||||
'AUTH_OPENID_PKCE', 'AUTH_OPENID_CODE_CHALLENGE_METHOD',
|
||||
'AUTH_OPENID_SCOPES', 'AUTH_OPENID_ID_TOKEN_MAX_AGE', 'AUTH_OPENID_ID_TOKEN_INCLUDE_CLAIMS',
|
||||
'AUTH_OPENID_USE_STATE', 'AUTH_OPENID_USE_NONCE', 'AUTH_OPENID_ALWAYS_UPDATE_USER',
|
||||
'AUTH_OPENID_IGNORE_SSL_VERIFICATION', 'AUTH_OPENID_SHARE_SESSION', 'AUTH_OPENID_USER_ATTR_MAP'
|
||||
@@ -87,6 +88,12 @@ export default {
|
||||
AUTH_OPENID_PROVIDER_SIGNATURE_KEY: {
|
||||
hidden: (form) => form['AUTH_OPENID_KEYCLOAK']
|
||||
},
|
||||
AUTH_OPENID_PKCE: {
|
||||
hidden: (form) => form['AUTH_OPENID_KEYCLOAK']
|
||||
},
|
||||
AUTH_OPENID_CODE_CHALLENGE_METHOD: {
|
||||
hidden: (form) => form['AUTH_OPENID_KEYCLOAK'] || !form['AUTH_OPENID_PKCE']
|
||||
},
|
||||
'AUTH_OPENID_SCOPES': {
|
||||
hidden: (form) => form['AUTH_OPENID_KEYCLOAK']
|
||||
},
|
||||
|
||||
@@ -115,6 +115,14 @@ export default {
|
||||
{
|
||||
key: this.$t('setting.Edition'),
|
||||
value: this.licenseData.edition
|
||||
},
|
||||
{
|
||||
key: this.$t('assets.SerialNumber'),
|
||||
value: this.licenseData?.serial_no || ''
|
||||
},
|
||||
{
|
||||
key: this.$t('common.Comment'),
|
||||
value: this.licenseData?.remark || ''
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
},
|
||||
|
||||
@@ -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'
|
||||
]
|
||||
]
|
||||
],
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
}
|
||||
|
||||
88
src/views/settings/SMS/SMSHuawei.vue
Normal file
88
src/views/settings/SMS/SMSHuawei.vue
Normal 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>
|
||||
@@ -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 })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -37,6 +37,12 @@ export default {
|
||||
[
|
||||
'TERMINAL_MAGNUS_ENABLED'
|
||||
]
|
||||
],
|
||||
[
|
||||
`Web ${comp}(Luna)`,
|
||||
[
|
||||
'TERMINAL_GRAPHICAL_RESOLUTION'
|
||||
]
|
||||
]
|
||||
],
|
||||
fieldsMeta: {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,6 +38,7 @@ export default {
|
||||
},
|
||||
actions: {
|
||||
formatterArgs: {
|
||||
canUpdate: this.$hasPerm('terminal.change_endpointrule'),
|
||||
updateRoute: 'EndpointRuleUpdate',
|
||||
cloneRoute: 'EndpointRuleCreate'
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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')
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -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 = []
|
||||
|
||||
|
||||
@@ -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 {
|
||||
// 工单创建 隐藏提示信息中的跳转连接
|
||||
|
||||
@@ -7,13 +7,13 @@
|
||||
<div v-for="item in comments" :key="item.id" class="feed-activity-list">
|
||||
<div class="feed-element">
|
||||
<a href="#" class="pull-left">
|
||||
<el-avatar :src="imageUrl" size="30" class="header-avatar" />
|
||||
<el-avatar :src="imageUrl" :size="30" class="header-avatar" />
|
||||
</a>
|
||||
<div class="media-body ">
|
||||
<strong>{{ item.user_display }}</strong> <small class="text-muted">{{ formatTime(item.date_created) }}</small>
|
||||
<br>
|
||||
<small class="text-muted">{{ toSafeLocalDateStr(item.date_created) }}</small>
|
||||
<div style="padding-top: 10px;" v-html="item.body" />
|
||||
<MarkDown :value="item.body" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -68,9 +68,11 @@
|
||||
import IBox from '@/components/IBox'
|
||||
import { formatTime, getDateTimeStamp } from '@/utils'
|
||||
import { toSafeLocalDateStr } from '@/utils/common'
|
||||
import MarkDown from '@/components/MarkDown'
|
||||
|
||||
export default {
|
||||
name: 'Comments',
|
||||
components: { IBox },
|
||||
components: { IBox, MarkDown },
|
||||
props: {
|
||||
object: {
|
||||
type: Object,
|
||||
@@ -105,7 +107,15 @@ export default {
|
||||
return this.object.process_map[this.object.approval_step - 1].assignees.indexOf(this.$store.state.users.profile.id) !== -1
|
||||
},
|
||||
isSelfTicket() {
|
||||
return this.object.applicant === this.$store.state.users.profile.id
|
||||
let applicant
|
||||
if (this.object.applicant.indexOf('(') > -1) {
|
||||
const applicantName = this.object.applicant.split('(')[1]
|
||||
applicant = applicantName.substring(0, applicantName.length - 1)
|
||||
} else {
|
||||
applicant = this.object.applicant
|
||||
}
|
||||
const userName = this.$store.state.users.profile?.username
|
||||
return applicant === userName
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +115,7 @@ export default {
|
||||
actions: {
|
||||
formatterArgs: {
|
||||
hasDelete: hasDelete,
|
||||
canUpdate: this.$hasPerm('users.change_user'),
|
||||
extraActions: [
|
||||
{
|
||||
title: this.$t('users.Remove'),
|
||||
|
||||
@@ -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'),
|
||||
|
||||
Reference in New Issue
Block a user