From 8f68d22572c8ee91601e1acd2d7dce5c6e0f2641 Mon Sep 17 00:00:00 2001 From: Richard Cox Date: Fri, 24 Jul 2020 08:57:05 +0100 Subject: [PATCH] Merge upstream (#414) * Improve recent and favourites display (#4421) * Improve recent and favourites display * Remove debug logging * Remove debug logging/subscription leak * Unit test fix * Tweaks following review * Changes following review - favourite & recent icon changes Co-authored-by: Richard Cox * Add line-height to favourite and recent entity labels (#4438) - missed out from another PR following review * Autoscaler e2e tests: Give better failure error when the test can't find the scaling row (#4424) * Improve autoscaler e2e tests * Remove duplicate fail statement * Helm Chart: Remove encryption key volume (#4355) * Remove encryption key volume * Remove encrpytion key volume migration from config-init job * Improve the logout experience (#4439) * Add support for including breaking changes in the changelog * Improve the logout experience * Fix unit tests * Add request for version info to github issues template (#4443) * Merge downstream (#4441) * Merge src/frontend from downstream * Merge src/jetstream from jetstream * Remove examples/custom-src * Merge deploy from downstream Does not include changes to - deploy/all-in-one/* - deploy/aio-entrypoint.sh - deploy/Dockerfile.all-in-one * Merge build from downstream * Add missing merge items from deploy * Updates to package-lock * Remove fdescribe * Fix e2e core tests * Remove favicon from packages/core/src * Changes following review * Show all favorites for an endpoint favorite if there is only one (#4440) * Show all favorites for the endpoint favorite if there is only one * Missing changes * Merge downstream - JSON Viewer with dark mode & Header Fixes (#4444) * Fix json-viewer dark mode * Fix profile page and side nav top position following header diet - Fix side nav top position - Update fix for profile page to also work in non-desktop mode * Fix issues with tests not running if build upload fails (#4453) * Fix issues with tests not running if build upload fails * Fix script * One more fix for script * Fix white space at start of file * Fix log out page when there's a custom log in page * Fix log out page given previous commit changes Co-authored-by: Neil MacDougall --- deploy/ci/travis/e2e-build-script.sh | 19 +-- deploy/ci/travis/e2e-mc-helper.sh | 3 +- deploy/containers/config-init/config-init.sh | 30 +---- .../console/templates/config-init.yaml | 16 --- .../kubernetes/console/templates/volumes.yaml | 27 +--- docs/issue_template.md | 8 +- package-lock.json | 115 ++++++++++-------- .../packages/core/sass/_all-theme.scss | 3 +- .../packages/core/sass/mat-desktop.scss | 9 ++ src/frontend/packages/core/src/app.routing.ts | 16 ++- .../src/core/extension/extension-service.ts | 3 +- .../log-out-dialog.component.spec.ts | 15 ++- .../log-out-dialog.component.ts | 10 +- src/frontend/packages/core/src/favicon.ico | Bin 15086 -> 0 bytes .../core/src/features/login/login.module.ts | 8 +- .../core/src/features/login/login.routing.ts | 15 --- .../logout-page/logout-page.component.html | 17 +++ .../logout-page/logout-page.component.scss | 14 +++ .../logout-page/logout-page.component.spec.ts | 42 +++++++ .../logout-page/logout-page.component.ts | 35 ++++++ .../profile-info/profile-info.component.scss | 4 +- .../app-action-monitor.component.html | 2 +- .../app-action-monitor.component.ts | 10 +- .../favorites-entity-list.component.html | 2 +- .../favorites-entity-list.component.ts | 9 +- .../favorites-global-list.component.html | 3 +- .../favorites-meta-card.component.scss | 1 + .../json-viewer.component.theme.scss | 15 +++ .../page-header/page-header.component.ts | 3 +- .../recent-entities.component.scss | 1 + .../store/src/reducers/auth.reducer.ts | 6 + .../suse-extensions/src/custom/suse.module.ts | 16 +-- src/frontend/packages/suse-theme/_index.scss | 2 +- .../application-autoscaler-e2e.spec.ts | 11 ++ 34 files changed, 299 insertions(+), 191 deletions(-) delete mode 100644 src/frontend/packages/core/src/favicon.ico delete mode 100644 src/frontend/packages/core/src/features/login/login.routing.ts create mode 100644 src/frontend/packages/core/src/features/login/logout-page/logout-page.component.html create mode 100644 src/frontend/packages/core/src/features/login/logout-page/logout-page.component.scss create mode 100644 src/frontend/packages/core/src/features/login/logout-page/logout-page.component.spec.ts create mode 100644 src/frontend/packages/core/src/features/login/logout-page/logout-page.component.ts create mode 100644 src/frontend/packages/core/src/shared/components/json-viewer/json-viewer.component.theme.scss diff --git a/deploy/ci/travis/e2e-build-script.sh b/deploy/ci/travis/e2e-build-script.sh index 48f58af62f..757bd7dd42 100755 --- a/deploy/ci/travis/e2e-build-script.sh +++ b/deploy/ci/travis/e2e-build-script.sh @@ -50,6 +50,7 @@ function tryGetExistingBuild() { fi } +# Need S3 endpoint - if we don't have it, we don't have the Travis env vars if [ -n "${AWS_ENDPOINT}" ]; then tryGetExistingBuild fi @@ -68,14 +69,16 @@ else npm run build npm run build-backend - set +e - tar cvfz ${GZIP_NAME} dist/* src/jetstream/jetstream + # Only try to upload if we have the S3 configuration + if [ -n "${AWS_ENDPOINT}" ]; then + set +e + tar cvfz ${GZIP_NAME} dist/* src/jetstream/jetstream - # Upload - mc cp -q --insecure ${GZIP_NAME} ${MC_HOST}/${S3_BUILDS_BUCKET} - - # Ignore error from uploading - should not fail build if we can't upload the build archive - # This just means we won't be able to us this cache next build - exit 0 + # Upload + mc cp -q --insecure ${GZIP_NAME} ${MC_HOST}/${S3_BUILDS_BUCKET} + # Ignore error from uploading - should not fail build if we can't upload the build archive + # This just means we won't be able to us this cache next build + echo "Uploaded builds" + fi fi diff --git a/deploy/ci/travis/e2e-mc-helper.sh b/deploy/ci/travis/e2e-mc-helper.sh index 4dbb3109b6..5201e0a46f 100644 --- a/deploy/ci/travis/e2e-mc-helper.sh +++ b/deploy/ci/travis/e2e-mc-helper.sh @@ -1,6 +1,7 @@ # Helper for mc command -mc version > /dev/null +# Check if mc command is available (don't log error if it is not) +mc version > /dev/null 2>&1 if [ $? -eq 0 ]; then echo "mc command already installed and confgiured" else diff --git a/deploy/containers/config-init/config-init.sh b/deploy/containers/config-init/config-init.sh index 31c7ac8876..d5bc58a4b5 100755 --- a/deploy/containers/config-init/config-init.sh +++ b/deploy/containers/config-init/config-init.sh @@ -11,10 +11,6 @@ echo "RELEASE_NAME : ${RELEASE_NAME}" echo "RELEASE_REVISION : ${RELEASE_REVISION}" echo "IS_UPGRADE : ${IS_UPGRADE}" echo "CONSOLE_TLS_SECRET_NAME : ${CONSOLE_TLS_SECRET_NAME}" -echo "ENCRYPTION_KEY_VOLUME : ${ENCRYPTION_KEY_VOLUME}" -echo "ENCRYPTION_KEY_FILENAME : ${ENCRYPTION_KEY_FILENAME}" -echo "CONSOLE_PROXY_CERT_PATH : ${CONSOLE_PROXY_CERT_PATH}" -echo "CONSOLE_PROXY_CERT_KEY_PATH : ${CONSOLE_PROXY_CERT_KEY_PATH}" echo "" echo "============================================" echo "" @@ -44,15 +40,6 @@ EOF } function generateCert { - if [ -n "${CONSOLE_PROXY_CERT_PATH}" ] && [ -n "${CONSOLE_PROXY_CERT_KEY_PATH}" ]; then - if [ -f "${CONSOLE_PROXY_CERT_PATH}" ] && [ -f "${CONSOLE_PROXY_CERT_KEY_PATH}" ]; then - echo "Found existing certificate on encryption key volume - going to use it" - CERT_CRT=$(cat ${CONSOLE_PROXY_CERT_PATH} | base64 -w 0) - CERT_KEY=$(cat ${CONSOLE_PROXY_CERT_KEY_PATH} | base64 -w 0) - return - fi - fi - echo "Using cert generator to generate a self-signed certificate ..." export CERTS_PATH=./certs export DEV_CERTS_DOMAIN=tls @@ -97,20 +84,9 @@ if [ $EXISTS -eq 0 ]; then else echo "Fresh installation - generating a new Encryption Key secret" - # Migrate existing key from the legacy encryption key volume if there is one - if [ ${ENCRYPTION_KEY_VOLUME} -a ${ENCRYPTION_KEY_FILENAME} ]; then - ekFile="${ENCRYPTION_KEY_VOLUME}/${ENCRYPTION_KEY_FILENAME}" - if [ -f "${ekFile}" ]; then - echo "Found encryption key file on the legacy encryption key volume" - KEY=$(cat ${ekFile} | base64 -w 0) - fi - fi - - if [ -z $KEY ]; then - # Generate a random encryption key - echo "Generating a new Encryption Key ..." - KEY=$(openssl enc -aes-256-cbc -k secret -P -md sha1 | grep key | cut -d '=' -f2 | base64 -w 0) - fi + # Generate a random encryption key + echo "Generating a new Encryption Key ..." + KEY=$(openssl enc -aes-256-cbc -k secret -P -md sha1 | grep key | cut -d '=' -f2 | base64 -w 0) # We will create a new secret for the encryption key cat << EOF > create-key-secret.yaml diff --git a/deploy/kubernetes/console/templates/config-init.yaml b/deploy/kubernetes/console/templates/config-init.yaml index 0cc82ee389..6ed17f1e88 100644 --- a/deploy/kubernetes/console/templates/config-init.yaml +++ b/deploy/kubernetes/console/templates/config-init.yaml @@ -118,26 +118,14 @@ spec: value: "{{ .Chart.AppVersion }}" - name: "HELM_CHART" value: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" - - name: ENCRYPTION_KEY_VOLUME - value: "/{{ .Release.Name }}-encryption-key-volume" - - name: ENCRYPTION_KEY_FILENAME - value: key - name: CONSOLE_TLS_SECRET_NAME value: "{{ default "" .Values.console.tlsSecretName }}" - - name: CONSOLE_PROXY_CERT_PATH - value: "/{{ .Release.Name }}-encryption-key-volume/console.crt" - - name: CONSOLE_PROXY_CERT_KEY_PATH - value: "/{{ .Release.Name }}-encryption-key-volume/console.key" image: {{.Values.kube.registry.hostname}}/{{.Values.kube.organization}}/{{default "stratos-config-init" .Values.images.configInit}}:{{.Values.consoleVersion}} command: ["/config-init.sh"] imagePullPolicy: {{.Values.imagePullPolicy}} livenessProbe: ~ name: "config-init" readinessProbe: ~ - volumeMounts: - - mountPath: "/{{ .Release.Name }}-encryption-key-volume" - name: "{{ .Release.Name }}-encryption-key-volume" - readOnly: true {{- if and .Values.kube.registry.username .Values.kube.registry.password }} imagePullSecrets: - name: {{.Values.dockerRegistrySecret}} @@ -147,10 +135,6 @@ spec: serviceAccountName: "config-init" {{- end }} terminationGracePeriodSeconds: 600 - volumes: - - name: "{{ .Release.Name }}-encryption-key-volume" - persistentVolumeClaim: - claimName: "{{ .Release.Name }}-encryption-key-volume" --- {{- if .Values.autoCleanup }} # Cleanup job will delete the created secret when the release is deleted diff --git a/deploy/kubernetes/console/templates/volumes.yaml b/deploy/kubernetes/console/templates/volumes.yaml index 9e0c9b3500..5483e79ae9 100644 --- a/deploy/kubernetes/console/templates/volumes.yaml +++ b/deploy/kubernetes/console/templates/volumes.yaml @@ -1,31 +1,6 @@ ---- -apiVersion: v1 -kind: PersistentVolumeClaim -metadata: - name: "{{ .Release.Name }}-encryption-key-volume" - labels: - app.kubernetes.io/name: "stratos" - app.kubernetes.io/instance: "{{ .Release.Name }}" - app.kubernetes.io/version: "{{ .Chart.AppVersion }}" - app.kubernetes.io/component: "console-encryption-volume" - helm.sh/chart: "{{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}" - annotations: - {{- if .Values.storageClass }} - volume.beta.kubernetes.io/storage-class: {{ .Values.storageClass | quote }} - {{- else if .Values.kube.storage_class.persistent }} - volume.beta.kubernetes.io/storage-class: {{ .Values.kube.storage_class.persistent | quote }} - {{- else }} - volume.alpha.kubernetes.io/storage-class: default - {{- end }} -spec: - accessModes: - - ReadWriteOnce - resources: - requests: - storage: 20Mi ---- {{- if (not .Values.mariadb.external) }} {{- if and .Values.mariadb.persistence.enabled (not .Values.mariadb.persistence.existingClaim) }} +--- kind: PersistentVolumeClaim apiVersion: v1 metadata: diff --git a/docs/issue_template.md b/docs/issue_template.md index 9950dfe804..dffaf1add3 100644 --- a/docs/issue_template.md +++ b/docs/issue_template.md @@ -1,4 +1,8 @@ +### Stratos Version + + + ### Frontend Deployment type @@ -21,11 +25,11 @@ ### Actual behaviour -### Steps to reproduce the behavior +### Steps to reproduce the behaviour ### Log output covering before error and any error statements ``` -Insert log hereCopy +Insert your log here ``` diff --git a/package-lock.json b/package-lock.json index 8a0a8847d4..fdfea562d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6995,7 +6995,7 @@ }, "duplexer": { "version": "0.1.1", - "resolved": "http://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", "dev": true }, @@ -7698,7 +7698,7 @@ }, "event-stream": { "version": "3.3.4", - "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", "dev": true, "requires": { @@ -10808,6 +10808,66 @@ "integrity": "sha512-nCeAiw37MIMA9w9IXso7bRaLl+c/ef3wnxsoSAlYrzS+Ot0zTG6nU8G/cIfGkqpkjX2wNaIW9RFG0TwIFnG6bA==", "dev": true }, + "jasmine-protractor-browser-log-reporter": { + "version": "github:cf-stratos/jasmine-protractor-browser-log-reporter#5c9170221db6562f6f2eb128f0652e1c3cf2d668", + "from": "github:cf-stratos/jasmine-protractor-browser-log-reporter", + "dev": true, + "requires": { + "chalk": "^4.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, "jasmine-spec-reporter": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-5.0.1.tgz", @@ -12022,7 +12082,7 @@ }, "map-stream": { "version": "0.1.0", - "resolved": "http://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", "dev": true }, @@ -14815,7 +14875,7 @@ }, "pause-stream": { "version": "0.0.11", - "resolved": "http://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", "dev": true, "requires": { @@ -15915,49 +15975,6 @@ } } }, - "protractor-console": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/protractor-console/-/protractor-console-3.0.0.tgz", - "integrity": "sha512-2BTh751CMjEAMxuZXb86jvs0TDWjvCk7fCnKTyb5vX/KE5f+olTeVCmcFm+4Aretpc6q/6yryuSJ8wjgL9QTKw==", - "dev": true, - "requires": { - "chalk": "^1.1.0", - "lodash": "^3.10.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "lodash": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", - "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", - "dev": true - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } - } - }, "proxy-addr": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", @@ -18398,7 +18415,7 @@ }, "split": { "version": "0.3.3", - "resolved": "http://registry.npmjs.org/split/-/split-0.3.3.tgz", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", "dev": true, "requires": { @@ -18575,7 +18592,7 @@ }, "stream-combiner": { "version": "0.0.4", - "resolved": "http://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", "dev": true, "requires": { diff --git a/src/frontend/packages/core/sass/_all-theme.scss b/src/frontend/packages/core/sass/_all-theme.scss index c611d62d9a..c929676d41 100644 --- a/src/frontend/packages/core/sass/_all-theme.scss +++ b/src/frontend/packages/core/sass/_all-theme.scss @@ -18,7 +18,7 @@ @import '../src/shared/components/list/list-table/table-row/table-row.component.theme'; @import '../src/shared/components/no-content-message/no-content-message.component.theme'; @import '../src/shared/components/boolean-indicator/boolean-indicator.component.theme'; - +@import '../src/shared/components/json-viewer/json-viewer.component.theme'; @import '../src/shared/components/loading-page/loading-page.component.theme'; @import '../src/shared/components/log-viewer/log-viewer.component.theme'; @import '../src/shared/components/chips/chips.component.theme'; @@ -126,5 +126,6 @@ @include restore-endpoints-theme($theme, $app-theme); @include metrics-component-theme($theme, $app-theme); @include intro-screen-theme($theme, $app-theme); + @include app-json-view-theme($theme, $app-theme); } diff --git a/src/frontend/packages/core/sass/mat-desktop.scss b/src/frontend/packages/core/sass/mat-desktop.scss index f47438d989..3538518e13 100644 --- a/src/frontend/packages/core/sass/mat-desktop.scss +++ b/src/frontend/packages/core/sass/mat-desktop.scss @@ -107,4 +107,13 @@ $desktop-toggle-button-item-height: $desktop-menu-item-height - 2px; flex: 0 0 $desktop-page-header-height; height: $desktop-page-header-height; } + + mat-drawer.dashboard__side_preview { + top: $desktop-page-header-height; + height: calc(100vw - #{$desktop-page-header-height} - 1px); + } + + app-profile-info .user-profile { + top: $desktop-page-header-height; + } } diff --git a/src/frontend/packages/core/src/app.routing.ts b/src/frontend/packages/core/src/app.routing.ts index 9441eb4583..2020929d92 100644 --- a/src/frontend/packages/core/src/app.routing.ts +++ b/src/frontend/packages/core/src/app.routing.ts @@ -10,6 +10,8 @@ import { PageNotFoundComponentComponent } from './core/page-not-found-component/ import { CustomRoutingImportModule } from './custom-import.module'; import { DashboardBaseComponent } from './features/dashboard/dashboard-base/dashboard-base.component'; import { HomePageComponent } from './features/home/home/home-page.component'; +import { LoginPageComponent } from './features/login/login-page/login-page.component'; +import { LogoutPageComponent } from './features/login/logout-page/logout-page.component'; import { NoEndpointsNonAdminComponent } from './features/no-endpoints-non-admin/no-endpoints-non-admin.component'; import { DomainMismatchComponent } from './features/setup/domain-mismatch/domain-mismatch.component'; import { LocalAccountWizardComponent } from './features/setup/local-account-wizard/local-account-wizard.component'; @@ -40,7 +42,19 @@ const appRoutes: Routes = [ }, { path: 'upgrade', component: UpgradePageComponent }, { path: 'domainMismatch', component: DomainMismatchComponent }, - { path: 'login', loadChildren: () => import('./features/login/login.module').then(m => m.LoginModule) }, + { + path: 'login', + children: [ + { + path: '', + component: LoginPageComponent + }, + { + path: 'logout', + component: LogoutPageComponent + }, + ] + }, { path: '', component: DashboardBaseComponent, diff --git a/src/frontend/packages/core/src/core/extension/extension-service.ts b/src/frontend/packages/core/src/core/extension/extension-service.ts index b43f57a0bf..c2d198c7d6 100644 --- a/src/frontend/packages/core/src/core/extension/extension-service.ts +++ b/src/frontend/packages/core/src/core/extension/extension-service.ts @@ -167,7 +167,8 @@ export class ExtensionService { if (extensionMetadata.loginComponent) { // Override the component used for the login route - const loginRoute = routeConfig.find(r => r.path === 'login') || {}; + const loginRouteRoot = routeConfig.find(r => r.path === 'login') || { children: [] }; + const loginRoute = loginRouteRoot.children.find(c => c.path === ''); loginRoute.component = extensionMetadata.loginComponent; needsReset = true; } diff --git a/src/frontend/packages/core/src/core/log-out-dialog/log-out-dialog.component.spec.ts b/src/frontend/packages/core/src/core/log-out-dialog/log-out-dialog.component.spec.ts index b497e9540e..7d15220d14 100644 --- a/src/frontend/packages/core/src/core/log-out-dialog/log-out-dialog.component.spec.ts +++ b/src/frontend/packages/core/src/core/log-out-dialog/log-out-dialog.component.spec.ts @@ -1,19 +1,21 @@ import { async, ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing'; import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { Store } from '@ngrx/store'; +import { Router } from '@angular/router'; +import { RouterTestingModule } from '@angular/router/testing'; import { createBasicStoreModule } from '@stratosui/store/testing'; import { CoreTestingModule } from '../../../test-framework/core-test.modules'; import { SharedModule } from '../../shared/shared.module'; import { CoreModule } from '../core.module'; +import { RouteModule } from './../../app.routing'; import { LogOutDialogComponent } from './log-out-dialog.component'; describe('LogOutDialogComponent', () => { let component: LogOutDialogComponent; let fixture: ComponentFixture; let element: HTMLElement; - let store: any; + let router: any; class MatDialogRefMock { } @@ -30,6 +32,8 @@ describe('LogOutDialogComponent', () => { ], imports: [ CoreModule, + RouterTestingModule, + RouteModule, SharedModule, MatDialogModule, NoopAnimationsModule, @@ -42,7 +46,7 @@ describe('LogOutDialogComponent', () => { beforeEach(() => { fixture = TestBed.createComponent(LogOutDialogComponent); - store = TestBed.get(Store); + router = TestBed.get(Router); component = fixture.componentInstance; fixture.detectChanges(); element = fixture.nativeElement; @@ -52,8 +56,8 @@ describe('LogOutDialogComponent', () => { expect(component).toBeTruthy(); }); - it('should dispatch logout action after countdown', fakeAsync(() => { - const spy = spyOn(store, 'dispatch'); + it('should naivgate after countdown', fakeAsync(() => { + const spy = spyOn(router, 'navigate'); component.data = { expiryDate: Date.now() + 1000, @@ -65,6 +69,7 @@ describe('LogOutDialogComponent', () => { expect(spy).not.toHaveBeenCalled(); tick(1500); expect(spy).toHaveBeenCalled(); + expect(spy).toHaveBeenCalledWith(['/login/logout']); })); afterEach(() => { diff --git a/src/frontend/packages/core/src/core/log-out-dialog/log-out-dialog.component.ts b/src/frontend/packages/core/src/core/log-out-dialog/log-out-dialog.component.ts index 477fc342d5..34574f7c51 100644 --- a/src/frontend/packages/core/src/core/log-out-dialog/log-out-dialog.component.ts +++ b/src/frontend/packages/core/src/core/log-out-dialog/log-out-dialog.component.ts @@ -1,12 +1,9 @@ import { Component, Inject, OnDestroy, OnInit, Optional } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { Store } from '@ngrx/store'; +import { Router } from '@angular/router'; import { interval, Subscription } from 'rxjs'; import { tap } from 'rxjs/operators'; -import { Logout } from '../../../../store/src/actions/auth.actions'; -import { GeneralEntityAppState } from '../../../../store/src/app-state'; - @Component({ selector: 'app-log-out-dialog', templateUrl: './log-out-dialog.component.html', @@ -16,7 +13,8 @@ export class LogOutDialogComponent implements OnInit, OnDestroy { constructor( public dialogRef: MatDialogRef, @Optional() @Inject(MAT_DIALOG_DATA) public data: any, - private store: Store) { } + private router: Router + ) { } private autoLogout: Subscription; private countDown: number; @@ -33,7 +31,7 @@ export class LogOutDialogComponent implements OnInit, OnDestroy { this.countDown = this.calcCountdown(); if (this.countDown <= 0) { this.autoLogout.unsubscribe(); - this.store.dispatch(new Logout()); + this.router.navigate(['/login/logout']); } else { this.percentage = ((this.countdownTotal - this.countDown) / this.countdownTotal) * 100; } diff --git a/src/frontend/packages/core/src/favicon.ico b/src/frontend/packages/core/src/favicon.ico deleted file mode 100644 index 21f49bc43b08f557f085d0ba170f388e5956373f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15086 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 + + +
+
An error occurred logging out
+ +
+ +
+
Logging out
+
+ +
+
+
+
+ diff --git a/src/frontend/packages/core/src/features/login/logout-page/logout-page.component.scss b/src/frontend/packages/core/src/features/login/logout-page/logout-page.component.scss new file mode 100644 index 0000000000..c1b0168e6d --- /dev/null +++ b/src/frontend/packages/core/src/features/login/logout-page/logout-page.component.scss @@ -0,0 +1,14 @@ +.logout { + &__card { + padding: 0; + width: 300px; + } + &__body { + padding: 24px; + text-align: center; + } + &__msg { + font-size: 18px; + padding-bottom: 20px; + } +} diff --git a/src/frontend/packages/core/src/features/login/logout-page/logout-page.component.spec.ts b/src/frontend/packages/core/src/features/login/logout-page/logout-page.component.spec.ts new file mode 100644 index 0000000000..fff7bac83e --- /dev/null +++ b/src/frontend/packages/core/src/features/login/logout-page/logout-page.component.spec.ts @@ -0,0 +1,42 @@ +import { CommonModule } from '@angular/common'; +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; +import { CoreModule } from '@angular/flex-layout'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { RouterTestingModule } from '@angular/router/testing'; +import { StoreModule } from '@ngrx/store'; + +import { appReducers } from '../../../../../store/src/reducers.module'; +import { SharedModule } from '../../../public-api'; +import { LogoutPageComponent } from './logout-page.component'; + +describe('LogoutPageComponent', () => { + let component: LogoutPageComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ LogoutPageComponent ], + imports: [ + CommonModule, + CoreModule, + SharedModule, + RouterTestingModule, + NoopAnimationsModule, + StoreModule.forRoot( + appReducers + ) + ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(LogoutPageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/frontend/packages/core/src/features/login/logout-page/logout-page.component.ts b/src/frontend/packages/core/src/features/login/logout-page/logout-page.component.ts new file mode 100644 index 0000000000..ed30fc6c6d --- /dev/null +++ b/src/frontend/packages/core/src/features/login/logout-page/logout-page.component.ts @@ -0,0 +1,35 @@ +import { Component, OnInit } from '@angular/core'; +import { Store } from '@ngrx/store'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; + +import { Logout } from '../../../../../store/src/actions/auth.actions'; +import { AppState } from '../../../../../store/src/app-state'; + +@Component({ + selector: 'app-logout-page', + templateUrl: './logout-page.component.html', + styleUrls: ['./logout-page.component.scss'] +}) +export class LogoutPageComponent implements OnInit { + + public error$: Observable; + + constructor(private store: Store) { + this.error$ = this.store.select(s => s.auth).pipe( + map(auth => auth.error) + ); + } + + ngOnInit() { + // Dispatch the logout action after 1 second - give the logging out screen time to show + setTimeout(() => { + this.store.dispatch(new Logout()); + }, 1000) + } + + reload() { + window.location.assign(window.location.origin); + } + +} diff --git a/src/frontend/packages/core/src/features/user-profile/profile-info/profile-info.component.scss b/src/frontend/packages/core/src/features/user-profile/profile-info/profile-info.component.scss index 0c5079208e..ba56f7161a 100644 --- a/src/frontend/packages/core/src/features/user-profile/profile-info/profile-info.component.scss +++ b/src/frontend/packages/core/src/features/user-profile/profile-info/profile-info.component.scss @@ -1,5 +1,3 @@ -@import '../../../../sass/mat-desktop'; - $user-profile-avatar-size: 48px; .user-profile { @@ -9,7 +7,7 @@ $user-profile-avatar-size: 48px; left: 0; position: absolute; right: 0; - top: $desktop-page-header-height; + top: 56px; mat-card:not(:first-child) { margin-top: 24px; } diff --git a/src/frontend/packages/core/src/shared/components/app-action-monitor/app-action-monitor.component.html b/src/frontend/packages/core/src/shared/components/app-action-monitor/app-action-monitor.component.html index 1c9713853c..a13bfa2bf3 100644 --- a/src/frontend/packages/core/src/shared/components/app-action-monitor/app-action-monitor.component.html +++ b/src/frontend/packages/core/src/shared/components/app-action-monitor/app-action-monitor.component.html @@ -1,4 +1,4 @@ -
+
\ No newline at end of file diff --git a/src/frontend/packages/core/src/shared/components/app-action-monitor/app-action-monitor.component.ts b/src/frontend/packages/core/src/shared/components/app-action-monitor/app-action-monitor.component.ts index 345af4a5c6..84b00b4d77 100644 --- a/src/frontend/packages/core/src/shared/components/app-action-monitor/app-action-monitor.component.ts +++ b/src/frontend/packages/core/src/shared/components/app-action-monitor/app-action-monitor.component.ts @@ -27,6 +27,8 @@ export class AppActionMonitorComponent implements OnInit { @Input() public data$: Observable> = observableNever(); + public replayData$: Observable>; + @Input() public entityKey: string; @@ -81,16 +83,16 @@ export class AppActionMonitorComponent implements OnInit { cellFlex: '0 0 24px' }; - // Some obs will only ever emit once, once consumed in template this meant table never received emitted data - // so wrap in publish replay - const replayData = this.data$.pipe( + // Some data$ obs only ever emit once. If we subscribed directly to this then that emit would be consumed and will not be available + // in the data source connect subscription. So wrap it in a replay to ensure the last emitted value is available + this.replayData$ = this.data$.pipe( publishReplay(1), refCount() ) this.allColumns = [...this.columns, monitorColumn]; this.dataSource = { - connect: () => replayData, + connect: () => this.replayData$, disconnect: () => { }, trackBy: (index, item) => { const fn = monitorColumn.cellConfig(item).getId; diff --git a/src/frontend/packages/core/src/shared/components/favorites-entity-list/favorites-entity-list.component.html b/src/frontend/packages/core/src/shared/components/favorites-entity-list/favorites-entity-list.component.html index ab46c56ea4..450f368b5f 100644 --- a/src/frontend/packages/core/src/shared/components/favorites-entity-list/favorites-entity-list.component.html +++ b/src/frontend/packages/core/src/shared/components/favorites-entity-list/favorites-entity-list.component.html @@ -20,7 +20,7 @@ [endpointDisconnected]="endpointDisconnected">
-