diff --git a/i18n/messages-en.xtb b/i18n/messages-en.xtb index e6888ae2c977b0e87303fed6b0bb2a1a59a87593..f50c46c27d8edf142fbf975651b1b9e0a97b0736 100644 --- a/i18n/messages-en.xtb +++ b/i18n/messages-en.xtb @@ -10,6 +10,9 @@ Delete Edit All namespaces + Logged in with auth header + Default service account + Logged in with token About Cluster Config and storage @@ -23,7 +26,7 @@ Ingresses Internal error Jobs - Log in + Login Logs Namespaces Nodes @@ -43,6 +46,9 @@ Workloads Create an application or any Kubernetes resource Create + Control panel + Logout + Login Cluster Namespaces Pods @@ -463,8 +469,9 @@ Show less Username Password - Log in to Kubernetes Dashboard + Kubernetes Dashboard Token + Authentication method: Token Authentication failed. Please try again. Logs from diff --git a/i18n/messages-ja.xtb b/i18n/messages-ja.xtb index 0324151a43694df21793c15d026f3a72b81b1b1b..5102f92d93a69569fee5d2fae180f16608691b6c 100644 --- a/i18n/messages-ja.xtb +++ b/i18n/messages-ja.xtb @@ -14,6 +14,9 @@ を編集 すべてのネームスペース + Logged in with auth header + Default service account + Logged in with token バージョン情報 クラスター コンフィグとストレージ @@ -27,7 +30,7 @@ イングレス 内部エラー ジョブ - Log in + Login ログ ネームスペース ノード @@ -47,6 +50,9 @@ ワークロード アプリケーションまたはKubernetesリソースを作成 作成 + Control panel + Logout + Login クラスター ネームスペース ポッド @@ -479,8 +485,9 @@ Show less Username Password - Log in to Kubernetes Dashboard + Kubernetes Dashboard Token + Authentication method: Token Authentication failed. Please try again. Logs from diff --git a/i18n/messages-zh.xtb b/i18n/messages-zh.xtb index 62b5198a04d2f12b3b3d780cab426059bd7734d1..7da8b097212691005d1ef14ae23769b13685add0 100644 --- a/i18n/messages-zh.xtb +++ b/i18n/messages-zh.xtb @@ -10,6 +10,9 @@ 删除 编辑 所有命名空间 + Logged in with auth header + Default service account + Logged in with token 关于 集群 配置与存储 @@ -23,7 +26,7 @@ 访问权 内部错误 任务 - Log in + Login 日志 命名空间 节点 @@ -43,6 +46,9 @@ 工作负载 创建应用或任意 Kubernetes 资源 创建 + Control panel + Logout + Login 集群 命名空间 容器组 @@ -463,8 +469,9 @@ 隐藏 Username Password - Log in to Kubernetes Dashboard + Kubernetes Dashboard Token + Authentication method: Token Authentication failed. Please try again. 容器日志 diff --git a/src/app/frontend/chrome/chrome.html b/src/app/frontend/chrome/chrome.html index 5b4ca098800fd3ecc228a21735c03d5a217f253b..9d726845160f6471734d662a17af137638956b2a 100644 --- a/src/app/frontend/chrome/chrome.html +++ b/src/app/frontend/chrome/chrome.html @@ -28,11 +28,13 @@ limitations under the License.
add - + [[Create an application or any Kubernetes resource|Tooltip for global action bar create button tooltip.]] [[Create|Label for global action bar create button.]] +
|
+
diff --git a/src/app/frontend/chrome/chrome.scss b/src/app/frontend/chrome/chrome.scss index b70e8814f6014496c894433e525120630c9fa931..596eecbad64f6b64d3ecb48faa8a032724c9ce9f 100644 --- a/src/app/frontend/chrome/chrome.scss +++ b/src/app/frontend/chrome/chrome.scss @@ -208,3 +208,11 @@ $chip-margin: 0 $baseline-grid ($baseline-grid / 2) 0; background-color: $delicate; } } + +.kd-action-separator { + cursor: default; + font-weight: $light-font-weight; + line-height: 5 * $baseline-grid; + padding: 0 $baseline-grid; + user-select: none; +} diff --git a/src/app/frontend/chrome/controlpanel/component.js b/src/app/frontend/chrome/controlpanel/component.js new file mode 100644 index 0000000000000000000000000000000000000000..03e272a2ebe2e722713baf31ccc9653d13a0b42b --- /dev/null +++ b/src/app/frontend/chrome/controlpanel/component.js @@ -0,0 +1,111 @@ +// Copyright 2017 The Kubernetes Dashboard Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @final + */ +export class ControlPanelController { + /** + * @param {!ui.router.$state} $state + * @param {!angular.$log} $log + * @param {!./../../common/auth/service.AuthService} kdAuthService + * @ngInject + */ + constructor($state, $log, kdAuthService) { + /** @private {!ui.router.$state} */ + this.state_ = $state; + /** @private {!angular.$log} */ + this.log_ = $log; + /** @private {!./../../common/auth/service.AuthService} */ + this.kdAuthService_ = kdAuthService; + /** @private {!backendApi.LoginStatus} */ + this.loginStatus_; + /** @export {boolean} */ + this.isLoginStatusLoaded = false; + } + + /** + * Checks if user is logged in using Dashboard log in mechanism and sets class variable after + * backend responds. + */ + $onInit() { + this.kdAuthService_.getLoginStatus().then( + (/** @type {!backendApi.LoginStatus} */ loginStatus) => { + this.loginStatus_ = loginStatus; + this.isLoginStatusLoaded = true; + }, + (err) => { + this.log_.error(err); + }); + } + + /** + * Returns current authentication status string. + * + * @return {string} + * @export + */ + getAuthStatus() { + if (this.loginStatus_.headerPresent) { + /** @type {string} @desc Login status displayed when authorization header is used. */ + let MSG_AUTH_STATUS_HEADER = goog.getMsg('Logged in with auth header'); + return MSG_AUTH_STATUS_HEADER; + } + if (this.loginStatus_.tokenPresent) { + /** @type {string} @desc Login status displayed when token is used. */ + let MSG_AUTH_STATUS_TOKEN = goog.getMsg('Logged in with token'); + return MSG_AUTH_STATUS_TOKEN; + } + /** @type {string} @desc Login status displayed when default service account is used. */ + let MSG_AUTH_STATUS_SKIPPED = goog.getMsg('Default service account'); + return MSG_AUTH_STATUS_SKIPPED; + } + + /** + * Checks if authentication was skipped and default service account is used. + * + * @return {boolean} + * @export + */ + isAuthSkipped() { + return !this.kdAuthService_.isLoginPageEnabled(); + } + + /** + * Checks if user is logged in. + * + * @return {boolean} + * @export + */ + isLoggedIn() { + return this.loginStatus_ && (this.loginStatus_.headerPresent || this.loginStatus_.tokenPresent); + } + + /** + * Logs out current user. + * + * @export + */ + logout() { + this.kdAuthService_.logout(); + } +} + +/** + * @type {!angular.Component} + */ +export const controlPanelComponent = { + controller: ControlPanelController, + templateUrl: 'chrome/controlpanel/controlpanel.html', +}; diff --git a/src/app/frontend/chrome/controlpanel/controlpanel.html b/src/app/frontend/chrome/controlpanel/controlpanel.html new file mode 100644 index 0000000000000000000000000000000000000000..7c39ba93e0cc30f57f642f5eba205f1f82d25536 --- /dev/null +++ b/src/app/frontend/chrome/controlpanel/controlpanel.html @@ -0,0 +1,58 @@ + + + + + account_circle + + + + + + [[Control panel|Tooltip for the control panel displayed in the right top corner.]] + + + + + +
+ {{$ctrl.getAuthStatus()}} +
+ + +
+
+ + + + [[Logout|Logout menu item.]] + + + + + [[Login|Login menu item.]] + + +
+
diff --git a/src/app/frontend/chrome/controlpanel/controlpanel.scss b/src/app/frontend/chrome/controlpanel/controlpanel.scss new file mode 100644 index 0000000000000000000000000000000000000000..bb3a10160601f5178f1764c7ed3d7628f9e3adaf --- /dev/null +++ b/src/app/frontend/chrome/controlpanel/controlpanel.scss @@ -0,0 +1,42 @@ +// Copyright 2017 The Kubernetes Dashboard Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +@import '../../variables'; + +.kd-auth-status { + font-weight: $bold-font-weight; + text-transform: uppercase; +} + +.kd-auth-status-spinner { + margin: 0 auto; +} + +.kd-cross-line-blue { + stroke: $primary; + stroke-width: 2; +} + +.kd-cross-line-white { + stroke: $content-background; + stroke-width: 4; +} + +.kd-cross-style { + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; +} diff --git a/src/app/frontend/chrome/module.js b/src/app/frontend/chrome/module.js index 07f484e39a0ffbeba52e77efc71d5c85e7d0a43a..e60f2342c4607a0b90b5ff35c5e67b36c1d8243e 100644 --- a/src/app/frontend/chrome/module.js +++ b/src/app/frontend/chrome/module.js @@ -16,6 +16,7 @@ import componentsModule from 'common/components/module'; import namespaceModule from 'common/namespace/module'; import {chromeComponent} from './component'; +import {controlPanelComponent} from './controlpanel/component'; import navModule from './nav/module'; import {searchComponent} from './search/component'; import stateConfig from './stateconfig'; @@ -35,4 +36,5 @@ export default angular ]) .config(stateConfig) .component('kdChrome', chromeComponent) + .component('kdControlPanel', controlPanelComponent) .component('kdSearch', searchComponent); diff --git a/src/app/frontend/common/auth/service.js b/src/app/frontend/common/auth/service.js index 18922027166817c60b82d5e9ed9297f140dadb47..611e480ece5b4a777bf2fd2b0795fe8cd229aab3 100644 --- a/src/app/frontend/common/auth/service.js +++ b/src/app/frontend/common/auth/service.js @@ -64,6 +64,14 @@ export class AuthService { this.cookies_.put(this.tokenCookieName_, token); } + /** + * Cleans cookies, but does not remove them. + */ + cleanAuthCookies() { + this.setTokenCookie_(''); + this.skipLoginPage(false); + } + /** * Sends a login request to the backend with filled in login spec structure. * @@ -105,6 +113,14 @@ export class AuthService { return deferred.promise; } + /** + * Cleans cookies and goes to login page. + */ + logout() { + this.cleanAuthCookies(); + this.state_.go(loginState); + } + /** * Returns promise that returns TargetState once backend decides whether user is logged in or not. * User is then redirected to target state (if logged in) or to login page. @@ -119,15 +135,6 @@ export class AuthService { */ isLoggedIn(transition) { let deferred = this.q_.defer(); - let token = this.cookies_.get(this.tokenCookieName_) || ''; - let resource = this.resource_('api/v1/login/status', {}, { - get: { - method: 'GET', - headers: { - [this.tokenHeaderName_]: token, - }, - }, - }); // Skip log in check if user is going to login page already or has chosen to skip it. if (!this.isLoginPageEnabled() || transition.to().name === loginState || @@ -136,7 +143,7 @@ export class AuthService { return deferred.promise; } - resource.get( + this.getLoginStatus().then( (/** @type {!backendApi.LoginStatus} */ loginStatus) => { if (loginStatus.headerPresent || loginStatus.tokenPresent) { deferred.resolve(true); @@ -154,6 +161,24 @@ export class AuthService { return deferred.promise; } + /** + * @return {!angular.$q.Promise} + */ + getLoginStatus() { + let token = this.cookies_.get(this.tokenCookieName_) || ''; + return this + .resource_('api/v1/login/status', {}, { + get: { + method: 'GET', + headers: { + [this.tokenHeaderName_]: token, + }, + }, + }) + .get() + .$promise; + } + /** * @param {boolean} skip */ diff --git a/src/app/frontend/login/login.html b/src/app/frontend/login/login.html index f7470d5e0f5611e9994c09322134c6f273582f3b..cf8897435d4e1af4c51785caaaf3d10e1a23c188 100644 --- a/src/app/frontend/login/login.html +++ b/src/app/frontend/login/login.html @@ -22,13 +22,13 @@ limitations under the License. novalidate> - [[Log in to Kubernetes Dashboard|Title shown on login page on login card]] + [[Kubernetes Dashboard|Title shown on login page on login card]] - diff --git a/src/app/frontend/login/login.scss b/src/app/frontend/login/login.scss index 7f8582156e48926f3c175feed5072d4e35f9f6a2..b0e05b40ffb5f7f3461c39c41ab0c57ef4387f6a 100644 --- a/src/app/frontend/login/login.scss +++ b/src/app/frontend/login/login.scss @@ -26,6 +26,14 @@ kd-login { margin: auto; padding-top: 2 * $baseline-grid; width: 50%; + + h1 { + background-color: $primary; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + color: $content-background; + margin: -1px; + } } .kd-login-card-content { @@ -41,6 +49,10 @@ kd-login { } } +.kd-option-title { + margin-bottom: 2 * $baseline-grid; +} + .kd-option-container { padding-top: $baseline-grid / 2; } diff --git a/src/app/frontend/login/options.html b/src/app/frontend/login/options.html index 7a1a4535b3b55d3b271e39a4c22cbca3c72015cc..d384074eb156235d189281631a0fcfc2a8b9a93d 100644 --- a/src/app/frontend/login/options.html +++ b/src/app/frontend/login/options.html @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. --> +
[[Authentication method:|Label of authentication method selector.]]
- [[Resource Status|Label 'Resource Status' for the allocated resources section.]] - -
-
-
-
- Pods -
-
- stop - [[Running|Label 'Running' for the pod statistics graphs legend.]] - + [[Resource Status|Label 'Resource Status' for the allocated resources section.]] + +
+
+
+
+ Pods +
+
+ stop + [[Running|Label 'Running' for the pod statistics graphs legend.]] + {{$ctrl.podStats.success}} -
-
- stop - [[Pending|Label 'Pending' for the pod statistics graphs legend.]] - +
+
+ stop + [[Pending|Label 'Pending' for the pod statistics graphs legend.]] + {{$ctrl.podStats.pending}} -
-
- stop - [[Failed|Label 'Failed' for the pod statistics graphs legend.]] - +
+
+ stop + [[Failed|Label 'Failed' for the pod statistics graphs legend.]] + {{$ctrl.podStats.failed}} -
-
- - -
+
+ + +
+
diff --git a/src/app/frontend/secret/detail/detail.html b/src/app/frontend/secret/detail/detail.html index 311809659e2941941269e6b98acbc3ac8a07647a..e73a6f7bd152a236974046a900fcfee55c35e10a 100644 --- a/src/app/frontend/secret/detail/detail.html +++ b/src/app/frontend/secret/detail/detail.html @@ -32,7 +32,7 @@ limitations under the License. width="40px" height="40px" viewBox="0 0 40 40" - style="left: 0; top:0; position:absolute; bottom:0, right: 0;"> + style="left: 0; top:0; position:absolute; bottom:0; right: 0;">