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 21f49bc43b..0000000000 Binary files a/src/frontend/packages/core/src/favicon.ico and /dev/null differ diff --git a/src/frontend/packages/core/src/features/login/login.module.ts b/src/frontend/packages/core/src/features/login/login.module.ts index 5655c0d3a8..64649d97ad 100644 --- a/src/frontend/packages/core/src/features/login/login.module.ts +++ b/src/frontend/packages/core/src/features/login/login.module.ts @@ -3,17 +3,17 @@ import { NgModule } from '@angular/core'; import { CoreModule } from '../../core/core.module'; import { SharedModule } from '../../shared/shared.module'; import { LoginPageComponent } from './login-page/login-page.component'; -import { LoginRoutingModule } from './login.routing'; +import { LogoutPageComponent } from './logout-page/logout-page.component'; @NgModule({ imports: [ CoreModule, - SharedModule, - LoginRoutingModule + SharedModule ], declarations: [ - LoginPageComponent + LoginPageComponent, + LogoutPageComponent ] }) export class LoginModule { } diff --git a/src/frontend/packages/core/src/features/login/login.routing.ts b/src/frontend/packages/core/src/features/login/login.routing.ts deleted file mode 100644 index 1ecf12b3d0..0000000000 --- a/src/frontend/packages/core/src/features/login/login.routing.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; - -import { LoginPageComponent } from './login-page/login-page.component'; - -const loginRoutes: Routes = [ - { path: '', component: LoginPageComponent, } -]; - -@NgModule({ - imports: [ - RouterModule.forChild(loginRoutes), - ] -}) -export class LoginRoutingModule { } diff --git a/src/frontend/packages/core/src/features/login/logout-page/logout-page.component.html b/src/frontend/packages/core/src/features/login/logout-page/logout-page.component.html new file mode 100644 index 0000000000..e0a4606837 --- /dev/null +++ b/src/frontend/packages/core/src/features/login/logout-page/logout-page.component.html @@ -0,0 +1,17 @@ + + + +
+
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">
-