mirror of
https://github.com/zitadel/zitadel.git
synced 2025-03-01 01:37:24 +00:00
fix(console): user create loading state and i18n, improved app create stepper, invalid token dialog, cleanup, new home (#509)
* fix iam member model * fix org member model * fix auth user loading * copytoclipboard directive * directive logs, load bar on init, create user * typo * welcome section, contributor spinner * fix home link * fix stepper flow * show dialog on invalid token * fix app table refresh, pin icons light theme * cleanup contributor * Update console/src/assets/i18n/en.json Co-authored-by: Florian Forster <florian@caos.ch> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <florian@caos.ch> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <florian@caos.ch> * Update console/src/assets/i18n/de.json Co-authored-by: Florian Forster <florian@caos.ch> Co-authored-by: Florian Forster <florian@caos.ch>
This commit is contained in:
parent
c105bf483b
commit
af60b88997
@ -204,6 +204,21 @@ export class AppComponent implements OnDestroy {
|
|||||||
this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/lock-reset.svg'),
|
this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/lock-reset.svg'),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
this.matIconRegistry.addSvgIcon(
|
||||||
|
'mdi_broom',
|
||||||
|
this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/broom.svg'),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.matIconRegistry.addSvgIcon(
|
||||||
|
'mdi_pin_outline',
|
||||||
|
this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/pin-outline.svg'),
|
||||||
|
);
|
||||||
|
|
||||||
|
this.matIconRegistry.addSvgIcon(
|
||||||
|
'mdi_pin',
|
||||||
|
this.domSanitizer.bypassSecurityTrustResourceUrl('assets/mdi/pin.svg'),
|
||||||
|
);
|
||||||
|
|
||||||
this.orgSub = this.authService.activeOrgChanged.subscribe(org => {
|
this.orgSub = this.authService.activeOrgChanged.subscribe(org => {
|
||||||
this.org = org;
|
this.org = org;
|
||||||
});
|
});
|
||||||
|
@ -5,6 +5,7 @@ import localeDe from '@angular/common/locales/de';
|
|||||||
import { APP_INITIALIZER, NgModule } from '@angular/core';
|
import { APP_INITIALIZER, NgModule } from '@angular/core';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatCardModule } from '@angular/material/card';
|
import { MatCardModule } from '@angular/material/card';
|
||||||
|
import { MatDialogModule } from '@angular/material/dialog';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatMenuModule } from '@angular/material/menu';
|
import { MatMenuModule } from '@angular/material/menu';
|
||||||
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||||
@ -27,6 +28,7 @@ import { HasRoleModule } from './directives/has-role/has-role.module';
|
|||||||
import { OutsideClickModule } from './directives/outside-click/outside-click.module';
|
import { OutsideClickModule } from './directives/outside-click/outside-click.module';
|
||||||
import { AccountsCardModule } from './modules/accounts-card/accounts-card.module';
|
import { AccountsCardModule } from './modules/accounts-card/accounts-card.module';
|
||||||
import { AvatarModule } from './modules/avatar/avatar.module';
|
import { AvatarModule } from './modules/avatar/avatar.module';
|
||||||
|
import { WarnDialogModule } from './modules/warn-dialog/warn-dialog.module';
|
||||||
import { SignedoutComponent } from './pages/signedout/signedout.component';
|
import { SignedoutComponent } from './pages/signedout/signedout.component';
|
||||||
import { HasRolePipeModule } from './pipes/has-role-pipe.module';
|
import { HasRolePipeModule } from './pipes/has-role-pipe.module';
|
||||||
import { AuthUserService } from './services/auth-user.service';
|
import { AuthUserService } from './services/auth-user.service';
|
||||||
@ -105,6 +107,8 @@ const authConfig: AuthConfig = {
|
|||||||
MatMenuModule,
|
MatMenuModule,
|
||||||
MatSnackBarModule,
|
MatSnackBarModule,
|
||||||
AvatarModule,
|
AvatarModule,
|
||||||
|
WarnDialogModule,
|
||||||
|
MatDialogModule,
|
||||||
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
|
ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
|
@ -0,0 +1,31 @@
|
|||||||
|
import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core';
|
||||||
|
|
||||||
|
@Directive({
|
||||||
|
selector: '[appCopyToClipboard]',
|
||||||
|
})
|
||||||
|
export class CopyToClipboardDirective {
|
||||||
|
@Input() valueToCopy: string = '';
|
||||||
|
@Output() copiedValue: EventEmitter<string> = new EventEmitter();
|
||||||
|
|
||||||
|
@HostListener('document:click', ['$event.target']) onMouseEnter(): void {
|
||||||
|
this.copytoclipboard(this.valueToCopy);
|
||||||
|
}
|
||||||
|
|
||||||
|
public copytoclipboard(value: string): void {
|
||||||
|
const selBox = document.createElement('textarea');
|
||||||
|
selBox.style.position = 'fixed';
|
||||||
|
selBox.style.left = '0';
|
||||||
|
selBox.style.top = '0';
|
||||||
|
selBox.style.opacity = '0';
|
||||||
|
selBox.value = value;
|
||||||
|
document.body.appendChild(selBox);
|
||||||
|
selBox.focus();
|
||||||
|
selBox.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
document.body.removeChild(selBox);
|
||||||
|
this.copiedValue.emit(value);
|
||||||
|
setTimeout(() => {
|
||||||
|
this.copiedValue.emit('');
|
||||||
|
}, 3000);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
import { CommonModule } from '@angular/common';
|
||||||
|
import { NgModule } from '@angular/core';
|
||||||
|
|
||||||
|
import { CopyToClipboardDirective } from './copy-to-clipboard.directive';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@NgModule({
|
||||||
|
declarations: [
|
||||||
|
CopyToClipboardDirective,
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
],
|
||||||
|
exports: [
|
||||||
|
CopyToClipboardDirective,
|
||||||
|
],
|
||||||
|
})
|
||||||
|
export class CopyToClipboardModule { }
|
@ -7,7 +7,7 @@
|
|||||||
<span class="u-email">{{profile?.preferredLoginName}}</span>
|
<span class="u-email">{{profile?.preferredLoginName}}</span>
|
||||||
<span class="iamuser" *ngIf="iamuser">IAM USER</span>
|
<span class="iamuser" *ngIf="iamuser">IAM USER</span>
|
||||||
|
|
||||||
<button (click)="editUserProfile()" mat-stroked-button>{{'USER.EDITACCOUNT' | translate}}</button>
|
<button color="primary" (click)="editUserProfile()" mat-stroked-button>{{'USER.EDITACCOUNT' | translate}}</button>
|
||||||
<div class="l-accounts">
|
<div class="l-accounts">
|
||||||
<mat-progress-bar *ngIf="loadingUsers" color="primary" mode="indeterminate"></mat-progress-bar>
|
<mat-progress-bar *ngIf="loadingUsers" color="primary" mode="indeterminate"></mat-progress-bar>
|
||||||
<a class="row" *ngFor="let user of users" (click)="selectAccount(user.loginName)">
|
<a class="row" *ngFor="let user of users" (click)="selectAccount(user.loginName)">
|
||||||
@ -35,5 +35,5 @@
|
|||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button (click)="logout()" mat-stroked-button>{{'MENU.LOGOUT' | translate}}</button>
|
<button (click)="logout()" color="primary" mat-stroked-button>{{'MENU.LOGOUT' | translate}}</button>
|
||||||
</div>
|
</div>
|
@ -1,4 +1,5 @@
|
|||||||
<div class="avatar-circle dontcloseonclick"
|
<div class="avatar-circle dontcloseonclick" matRipple [matRippleColor]="'#ffffff20'" matRippleUnbounded="true"
|
||||||
|
matRippleCentered="true"
|
||||||
[ngStyle]="{'height': size+'px', 'width': size+'px', 'fontSize': (fontSize-1)+'px', 'background-color': color}"
|
[ngStyle]="{'height': size+'px', 'width': size+'px', 'fontSize': (fontSize-1)+'px', 'background-color': color}"
|
||||||
[ngClass]="{'active': active}">
|
[ngClass]="{'active': active}">
|
||||||
{{credentials}}
|
{{credentials}}
|
||||||
|
@ -16,8 +16,8 @@
|
|||||||
outline: none;
|
outline: none;
|
||||||
color: white;
|
color: white;
|
||||||
|
|
||||||
&.active:hover {
|
// &.active:hover {
|
||||||
border: 2px solid #8795a1;
|
// border: 2px solid #8795a1;
|
||||||
}
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,6 @@
|
|||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
|
import { MatRippleModule } from '@angular/material/core';
|
||||||
|
|
||||||
import { AvatarComponent } from './avatar.component';
|
import { AvatarComponent } from './avatar.component';
|
||||||
|
|
||||||
@ -9,6 +10,7 @@ import { AvatarComponent } from './avatar.component';
|
|||||||
declarations: [AvatarComponent],
|
declarations: [AvatarComponent],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
MatRippleModule,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
AvatarComponent,
|
AvatarComponent,
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
<span class="sub-header">{{ description }}</span>
|
<span class="sub-header">{{ description }}</span>
|
||||||
<div class="people">
|
<div class="people">
|
||||||
<div class="img-list">
|
<div class="img-list">
|
||||||
|
<mat-spinner diameter="20" *ngIf="loading"></mat-spinner>
|
||||||
|
|
||||||
<ng-container *ngIf="totalResult < 10; else compact">
|
<ng-container *ngIf="totalResult < 10; else compact">
|
||||||
<ng-container *ngFor="let member of membersSubject | async; index as i">
|
<ng-container *ngFor="let member of membersSubject | async; index as i">
|
||||||
<div (click)="emitShowDetail()" class="avatar-circle"
|
<div (click)="emitShowDetail()" class="avatar-circle"
|
||||||
|
@ -28,10 +28,13 @@
|
|||||||
margin-left: 1rem;
|
margin-left: 1rem;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
transition: all .15s ease-in-out;
|
|
||||||
|
mat-spinner {
|
||||||
|
margin-left: -15px;
|
||||||
|
margin-right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
.avatar-circle {
|
.avatar-circle {
|
||||||
transition: all .3s ease-in-out;
|
|
||||||
float: left;
|
float: left;
|
||||||
margin: 0 8px 0 -15px;
|
margin: 0 8px 0 -15px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { animate, animateChild, query, stagger, style, transition, trigger } from '@angular/animations';
|
||||||
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
import { Component, EventEmitter, Input, Output } from '@angular/core';
|
||||||
import { BehaviorSubject } from 'rxjs';
|
import { BehaviorSubject } from 'rxjs';
|
||||||
|
|
||||||
@ -5,12 +6,28 @@ import { BehaviorSubject } from 'rxjs';
|
|||||||
selector: 'app-contributors',
|
selector: 'app-contributors',
|
||||||
templateUrl: './contributors.component.html',
|
templateUrl: './contributors.component.html',
|
||||||
styleUrls: ['./contributors.component.scss'],
|
styleUrls: ['./contributors.component.scss'],
|
||||||
|
animations: [
|
||||||
|
trigger('list', [
|
||||||
|
transition(':enter', [
|
||||||
|
query('@animate',
|
||||||
|
stagger(80, animateChild()),
|
||||||
|
),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
trigger('animate', [
|
||||||
|
transition(':enter', [
|
||||||
|
style({ opacity: 0, transform: 'translateX(100%)' }),
|
||||||
|
animate('100ms', style({ opacity: 1, transform: 'translateX(0)' })),
|
||||||
|
]),
|
||||||
|
]),
|
||||||
|
],
|
||||||
})
|
})
|
||||||
export class ContributorsComponent {
|
export class ContributorsComponent {
|
||||||
@Input() title: string = '';
|
@Input() title: string = '';
|
||||||
@Input() description: string = '';
|
@Input() description: string = '';
|
||||||
@Input() disabled: boolean = false;
|
@Input() disabled: boolean = false;
|
||||||
@Input() totalResult: number = 0;
|
@Input() totalResult: number = 0;
|
||||||
|
@Input() loading: boolean = false;
|
||||||
@Input() membersSubject!: BehaviorSubject<any[]>;
|
@Input() membersSubject!: BehaviorSubject<any[]>;
|
||||||
@Output() addClicked: EventEmitter<void> = new EventEmitter();
|
@Output() addClicked: EventEmitter<void> = new EventEmitter();
|
||||||
@Output() showDetailClicked: EventEmitter<void> = new EventEmitter();
|
@Output() showDetailClicked: EventEmitter<void> = new EventEmitter();
|
||||||
|
@ -2,6 +2,7 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
|
|
||||||
import { AvatarModule } from '../avatar/avatar.module';
|
import { AvatarModule } from '../avatar/avatar.module';
|
||||||
@ -17,6 +18,7 @@ import { ContributorsComponent } from './contributors.component';
|
|||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
|
MatProgressSpinnerModule,
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
ContributorsComponent,
|
ContributorsComponent,
|
||||||
|
@ -3,10 +3,10 @@
|
|||||||
<p class="desc"> {{data.descriptionKey | translate}}</p>
|
<p class="desc"> {{data.descriptionKey | translate}}</p>
|
||||||
</div>
|
</div>
|
||||||
<div mat-dialog-actions class="action">
|
<div mat-dialog-actions class="action">
|
||||||
<button mat-button (click)="closeDialog()">
|
<button *ngIf="data.cancelKey" mat-button (click)="closeDialog()">
|
||||||
{{data.cancelKey | translate}}
|
{{data.cancelKey | translate}}
|
||||||
</button>
|
</button>
|
||||||
|
<span class="fill-space"></span>
|
||||||
<button color="warn" mat-raised-button class="ok-button" (click)="closeDialogWithSuccess()">
|
<button color="warn" mat-raised-button class="ok-button" (click)="closeDialogWithSuccess()">
|
||||||
{{data.confirmKey | translate}}
|
{{data.confirmKey | translate}}
|
||||||
</button>
|
</button>
|
||||||
|
@ -10,12 +10,15 @@
|
|||||||
|
|
||||||
.action {
|
.action {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: flex-end;
|
|
||||||
|
|
||||||
.ok-button {
|
.ok-button {
|
||||||
margin-left: 0.5rem;
|
margin-left: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.fill-space {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
button {
|
button {
|
||||||
border-radius: 0.5rem;
|
border-radius: 0.5rem;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,17 @@
|
|||||||
<div class="wrapper">
|
<div class="wrapper max-width-container">
|
||||||
<div class="header">
|
<div class="header" *ngIf="(authService.user | async) || {} as user">
|
||||||
<img alt="zitadel logo" *ngIf="dark; else lighttheme"
|
<app-avatar [routerLink]="['/users/me']" *ngIf="user && (user.displayName || (user.firstName && user.lastName))"
|
||||||
src="../assets/images/zitadel-logo-oneline-darkdesign.svg" />
|
class="avatar" [name]="user.displayName ? user.displayName : (user.firstName + ' '+ user.lastName)"
|
||||||
<ng-template #lighttheme>
|
[size]="100">
|
||||||
<img alt="zitadel logo" src="../assets/images/zitadel-logo-oneline-lightdesign.svg" />
|
</app-avatar>
|
||||||
|
<h3 *ngIf="(user.displayName || user.firstName || user.lastName); else loader">
|
||||||
|
{{'HOME.WELCOME' | translate}},
|
||||||
|
{{user?.displayName ? user.displayName : (user.firstName + ' '+ user.lastName)}}</h3>
|
||||||
|
<p>{{user?.userName}}</p>
|
||||||
|
|
||||||
|
<p class="wlc_stnce">{{'HOME.WELCOMESENTENCE' | translate}}</p>
|
||||||
|
<ng-template #loader>
|
||||||
|
<mat-spinner diameter="50"></mat-spinner>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -77,9 +85,14 @@
|
|||||||
</div>
|
</div>
|
||||||
<span class="fill-space"></span>
|
<span class="fill-space"></span>
|
||||||
<div class="footer">
|
<div class="footer">
|
||||||
<a color="primary" mat-button [routerLink]="['/users/me']">{{'HOME.USERS_BUTTON' | translate}}</a>
|
<a color="primary" mat-button [routerLink]="['/users/all']">{{'HOME.USERS_BUTTON' | translate}}</a>
|
||||||
</div>
|
</div>
|
||||||
</app-card>
|
</app-card>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<p class="disclaimer">{{'HOME.DISCLAIMER' | translate}}
|
||||||
|
<!-- TODO: Add doc link to security here -->
|
||||||
|
<!-- <a href="https://caos.github.io/site#security"></a> -->
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
@ -1,39 +1,25 @@
|
|||||||
|
|
||||||
.wrapper {
|
.wrapper {
|
||||||
width: 80%;
|
padding-bottom: 100px;
|
||||||
max-width: 1350px;
|
|
||||||
@media only screen and (max-width: 700px) {
|
|
||||||
width: 90%;
|
|
||||||
}
|
|
||||||
margin: auto;
|
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin: 4rem 0;
|
margin: 4rem 0;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|
||||||
.avatar {
|
h3 {
|
||||||
width: 100px;
|
font-size: 24px;
|
||||||
height: 100px;
|
margin-bottom: 1rem;
|
||||||
font-size: 100px;
|
|
||||||
line-height: 100px;
|
|
||||||
margin-top: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 3rem;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
color: #8795a1;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 1rem;
|
|
||||||
margin: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
img {
|
.wlc_stnce {
|
||||||
height: 60px;
|
color: #8795a1;
|
||||||
align-self: flex-end;
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar {
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,5 +70,11 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.disclaimer {
|
||||||
|
color: #8795a1;
|
||||||
|
font-size: 14px;
|
||||||
|
margin-top: 3rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { Component } from '@angular/core';
|
import { Component } from '@angular/core';
|
||||||
|
import { AuthService } from 'src/app/services/auth.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-home',
|
selector: 'app-home',
|
||||||
@ -7,9 +8,9 @@ import { Component } from '@angular/core';
|
|||||||
})
|
})
|
||||||
export class HomeComponent {
|
export class HomeComponent {
|
||||||
public dark: boolean = true;
|
public dark: boolean = true;
|
||||||
|
constructor(public authService: AuthService) {
|
||||||
constructor() {
|
|
||||||
const theme = localStorage.getItem('theme');
|
const theme = localStorage.getItem('theme');
|
||||||
this.dark = theme === 'dark-theme' ? true : theme === 'light-theme' ? false : true;
|
this.dark = theme === 'dark-theme' ? true : theme === 'light-theme' ? false : true;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,10 @@ import { CommonModule } from '@angular/common';
|
|||||||
import { NgModule } from '@angular/core';
|
import { NgModule } from '@angular/core';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||||
|
import { AvatarModule } from 'src/app/modules/avatar/avatar.module';
|
||||||
import { CardModule } from 'src/app/modules/card/card.module';
|
import { CardModule } from 'src/app/modules/card/card.module';
|
||||||
import { SharedModule } from 'src/app/modules/shared/shared.module';
|
import { SharedModule } from 'src/app/modules/shared/shared.module';
|
||||||
|
|
||||||
@ -21,7 +23,9 @@ import { HomeComponent } from './home.component';
|
|||||||
HomeRoutingModule,
|
HomeRoutingModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
TranslateModule,
|
TranslateModule,
|
||||||
|
AvatarModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
|
MatProgressSpinnerModule,
|
||||||
CardModule,
|
CardModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
import { DataSource } from '@angular/cdk/collections';
|
import { DataSource } from '@angular/cdk/collections';
|
||||||
import { BehaviorSubject, from, Observable, of } from 'rxjs';
|
import { BehaviorSubject, from, Observable, of } from 'rxjs';
|
||||||
import { catchError, finalize, map } from 'rxjs/operators';
|
import { catchError, finalize, map } from 'rxjs/operators';
|
||||||
import { IamMemberSearchResponse } from 'src/app/proto/generated/admin_pb';
|
import { IamMemberView } from 'src/app/proto/generated/admin_pb';
|
||||||
import { ProjectMember } from 'src/app/proto/generated/management_pb';
|
|
||||||
import { AdminService } from 'src/app/services/admin.service';
|
import { AdminService } from 'src/app/services/admin.service';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -10,9 +9,9 @@ import { AdminService } from 'src/app/services/admin.service';
|
|||||||
* encapsulate all logic for fetching and manipulating the displayed data
|
* encapsulate all logic for fetching and manipulating the displayed data
|
||||||
* (including sorting, pagination, and filtering).
|
* (including sorting, pagination, and filtering).
|
||||||
*/
|
*/
|
||||||
export class IamMembersDataSource extends DataSource<ProjectMember.AsObject> {
|
export class IamMembersDataSource extends DataSource<IamMemberView.AsObject> {
|
||||||
public totalResult: number = 0;
|
public totalResult: number = 0;
|
||||||
public membersSubject: BehaviorSubject<ProjectMember.AsObject[]> = new BehaviorSubject<ProjectMember.AsObject[]>([]);
|
public membersSubject: BehaviorSubject<IamMemberView.AsObject[]> = new BehaviorSubject<IamMemberView.AsObject[]>([]);
|
||||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||||
|
|
||||||
@ -21,25 +20,21 @@ export class IamMembersDataSource extends DataSource<ProjectMember.AsObject> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public loadMembers(
|
public loadMembers(
|
||||||
pageIndex: number, pageSize: number, grantId?: string, sortDirection?: string): void {
|
pageIndex: number, pageSize: number): void {
|
||||||
const offset = pageIndex * pageSize;
|
const offset = pageIndex * pageSize;
|
||||||
|
|
||||||
this.loadingSubject.next(true);
|
this.loadingSubject.next(true);
|
||||||
// TODO
|
|
||||||
const promise: Promise<IamMemberSearchResponse> =
|
from(this.adminService.SearchIamMembers(pageSize, offset)).pipe(
|
||||||
this.adminService.SearchIamMembers(pageSize, offset);
|
map(resp => {
|
||||||
if (promise) {
|
this.totalResult = resp.toObject().totalResult;
|
||||||
from(promise).pipe(
|
return resp.toObject().resultList;
|
||||||
map(resp => {
|
}),
|
||||||
this.totalResult = resp.toObject().totalResult;
|
catchError(() => of([])),
|
||||||
return resp.toObject().resultList;
|
finalize(() => this.loadingSubject.next(false)),
|
||||||
}),
|
).subscribe(members => {
|
||||||
catchError(() => of([])),
|
this.membersSubject.next(members);
|
||||||
finalize(() => this.loadingSubject.next(false)),
|
});
|
||||||
).subscribe(members => {
|
|
||||||
this.membersSubject.next(members);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -48,7 +43,7 @@ export class IamMembersDataSource extends DataSource<ProjectMember.AsObject> {
|
|||||||
* the returned stream emits new items.
|
* the returned stream emits new items.
|
||||||
* @returns A stream of the items to be rendered.
|
* @returns A stream of the items to be rendered.
|
||||||
*/
|
*/
|
||||||
public connect(): Observable<ProjectMember.AsObject[]> {
|
public connect(): Observable<IamMemberView.AsObject[]> {
|
||||||
return this.membersSubject.asObservable();
|
return this.membersSubject.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import { MatPaginator } from '@angular/material/paginator';
|
|||||||
import { MatTable } from '@angular/material/table';
|
import { MatTable } from '@angular/material/table';
|
||||||
import { tap } from 'rxjs/operators';
|
import { tap } from 'rxjs/operators';
|
||||||
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
|
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
|
||||||
|
import { IamMemberView } from 'src/app/proto/generated/admin_pb';
|
||||||
import { ProjectMember, ProjectType, User } from 'src/app/proto/generated/management_pb';
|
import { ProjectMember, ProjectType, User } from 'src/app/proto/generated/management_pb';
|
||||||
import { AdminService } from 'src/app/services/admin.service';
|
import { AdminService } from 'src/app/services/admin.service';
|
||||||
import { ToastService } from 'src/app/services/toast.service';
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
@ -20,9 +21,9 @@ export class IamMembersComponent implements AfterViewInit {
|
|||||||
public projectType: ProjectType = ProjectType.PROJECTTYPE_OWNED;
|
public projectType: ProjectType = ProjectType.PROJECTTYPE_OWNED;
|
||||||
public disabled: boolean = false;
|
public disabled: boolean = false;
|
||||||
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
||||||
@ViewChild(MatTable) public table!: MatTable<ProjectMember.AsObject>;
|
@ViewChild(MatTable) public table!: MatTable<IamMemberView.AsObject>;
|
||||||
public dataSource!: IamMembersDataSource;
|
public dataSource!: IamMembersDataSource;
|
||||||
public selection: SelectionModel<ProjectMember.AsObject> = new SelectionModel<ProjectMember.AsObject>(true, []);
|
public selection: SelectionModel<IamMemberView.AsObject> = new SelectionModel<IamMemberView.AsObject>(true, []);
|
||||||
|
|
||||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||||
public displayedColumns: string[] = ['select', 'firstname', 'lastname', 'username', 'email', 'roles'];
|
public displayedColumns: string[] = ['select', 'firstname', 'lastname', 'username', 'email', 'roles'];
|
||||||
@ -32,7 +33,7 @@ export class IamMembersComponent implements AfterViewInit {
|
|||||||
private toast: ToastService) {
|
private toast: ToastService) {
|
||||||
|
|
||||||
this.dataSource = new IamMembersDataSource(this.adminService);
|
this.dataSource = new IamMembersDataSource(this.adminService);
|
||||||
this.dataSource.loadMembers(0, 25, 'asc');
|
this.dataSource.loadMembers(0, 25);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngAfterViewInit(): void {
|
public ngAfterViewInit(): void {
|
||||||
|
@ -41,7 +41,9 @@
|
|||||||
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.VIEWS.ACTIONS' | translate }} </th>
|
<th mat-header-cell *matHeaderCellDef> {{ 'IAM.VIEWS.ACTIONS' | translate }} </th>
|
||||||
<td mat-cell *matCellDef="let role">
|
<td mat-cell *matCellDef="let role">
|
||||||
<button mat-icon-button matTooltip="{{'IAM.VIEWS.CLEAR' | translate}}"
|
<button mat-icon-button matTooltip="{{'IAM.VIEWS.CLEAR' | translate}}"
|
||||||
(click)="cancelView(role.viewName, role.database)"><i class="las la-redo-alt"></i></button>
|
(click)="cancelView(role.viewName, role.database)">
|
||||||
|
<mat-icon svgIcon="mdi_broom"></mat-icon>
|
||||||
|
</button>
|
||||||
</td>
|
</td>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
|
|
||||||
|
@ -9,9 +9,10 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="side" metainfo>
|
<div class="side" metainfo>
|
||||||
<app-contributors [totalResult]="totalMemberResult" [membersSubject]="membersSubject"
|
<app-contributors [totalResult]="totalMemberResult" [loading]="loading$ | async"
|
||||||
title="{{ 'PROJECT.MEMBER.TITLE' | translate }}" description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}"
|
[membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
|
||||||
(addClicked)="openAddMember()" (showDetailClicked)="showDetail()" [disabled]="false">
|
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
|
||||||
|
(showDetailClicked)="showDetail()" [disabled]="false">
|
||||||
</app-contributors>
|
</app-contributors>
|
||||||
</div>
|
</div>
|
||||||
</app-meta-layout>
|
</app-meta-layout>
|
@ -39,8 +39,8 @@
|
|||||||
|
|
||||||
<mat-tab-group mat-stretch-tabs class="tab-group" disablePagination="true">
|
<mat-tab-group mat-stretch-tabs class="tab-group" disablePagination="true">
|
||||||
<mat-tab label="Details">
|
<mat-tab label="Details">
|
||||||
<app-contributors [totalResult]="totalMemberResult" [membersSubject]="membersSubject"
|
<app-contributors [totalResult]="totalMemberResult" [loading]="loading$ | async"
|
||||||
title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
|
[membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
|
||||||
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
|
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
|
||||||
(showDetailClicked)="showDetail()" [disabled]="false">
|
(showDetailClicked)="showDetail()" [disabled]="false">
|
||||||
</app-contributors>
|
</app-contributors>
|
||||||
|
@ -1,17 +1,12 @@
|
|||||||
import { DataSource } from '@angular/cdk/collections';
|
import { DataSource } from '@angular/cdk/collections';
|
||||||
import { BehaviorSubject, from, Observable, of } from 'rxjs';
|
import { BehaviorSubject, from, Observable, of } from 'rxjs';
|
||||||
import { catchError, finalize, map } from 'rxjs/operators';
|
import { catchError, finalize, map } from 'rxjs/operators';
|
||||||
import { ProjectMember, ProjectMemberSearchResponse } from 'src/app/proto/generated/management_pb';
|
import { OrgMemberView } from 'src/app/proto/generated/management_pb';
|
||||||
import { OrgService } from 'src/app/services/org.service';
|
import { OrgService } from 'src/app/services/org.service';
|
||||||
|
|
||||||
/**
|
export class OrgMembersDataSource extends DataSource<OrgMemberView.AsObject> {
|
||||||
* Data source for the ProjectMembers view. This class should
|
|
||||||
* encapsulate all logic for fetching and manipulating the displayed data
|
|
||||||
* (including sorting, pagination, and filtering).
|
|
||||||
*/
|
|
||||||
export class ProjectMembersDataSource extends DataSource<ProjectMember.AsObject> {
|
|
||||||
public totalResult: number = 0;
|
public totalResult: number = 0;
|
||||||
public membersSubject: BehaviorSubject<ProjectMember.AsObject[]> = new BehaviorSubject<ProjectMember.AsObject[]>([]);
|
public membersSubject: BehaviorSubject<OrgMemberView.AsObject[]> = new BehaviorSubject<OrgMemberView.AsObject[]>([]);
|
||||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
||||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||||
|
|
||||||
@ -19,26 +14,20 @@ export class ProjectMembersDataSource extends DataSource<ProjectMember.AsObject>
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public loadMembers(
|
public loadMembers(pageIndex: number, pageSize: number): void {
|
||||||
pageIndex: number, pageSize: number, grantId?: string, sortDirection?: string): void {
|
|
||||||
const offset = pageIndex * pageSize;
|
const offset = pageIndex * pageSize;
|
||||||
|
|
||||||
this.loadingSubject.next(true);
|
this.loadingSubject.next(true);
|
||||||
// TODO
|
from(this.orgService.SearchMyOrgMembers(pageSize, offset)).pipe(
|
||||||
const promise: Promise<ProjectMemberSearchResponse> =
|
map(resp => {
|
||||||
this.orgService.SearchMyOrgMembers(pageSize, offset);
|
this.totalResult = resp.toObject().totalResult;
|
||||||
if (promise) {
|
return resp.toObject().resultList;
|
||||||
from(promise).pipe(
|
}),
|
||||||
map(resp => {
|
catchError(() => of([])),
|
||||||
this.totalResult = resp.toObject().totalResult;
|
finalize(() => this.loadingSubject.next(false)),
|
||||||
return resp.toObject().resultList;
|
).subscribe(members => {
|
||||||
}),
|
this.membersSubject.next(members);
|
||||||
catchError(() => of([])),
|
});
|
||||||
finalize(() => this.loadingSubject.next(false)),
|
|
||||||
).subscribe(members => {
|
|
||||||
this.membersSubject.next(members);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -47,7 +36,7 @@ export class ProjectMembersDataSource extends DataSource<ProjectMember.AsObject>
|
|||||||
* the returned stream emits new items.
|
* the returned stream emits new items.
|
||||||
* @returns A stream of the items to be rendered.
|
* @returns A stream of the items to be rendered.
|
||||||
*/
|
*/
|
||||||
public connect(): Observable<ProjectMember.AsObject[]> {
|
public connect(): Observable<OrgMemberView.AsObject[]> {
|
||||||
return this.membersSubject.asObservable();
|
return this.membersSubject.asObservable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,11 +5,11 @@ import { MatPaginator } from '@angular/material/paginator';
|
|||||||
import { MatTable } from '@angular/material/table';
|
import { MatTable } from '@angular/material/table';
|
||||||
import { tap } from 'rxjs/operators';
|
import { tap } from 'rxjs/operators';
|
||||||
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
|
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
|
||||||
import { Org, ProjectMember, ProjectType, User } from 'src/app/proto/generated/management_pb';
|
import { Org, OrgMemberView, ProjectMember, ProjectType, User } from 'src/app/proto/generated/management_pb';
|
||||||
import { OrgService } from 'src/app/services/org.service';
|
import { OrgService } from 'src/app/services/org.service';
|
||||||
import { ToastService } from 'src/app/services/toast.service';
|
import { ToastService } from 'src/app/services/toast.service';
|
||||||
|
|
||||||
import { ProjectMembersDataSource } from './org-members-datasource';
|
import { OrgMembersDataSource } from './org-members-datasource';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-org-members',
|
selector: 'app-org-members',
|
||||||
@ -21,9 +21,9 @@ export class OrgMembersComponent implements AfterViewInit {
|
|||||||
public projectType: ProjectType = ProjectType.PROJECTTYPE_OWNED;
|
public projectType: ProjectType = ProjectType.PROJECTTYPE_OWNED;
|
||||||
public disabled: boolean = false;
|
public disabled: boolean = false;
|
||||||
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
@ViewChild(MatPaginator) public paginator!: MatPaginator;
|
||||||
@ViewChild(MatTable) public table!: MatTable<ProjectMember.AsObject>;
|
@ViewChild(MatTable) public table!: MatTable<OrgMemberView.AsObject>;
|
||||||
public dataSource!: ProjectMembersDataSource;
|
public dataSource!: OrgMembersDataSource;
|
||||||
public selection: SelectionModel<ProjectMember.AsObject> = new SelectionModel<ProjectMember.AsObject>(true, []);
|
public selection: SelectionModel<OrgMemberView.AsObject> = new SelectionModel<OrgMemberView.AsObject>(true, []);
|
||||||
|
|
||||||
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
/** Columns displayed in the table. Columns IDs can be added, removed, or reordered. */
|
||||||
public displayedColumns: string[] = ['select', 'firstname', 'lastname', 'username', 'email', 'roles'];
|
public displayedColumns: string[] = ['select', 'firstname', 'lastname', 'username', 'email', 'roles'];
|
||||||
@ -33,8 +33,8 @@ export class OrgMembersComponent implements AfterViewInit {
|
|||||||
private toast: ToastService) {
|
private toast: ToastService) {
|
||||||
this.orgService.GetMyOrg().then(org => {
|
this.orgService.GetMyOrg().then(org => {
|
||||||
this.org = org.toObject();
|
this.org = org.toObject();
|
||||||
this.dataSource = new ProjectMembersDataSource(this.orgService);
|
this.dataSource = new OrgMembersDataSource(this.orgService);
|
||||||
this.dataSource.loadMembers(0, 25, 'asc');
|
this.dataSource.loadMembers(0, 25);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,29 +41,13 @@
|
|||||||
</form>
|
</form>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
|
|
||||||
<mat-step [editable]="true">
|
<mat-step [editable]="true"
|
||||||
<ng-template matStepLabel>{{'APP.OIDC.GRANTSECTION' | translate}}</ng-template>
|
*ngIf="oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT">
|
||||||
|
|
||||||
<p class="step-title">{{'APP.OIDC.GRANTTITLE' | translate}}</p>
|
|
||||||
|
|
||||||
<div class="checkbox-container">
|
|
||||||
<mat-checkbox (change)="changeGrant()" *ngFor="let granttype of oidcGrantTypes" color="primary"
|
|
||||||
[(ngModel)]="granttype.checked" [disabled]="granttype.disabled">
|
|
||||||
{{'APP.OIDC.GRANT'+granttype.type | translate}}
|
|
||||||
</mat-checkbox>
|
|
||||||
</div>
|
|
||||||
<div class="actions">
|
|
||||||
<button mat-stroked-button color="primary" matStepperPrevious>{{'ACTIONS.BACK' | translate}}</button>
|
|
||||||
<button mat-raised-button color="primary" matStepperNext>{{'ACTIONS.CONTINUE' | translate}}</button>
|
|
||||||
</div>
|
|
||||||
</mat-step>
|
|
||||||
|
|
||||||
<mat-step [editable]="true" *ngIf="!grantTypeChecked(OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE)">
|
|
||||||
<ng-template matStepLabel>{{'APP.OIDC.RESPONSESECTION' | translate}}</ng-template>
|
<ng-template matStepLabel>{{'APP.OIDC.RESPONSESECTION' | translate}}</ng-template>
|
||||||
<div class="checkbox-container">
|
<div class="checkbox-container">
|
||||||
<mat-checkbox *ngFor="let responsetype of oidcResponseTypes | keyvalue" (change)="changeResponseType()"
|
<mat-checkbox *ngFor="let responsetype of oidcResponseTypes" (change)="changeResponseType()"
|
||||||
color="primary" [(ngModel)]="responsetype.checked">
|
color="primary" [(ngModel)]="responsetype.checked" [disabled]="responsetype.disabled">
|
||||||
{{'APP.OIDC.RESPONSE'+responsetype.key | translate}}
|
{{'APP.OIDC.RESPONSE'+responsetype.type | translate}}
|
||||||
</mat-checkbox>
|
</mat-checkbox>
|
||||||
</div>
|
</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
@ -72,8 +56,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</mat-step>
|
</mat-step>
|
||||||
|
|
||||||
<mat-step [stepControl]="secondFormGroup" [editable]="true"
|
<mat-step *ngIf="oidcApp.applicationType === OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB"
|
||||||
*ngIf="applicationType?.value !== OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE">
|
[stepControl]="secondFormGroup" [editable]="true">
|
||||||
<form [formGroup]="secondFormGroup">
|
<form [formGroup]="secondFormGroup">
|
||||||
<ng-template matStepLabel>{{'APP.OIDC.AUTHMETHODSECTION' | translate}}</ng-template>
|
<ng-template matStepLabel>{{'APP.OIDC.AUTHMETHODSECTION' | translate}}</ng-template>
|
||||||
|
|
||||||
@ -157,19 +141,32 @@
|
|||||||
<span class="left">
|
<span class="left">
|
||||||
{{ 'APP.GRANT' | translate }}
|
{{ 'APP.GRANT' | translate }}
|
||||||
</span>
|
</span>
|
||||||
<span class="right">
|
<span class="right" *ngIf="oidcApp.grantTypesList?.length > 0">
|
||||||
<span *ngFor="let element of oidcApp.grantTypesList">
|
[<span *ngFor="let element of oidcApp.grantTypesList; index as i">
|
||||||
{{'APP.OIDC.GRANT'+element | translate}}
|
{{'APP.OIDC.GRANT'+element | translate}}
|
||||||
</span>
|
{{i < oidcApp.grantTypesList.length - 1 ? ', ': ''}}
|
||||||
|
</span>]
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<span class="left">
|
<span class="left">
|
||||||
{{ 'APP.OIDC.RESPONSE' | translate }}
|
{{ 'APP.OIDC.RESPONSE' | translate }}
|
||||||
</span>
|
</span>
|
||||||
|
<span class="right" *ngIf="oidcApp.responseTypesList?.length > 0">
|
||||||
|
[<span *ngFor="let element of oidcApp.responseTypesList; index as i">
|
||||||
|
{{('APP.OIDC.RESPONSE'+element | translate)}}
|
||||||
|
{{i < oidcApp.responseTypesList.length - 1 ? ', ': ''}}
|
||||||
|
</span>]
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<span class="left">
|
||||||
|
{{ 'APP.OIDC.AUTHMETHOD' | translate }}
|
||||||
|
</span>
|
||||||
<span class="right">
|
<span class="right">
|
||||||
<span *ngFor="let element of oidcApp.responseTypesList">
|
<span>
|
||||||
{{'APP.OIDC.RESPONSE'+element | translate}}
|
{{'APP.OIDC.AUTHMETHOD'+oidcApp?.authMethodType | translate}}
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@ -178,10 +175,11 @@
|
|||||||
<span class="left">
|
<span class="left">
|
||||||
{{ 'APP.OIDC.REDIRECT' | translate }}
|
{{ 'APP.OIDC.REDIRECT' | translate }}
|
||||||
</span>
|
</span>
|
||||||
<span class="right">
|
<span class="right" *ngIf="oidcApp.redirectUrisList?.length > 0">
|
||||||
<span *ngFor="let redirect of oidcApp.redirectUrisList">
|
[<span *ngFor="let redirect of oidcApp.redirectUrisList; index as i">
|
||||||
{{redirect}}
|
{{redirect}}
|
||||||
</span>
|
{{i < oidcApp.redirectUrisList.length - 1 ? ', ': ''}}
|
||||||
|
</span>]
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -189,10 +187,11 @@
|
|||||||
<span class="left">
|
<span class="left">
|
||||||
{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}
|
{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}
|
||||||
</span>
|
</span>
|
||||||
<span class="right">
|
<span class="right" *ngIf="oidcApp.postLogoutRedirectUrisList?.length > 0">
|
||||||
<span *ngFor="let redirect of oidcApp.postLogoutRedirectUrisList">
|
[<span *ngFor="let redirect of oidcApp.postLogoutRedirectUrisList; index as i">
|
||||||
{{redirect}}
|
{{redirect}}
|
||||||
</span>
|
{{i < oidcApp.postLogoutRedirectUrisList.length - 1 ? ', ': ''}}
|
||||||
|
</span>]
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -14,7 +14,11 @@ p.desc {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.container {
|
.container {
|
||||||
padding: 4rem 4rem 2rem 4rem;
|
padding: 4rem 4rem 2rem 4rem;
|
||||||
|
|
||||||
|
mat-progress-bar {
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
.abort-container {
|
.abort-container {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -32,11 +32,36 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
|||||||
public loading: boolean = false;
|
public loading: boolean = false;
|
||||||
public oidcApp: OIDCApplicationCreate.AsObject = new OIDCApplicationCreate().toObject();
|
public oidcApp: OIDCApplicationCreate.AsObject = new OIDCApplicationCreate().toObject();
|
||||||
|
|
||||||
public oidcResponseTypes: { type: OIDCResponseType, checked: boolean; }[] = [
|
public oidcResponseTypes: { type: OIDCResponseType, checked: boolean; disabled: boolean; }[] = [
|
||||||
{ type: OIDCResponseType.OIDCRESPONSETYPE_CODE, checked: false },
|
{ type: OIDCResponseType.OIDCRESPONSETYPE_CODE, checked: false, disabled: false },
|
||||||
{ type: OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN, checked: false },
|
{ type: OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN, checked: false, disabled: false },
|
||||||
{ type: OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN_TOKEN, checked: false },
|
{ type: OIDCResponseType.OIDCRESPONSETYPE_ID_TOKEN_TOKEN, checked: false, disabled: false },
|
||||||
];
|
];
|
||||||
|
|
||||||
|
public oidcAppTypes: OIDCApplicationType[] = [
|
||||||
|
OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB,
|
||||||
|
OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT,
|
||||||
|
OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE,
|
||||||
|
];
|
||||||
|
|
||||||
|
public oidcAuthMethodType: { type: OIDCAuthMethodType, checked: boolean, disabled: boolean; }[] = [
|
||||||
|
{ type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, checked: false, disabled: false },
|
||||||
|
{ type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, checked: false, disabled: false },
|
||||||
|
{ type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST, checked: false, disabled: false },
|
||||||
|
];
|
||||||
|
|
||||||
|
// stepper
|
||||||
|
firstFormGroup!: FormGroup;
|
||||||
|
secondFormGroup!: FormGroup;
|
||||||
|
// thirdFormGroup!: FormGroup;
|
||||||
|
|
||||||
|
// devmode
|
||||||
|
public form!: FormGroup;
|
||||||
|
|
||||||
|
public OIDCApplicationType: any = OIDCApplicationType;
|
||||||
|
public OIDCGrantType: any = OIDCGrantType;
|
||||||
|
public OIDCAuthMethodType: any = OIDCAuthMethodType;
|
||||||
|
|
||||||
public oidcGrantTypes: {
|
public oidcGrantTypes: {
|
||||||
type: OIDCGrantType,
|
type: OIDCGrantType,
|
||||||
checked: boolean,
|
checked: boolean,
|
||||||
@ -47,28 +72,6 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
|||||||
// { type: OIDCGrantType.OIDCGRANTTYPE_REFRESH_TOKEN, checked: false, disabled: true },
|
// { type: OIDCGrantType.OIDCGRANTTYPE_REFRESH_TOKEN, checked: false, disabled: true },
|
||||||
// TODO show when implemented
|
// TODO show when implemented
|
||||||
];
|
];
|
||||||
public oidcAppTypes: OIDCApplicationType[] = [
|
|
||||||
OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB,
|
|
||||||
OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT,
|
|
||||||
OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE,
|
|
||||||
];
|
|
||||||
public oidcAuthMethodType: { type: OIDCAuthMethodType, checked: boolean, disabled: boolean; }[] = [
|
|
||||||
{ type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, checked: false, disabled: false },
|
|
||||||
{ type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE, checked: false, disabled: false },
|
|
||||||
{ type: OIDCAuthMethodType.OIDCAUTHMETHODTYPE_POST, checked: false, disabled: false },
|
|
||||||
];
|
|
||||||
|
|
||||||
// stepper
|
|
||||||
firstFormGroup!: FormGroup;
|
|
||||||
secondFormGroup!: FormGroup;
|
|
||||||
thirdFormGroup!: FormGroup;
|
|
||||||
|
|
||||||
// devmode
|
|
||||||
public form!: FormGroup;
|
|
||||||
|
|
||||||
public OIDCApplicationType: any = OIDCApplicationType;
|
|
||||||
public OIDCGrantType: any = OIDCGrantType;
|
|
||||||
public OIDCAuthMethodType: any = OIDCAuthMethodType;
|
|
||||||
|
|
||||||
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
|
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
|
||||||
|
|
||||||
@ -92,8 +95,8 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
|||||||
this.form.valueChanges.pipe(debounceTime(300)).subscribe((value) => {
|
this.form.valueChanges.pipe(debounceTime(300)).subscribe((value) => {
|
||||||
this.oidcApp.name = this.formname?.value;
|
this.oidcApp.name = this.formname?.value;
|
||||||
this.oidcApp.applicationType = this.formapplicationType?.value;
|
this.oidcApp.applicationType = this.formapplicationType?.value;
|
||||||
this.oidcApp.grantTypesList = this.formgrantTypesList?.value;
|
|
||||||
this.oidcApp.responseTypesList = this.formresponseTypesList?.value;
|
this.oidcApp.responseTypesList = this.formresponseTypesList?.value;
|
||||||
|
this.oidcApp.grantTypesList = this.formgrantTypesList?.value;
|
||||||
this.oidcApp.authMethodType = this.formauthMethodType?.value;
|
this.oidcApp.authMethodType = this.formauthMethodType?.value;
|
||||||
|
|
||||||
console.log(this.oidcApp);
|
console.log(this.oidcApp);
|
||||||
@ -103,48 +106,60 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
|||||||
name: ['', [Validators.required]],
|
name: ['', [Validators.required]],
|
||||||
applicationType: ['', [Validators.required]],
|
applicationType: ['', [Validators.required]],
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.firstFormGroup.valueChanges.subscribe(value => {
|
||||||
|
if (this.firstFormGroup.valid) {
|
||||||
|
console.log('change firstform', value);
|
||||||
|
switch (value.applicationType) {
|
||||||
|
case OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE:
|
||||||
|
console.log('NATIVE');
|
||||||
|
this.oidcResponseTypes[0].checked = true;
|
||||||
|
this.oidcApp.responseTypesList = [OIDCResponseType.OIDCRESPONSETYPE_CODE];
|
||||||
|
|
||||||
|
this.oidcApp.grantTypesList =
|
||||||
|
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE];
|
||||||
|
this.oidcApp.authMethodType = OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE;
|
||||||
|
break;
|
||||||
|
case OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB:
|
||||||
|
console.log('WEB');
|
||||||
|
|
||||||
|
this.oidcAuthMethodType[0].disabled = false;
|
||||||
|
this.oidcAuthMethodType[1].disabled = true; // NONE DISABLED
|
||||||
|
this.oidcAuthMethodType[2].disabled = false; // POST POSSIBLE
|
||||||
|
this.authMethodType?.setValue(OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC); // BASIC DEFAULT
|
||||||
|
this.oidcApp.authMethodType = OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC;
|
||||||
|
|
||||||
|
this.oidcResponseTypes[0].checked = true;
|
||||||
|
this.oidcApp.responseTypesList = [OIDCResponseType.OIDCRESPONSETYPE_CODE];
|
||||||
|
this.changeResponseType();
|
||||||
|
|
||||||
|
this.oidcApp.grantTypesList =
|
||||||
|
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE];
|
||||||
|
|
||||||
|
break;
|
||||||
|
case OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT:
|
||||||
|
console.log('USERAGENT');
|
||||||
|
|
||||||
|
this.oidcResponseTypes[0].checked = true;
|
||||||
|
this.oidcApp.responseTypesList = [OIDCResponseType.OIDCRESPONSETYPE_CODE];
|
||||||
|
|
||||||
|
this.oidcApp.grantTypesList =
|
||||||
|
[OIDCGrantType.OIDCGRANTTYPE_AUTHORIZATION_CODE, OIDCGrantType.OIDCGRANTTYPE_IMPLICIT];
|
||||||
|
|
||||||
|
this.oidcApp.authMethodType = OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.oidcApp.name = this.name?.value;
|
||||||
|
this.oidcApp.applicationType = this.applicationType?.value;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
this.secondFormGroup = this.fb.group({
|
this.secondFormGroup = this.fb.group({
|
||||||
authMethodType: [OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, [Validators.required]],
|
authMethodType: [OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC, [Validators.required]],
|
||||||
});
|
});
|
||||||
|
|
||||||
this.oidcApp.authMethodType = OIDCAuthMethodType.OIDCAUTHMETHODTYPE_BASIC;
|
|
||||||
|
|
||||||
this.firstFormGroup.valueChanges.subscribe(value => {
|
|
||||||
if (this.applicationType?.value === OIDCApplicationType.OIDCAPPLICATIONTYPE_NATIVE) {
|
|
||||||
this.oidcResponseTypes[0].checked = true;
|
|
||||||
// this.oidcApp.responseTypesList = [this.oidcResponseTypes[0].type];
|
|
||||||
|
|
||||||
this.authMethodType?.setValue(OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE);
|
|
||||||
this.oidcAuthMethodType[1].disabled = true;
|
|
||||||
}
|
|
||||||
if (this.applicationType?.value === OIDCApplicationType.OIDCAPPLICATIONTYPE_WEB) {
|
|
||||||
this.oidcResponseTypes[0].checked = true;
|
|
||||||
this.oidcApp.responseTypesList = [this.oidcResponseTypes[0].type];
|
|
||||||
|
|
||||||
this.authMethodType?.setValue(OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE);
|
|
||||||
this.oidcAuthMethodType[0].disabled = true;
|
|
||||||
this.oidcAuthMethodType[2].disabled = true;
|
|
||||||
}
|
|
||||||
if (this.applicationType?.value === OIDCApplicationType.OIDCAPPLICATIONTYPE_USER_AGENT) {
|
|
||||||
this.oidcResponseTypes[0].checked = true;
|
|
||||||
this.oidcApp.responseTypesList = [this.oidcResponseTypes[0].type];
|
|
||||||
|
|
||||||
this.authMethodType?.setValue(OIDCAuthMethodType.OIDCAUTHMETHODTYPE_NONE);
|
|
||||||
this.oidcAuthMethodType[0].disabled = true;
|
|
||||||
this.oidcAuthMethodType[2].disabled = true;
|
|
||||||
|
|
||||||
this.oidcGrantTypes[1].disabled = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.changeResponseType();
|
|
||||||
this.changeGrant();
|
|
||||||
|
|
||||||
this.oidcApp.name = this.name?.value;
|
|
||||||
this.oidcApp.applicationType = this.applicationType?.value;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.secondFormGroup.valueChanges.subscribe(value => {
|
this.secondFormGroup.valueChanges.subscribe(value => {
|
||||||
this.oidcApp.authMethodType = this.authMethodType?.value;
|
this.oidcApp.authMethodType = value.authMethodType;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -226,14 +241,14 @@ export class AppCreateComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
changeGrant(): void {
|
|
||||||
this.oidcApp.grantTypesList = this.oidcGrantTypes.filter(gt => gt.checked).map(gt => gt.type);
|
|
||||||
}
|
|
||||||
|
|
||||||
changeResponseType(): void {
|
changeResponseType(): void {
|
||||||
this.oidcApp.responseTypesList = this.oidcResponseTypes.filter(gt => gt.checked).map(gt => gt.type);
|
this.oidcApp.responseTypesList = this.oidcResponseTypes.filter(gt => gt.checked).map(gt => gt.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
moreThanOneOption(options: Array<{ type: OIDCGrantType, checked: boolean, disabled: boolean; }>): boolean {
|
||||||
|
return options.filter(option => option.disabled === false).length > 1;
|
||||||
|
}
|
||||||
|
|
||||||
get name(): AbstractControl | null {
|
get name(): AbstractControl | null {
|
||||||
return this.firstFormGroup.get('name');
|
return this.firstFormGroup.get('name');
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,9 @@
|
|||||||
<mat-form-field class="full-width" appearance="outline">
|
<mat-form-field class="full-width" appearance="outline">
|
||||||
<mat-label>{{ 'APP.OIDC.REDIRECT' | translate }}</mat-label>
|
<mat-label>{{ 'APP.OIDC.REDIRECT' | translate }}</mat-label>
|
||||||
<mat-chip-list #chipRedirectList>
|
<mat-chip-list #chipRedirectList>
|
||||||
<mat-chip *ngFor="let redirect of redirectUrisList" [selectable]="selectable"
|
<mat-chip *ngFor="let redirect of redirectUrisList" selected
|
||||||
|
[matTooltip]="!redirect.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
|
||||||
|
[color]="!redirect.startsWith('https://') ? 'warn': 'green'"
|
||||||
(removed)="remove(redirect, RedirectType.REDIRECT)">
|
(removed)="remove(redirect, RedirectType.REDIRECT)">
|
||||||
{{redirect}}
|
{{redirect}}
|
||||||
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
|
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
|
||||||
@ -100,8 +102,10 @@
|
|||||||
<mat-form-field class="full-width" appearance="outline">
|
<mat-form-field class="full-width" appearance="outline">
|
||||||
<mat-label>{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}</mat-label>
|
<mat-label>{{ 'APP.OIDC.POSTLOGOUTREDIRECT' | translate }}</mat-label>
|
||||||
<mat-chip-list #chipPostRedirectList>
|
<mat-chip-list #chipPostRedirectList>
|
||||||
<mat-chip *ngFor="let redirect of postLogoutRedirectUrisList" [selectable]="selectable"
|
<mat-chip *ngFor="let redirect of postLogoutRedirectUrisList" selected
|
||||||
(removed)="remove(redirect, RedirectType.POSTREDIRECT)">
|
(removed)="remove(redirect, RedirectType.POSTREDIRECT)"
|
||||||
|
[matTooltip]="!redirect.startsWith('https://') ? ('APP.OIDC.UNSECUREREDIRECT' | translate): ''"
|
||||||
|
[color]="!redirect.startsWith('https://') ? 'warn': 'green'">
|
||||||
{{redirect}}
|
{{redirect}}
|
||||||
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
|
<mat-icon matChipRemove *ngIf="removable">cancel</mat-icon>
|
||||||
</mat-chip>
|
</mat-chip>
|
||||||
|
@ -84,4 +84,8 @@
|
|||||||
border-radius: .5rem;
|
border-radius: .5rem;
|
||||||
margin: 0 .5rem;
|
margin: 0 .5rem;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mat-chip[color='green'] {
|
||||||
|
background-color: #56a392 !important;
|
||||||
}
|
}
|
@ -35,7 +35,6 @@ enum RedirectType {
|
|||||||
})
|
})
|
||||||
export class AppDetailComponent implements OnInit, OnDestroy {
|
export class AppDetailComponent implements OnInit, OnDestroy {
|
||||||
public errorMessage: string = '';
|
public errorMessage: string = '';
|
||||||
public selectable: boolean = false;
|
|
||||||
public removable: boolean = true;
|
public removable: boolean = true;
|
||||||
public addOnBlur: boolean = true;
|
public addOnBlur: boolean = true;
|
||||||
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
|
public readonly separatorKeysCodes: number[] = [ENTER, COMMA, SPACE];
|
||||||
@ -219,7 +218,7 @@ export class AppDetailComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
this.projectService
|
this.projectService
|
||||||
.UpdateOIDCAppConfig(this.projectId, this.app.id, this.app.oidcConfig)
|
.UpdateOIDCAppConfig(this.projectId, this.app.id, this.app.oidcConfig)
|
||||||
.then((data: OIDCConfig) => {
|
.then(() => {
|
||||||
this.toast.showInfo('APP.TOAST.OIDCUPDATED', true);
|
this.toast.showInfo('APP.TOAST.OIDCUPDATED', true);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
<div *ngIf="data.clientSecret" class="flex">
|
<div *ngIf="data.clientSecret" class="flex">
|
||||||
<button color="primary" [disabled]="copied == data.clientSecret" matTooltip="copy to clipboard"
|
<button color="primary" [disabled]="copied == data.clientSecret" matTooltip="copy to clipboard"
|
||||||
(click)="copytoclipboard(data.clientSecret)" mat-icon-button>
|
appCopyToClipboard [valueToCopy]="data.clientSecret" (copiedValue)="this.copied = $event" mat-icon-button>
|
||||||
<i *ngIf="copied != data.clientSecret" class="las la-clipboard"></i>
|
<i *ngIf="copied != data.clientSecret" class="las la-clipboard"></i>
|
||||||
<i *ngIf="copied == data.clientSecret" class="las la-clipboard-check"></i>
|
<i *ngIf="copied == data.clientSecret" class="las la-clipboard-check"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -14,22 +14,4 @@ export class AppSecretDialogComponent {
|
|||||||
public closeDialog(): void {
|
public closeDialog(): void {
|
||||||
this.dialogRef.close(false);
|
this.dialogRef.close(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public copytoclipboard(value: string): void {
|
|
||||||
const selBox = document.createElement('textarea');
|
|
||||||
selBox.style.position = 'fixed';
|
|
||||||
selBox.style.left = '0';
|
|
||||||
selBox.style.top = '0';
|
|
||||||
selBox.style.opacity = '0';
|
|
||||||
selBox.value = value;
|
|
||||||
document.body.appendChild(selBox);
|
|
||||||
selBox.focus();
|
|
||||||
selBox.select();
|
|
||||||
document.execCommand('copy');
|
|
||||||
document.body.removeChild(selBox);
|
|
||||||
this.copied = value;
|
|
||||||
setTimeout(() => {
|
|
||||||
this.copied = '';
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,7 @@ import { MatSelectModule } from '@angular/material/select';
|
|||||||
import { MatStepperModule } from '@angular/material/stepper';
|
import { MatStepperModule } from '@angular/material/stepper';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
|
import { CopyToClipboardModule } from 'src/app/directives/copy-to-clipboard/copy-to-clipboard.module';
|
||||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||||
import { CardModule } from 'src/app/modules/card/card.module';
|
import { CardModule } from 'src/app/modules/card/card.module';
|
||||||
|
|
||||||
@ -55,6 +56,7 @@ import { AppsRoutingModule } from './apps-routing.module';
|
|||||||
TranslateModule,
|
TranslateModule,
|
||||||
MatStepperModule,
|
MatStepperModule,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
|
CopyToClipboardModule,
|
||||||
],
|
],
|
||||||
exports: [TranslateModule],
|
exports: [TranslateModule],
|
||||||
})
|
})
|
||||||
|
@ -34,8 +34,8 @@
|
|||||||
|
|
||||||
<mat-tab-group mat-stretch-tabs class="tab-group" disablePagination="true">
|
<mat-tab-group mat-stretch-tabs class="tab-group" disablePagination="true">
|
||||||
<mat-tab label="Details">
|
<mat-tab label="Details">
|
||||||
<app-contributors [totalResult]="totalMemberResult" [membersSubject]="membersSubject"
|
<app-contributors [totalResult]="totalMemberResult" [loading]="loading$ | async"
|
||||||
title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
|
[membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
|
||||||
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
|
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
|
||||||
(showDetailClicked)="showDetail()" [disabled]="false">
|
(showDetailClicked)="showDetail()" [disabled]="false">
|
||||||
</app-contributors>
|
</app-contributors>
|
||||||
|
@ -5,7 +5,7 @@ import { MatDialog } from '@angular/material/dialog';
|
|||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { BehaviorSubject, from, of, Subscription } from 'rxjs';
|
import { BehaviorSubject, from, Observable, of, Subscription } from 'rxjs';
|
||||||
import { catchError, finalize, map } from 'rxjs/operators';
|
import { catchError, finalize, map } from 'rxjs/operators';
|
||||||
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
|
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
|
||||||
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||||
@ -72,7 +72,8 @@ export class GrantedProjectDetailComponent implements OnInit, OnDestroy {
|
|||||||
public totalMemberResult: number = 0;
|
public totalMemberResult: number = 0;
|
||||||
public membersSubject: BehaviorSubject<ProjectMemberView.AsObject[]>
|
public membersSubject: BehaviorSubject<ProjectMemberView.AsObject[]>
|
||||||
= new BehaviorSubject<ProjectMemberView.AsObject[]>([]);
|
= new BehaviorSubject<ProjectMemberView.AsObject[]>([]);
|
||||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||||
|
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public translate: TranslateService,
|
public translate: TranslateService,
|
||||||
|
@ -26,7 +26,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<button [ngClass]="{ selected: selection.isSelected(item)}" (click)="selection.toggle(item)" class="edit-button"
|
<button [ngClass]="{ selected: selection.isSelected(item)}" (click)="selection.toggle(item)" class="edit-button"
|
||||||
mat-icon-button>
|
mat-icon-button>
|
||||||
<mat-icon>push_pin_outline</mat-icon>
|
<mat-icon *ngIf="selection.isSelected(item)" svgIcon="mdi_pin"></mat-icon>
|
||||||
|
<mat-icon svgIcon="mdi_pin_outline" *ngIf="!selection.isSelected(item)"></mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -52,7 +53,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<button [ngClass]="{ selected: selection.isSelected(item)}" (click)="selection.toggle(item)" class="edit-button"
|
<button [ngClass]="{ selected: selection.isSelected(item)}" (click)="selection.toggle(item)" class="edit-button"
|
||||||
mat-icon-button>
|
mat-icon-button>
|
||||||
<mat-icon>push_pin_outline</mat-icon>
|
<mat-icon *ngIf="selection.isSelected(item)" svgIcon="mdi_pin"></mat-icon>
|
||||||
|
<mat-icon svgIcon="mdi_pin_outline" *ngIf="!selection.isSelected(item)"></mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p class="n-items" *ngIf="!loading && items.length === 0 && selection.selected.length === 0">
|
<p class="n-items" *ngIf="!loading && items.length === 0 && selection.selected.length === 0">
|
||||||
|
@ -6,16 +6,21 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="app-container">
|
<div class="app-container">
|
||||||
|
<div class="sp-container" *ngIf="(loading$ | async)">
|
||||||
|
<mat-spinner color="accent" diameter="50"></mat-spinner>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div [routerLink]="['/projects', projectId, 'apps', app.id ]" class="app-wrap"
|
<div [routerLink]="['/projects', projectId, 'apps', app.id ]" class="app-wrap"
|
||||||
*ngFor="let app of appsSubject | async">
|
*ngFor="let app of appsSubject | async">
|
||||||
<div class="morph-card">
|
<div class="morph-card" matRipple>
|
||||||
{{ app.name.charAt(0)}}
|
{{ app.name.charAt(0)}}
|
||||||
</div>
|
</div>
|
||||||
<span class="name">{{app.name}}</span>
|
<span class="name">{{app.name}}</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ng-template appHasRole [appHasRole]="['project.app.write']">
|
<ng-template appHasRole [appHasRole]="['project.app.write']">
|
||||||
<div class="app-wrap" *ngIf="!disabled" [routerLink]="[ '/projects', projectId, 'apps', 'create']">
|
<div class="app-wrap" *ngIf="!disabled" [routerLink]="[ '/projects', projectId, 'apps', 'create']">
|
||||||
<div class="morph-card add">
|
<div class="morph-card add" matRipple>
|
||||||
<mat-icon>add</mat-icon>
|
<mat-icon>add</mat-icon>
|
||||||
</div>
|
</div>
|
||||||
<span class="name">{{ 'ACTIONS.NEW' | translate }}</span>
|
<span class="name">{{ 'ACTIONS.NEW' | translate }}</span>
|
||||||
|
@ -21,6 +21,14 @@
|
|||||||
margin: 0 -1rem;
|
margin: 0 -1rem;
|
||||||
padding-bottom: 2rem;
|
padding-bottom: 2rem;
|
||||||
|
|
||||||
|
.sp-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: calc(82px + 2rem);
|
||||||
|
height: calc(82px + 2rem);
|
||||||
|
}
|
||||||
|
|
||||||
.app-wrap {
|
.app-wrap {
|
||||||
outline: none;
|
outline: none;
|
||||||
display: flex;
|
display: flex;
|
||||||
@ -40,11 +48,24 @@
|
|||||||
margin: 1rem;
|
margin: 1rem;
|
||||||
border-radius: .5rem;
|
border-radius: .5rem;
|
||||||
border: 1px solid $accent-color;
|
border: 1px solid $accent-color;
|
||||||
|
font-weight: 800;
|
||||||
background-color: $primary-dark;
|
background-color: $primary-dark;
|
||||||
transition: background-color .4s ease-in-out;
|
transition: background-color .2s ease-in-out;
|
||||||
|
background-image:
|
||||||
|
linear-gradient(transparent 11px, rgba($accent-color,.5) 12px, transparent 12px),
|
||||||
|
linear-gradient(90deg, transparent 11px, rgba($accent-color,.5) 12px, transparent 12px);
|
||||||
|
background-size: 100% 12px, 12px 100%;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba($accent-color,.2);
|
||||||
|
}
|
||||||
|
|
||||||
&.add {
|
&.add {
|
||||||
background: $accent-color;
|
background: $accent-color;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background-color: rgba($accent-color,.8);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ export class ApplicationGridComponent implements OnInit {
|
|||||||
@Input() public disabled: boolean = false;
|
@Input() public disabled: boolean = false;
|
||||||
@Output() public changeView: EventEmitter<void> = new EventEmitter();
|
@Output() public changeView: EventEmitter<void> = new EventEmitter();
|
||||||
public appsSubject: BehaviorSubject<Application.AsObject[]> = new BehaviorSubject<Application.AsObject[]>([]);
|
public appsSubject: BehaviorSubject<Application.AsObject[]> = new BehaviorSubject<Application.AsObject[]>([]);
|
||||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||||
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||||
|
|
||||||
constructor(private projectService: ProjectService) { }
|
constructor(private projectService: ProjectService) { }
|
||||||
|
@ -19,7 +19,7 @@ export class ProjectApplicationsDataSource extends DataSource<Application.AsObje
|
|||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
public loadApps(projectId: string, pageIndex: number, pageSize: number, sortDirection?: string): void {
|
public loadApps(projectId: string, pageIndex: number, pageSize: number): void {
|
||||||
const offset = pageIndex * pageSize;
|
const offset = pageIndex * pageSize;
|
||||||
|
|
||||||
this.loadingSubject.next(true);
|
this.loadingSubject.next(true);
|
||||||
|
@ -1,54 +1,41 @@
|
|||||||
<div class="table-header-row">
|
<app-refresh-table [loading]="dataSource.loading$ | async" [selection]="selection" (refreshed)="refreshPage()"
|
||||||
<div class="col">
|
[dataSize]="dataSource.totalResult">
|
||||||
<ng-container *ngIf="!selection.hasValue()">
|
<ng-template appHasRole [appHasRole]="['project.app.write']" actions>
|
||||||
<span class="desc">{{'ORG_DETAIL.TABLE.TOTAL' | translate}}</span>
|
|
||||||
<span class="count">{{dataSource?.appsSubject.value.length}}</span>
|
|
||||||
</ng-container>
|
|
||||||
<ng-container *ngIf="selection.hasValue()">
|
|
||||||
<span class="desc">{{'ORG_DETAIL.TABLE.SELECTION' | translate}}</span>
|
|
||||||
<span class="count">{{selection?.selected?.length}}</span>
|
|
||||||
</ng-container>
|
|
||||||
</div>
|
|
||||||
<span class="fill-space"></span>
|
|
||||||
<ng-template appHasRole [appHasRole]="['project.app.write']">
|
|
||||||
<a [disabled]="disabled" class="add-button" [routerLink]="[ '/projects', projectId, 'apps', 'create']"
|
<a [disabled]="disabled" class="add-button" [routerLink]="[ '/projects', projectId, 'apps', 'create']"
|
||||||
color="primary" mat-raised-button>
|
color="primary" mat-raised-button>
|
||||||
<mat-icon class="icon">add</mat-icon>{{ 'ACTIONS.NEW' | translate }}
|
<mat-icon class="icon">add</mat-icon>{{ 'ACTIONS.NEW' | translate }}
|
||||||
</a>
|
</a>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="table-wrapper">
|
<div class="table-wrapper">
|
||||||
<div class="spinner-container" *ngIf="dataSource.loading$ | async">
|
<table [dataSource]="dataSource" mat-table class="full-width-table" matSort aria-label="Elements">
|
||||||
<mat-spinner diameter="50"></mat-spinner>
|
<ng-container matColumnDef="select">
|
||||||
|
<th class="selection" mat-header-cell *matHeaderCellDef>
|
||||||
|
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
|
||||||
|
[checked]="selection.hasValue() && isAllSelected()"
|
||||||
|
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
||||||
|
</mat-checkbox>
|
||||||
|
</th>
|
||||||
|
<td class="selection" mat-cell *matCellDef="let row">
|
||||||
|
<mat-checkbox color="primary" (click)="$event.stopPropagation()"
|
||||||
|
(change)="$event ? selection.toggle(row) : null" [checked]="selection.isSelected(row)">
|
||||||
|
</mat-checkbox>
|
||||||
|
</td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<ng-container matColumnDef="name">
|
||||||
|
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.ROLE.NAME' | translate }} </th>
|
||||||
|
<td class="pointer" [routerLink]="['/projects', projectId, 'apps', role.id ]" mat-cell
|
||||||
|
*matCellDef="let role">
|
||||||
|
{{role.name}} </td>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
|
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||||
|
<tr class="data-row" mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<mat-paginator #paginator [length]="dataSource.totalResult" [pageSize]="25"
|
||||||
|
[pageSizeOptions]="[25, 50, 100, 250]">
|
||||||
|
</mat-paginator>
|
||||||
</div>
|
</div>
|
||||||
|
</app-refresh-table>
|
||||||
<table [dataSource]="dataSource" mat-table class="full-width-table" matSort aria-label="Elements">
|
|
||||||
<ng-container matColumnDef="select">
|
|
||||||
<th class="selection" mat-header-cell *matHeaderCellDef>
|
|
||||||
<mat-checkbox color="primary" (change)="$event ? masterToggle() : null"
|
|
||||||
[checked]="selection.hasValue() && isAllSelected()"
|
|
||||||
[indeterminate]="selection.hasValue() && !isAllSelected()">
|
|
||||||
</mat-checkbox>
|
|
||||||
</th>
|
|
||||||
<td class="selection" mat-cell *matCellDef="let row">
|
|
||||||
<mat-checkbox color="primary" (click)="$event.stopPropagation()"
|
|
||||||
(change)="$event ? selection.toggle(row) : null" [checked]="selection.isSelected(row)">
|
|
||||||
</mat-checkbox>
|
|
||||||
</td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<ng-container matColumnDef="name">
|
|
||||||
<th mat-header-cell *matHeaderCellDef> {{ 'PROJECT.ROLE.NAME' | translate }} </th>
|
|
||||||
<td class="pointer" [routerLink]="['/projects', projectId, 'apps', role.id ]" mat-cell
|
|
||||||
*matCellDef="let role">
|
|
||||||
{{role.name}} </td>
|
|
||||||
</ng-container>
|
|
||||||
|
|
||||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
|
||||||
<tr class="data-row" mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<mat-paginator #paginator [length]="dataSource.totalResult" [pageSize]="50" [pageSizeOptions]="[25, 50, 100, 250]">
|
|
||||||
</mat-paginator>
|
|
||||||
</div>
|
|
@ -1,73 +1,39 @@
|
|||||||
|
|
||||||
.table-header-row {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
.col {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
.desc {
|
|
||||||
font-size: .8rem;
|
|
||||||
color: #8795a1;
|
|
||||||
}
|
|
||||||
.count {
|
|
||||||
font-size: 2rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fill-space {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.icon-button {
|
|
||||||
margin-right: .5rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.add-button {
|
|
||||||
border-radius: .5rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.table-wrapper {
|
.table-wrapper {
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
|
||||||
.spinner-container {
|
table, mat-paginator {
|
||||||
display: flex;
|
width: 100%;
|
||||||
align-items: center;
|
background-color: #2d2e30;
|
||||||
justify-content: center;
|
|
||||||
|
td, th {
|
||||||
|
&:first-child {
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
padding-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-row {
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
background-color: #ffffff05;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.selection {
|
||||||
|
width: 50px;
|
||||||
|
max-width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.margin-neg {
|
||||||
|
margin-left: -1rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table, mat-paginator {
|
|
||||||
width: 100%;
|
|
||||||
background-color: #2d2e30;
|
|
||||||
|
|
||||||
td, th {
|
|
||||||
&:first-child {
|
|
||||||
padding-left: 0;
|
|
||||||
padding-right: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:last-child {
|
|
||||||
padding-right: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.data-row {
|
|
||||||
cursor: pointer;
|
|
||||||
&:hover {
|
|
||||||
background-color: #ffffff05;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.selection {
|
|
||||||
width: 50px;
|
|
||||||
max-width: 50px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.margin-neg {
|
|
||||||
margin-left: -1rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.pointer {
|
.pointer {
|
||||||
|
@ -33,7 +33,7 @@ export class ApplicationsComponent implements AfterViewInit, OnInit {
|
|||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
this.dataSource = new ProjectApplicationsDataSource(this.projectService);
|
this.dataSource = new ProjectApplicationsDataSource(this.projectService);
|
||||||
this.dataSource.loadApps(this.projectId, 0, 25, 'asc');
|
this.dataSource.loadApps(this.projectId, 0, 25);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ngAfterViewInit(): void {
|
public ngAfterViewInit(): void {
|
||||||
@ -51,7 +51,6 @@ export class ApplicationsComponent implements AfterViewInit, OnInit {
|
|||||||
this.projectId,
|
this.projectId,
|
||||||
this.paginator.pageIndex,
|
this.paginator.pageIndex,
|
||||||
this.paginator.pageSize,
|
this.paginator.pageSize,
|
||||||
this.sort.direction,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -66,4 +65,8 @@ export class ApplicationsComponent implements AfterViewInit, OnInit {
|
|||||||
this.selection.clear() :
|
this.selection.clear() :
|
||||||
this.dataSource.appsSubject.value.forEach((row: Application.AsObject) => this.selection.select(row));
|
this.dataSource.appsSubject.value.forEach((row: Application.AsObject) => this.selection.select(row));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public refreshPage(): void {
|
||||||
|
this.dataSource.loadApps(this.projectId, this.paginator.pageIndex, this.paginator.pageSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -101,8 +101,8 @@
|
|||||||
|
|
||||||
<mat-tab-group mat-stretch-tabs class="tab-group" disablePagination="true">
|
<mat-tab-group mat-stretch-tabs class="tab-group" disablePagination="true">
|
||||||
<mat-tab label="Details">
|
<mat-tab label="Details">
|
||||||
<app-contributors [totalResult]="totalMemberResult" [membersSubject]="membersSubject"
|
<app-contributors [loading]="loading$ | async" [totalResult]="totalMemberResult"
|
||||||
title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
|
[membersSubject]="membersSubject" title="{{ 'PROJECT.MEMBER.TITLE' | translate }}"
|
||||||
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
|
description="{{ 'PROJECT.MEMBER.TITLEDESC' | translate }}" (addClicked)="openAddMember()"
|
||||||
(showDetailClicked)="showDetail()" [disabled]="false">
|
(showDetailClicked)="showDetail()" [disabled]="false">
|
||||||
</app-contributors>
|
</app-contributors>
|
||||||
|
@ -5,7 +5,7 @@ import { MatDialog } from '@angular/material/dialog';
|
|||||||
import { MatTableDataSource } from '@angular/material/table';
|
import { MatTableDataSource } from '@angular/material/table';
|
||||||
import { ActivatedRoute, Params, Router } from '@angular/router';
|
import { ActivatedRoute, Params, Router } from '@angular/router';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { BehaviorSubject, from, of, Subscription } from 'rxjs';
|
import { BehaviorSubject, from, Observable, of, Subscription } from 'rxjs';
|
||||||
import { catchError, finalize, map } from 'rxjs/operators';
|
import { catchError, finalize, map } from 'rxjs/operators';
|
||||||
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
|
import { CreationType, MemberCreateDialogComponent } from 'src/app/modules/add-member-dialog/member-create-dialog.component';
|
||||||
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||||
@ -72,7 +72,8 @@ export class OwnedProjectDetailComponent implements OnInit, OnDestroy {
|
|||||||
public totalMemberResult: number = 0;
|
public totalMemberResult: number = 0;
|
||||||
public membersSubject: BehaviorSubject<ProjectMemberView.AsObject[]>
|
public membersSubject: BehaviorSubject<ProjectMemberView.AsObject[]>
|
||||||
= new BehaviorSubject<ProjectMemberView.AsObject[]>([]);
|
= new BehaviorSubject<ProjectMemberView.AsObject[]>([]);
|
||||||
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
|
private loadingSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(true);
|
||||||
|
public loading$: Observable<boolean> = this.loadingSubject.asObservable();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public translate: TranslateService,
|
public translate: TranslateService,
|
||||||
|
@ -3,6 +3,7 @@ import { NgModule } from '@angular/core';
|
|||||||
import { FormsModule } from '@angular/forms';
|
import { FormsModule } from '@angular/forms';
|
||||||
import { MatButtonModule } from '@angular/material/button';
|
import { MatButtonModule } from '@angular/material/button';
|
||||||
import { MatCheckboxModule } from '@angular/material/checkbox';
|
import { MatCheckboxModule } from '@angular/material/checkbox';
|
||||||
|
import { MatRippleModule } from '@angular/material/core';
|
||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||||
@ -56,6 +57,7 @@ import { ProjectGrantsComponent } from './project-grants/project-grants.componen
|
|||||||
MatFormFieldModule,
|
MatFormFieldModule,
|
||||||
CardModule,
|
CardModule,
|
||||||
MatPaginatorModule,
|
MatPaginatorModule,
|
||||||
|
MatRippleModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatSelectModule,
|
MatSelectModule,
|
||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
|
@ -29,7 +29,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<button [ngClass]="{ selected: selection.isSelected(item)}" (click)="selection.toggle(item)" class="edit-button"
|
<button [ngClass]="{ selected: selection.isSelected(item)}" (click)="selection.toggle(item)" class="edit-button"
|
||||||
mat-icon-button>
|
mat-icon-button>
|
||||||
<mat-icon>push_pin</mat-icon>
|
<mat-icon *ngIf="selection.isSelected(item)" svgIcon="mdi_pin"></mat-icon>
|
||||||
|
<mat-icon svgIcon="mdi_pin_outline" *ngIf="!selection.isSelected(item)"></mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -57,7 +58,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<button [ngClass]="{ selected: selection.isSelected(item)}" (click)="selection.toggle(item)" class="edit-button"
|
<button [ngClass]="{ selected: selection.isSelected(item)}" (click)="selection.toggle(item)" class="edit-button"
|
||||||
mat-icon-button>
|
mat-icon-button>
|
||||||
<mat-icon>push_pin</mat-icon>
|
<mat-icon *ngIf="selection.isSelected(item)" svgIcon="mdi_pin"></mat-icon>
|
||||||
|
<mat-icon svgIcon="mdi_pin_outline" *ngIf="!selection.isSelected(item)"></mat-icon>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -133,10 +133,6 @@
|
|||||||
margin-bottom: 0.25rem;
|
margin-bottom: 0.25rem;
|
||||||
color: #8795a1;
|
color: #8795a1;
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import { MatFormFieldModule } from '@angular/material/form-field';
|
|||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import { MatTableModule } from '@angular/material/table';
|
import { MatTableModule } from '@angular/material/table';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
@ -39,6 +40,7 @@ import { ProjectGrantMembersModule } from './project-grant-members/project-grant
|
|||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
FormsModule,
|
FormsModule,
|
||||||
TranslateModule,
|
TranslateModule,
|
||||||
|
MatSelectModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class ProjectGrantDetailModule { }
|
export class ProjectGrantDetailModule { }
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
<p class="desc">{{ 'USER.CREATE.DESCRIPTION' | translate }}</p>
|
<p class="desc">{{ 'USER.CREATE.DESCRIPTION' | translate }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<mat-progress-bar *ngIf="loading" color="accent" mode="indeterminate"></mat-progress-bar>
|
||||||
|
|
||||||
<form *ngIf="userForm" [formGroup]="userForm" (ngSubmit)="createUser()" class="form">
|
<form *ngIf="userForm" [formGroup]="userForm" (ngSubmit)="createUser()" class="form">
|
||||||
<!-- <h2>{{ 'USER.PAGES.CREATE' | translate}}</h2> -->
|
<!-- <h2>{{ 'USER.PAGES.CREATE' | translate}}</h2> -->
|
||||||
<div class="content">
|
<div class="content">
|
||||||
|
@ -39,6 +39,7 @@ export class UserCreateComponent implements OnDestroy {
|
|||||||
private sub: Subscription = new Subscription();
|
private sub: Subscription = new Subscription();
|
||||||
|
|
||||||
public userLoginMustBeDomain: boolean = false;
|
public userLoginMustBeDomain: boolean = false;
|
||||||
|
public loading: boolean = false;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private router: Router,
|
private router: Router,
|
||||||
@ -47,12 +48,15 @@ export class UserCreateComponent implements OnDestroy {
|
|||||||
private fb: FormBuilder,
|
private fb: FormBuilder,
|
||||||
private orgService: OrgService,
|
private orgService: OrgService,
|
||||||
) {
|
) {
|
||||||
|
this.loading = true;
|
||||||
this.orgService.GetMyOrgIamPolicy().then((iampolicy) => {
|
this.orgService.GetMyOrgIamPolicy().then((iampolicy) => {
|
||||||
this.userLoginMustBeDomain = iampolicy.toObject().userLoginMustBeDomain;
|
this.userLoginMustBeDomain = iampolicy.toObject().userLoginMustBeDomain;
|
||||||
this.initForm();
|
this.initForm();
|
||||||
|
this.loading = false;
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
this.initForm();
|
this.initForm();
|
||||||
|
this.loading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -83,13 +87,16 @@ export class UserCreateComponent implements OnDestroy {
|
|||||||
public createUser(): void {
|
public createUser(): void {
|
||||||
this.user = this.userForm.value;
|
this.user = this.userForm.value;
|
||||||
|
|
||||||
|
this.loading = true;
|
||||||
this.userService
|
this.userService
|
||||||
.CreateUser(this.user)
|
.CreateUser(this.user)
|
||||||
.then((data: User) => {
|
.then((data: User) => {
|
||||||
|
this.loading = false;
|
||||||
this.toast.showInfo('USER.TOAST.CREATED', true);
|
this.toast.showInfo('USER.TOAST.CREATED', true);
|
||||||
this.router.navigate(['users', data.getId()]);
|
this.router.navigate(['users', data.getId()]);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
this.loading = false;
|
||||||
this.toast.showError(error);
|
this.toast.showError(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ import { MatCheckboxModule } from '@angular/material/checkbox';
|
|||||||
import { MatFormFieldModule } from '@angular/material/form-field';
|
import { MatFormFieldModule } from '@angular/material/form-field';
|
||||||
import { MatIconModule } from '@angular/material/icon';
|
import { MatIconModule } from '@angular/material/icon';
|
||||||
import { MatInputModule } from '@angular/material/input';
|
import { MatInputModule } from '@angular/material/input';
|
||||||
|
import { MatProgressBarModule } from '@angular/material/progress-bar';
|
||||||
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
||||||
import { MatSelectModule } from '@angular/material/select';
|
import { MatSelectModule } from '@angular/material/select';
|
||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
@ -29,6 +30,7 @@ import { UserCreateComponent } from './user-create.component';
|
|||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
MatIconModule,
|
MatIconModule,
|
||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
|
MatProgressBarModule,
|
||||||
MatCheckboxModule,
|
MatCheckboxModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
TranslateModule,
|
TranslateModule,
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
<span>{{login}}</span>
|
<span>{{login}}</span>
|
||||||
<button color="primary" [disabled]="copied == login"
|
<button color="primary" [disabled]="copied == login"
|
||||||
[matTooltip]="(copied != login ? 'USER.PAGES.COPY' : 'USER.PAGES.COPIED' ) | translate"
|
[matTooltip]="(copied != login ? 'USER.PAGES.COPY' : 'USER.PAGES.COPIED' ) | translate"
|
||||||
(click)="copytoclipboard(login)" mat-icon-button>
|
appCopyToClipboard [valueToCopy]="login" (copiedValue)="copied = $event" mat-icon-button>
|
||||||
<i *ngIf="copied != login" class="las la-clipboard"></i>
|
<i *ngIf="copied != login" class="las la-clipboard"></i>
|
||||||
<i *ngIf="copied == login" class="las la-clipboard-check"></i>
|
<i *ngIf="copied == login" class="las la-clipboard-check"></i>
|
||||||
</button>
|
</button>
|
||||||
|
@ -39,9 +39,11 @@ export class AuthUserDetailComponent implements OnDestroy {
|
|||||||
private dialog: MatDialog,
|
private dialog: MatDialog,
|
||||||
) {
|
) {
|
||||||
this.loading = true;
|
this.loading = true;
|
||||||
this.getData().then(() => {
|
this.userService.GetMyUser().then(user => {
|
||||||
|
this.user = user.toObject();
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
}).catch(error => {
|
}).catch(error => {
|
||||||
|
this.toast.showError(error);
|
||||||
this.loading = false;
|
this.loading = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -149,30 +151,4 @@ export class AuthUserDetailComponent implements OnDestroy {
|
|||||||
this.phoneEditState = false;
|
this.phoneEditState = false;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getData(): Promise<void> {
|
|
||||||
this.userService.GetMyUser().then(user => {
|
|
||||||
this.user = user.toObject();
|
|
||||||
}).catch(error => {
|
|
||||||
this.toast.showError(error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public copytoclipboard(value: string): void {
|
|
||||||
const selBox = document.createElement('textarea');
|
|
||||||
selBox.style.position = 'fixed';
|
|
||||||
selBox.style.left = '0';
|
|
||||||
selBox.style.top = '0';
|
|
||||||
selBox.style.opacity = '0';
|
|
||||||
selBox.value = value;
|
|
||||||
document.body.appendChild(selBox);
|
|
||||||
selBox.focus();
|
|
||||||
selBox.select();
|
|
||||||
document.execCommand('copy');
|
|
||||||
document.body.removeChild(selBox);
|
|
||||||
this.copied = value;
|
|
||||||
setTimeout(() => {
|
|
||||||
this.copied = '';
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,6 @@ export class AuthUserMfaComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
public getOTP(): void {
|
public getOTP(): void {
|
||||||
this.service.GetMyMfas().then(mfas => {
|
this.service.GetMyMfas().then(mfas => {
|
||||||
console.log(mfas.toObject().mfasList);
|
|
||||||
this.dataSource = new MatTableDataSource(mfas.toObject().mfasList);
|
this.dataSource = new MatTableDataSource(mfas.toObject().mfasList);
|
||||||
this.dataSource.sort = this.sort;
|
this.dataSource.sort = this.sort;
|
||||||
|
|
||||||
|
@ -0,0 +1,11 @@
|
|||||||
|
@import '~@angular/material/theming';
|
||||||
|
|
||||||
|
@mixin theme-card($theme) {
|
||||||
|
$primary: map-get($theme, primary);
|
||||||
|
$primary-dark: mat-color($primary, A800);
|
||||||
|
|
||||||
|
.theme-conent, .theme-app , .crescent {
|
||||||
|
background-color: $primary-dark;
|
||||||
|
transition: background-color .4s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
$dark-background: #2d2e30;
|
$dark-background: #2d2e30;
|
||||||
|
$light-background: #fafafa;
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
transition: none;
|
transition: none;
|
||||||
@ -21,6 +22,7 @@ $dark-background: #2d2e30;
|
|||||||
height: 6rem;
|
height: 6rem;
|
||||||
background: linear-gradient(40deg, #FF0080,#FF8C00 70%);
|
background: linear-gradient(40deg, #FF0080,#FF8C00 70%);
|
||||||
margin: auto;
|
margin: auto;
|
||||||
|
box-shadow: 0 30px 60px rgba(0,0,0,0.12);
|
||||||
}
|
}
|
||||||
|
|
||||||
.crescent {
|
.crescent {
|
||||||
@ -29,10 +31,10 @@ $dark-background: #2d2e30;
|
|||||||
right: 0;
|
right: 0;
|
||||||
width: 4rem;
|
width: 4rem;
|
||||||
height: 4rem;
|
height: 4rem;
|
||||||
background: #fafafa;
|
background: $light-background;
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
transform-origin: top right;
|
transform-origin: top right;
|
||||||
transition: transform .6s cubic-bezier(0.645, 0.045, 0.355, 1);
|
transition: transform .4s cubic-bezier(0.645, 0.045, 0.355, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
@ -66,7 +68,7 @@ label {
|
|||||||
|
|
||||||
.toggle {
|
.toggle {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
background-color: #fafafa;
|
background-color: $light-background;
|
||||||
box-shadow: 0 2px 15px rgba(0,0,0,.15);
|
box-shadow: 0 2px 15px rgba(0,0,0,.15);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +103,7 @@ label {
|
|||||||
|
|
||||||
[type="checkbox"]:checked + .theme-app{
|
[type="checkbox"]:checked + .theme-app{
|
||||||
background-color: $dark-background;
|
background-color: $dark-background;
|
||||||
color: #fafafa;
|
color: $light-background;
|
||||||
}
|
}
|
||||||
|
|
||||||
[type="checkbox"]:checked + .theme-app .crescent{
|
[type="checkbox"]:checked + .theme-app .crescent{
|
||||||
|
@ -13,6 +13,7 @@ import { MatTableModule } from '@angular/material/table';
|
|||||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||||
import { TranslateModule } from '@ngx-translate/core';
|
import { TranslateModule } from '@ngx-translate/core';
|
||||||
import { QRCodeModule } from 'angularx-qrcode';
|
import { QRCodeModule } from 'angularx-qrcode';
|
||||||
|
import { CopyToClipboardModule } from 'src/app/directives/copy-to-clipboard/copy-to-clipboard.module';
|
||||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||||
import { CardModule } from 'src/app/modules/card/card.module';
|
import { CardModule } from 'src/app/modules/card/card.module';
|
||||||
import { ChangesModule } from 'src/app/modules/changes/changes.module';
|
import { ChangesModule } from 'src/app/modules/changes/changes.module';
|
||||||
@ -70,6 +71,7 @@ import { UserMfaComponent } from './user-detail/user-mfa/user-mfa.component';
|
|||||||
MatPaginatorModule,
|
MatPaginatorModule,
|
||||||
SharedModule,
|
SharedModule,
|
||||||
RefreshTableModule,
|
RefreshTableModule,
|
||||||
|
CopyToClipboardModule,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
export class UserDetailModule { }
|
export class UserDetailModule { }
|
||||||
|
@ -25,12 +25,13 @@
|
|||||||
<app-card title="{{ 'USER.PAGES.LOGINNAMES' | translate }}"
|
<app-card title="{{ 'USER.PAGES.LOGINNAMES' | translate }}"
|
||||||
description="{{ 'USER.PAGES.LOGINNAMESDESC' | translate }}" *ngIf="user">
|
description="{{ 'USER.PAGES.LOGINNAMESDESC' | translate }}" *ngIf="user">
|
||||||
<div class="login-name-row" *ngFor="let login of user?.loginNamesList">
|
<div class="login-name-row" *ngFor="let login of user?.loginNamesList">
|
||||||
<span>{{login}}</span>
|
<span>{{login}} </span>
|
||||||
<button color="primary" [disabled]="copied == login"
|
<button color="primary" [disabled]="copied == login"
|
||||||
[matTooltip]="(copied != login ? 'USER.PAGES.COPY' : 'USER.PAGES.COPIED' ) | translate"
|
[matTooltip]="(copied != login ? 'USER.PAGES.COPY' : 'USER.PAGES.COPIED' ) | translate"
|
||||||
(click)="copytoclipboard(login)" mat-icon-button>
|
appCopyToClipboard [valueToCopy]="login" (copiedValue)="copied = $event" mat-icon-button>
|
||||||
<i *ngIf="copied != login" class="las la-clipboard"></i>
|
<i *ngIf="copied != login" class="las la-clipboard"></i>
|
||||||
<i *ngIf="copied == login" class="las la-clipboard-check"></i>
|
<i *ngIf="copied == login" class="las la-clipboard-check"></i>
|
||||||
|
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</app-card>
|
</app-card>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Location } from '@angular/common';
|
import { Location } from '@angular/common';
|
||||||
import { Component, OnDestroy, OnInit } from '@angular/core';
|
import { Component, OnDestroy, OnInit } from '@angular/core';
|
||||||
import { ActivatedRoute, Params } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
import { ChangeType } from 'src/app/modules/changes/changes.component';
|
||||||
@ -27,7 +27,6 @@ export class UserDetailComponent implements OnInit, OnDestroy {
|
|||||||
public genders: Gender[] = [Gender.GENDER_MALE, Gender.GENDER_FEMALE, Gender.GENDER_DIVERSE];
|
public genders: Gender[] = [Gender.GENDER_MALE, Gender.GENDER_FEMALE, Gender.GENDER_DIVERSE];
|
||||||
public languages: string[] = ['de', 'en'];
|
public languages: string[] = ['de', 'en'];
|
||||||
|
|
||||||
public isMgmt: boolean = false;
|
|
||||||
private subscription: Subscription = new Subscription();
|
private subscription: Subscription = new Subscription();
|
||||||
public emailEditState: boolean = false;
|
public emailEditState: boolean = false;
|
||||||
public phoneEditState: boolean = false;
|
public phoneEditState: boolean = false;
|
||||||
@ -49,11 +48,11 @@ export class UserDetailComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
public ngOnInit(): void {
|
public ngOnInit(): void {
|
||||||
this.subscription = this.route.params.subscribe(params => {
|
this.subscription = this.route.params.subscribe(params => {
|
||||||
this.loading = true;
|
const { id } = params;
|
||||||
this.getData(params).then(() => {
|
this.mgmtUserService.GetUserByID(id).then(user => {
|
||||||
this.loading = false;
|
this.user = user.toObject();
|
||||||
}).catch(error => {
|
}).catch(err => {
|
||||||
this.loading = false;
|
console.error(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -157,15 +156,6 @@ export class UserDetailComponent implements OnInit, OnDestroy {
|
|||||||
this._location.back();
|
this._location.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async getData({ id }: Params): Promise<void> {
|
|
||||||
this.isMgmt = true;
|
|
||||||
this.mgmtUserService.GetUserByID(id).then(user => {
|
|
||||||
this.user = user.toObject();
|
|
||||||
}).catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public sendSetPasswordNotification(): void {
|
public sendSetPasswordNotification(): void {
|
||||||
this.mgmtUserService.SendSetPasswordNotification(this.user.id, NotificationType.NOTIFICATIONTYPE_EMAIL)
|
this.mgmtUserService.SendSetPasswordNotification(this.user.id, NotificationType.NOTIFICATIONTYPE_EMAIL)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
@ -174,22 +164,4 @@ export class UserDetailComponent implements OnInit, OnDestroy {
|
|||||||
this.toast.showError(error);
|
this.toast.showError(error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public copytoclipboard(value: string): void {
|
|
||||||
const selBox = document.createElement('textarea');
|
|
||||||
selBox.style.position = 'fixed';
|
|
||||||
selBox.style.left = '0';
|
|
||||||
selBox.style.top = '0';
|
|
||||||
selBox.style.opacity = '0';
|
|
||||||
selBox.value = value;
|
|
||||||
document.body.appendChild(selBox);
|
|
||||||
selBox.focus();
|
|
||||||
selBox.select();
|
|
||||||
document.execCommand('copy');
|
|
||||||
document.body.removeChild(selBox);
|
|
||||||
this.copied = value;
|
|
||||||
setTimeout(() => {
|
|
||||||
this.copied = '';
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,16 +1,22 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
|
import { MatDialog } from '@angular/material/dialog';
|
||||||
import { MatSnackBar, MatSnackBarConfig } from '@angular/material/snack-bar';
|
import { MatSnackBar, MatSnackBarConfig } from '@angular/material/snack-bar';
|
||||||
import { TranslateService } from '@ngx-translate/core';
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { take } from 'rxjs/operators';
|
import { take } from 'rxjs/operators';
|
||||||
|
|
||||||
|
import { WarnDialogComponent } from '../modules/warn-dialog/warn-dialog.component';
|
||||||
import { AuthService } from './auth.service';
|
import { AuthService } from './auth.service';
|
||||||
|
|
||||||
@Injectable({
|
@Injectable({
|
||||||
providedIn: 'root',
|
providedIn: 'root',
|
||||||
})
|
})
|
||||||
export class ToastService {
|
export class ToastService {
|
||||||
constructor(private snackBar: MatSnackBar, private translate: TranslateService, private authService: AuthService) { }
|
constructor(private dialog: MatDialog,
|
||||||
|
private snackBar: MatSnackBar,
|
||||||
|
private translate: TranslateService,
|
||||||
|
private authService: AuthService,
|
||||||
|
) { }
|
||||||
|
|
||||||
public showInfo(message: string, i18nkey: boolean = false): void {
|
public showInfo(message: string, i18nkey: boolean = false): void {
|
||||||
if (i18nkey) {
|
if (i18nkey) {
|
||||||
@ -28,10 +34,19 @@ export class ToastService {
|
|||||||
const { message, code, metadata } = grpcError;
|
const { message, code, metadata } = grpcError;
|
||||||
// TODO: remove check for code === 7
|
// TODO: remove check for code === 7
|
||||||
if (code === 16 || (code === 7 && message === 'invalid token')) {
|
if (code === 16 || (code === 7 && message === 'invalid token')) {
|
||||||
const actionObserver$ = this.showMessage(decodeURI(message), 'Login');
|
const dialogRef = this.dialog.open(WarnDialogComponent, {
|
||||||
|
data: {
|
||||||
|
confirmKey: 'ACTIONS.LOGIN',
|
||||||
|
titleKey: 'ERRORS.TOKENINVALID.TITLE',
|
||||||
|
descriptionKey: 'ERRORS.TOKENINVALID.DESCRIPTION',
|
||||||
|
},
|
||||||
|
width: '400px',
|
||||||
|
});
|
||||||
|
|
||||||
actionObserver$.pipe(take(1)).subscribe(() => {
|
dialogRef.afterClosed().pipe(take(1)).subscribe(resp => {
|
||||||
this.authService.authenticate(undefined, true, true);
|
if (resp) {
|
||||||
|
this.authService.authenticate(undefined, true, true);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
this.showMessage(decodeURI(message), 'close', { duration: 3000 });
|
this.showMessage(decodeURI(message), 'close', { duration: 3000 });
|
||||||
|
@ -16,7 +16,11 @@
|
|||||||
"USERS_BUTTON": "Benutzer anzeigen",
|
"USERS_BUTTON": "Benutzer anzeigen",
|
||||||
"IAM": "Identity and Access Management",
|
"IAM": "Identity and Access Management",
|
||||||
"IAM_DESC": "Verwalte deine Organisationen und Administratoren.",
|
"IAM_DESC": "Verwalte deine Organisationen und Administratoren.",
|
||||||
"IAM_BUTTON": "ZITADEL verwalten"
|
"IAM_BUTTON": "ZITADEL verwalten",
|
||||||
|
"WELCOME":"Willkommen",
|
||||||
|
"WELCOMESENTENCE":"Hier findest du die empfohlenen Aktionen basierend auf deinen zuletzt erworbenen Berechtigungen. Beachte bitte, dass du möglicherweise deine Organisation in der Kopfzeile wechseln musst.",
|
||||||
|
"DISCLAIMER":"Du kannst nur die Einstellungen deiner aktuellen Organisation sehen, die in der Kopfzeile angegeben ist. ZITADEL behandelt deine Daten vertraulich und sicher.",
|
||||||
|
"DISCLAIMERLINK":"Mehr Informationen zur Sicherheit"
|
||||||
},
|
},
|
||||||
"MENU": {
|
"MENU": {
|
||||||
"PERSONAL_INFO": "Persönliche Informationen",
|
"PERSONAL_INFO": "Persönliche Informationen",
|
||||||
@ -51,10 +55,15 @@
|
|||||||
"CHANGE":"Ändern",
|
"CHANGE":"Ändern",
|
||||||
"REACTIVATE":"Aktivieren",
|
"REACTIVATE":"Aktivieren",
|
||||||
"DEACTIVATE":"Deaktivieren",
|
"DEACTIVATE":"Deaktivieren",
|
||||||
"REFRESH":"Aktualisieren"
|
"REFRESH":"Aktualisieren",
|
||||||
|
"LOGIN":"Login"
|
||||||
},
|
},
|
||||||
"ERRORS": {
|
"ERRORS": {
|
||||||
"REQUIRED": "Bitte fülle alle benötigten Felder aus!"
|
"REQUIRED": "Bitte fülle alle benötigten Felder aus!",
|
||||||
|
"TOKENINVALID": {
|
||||||
|
"TITLE":"Du bist abgemeldet",
|
||||||
|
"DESCRIPTION":"Klicke auf Knopf Login um dich wieder einzuloggen!"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"USER": {
|
"USER": {
|
||||||
"TITLE": "Persönliche Informationen",
|
"TITLE": "Persönliche Informationen",
|
||||||
@ -102,7 +111,8 @@
|
|||||||
"NAMEANDEMAILSECTION":"Name und Email",
|
"NAMEANDEMAILSECTION":"Name und Email",
|
||||||
"GENDERLANGSECTION":"Geschlecht und Sprache",
|
"GENDERLANGSECTION":"Geschlecht und Sprache",
|
||||||
"PHONESECTION":"Telefonnummer",
|
"PHONESECTION":"Telefonnummer",
|
||||||
"PASSWORDSECTION":"Setze ein initiales Passwort."
|
"PASSWORDSECTION":"Setze ein initiales Passwort.",
|
||||||
|
"ADDRESSANDPHONESECTION":"Telefonnummer"
|
||||||
},
|
},
|
||||||
"CODEDIALOG": {
|
"CODEDIALOG": {
|
||||||
"TITLE":"Telefonnummer verifizieren",
|
"TITLE":"Telefonnummer verifizieren",
|
||||||
|
@ -16,7 +16,11 @@
|
|||||||
"USERS_BUTTON": "Show users",
|
"USERS_BUTTON": "Show users",
|
||||||
"IAM": "Identity and Access Management",
|
"IAM": "Identity and Access Management",
|
||||||
"IAM_DESC": "Manage your organisations and administrators.",
|
"IAM_DESC": "Manage your organisations and administrators.",
|
||||||
"IAM_BUTTON": "Manage ZITADEL"
|
"IAM_BUTTON": "Manage ZITADEL",
|
||||||
|
"WELCOME":"Welcome",
|
||||||
|
"WELCOMESENTENCE":"Here you can find recommended Actions based on your last acquired permissions. Note that you may have to select your organisation in the header above.",
|
||||||
|
"DISCLAIMER":"You can only see settings of your current organisation specified in the header. ZITADEL treats your data confidentially and securely.",
|
||||||
|
"DISCLAIMERLINK":"Further information"
|
||||||
},
|
},
|
||||||
"MENU": {
|
"MENU": {
|
||||||
"PERSONAL_INFO": "Personal Information",
|
"PERSONAL_INFO": "Personal Information",
|
||||||
@ -51,10 +55,15 @@
|
|||||||
"CHANGE":"Change",
|
"CHANGE":"Change",
|
||||||
"REACTIVATE":"Reactivate",
|
"REACTIVATE":"Reactivate",
|
||||||
"DEACTIVATE":"Deactivate",
|
"DEACTIVATE":"Deactivate",
|
||||||
"REFRESH":"Refresh"
|
"REFRESH":"Refresh",
|
||||||
|
"LOGIN":"Login"
|
||||||
},
|
},
|
||||||
"ERRORS": {
|
"ERRORS": {
|
||||||
"REQUIRED": "Some required fields are missing!"
|
"REQUIRED": "Some required fields are missing!",
|
||||||
|
"TOKENINVALID": {
|
||||||
|
"TITLE":"Your auth token has expired",
|
||||||
|
"DESCRIPTION":"Click the button below to login again!"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"USER": {
|
"USER": {
|
||||||
"TITLE": "Personal Information",
|
"TITLE": "Personal Information",
|
||||||
@ -102,7 +111,8 @@
|
|||||||
"NAMEANDEMAILSECTION":"Name and Email",
|
"NAMEANDEMAILSECTION":"Name and Email",
|
||||||
"GENDERLANGSECTION":"Gender and Language",
|
"GENDERLANGSECTION":"Gender and Language",
|
||||||
"PHONESECTION":"Phonenumbers",
|
"PHONESECTION":"Phonenumbers",
|
||||||
"PASSWORDSECTION":"Set the initial Password."
|
"PASSWORDSECTION":"Set the initial Password.",
|
||||||
|
"ADDRESSANDPHONESECTION":"Phonenumber"
|
||||||
},
|
},
|
||||||
"CODEDIALOG": {
|
"CODEDIALOG": {
|
||||||
"TITLE":"Verify Phone Number",
|
"TITLE":"Verify Phone Number",
|
||||||
|
@ -61,29 +61,29 @@
|
|||||||
<path d="M1496.17,759.473L1555.54,720.014" style="fill:none;"/>
|
<path d="M1496.17,759.473L1555.54,720.014" style="fill:none;"/>
|
||||||
</g>
|
</g>
|
||||||
<g transform="matrix(1.32803,-0.355844,-0.311363,-1.16202,-1672.97,1561.28)">
|
<g transform="matrix(1.32803,-0.355844,-0.311363,-1.16202,-1672.97,1561.28)">
|
||||||
<path d="M1496.1,754.362C1496.1,754.362 1497.2,755.607 1501.13,753.598C1503.25,752.509 1505.74,751.023 1508.49,749.329C1513.52,746.234 1519.35,742.314 1525.19,738.438C1530.13,735.166 1534.94,731.832 1539.27,728.802C1542.87,726.279 1549.36,722.059 1549.81,721.75C1552.75,719.73 1552.18,718.196 1552.18,718.196L1555.28,724.152C1555.28,724.152 1553.77,722.905 1551.37,724.681C1550.93,725.006 1544.52,729.349 1540.82,731.68C1536.38,734.479 1531.45,737.766 1526.52,741.049C1520.68,744.94 1514.82,748.79 1509.98,752.255C1507.33,754.151 1504.89,755.771 1503.09,757.456C1499.47,760.841 1501.26,763.283 1501.26,763.283L1496.1,754.362Z" style="fill:rgb(35,35,35);"/>
|
<path d="M1496.1,754.362C1496.1,754.362 1497.2,755.607 1501.13,753.598C1503.25,752.509 1505.74,751.023 1508.49,749.329C1513.52,746.234 1519.35,742.314 1525.19,738.438C1530.13,735.166 1534.94,731.832 1539.27,728.802C1542.87,726.279 1549.36,722.059 1549.81,721.75C1552.75,719.73 1552.18,718.196 1552.18,718.196L1555.28,724.152C1555.28,724.152 1553.77,722.905 1551.37,724.681C1550.93,725.006 1544.52,729.349 1540.82,731.68C1536.38,734.479 1531.45,737.766 1526.52,741.049C1520.68,744.94 1514.82,748.79 1509.98,752.255C1507.33,754.151 1504.89,755.771 1503.09,757.456C1499.47,760.841 1501.26,763.283 1501.26,763.283L1496.1,754.362Z" style="fill:#8795a1;"/>
|
||||||
</g>
|
</g>
|
||||||
<g transform="matrix(1.299,0,0,1.08306,-3394.18,-2084.88)">
|
<g transform="matrix(1.299,0,0,1.08306,-3394.18,-2084.88)">
|
||||||
<g transform="matrix(94.2338,0,0,94.1776,2827.58,2063)">
|
<g transform="matrix(94.2338,0,0,94.1776,2827.58,2063)">
|
||||||
<path d="M0.449,-0.7L0.177,-0.7C0.185,-0.682 0.197,-0.654 0.2,-0.648C0.205,-0.639 0.216,-0.628 0.239,-0.628L0.32,-0.628C0.332,-0.628 0.336,-0.62 0.334,-0.611L0.128,0L0.389,0C0.412,0 0.422,-0.01 0.427,-0.02L0.45,-0.071L0.255,-0.071C0.245,-0.071 0.239,-0.078 0.242,-0.09L0.449,-0.7Z" style="fill:rgb(35,35,35);fill-rule:nonzero;"/>
|
<path d="M0.449,-0.7L0.177,-0.7C0.185,-0.682 0.197,-0.654 0.2,-0.648C0.205,-0.639 0.216,-0.628 0.239,-0.628L0.32,-0.628C0.332,-0.628 0.336,-0.62 0.334,-0.611L0.128,0L0.389,0C0.412,0 0.422,-0.01 0.427,-0.02L0.45,-0.071L0.255,-0.071C0.245,-0.071 0.239,-0.078 0.242,-0.09L0.449,-0.7Z" style="fill:#8795a1;fill-rule:nonzero;"/>
|
||||||
</g>
|
</g>
|
||||||
<g transform="matrix(94.2338,0,0,94.1776,2912.39,2063)">
|
<g transform="matrix(94.2338,0,0,94.1776,2912.39,2063)">
|
||||||
<path d="M0.214,-0.7L0.214,-0.015C0.215,-0.01 0.218,0 0.235,0L0.286,0L0.286,-0.672C0.286,-0.684 0.278,-0.7 0.257,-0.7L0.214,-0.7Z" style="fill:rgb(35,35,35);fill-rule:nonzero;"/>
|
<path d="M0.214,-0.7L0.214,-0.015C0.215,-0.01 0.218,0 0.235,0L0.286,0L0.286,-0.672C0.286,-0.684 0.278,-0.7 0.257,-0.7L0.214,-0.7Z" style="fill:#8795a1;fill-rule:nonzero;"/>
|
||||||
</g>
|
</g>
|
||||||
<g transform="matrix(94.2338,0,0,94.1776,2987.78,2063)">
|
<g transform="matrix(94.2338,0,0,94.1776,2987.78,2063)">
|
||||||
<path d="M0.441,-0.7L0.155,-0.7C0.143,-0.7 0.133,-0.69 0.133,-0.678L0.133,-0.629L0.234,-0.629L0.234,-0.015C0.234,-0.01 0.237,0 0.254,0L0.305,0L0.305,-0.612C0.306,-0.621 0.313,-0.629 0.323,-0.629L0.379,-0.629C0.402,-0.629 0.413,-0.639 0.417,-0.648L0.441,-0.7Z" style="fill:rgb(35,35,35);fill-rule:nonzero;"/>
|
<path d="M0.441,-0.7L0.155,-0.7C0.143,-0.7 0.133,-0.69 0.133,-0.678L0.133,-0.629L0.234,-0.629L0.234,-0.015C0.234,-0.01 0.237,0 0.254,0L0.305,0L0.305,-0.612C0.306,-0.621 0.313,-0.629 0.323,-0.629L0.379,-0.629C0.402,-0.629 0.413,-0.639 0.417,-0.648L0.441,-0.7Z" style="fill:#8795a1;fill-rule:nonzero;"/>
|
||||||
</g>
|
</g>
|
||||||
<g transform="matrix(94.2338,0,0,94.1776,3067.88,2063)">
|
<g transform="matrix(94.2338,0,0,94.1776,3067.88,2063)">
|
||||||
<path d="M0.422,0L0.343,0L0.28,-0.482L0.217,0L0.138,0L0.244,-0.7L0.283,-0.7C0.313,-0.7 0.318,-0.681 0.321,-0.662L0.422,0Z" style="fill:rgb(35,35,35);fill-rule:nonzero;"/>
|
<path d="M0.422,0L0.343,0L0.28,-0.482L0.217,0L0.138,0L0.244,-0.7L0.283,-0.7C0.313,-0.7 0.318,-0.681 0.321,-0.662L0.422,0Z" style="fill:#8795a1;fill-rule:nonzero;"/>
|
||||||
</g>
|
</g>
|
||||||
<g transform="matrix(94.2338,0,0,94.1776,3148.92,2063)">
|
<g transform="matrix(94.2338,0,0,94.1776,3148.92,2063)">
|
||||||
<path d="M0.186,-0.7L0.186,0L0.325,0C0.374,0 0.413,-0.039 0.414,-0.088L0.414,-0.612C0.413,-0.661 0.374,-0.7 0.325,-0.7L0.186,-0.7ZM0.343,-0.108C0.343,-0.081 0.325,-0.071 0.305,-0.071L0.258,-0.071L0.258,-0.628L0.305,-0.628C0.325,-0.628 0.343,-0.618 0.343,-0.592L0.343,-0.108Z" style="fill:rgb(35,35,35);fill-rule:nonzero;"/>
|
<path d="M0.186,-0.7L0.186,0L0.325,0C0.374,0 0.413,-0.039 0.414,-0.088L0.414,-0.612C0.413,-0.661 0.374,-0.7 0.325,-0.7L0.186,-0.7ZM0.343,-0.108C0.343,-0.081 0.325,-0.071 0.305,-0.071L0.258,-0.071L0.258,-0.628L0.305,-0.628C0.325,-0.628 0.343,-0.618 0.343,-0.592L0.343,-0.108Z" style="fill:#8795a1;fill-rule:nonzero;"/>
|
||||||
</g>
|
</g>
|
||||||
<g transform="matrix(94.2338,0,0,94.1776,3233.73,2063)">
|
<g transform="matrix(94.2338,0,0,94.1776,3233.73,2063)">
|
||||||
<path d="M0.291,-0.071L0.291,-0.314C0.291,-0.323 0.299,-0.331 0.308,-0.331L0.338,-0.331C0.361,-0.331 0.371,-0.341 0.376,-0.35C0.379,-0.356 0.391,-0.385 0.399,-0.403L0.291,-0.403L0.291,-0.611C0.291,-0.621 0.298,-0.628 0.308,-0.628L0.366,-0.628C0.389,-0.628 0.4,-0.639 0.404,-0.648L0.428,-0.7L0.241,-0.7C0.229,-0.7 0.22,-0.691 0.219,-0.68L0.219,0L0.379,0C0.402,0 0.413,-0.01 0.418,-0.019C0.421,-0.025 0.433,-0.053 0.441,-0.071L0.291,-0.071Z" style="fill:rgb(35,35,35);fill-rule:nonzero;"/>
|
<path d="M0.291,-0.071L0.291,-0.314C0.291,-0.323 0.299,-0.331 0.308,-0.331L0.338,-0.331C0.361,-0.331 0.371,-0.341 0.376,-0.35C0.379,-0.356 0.391,-0.385 0.399,-0.403L0.291,-0.403L0.291,-0.611C0.291,-0.621 0.298,-0.628 0.308,-0.628L0.366,-0.628C0.389,-0.628 0.4,-0.639 0.404,-0.648L0.428,-0.7L0.241,-0.7C0.229,-0.7 0.22,-0.691 0.219,-0.68L0.219,0L0.379,0C0.402,0 0.413,-0.01 0.418,-0.019C0.421,-0.025 0.433,-0.053 0.441,-0.071L0.291,-0.071Z" style="fill:#8795a1;fill-rule:nonzero;"/>
|
||||||
</g>
|
</g>
|
||||||
<g transform="matrix(94.2338,0,0,94.1776,3318.54,2063)">
|
<g transform="matrix(94.2338,0,0,94.1776,3318.54,2063)">
|
||||||
<path d="M0.283,-0.071L0.283,-0.678C0.283,-0.69 0.273,-0.699 0.261,-0.7L0.211,-0.7L0.211,0L0.383,0C0.406,0 0.417,-0.01 0.422,-0.019C0.425,-0.025 0.437,-0.053 0.445,-0.071L0.283,-0.071Z" style="fill:rgb(35,35,35);fill-rule:nonzero;"/>
|
<path d="M0.283,-0.071L0.283,-0.678C0.283,-0.69 0.273,-0.699 0.261,-0.7L0.211,-0.7L0.211,0L0.383,0C0.406,0 0.417,-0.01 0.422,-0.019C0.425,-0.025 0.437,-0.053 0.445,-0.071L0.283,-0.071Z" style="fill:#8795a1;fill-rule:nonzero;"/>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
</g>
|
</g>
|
||||||
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
1
console/src/assets/mdi/broom.svg
Normal file
1
console/src/assets/mdi/broom.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M19.36,2.72L20.78,4.14L15.06,9.85C16.13,11.39 16.28,13.24 15.38,14.44L9.06,8.12C10.26,7.22 12.11,7.37 13.65,8.44L19.36,2.72M5.93,17.57C3.92,15.56 2.69,13.16 2.35,10.92L7.23,8.83L14.67,16.27L12.58,21.15C10.34,20.81 7.94,19.58 5.93,17.57Z" /></svg>
|
After Width: | Height: | Size: 531 B |
1
console/src/assets/mdi/pin-outline.svg
Normal file
1
console/src/assets/mdi/pin-outline.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12M8.8,14L10,12.8V4H14V12.8L15.2,14H8.8Z" /></svg>
|
After Width: | Height: | Size: 391 B |
1
console/src/assets/mdi/pin.svg
Normal file
1
console/src/assets/mdi/pin.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M16,12V4H17V2H7V4H8V12L6,14V16H11.2V22H12.8V16H18V14L16,12Z" /></svg>
|
After Width: | Height: | Size: 354 B |
@ -5,7 +5,7 @@
|
|||||||
@import './styles/changes';
|
@import './styles/changes';
|
||||||
@import 'src/app/pages/projects/owned-projects/owned-project-detail/application-grid/application-grid.component';
|
@import 'src/app/pages/projects/owned-projects/owned-project-detail/application-grid/application-grid.component';
|
||||||
@import './styles/meta';
|
@import './styles/meta';
|
||||||
@import './styles/theme-card';
|
@import 'src/app/pages/users/user-detail/auth-user-detail/theme-setting/theme-card';
|
||||||
|
|
||||||
@mixin component-themes($theme) {
|
@mixin component-themes($theme) {
|
||||||
@include avatar-theme($theme);
|
@include avatar-theme($theme);
|
||||||
|
@ -154,7 +154,7 @@ $custom-typography: mat-typography-config(
|
|||||||
@include angular-material-theme($light-theme);
|
@include angular-material-theme($light-theme);
|
||||||
color: #202124;
|
color: #202124;
|
||||||
|
|
||||||
.sidenav, .main-container {
|
.sidenav, .main-container, .mat-dialog-container {
|
||||||
background-color: #fafafa;
|
background-color: #fafafa;
|
||||||
transition: background-color .4s ease-in-out;
|
transition: background-color .4s ease-in-out;
|
||||||
}
|
}
|
||||||
@ -183,7 +183,7 @@ $custom-typography: mat-typography-config(
|
|||||||
@include component-themes($dark-theme);
|
@include component-themes($dark-theme);
|
||||||
@include angular-material-theme($dark-theme);
|
@include angular-material-theme($dark-theme);
|
||||||
|
|
||||||
.sidenav, .main-container {
|
.sidenav, .main-container, .mat-dialog-container {
|
||||||
background-color: #212224;
|
background-color: #212224;
|
||||||
transition: background-color .4s ease-in-out;
|
transition: background-color .4s ease-in-out;
|
||||||
}
|
}
|
||||||
|
@ -45,5 +45,11 @@
|
|||||||
.iamuser {
|
.iamuser {
|
||||||
color: $primary-color;
|
color: $primary-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.edit-button {
|
||||||
|
&:hover {
|
||||||
|
color: $border-selected-color;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.root-header {
|
.root-header {
|
||||||
box-shadow: 0px 2px 1px -1px rgba(0, 0, 0, 0.1), 0px 1px 1px 0px rgba(0, 0, 0, 0.1), 0px 1px 3px 0px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 5px 10px rgba(0,0,0,0.12);
|
||||||
background-color: $primary-dark !important;
|
background-color: $primary-dark !important;
|
||||||
transition: background-color .4s ease-in-out;
|
transition: background-color .4s ease-in-out;
|
||||||
}
|
}
|
||||||
@ -56,6 +56,9 @@
|
|||||||
.admin-line {
|
.admin-line {
|
||||||
background: $accent-color;
|
background: $accent-color;
|
||||||
color: white;
|
color: white;
|
||||||
|
margin-right: 1rem;
|
||||||
|
border-top-right-radius: 50vw;
|
||||||
|
border-bottom-right-radius: 50vw;
|
||||||
|
|
||||||
// &::after {
|
// &::after {
|
||||||
// content: '';
|
// content: '';
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
@import '~@angular/material/theming';
|
|
||||||
|
|
||||||
@mixin theme-card($theme) {
|
|
||||||
$primary: map-get($theme, primary);
|
|
||||||
$primary-dark: mat-color($primary, A800);
|
|
||||||
|
|
||||||
.theme-conent {
|
|
||||||
background-color: $primary-dark;
|
|
||||||
transition: background-color .4s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-app {
|
|
||||||
background-color: $primary-dark;
|
|
||||||
transition: background-color .4s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.crescent {
|
|
||||||
background-color: $primary-dark;
|
|
||||||
transition: background-color .4s ease-in-out;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user