mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-12 00:55:12 +00:00
feat(console): onboarding flow (#5225)
Implements an onboarding UI for users
This commit is contained in:
@@ -212,7 +212,46 @@
|
||||
|
||||
<ng-template #shortcutKeyRef>
|
||||
<ng-container *ngIf="(isHandset$ | async) === false">
|
||||
<span class="fill-space"></span>
|
||||
<ng-template cnslHasRole [hasRole]="['iam.read']">
|
||||
<span class="fill-space"></span>
|
||||
<ng-container *ngIf="!adminService.hideOnboarding && (adminService.progressAllDone | async) === false">
|
||||
<button
|
||||
cdkOverlayOrigin
|
||||
#trigger="cdkOverlayOrigin"
|
||||
matRipple
|
||||
class="progress-bar"
|
||||
(click)="showInstanceProgress = !showInstanceProgress"
|
||||
>
|
||||
<mat-progress-bar
|
||||
class="progress"
|
||||
mode="determinate"
|
||||
[value]="adminService.progressPercentage | async"
|
||||
></mat-progress-bar>
|
||||
</button>
|
||||
|
||||
<ng-template
|
||||
cdkConnectedOverlay
|
||||
[cdkConnectedOverlayOrigin]="trigger"
|
||||
[flexibleDimensions]="true"
|
||||
[lockPosition]="true"
|
||||
[cdkConnectedOverlayOffsetY]="10"
|
||||
[cdkConnectedOverlayHasBackdrop]="true"
|
||||
[cdkConnectedOverlayPositions]="positions"
|
||||
cdkConnectedOverlayBackdropClass="transparent-backdrop"
|
||||
[cdkConnectedOverlayOpen]="showInstanceProgress"
|
||||
(backdropClick)="showInstanceProgress = false"
|
||||
(detach)="showInstanceProgress = false"
|
||||
>
|
||||
<cnsl-onboarding-card
|
||||
(dismissedCard)="dismissOnboarding()"
|
||||
class="onboarding_card"
|
||||
*ngIf="org && showInstanceProgress"
|
||||
>
|
||||
</cnsl-onboarding-card>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</ng-template>
|
||||
|
||||
<div (click)="openHelp()" class="nav-shortcut-action-key" matTooltip="{{ 'MENU.OPENSHORTCUTSTOOLTIP' | translate }}">
|
||||
<div class="nav-key-overlay"></div>
|
||||
<span>?</span>
|
||||
|
||||
@@ -181,8 +181,39 @@
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
margin-right: 0.5rem;
|
||||
width: 100px;
|
||||
min-width: 50px;
|
||||
background: if($is-dark-theme, #ffffff20, #00000010);
|
||||
border: none;
|
||||
padding: 2px;
|
||||
border-radius: 50vw;
|
||||
|
||||
&:hover {
|
||||
background: if($is-dark-theme, #ffffff, $primary-color);
|
||||
transition: background ease 0.15s;
|
||||
}
|
||||
|
||||
.progress {
|
||||
border-radius: 50vw;
|
||||
height: 8px;
|
||||
|
||||
.mat-progress-bar-buffer {
|
||||
background-color: if($is-dark-theme, rgb(69, 91, 84), #cccccc) !important;
|
||||
}
|
||||
.mat-progress-bar-background {
|
||||
fill: if($is-dark-theme, rgb(69, 91, 84), #cccccc) !important;
|
||||
}
|
||||
.mat-progress-bar-fill:after {
|
||||
background-color: var(--success);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.nav-shortcut-action-key {
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 12px;
|
||||
@@ -213,3 +244,9 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.onboarding_card {
|
||||
border-radius: 0.5rem;
|
||||
box-shadow: 0 0 15px 0 rgb(0 0 0 / 10%);
|
||||
border: 1px solid rgba(#8795a1, 0.2);
|
||||
}
|
||||
|
||||
@@ -1,17 +1,20 @@
|
||||
import { animate, keyframes, style, transition, trigger } from '@angular/animations';
|
||||
import { BreakpointObserver } from '@angular/cdk/layout';
|
||||
import { ConnectedPosition, ConnectionPositionPair } from '@angular/cdk/overlay';
|
||||
import { HttpClient } from '@angular/common/http';
|
||||
import { Component, ElementRef, Input, OnDestroy, ViewChild } from '@angular/core';
|
||||
import { UntypedFormControl } from '@angular/forms';
|
||||
import { Router } from '@angular/router';
|
||||
import { BehaviorSubject, combineLatest, forkJoin, map, merge, Observable, Subject, switchMap, take } from 'rxjs';
|
||||
import { BehaviorSubject, combineLatest, map, Observable, Subject, take, tap } from 'rxjs';
|
||||
import { Org } from 'src/app/proto/generated/zitadel/org_pb';
|
||||
import { User } from 'src/app/proto/generated/zitadel/user_pb';
|
||||
import { AdminService } from 'src/app/services/admin.service';
|
||||
import { AuthenticationService } from 'src/app/services/authentication.service';
|
||||
import { BreadcrumbService, BreadcrumbType } from 'src/app/services/breadcrumb.service';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { KeyboardShortcutsService } from 'src/app/services/keyboard-shortcuts/keyboard-shortcuts.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { StorageLocation, StorageService } from 'src/app/services/storage.service';
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-nav',
|
||||
@@ -73,6 +76,7 @@ export class NavComponent implements OnDestroy {
|
||||
|
||||
@Input() public isDarkTheme: boolean = true;
|
||||
@Input() public user!: User.AsObject;
|
||||
public showInstanceProgress: boolean = false;
|
||||
public isHandset$: Observable<boolean> = this.breakpointObserver.observe('(max-width: 599px)').pipe(
|
||||
map((result) => {
|
||||
return result.matches;
|
||||
@@ -83,14 +87,19 @@ export class NavComponent implements OnDestroy {
|
||||
public filterControl: UntypedFormControl = new UntypedFormControl('');
|
||||
public orgLoading$: BehaviorSubject<any> = new BehaviorSubject(false);
|
||||
public showAccount: boolean = false;
|
||||
public hideAdminWarn: boolean = true;
|
||||
private destroy$: Subject<void> = new Subject();
|
||||
|
||||
public BreadcrumbType: any = BreadcrumbType;
|
||||
public customerPortalLink: string = '';
|
||||
|
||||
public positions: ConnectedPosition[] = [
|
||||
new ConnectionPositionPair({ originX: 'start', originY: 'bottom' }, { overlayX: 'start', overlayY: 'top' }, 0, 10),
|
||||
new ConnectionPositionPair({ originX: 'end', originY: 'bottom' }, { overlayX: 'end', overlayY: 'top' }, 0, 10),
|
||||
];
|
||||
|
||||
constructor(
|
||||
public authService: GrpcAuthService,
|
||||
public adminService: AdminService,
|
||||
public authenticationService: AuthenticationService,
|
||||
public breadcrumbService: BreadcrumbService,
|
||||
public mgmtService: ManagementService,
|
||||
@@ -98,8 +107,8 @@ export class NavComponent implements OnDestroy {
|
||||
private breakpointObserver: BreakpointObserver,
|
||||
private http: HttpClient,
|
||||
private shortcutService: KeyboardShortcutsService,
|
||||
private storageService: StorageService,
|
||||
) {
|
||||
this.hideAdminWarn = localStorage.getItem('hideAdministratorWarning') === 'true' ? true : false;
|
||||
this.loadEnvironment();
|
||||
}
|
||||
|
||||
@@ -114,16 +123,18 @@ export class NavComponent implements OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
public toggleAdminHide(): void {
|
||||
this.hideAdminWarn = !this.hideAdminWarn;
|
||||
localStorage.setItem('hideAdministratorWarning', this.hideAdminWarn.toString());
|
||||
}
|
||||
|
||||
public ngOnDestroy() {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
public dismissOnboarding(): void {
|
||||
this.showInstanceProgress = false;
|
||||
this.adminService.hideOnboarding = true;
|
||||
this.storageService.setItem('onboarding-dismissed', 'true', StorageLocation.local);
|
||||
this.adminService.progressAllDone.next(true);
|
||||
}
|
||||
|
||||
public get isUserLinkActive(): boolean {
|
||||
const url = this.router.url;
|
||||
return url.substring(0, 6) === '/users';
|
||||
|
||||
@@ -12,12 +12,15 @@ import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||
import { HasRolePipeModule } from 'src/app/pipes/has-role-pipe/has-role-pipe.module';
|
||||
|
||||
import { MatLegacyProgressBarModule } from '@angular/material/legacy-progress-bar';
|
||||
import OnboardingCardModule from '../onboarding-card/onboarding-card.module';
|
||||
import { NavComponent } from './nav.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [NavComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
OnboardingCardModule,
|
||||
FormsModule,
|
||||
ReactiveFormsModule,
|
||||
TranslateModule,
|
||||
@@ -25,6 +28,7 @@ import { NavComponent } from './nav.component';
|
||||
RouterModule,
|
||||
MatTooltipModule,
|
||||
HasRolePipeModule,
|
||||
MatLegacyProgressBarModule,
|
||||
HasRoleModule,
|
||||
MatMenuModule,
|
||||
MatButtonModule,
|
||||
|
||||
Reference in New Issue
Block a user