diff --git a/src/app/elements/connect/acl-dialog/acl-dialog.component.html b/src/app/elements/connect/acl-dialog/acl-dialog.component.html
index aeb306a3..c969cc54 100644
--- a/src/app/elements/connect/acl-dialog/acl-dialog.component.html
+++ b/src/app/elements/connect/acl-dialog/acl-dialog.component.html
@@ -74,6 +74,14 @@
{{ 'Login reminder' | translate }}
-
+
+
+ {{ JSON.stringify(data.error.error) }}
+
+
+
+
+
+
diff --git a/src/app/elements/connect/acl-dialog/acl-dialog.component.ts b/src/app/elements/connect/acl-dialog/acl-dialog.component.ts
index d899f126..e4e0eec7 100644
--- a/src/app/elements/connect/acl-dialog/acl-dialog.component.ts
+++ b/src/app/elements/connect/acl-dialog/acl-dialog.component.ts
@@ -3,6 +3,7 @@ import {Asset, ConnectData, ConnectionToken} from '@app/model';
import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material';
import {HttpService, I18nService} from '@app/services';
import {ToastrService} from 'ngx-toastr';
+import {HttpErrorResponse} from '@angular/common/http';
@Component({
selector: 'elements-acl-dialog',
@@ -14,6 +15,7 @@ export class ElementACLDialogComponent implements OnInit {
public connectInfo: ConnectData;
public code: string;
public connectionToken: ConnectionToken = null;
+ public error: HttpErrorResponse;
public otherError: string;
public ticketAssignees: string = '-';
// Token 的行为,创建或者兑换 Token, create, exchange
@@ -121,4 +123,6 @@ export class ElementACLDialogComponent implements OnInit {
);
}, 3000);
}
+
+ protected readonly JSON = JSON;
}
diff --git a/src/app/elements/content/content-window/magnus/magnus.component.html b/src/app/elements/content/content-window/magnus/magnus.component.html
index 603f97b0..ec64fa53 100644
--- a/src/app/elements/content/content-window/magnus/magnus.component.html
+++ b/src/app/elements/content/content-window/magnus/magnus.component.html
@@ -6,10 +6,11 @@ {{ 'Database connect info' | translate }}
{{ item.label | async }} |
@@ -18,9 +19,17 @@ {{ 'Database connect info' | translate }}
-
+
{{ this.info[item.name] }}
+
+
+ {{ "Re-use for a long time after opening" | translate }}
+
+
diff --git a/src/app/elements/content/content-window/magnus/magnus.component.scss b/src/app/elements/content/content-window/magnus/magnus.component.scss
index 7b7b78b4..614d19a1 100644
--- a/src/app/elements/content/content-window/magnus/magnus.component.scss
+++ b/src/app/elements/content/content-window/magnus/magnus.component.scss
@@ -98,3 +98,15 @@ iframe {
width: 15px;
height: 15px;
}
+
+.reusable-button ::ng-deep {
+ .mat-slide-toggle-bar {
+ background-color: gray;
+ }
+ .mat-slide-toggle.mat-checked .mat-slide-toggle-bar {
+ background-color: var(--primary-color) !important;
+ }
+ .mat-slide-toggle.mat-checked:not(.mat-disabled) .mat-slide-toggle-thumb {
+ background-color: white;
+ }
+}
diff --git a/src/app/elements/content/content-window/magnus/magnus.component.ts b/src/app/elements/content/content-window/magnus/magnus.component.ts
index 3998edf3..584de850 100644
--- a/src/app/elements/content/content-window/magnus/magnus.component.ts
+++ b/src/app/elements/content/content-window/magnus/magnus.component.ts
@@ -1,8 +1,9 @@
-import {Component, Input, OnInit} from '@angular/core';
+import {Component, Input, OnInit, ViewChild} from '@angular/core';
import {View, Account, Endpoint, Asset, ConnectionToken} from '@app/model';
import {ConnectTokenService, HttpService, I18nService, SettingService} from '@app/services';
import {User} from '@app/globals';
import {ToastrService} from 'ngx-toastr';
+import {MatTooltip} from '@angular/material/tooltip';
interface InfoItem {
name: string;
@@ -18,6 +19,7 @@ interface InfoItem {
export class ElementConnectorMagnusComponent implements OnInit {
@Input() view: View;
+ @ViewChild(MatTooltip, {static: false}) tooltip: MatTooltip;
asset: Asset;
account: Account;
@@ -34,6 +36,8 @@ export class ElementConnectorMagnusComponent implements OnInit {
passwordMask = '******';
passwordShow = '******';
token: ConnectionToken;
+ showSetReusable: boolean;
+ hoverTip: string = this._i18n.instant('Click to copy');
constructor(private _http: HttpService,
private _i18n: I18nService,
@@ -42,6 +46,7 @@ export class ElementConnectorMagnusComponent implements OnInit {
private _settingSvc: SettingService
) {
this.globalSetting = this._settingSvc.globalSetting;
+ this.showSetReusable = this.globalSetting.CONNECTION_TOKEN_REUSABLE;
}
async ngOnInit() {
@@ -57,7 +62,7 @@ export class ElementConnectorMagnusComponent implements OnInit {
this.setDBInfo();
this.generateConnCli();
this.loading = false;
- this.view.termComp = this
+ this.view.termComp = this;
}
setDBInfo() {
@@ -72,8 +77,11 @@ export class ElementConnectorMagnusComponent implements OnInit {
{name: 'password', value: this.token.value, label: this._i18n.t('Password')},
{name: 'database', value: database, label: this._i18n.t('Database')},
{name: 'protocol', value: this.protocol, label: this._i18n.t('Protocol')},
- {name: 'expire_time', value: `${this.token.expire_time} s` , label: this._i18n.t('Expire time')},
+ {name: 'date_expired', value: `${this.token.date_expired}` , label: this._i18n.t('Expire time')},
];
+ if (this.showSetReusable) {
+ this.infoItems.push({name: 'set_reusable', value: '', label: this._i18n.t('Set reusable')});
+ }
this.info = this.infoItems.reduce((pre, current) => {
pre[current.name] = current.value;
return pre;
@@ -126,6 +134,19 @@ export class ElementConnectorMagnusComponent implements OnInit {
this.cli = cli.replace(passwordHolder, password);
}
+ setReusable(event) {
+ this._connectTokenSvc.setReusable(this.token, event.checked).subscribe(
+ res => {
+ this.token = Object.assign(this.token, res);
+ this.info['date_expired'] = `${this.token.date_expired}`;
+ },
+ error => {
+ this.token.is_reusable = false;
+ this._toastr.error(error.error.msg || error.error.is_reusable || error.message );
+ }
+ );
+ }
+
startClient() {
const {protocol} = this.info;
const data = {
@@ -149,19 +170,22 @@ export class ElementConnectorMagnusComponent implements OnInit {
}
async onCopySuccess(evt) {
- const msg = await this._i18n.t('Copied');
- this._toastr.success(msg);
+ this.hoverTip = this._i18n.instant('Copied');
+ }
+
+ onHover(evt) {
+ this.hoverTip = this._i18n.instant('Click to copy');
}
async reconnect() {
- const oldConnectToken = this.view.connectToken
- const newConnectToken = await this._connectTokenSvc.exchange(oldConnectToken)
+ const oldConnectToken = this.view.connectToken;
+ const newConnectToken = await this._connectTokenSvc.exchange(oldConnectToken);
if (!newConnectToken) {
- return
+ return;
}
// 更新当前 view 的 connectToken
- this.view.connectToken = newConnectToken
- await this.ngOnInit()
+ this.view.connectToken = newConnectToken;
+ await this.ngOnInit();
// 刷新完成隐藏密码
this.passwordShow = this.passwordMask;
}
diff --git a/src/app/model.ts b/src/app/model.ts
index 695b3ee0..022eea48 100644
--- a/src/app/model.ts
+++ b/src/app/model.ts
@@ -267,6 +267,7 @@ export class GlobalSetting {
INTERFACE: any;
TERMINAL_OMNIDB_ENABLED: boolean;
TERMINAL_GRAPHICAL_RESOLUTION: string;
+ CONNECTION_TOKEN_REUSABLE: boolean;
}
export class Setting {
@@ -389,6 +390,8 @@ export class ConnectionToken {
account: string;
expire_time: number;
is_active: boolean;
+ date_expired: Date;
+ is_reusable: boolean;
from_ticket: {
id: string;
};
diff --git a/src/app/services/connect-token.ts b/src/app/services/connect-token.ts
index 53ab5224..128cf189 100644
--- a/src/app/services/connect-token.ts
+++ b/src/app/services/connect-token.ts
@@ -25,9 +25,10 @@ export class ConnectTokenService {
create(asset: Asset, connectInfo: ConnectData): Promise {
return new Promise((resolve, reject) => {
this._http.createConnectToken(asset, connectInfo).subscribe(
- (token: ConnectionToken) => {resolve(token);},
+ (token: ConnectionToken) => { resolve(token); },
(error) => {
- this.handleError({asset, connectInfo, code: error.error.code, tokenAction: 'create'}, resolve)
+ console.log('Error: ', error);
+ this.handleError({asset, connectInfo, code: error.error.code, tokenAction: 'create', error: error}, resolve );
}
);
});
@@ -38,9 +39,15 @@ export class ConnectTokenService {
this._http.exchangeConnectToken(connectToken.id).subscribe(
(token: ConnectionToken) => { resolve(token); },
(error) => {
- this.handleError({tokenID: connectToken.id, code: error.error.code, tokenAction: 'exchange'}, resolve)
+ this.handleError({tokenID: connectToken.id, code: error.error.code, tokenAction: 'exchange'}, resolve);
}
);
});
}
+
+ setReusable(connectToken: ConnectionToken, reusable: Boolean) {
+ const url = `/api/v1/authentication/connection-token/${connectToken.id}/`;
+ const data = {is_reusable: reusable};
+ return this._http.patch(url, data);
+ }
}
diff --git a/src/app/services/http.ts b/src/app/services/http.ts
index 6538bf6c..97a520e8 100644
--- a/src/app/services/http.ts
+++ b/src/app/services/http.ts
@@ -84,9 +84,9 @@ export class HttpService {
);
}
- patch(url: string, options?: any): Observable {
+ patch(url: string, body?: any, options?: any): Observable {
options = this.setOptionsCSRFToken(options);
- return this.http.patch(url, options).pipe(
+ return this.http.patch(url, body, options).pipe(
catchError(this.handleError.bind(this))
);
}
@@ -282,11 +282,13 @@ export class HttpService {
}
async handleConnectMethodExpiredError(error) {
- if (error.status === 400 && error.error && error.error.error && error.error.error.startsWith('Connect method')) {
- const errMsg = await this._i18n.t('The connection method is invalid, please refresh the page')
- alert(errMsg)
+ if (error.status === 400 ) {
+ if (error.error && error.error.error && error.error.error.startsWith('Connect method')) {
+ const errMsg = await this._i18n.t('The connection method is invalid, please refresh the page');
+ alert(errMsg);
+ }
}
- throw error
+ throw error;
}
getSmartEndpoint({ assetId, sessionId, token }, protocol ): Promise {
diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json
index bd20f267..1b45d30f 100644
--- a/src/assets/i18n/en.json
+++ b/src/assets/i18n/en.json
@@ -143,5 +143,7 @@
"Copy link": "Copy link",
"Login review approved": "Login review has been approved, connecting assets...",
"No account available": "No available accounts",
+ "Set reusable": "Set reusable",
+ "Re-use for a long time after opening": "Re-use for a long time after opening",
"The connection method is invalid, please refresh the page": "The connection method is invalid, please refresh the page"
}
diff --git a/src/assets/i18n/ja.json b/src/assets/i18n/ja.json
index 22268052..c887a98d 100644
--- a/src/assets/i18n/ja.json
+++ b/src/assets/i18n/ja.json
@@ -146,5 +146,7 @@
"Copy link": "リンクをコピーする",
"Login review approved": "ログイン監査に合格し、アセットを接続しています...",
"No account available": "アカウントがありません",
+ "Set reusable": "再利用可能な",
+ "Re-use for a long time after opening": "開いた後、長い間再利用する",
"The connection method is invalid, please refresh the page": "接続方法が無効です。ページを更新してください"
}
diff --git a/src/assets/i18n/zh.json b/src/assets/i18n/zh.json
index 34f8b889..91579797 100644
--- a/src/assets/i18n/zh.json
+++ b/src/assets/i18n/zh.json
@@ -124,7 +124,7 @@
"General": "基本配置",
"Applet connect method": "远程应用连接方式",
"Client": "客户端",
-
+
"Keyboard layout": "键盘布局",
"UK English keyboard layout": "UK English (Qwerty)",
"US English keyboard layout": "US English (Qwerty)",
@@ -146,6 +146,8 @@
"Copy link": "复制链接",
"Login review approved": "登录审核已通过, 正在连接资产...",
"No account available": "没有可用账号",
+ "Set reusable": "开启复用",
+ "Re-use for a long time after opening": "开启后该连接信息可长时间多次使用",
"The connection method is invalid, please refresh the page": "该连接方式已失效,请刷新页面"
}
|