mirror of
https://github.com/andwati/zitadel.git
synced 2026-11-14 01:45:12 +00:00
feat: rehauled console (#3525)
* new console * move npm ci to angular build * rel path for assets * local grpc copy * login policy, rm clear views, features rel path * lock Co-authored-by: Livio Amstutz <[email protected]>
This commit is contained in:
co-authored by
Livio Amstutz
parent
00f7dbe875
commit
08ae39ae19
@@ -0,0 +1,210 @@
|
||||
<div cdkDropListGroup>
|
||||
<div class="shortcut-container">
|
||||
<div class="shortcut-title-container">
|
||||
<h2>{{'HOME.SHORTCUTS.SHORTCUTS' | translate}}</h2>
|
||||
<button [matTooltip]="(editState ? 'ACTIONS.CLOSE' : 'ACTIONS.EDIT') | translate" class="shortcut-btn"
|
||||
(click)="editState = !editState" mat-icon-button>
|
||||
<i *ngIf="!editState" class=" las la-pen"></i>
|
||||
<mat-icon *ngIf="editState">close</mat-icon>
|
||||
</button>
|
||||
<button matTooltip="{{'ACTIONS.RESETDEFAULT' | translate}}" (click)="reset()" *ngIf="editState" mat-icon-button>
|
||||
<i *ngIf="editState" class="las la-undo-alt"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div class="shortcut-list-row">
|
||||
<div cdkDropList [cdkDropListData]="main" class="shortcut-list" (cdkDropListDropped)="drop($event, 'main')">
|
||||
<p *ngIf="editState" class="shortcut-desc">{{'HOME.SHORTCUTS.REORDER' | translate}}</p>
|
||||
<ng-container *ngFor="let shortcut of main">
|
||||
<ng-template cnslHasRole [hasRole]="shortcut.withRole">
|
||||
<a [routerLink]="!editState ? shortcut.routerLink : null" class="shortcut-box"
|
||||
[ngClass]="{'edit-state': editState && !shortcut.disabled, 'disabled': editState && shortcut.disabled}"
|
||||
cdkDrag [cdkDragDisabled]="shortcut.disabled || !editState">
|
||||
<div class="shortcuts-avatar {{shortcut.color}}">
|
||||
<mat-icon *ngIf="shortcut.svgIcon" class="icon" [svgIcon]="shortcut.svgIcon"></mat-icon>
|
||||
<i *ngIf="shortcut.icon" class="icon {{shortcut.icon}}"></i>
|
||||
<span *ngIf="shortcut.label" class="shortcuts-avatar-label">{{shortcut.label}}</span>
|
||||
</div>
|
||||
<div class="shortcut-col">
|
||||
<span *ngIf="shortcut.i18nTitle">{{shortcut.i18nTitle | translate}}</span>
|
||||
<span *ngIf="shortcut.title">{{shortcut.title}}</span>
|
||||
</div>
|
||||
|
||||
<span class="fill-space"></span>
|
||||
|
||||
<div class="shortcut-state-dot" *ngIf="shortcut && shortcut.state !== undefined"
|
||||
matTooltip="{{'PROJECT.STATE.'+shortcut.state | translate}}"
|
||||
[ngClass]="{'active': shortcut.state === ProjectState.PROJECT_STATE_ACTIVE, 'inactive': shortcut.state === ProjectState.PROJECT_STATE_INACTIVE }">
|
||||
</div>
|
||||
</a>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div cdkDropList [cdkDropListData]="secondary" class="shortcut-list"
|
||||
(cdkDropListDropped)="drop($event, 'secondary')">
|
||||
<p *ngIf="editState" class="shortcut-desc">{{'HOME.SHORTCUTS.REORDER' | translate}}</p>
|
||||
<ng-container *ngFor="let shortcut of secondary">
|
||||
<ng-template cnslHasRole [hasRole]="shortcut.withRole">
|
||||
<a [routerLink]="!editState ? shortcut.routerLink : null" class="shortcut-box"
|
||||
[ngClass]="{'edit-state': editState && !shortcut.disabled}" cdkDrag
|
||||
[cdkDragDisabled]="shortcut.disabled || !editState">
|
||||
<div class="shortcuts-avatar {{shortcut.color}}">
|
||||
<mat-icon *ngIf="shortcut.svgIcon" class="icon" [svgIcon]="shortcut.svgIcon"></mat-icon>
|
||||
<i *ngIf="shortcut.icon" class="icon {{shortcut.icon}}"></i>
|
||||
<span *ngIf="shortcut.label" class="shortcuts-avatar-label">{{shortcut.label}}</span>
|
||||
</div>
|
||||
<div class="shortcut-col">
|
||||
<span *ngIf="shortcut.i18nTitle">{{shortcut.i18nTitle | translate}}</span>
|
||||
<span *ngIf="shortcut.title">{{shortcut.title}}</span>
|
||||
</div>
|
||||
|
||||
<span class="fill-space"></span>
|
||||
|
||||
<div class="shortcut-state-dot" *ngIf="shortcut && shortcut.state !== undefined"
|
||||
matTooltip="{{'PROJECT.STATE.'+shortcut.state | translate}}"
|
||||
[ngClass]="{'active': shortcut.state === ProjectState.PROJECT_STATE_ACTIVE, 'inactive': shortcut.state === ProjectState.PROJECT_STATE_INACTIVE }">
|
||||
</div>
|
||||
</a>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div cdkDropList [cdkDropListData]="third" class="shortcut-list" (cdkDropListDropped)="drop($event, 'third')">
|
||||
<p *ngIf="editState" class="shortcut-desc">{{'HOME.SHORTCUTS.REORDER' | translate}}</p>
|
||||
<ng-container *ngFor="let shortcut of third">
|
||||
<ng-template cnslHasRole [hasRole]="shortcut.withRole">
|
||||
<a [routerLink]="!editState ? shortcut.routerLink : null" class="shortcut-box"
|
||||
[ngClass]="{'edit-state': editState && !shortcut.disabled}" cdkDrag
|
||||
[cdkDragDisabled]="shortcut.disabled || !editState">
|
||||
<div class="shortcuts-avatar {{shortcut.color}}">
|
||||
<mat-icon *ngIf="shortcut.svgIcon" class="icon" [svgIcon]="shortcut.svgIcon"></mat-icon>
|
||||
<i *ngIf="shortcut.icon" class="icon {{shortcut.icon}}"></i>
|
||||
<span *ngIf="shortcut.label" class="shortcuts-avatar-label">{{shortcut.label}}</span>
|
||||
</div>
|
||||
|
||||
<div class="shortcut-col">
|
||||
<span *ngIf="shortcut.i18nTitle">{{shortcut.i18nTitle | translate}}</span>
|
||||
<span *ngIf="shortcut.title">{{shortcut.title}}</span>
|
||||
</div>
|
||||
|
||||
<span class="fill-space"></span>
|
||||
|
||||
<div class="shortcut-state-dot" *ngIf="shortcut && shortcut.state !== undefined"
|
||||
matTooltip="{{'PROJECT.STATE.'+shortcut.state | translate}}"
|
||||
[ngClass]="{'active': shortcut.state === ProjectState.PROJECT_STATE_ACTIVE, 'inactive': shortcut.state === ProjectState.PROJECT_STATE_INACTIVE }">
|
||||
</div>
|
||||
</a>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="shortcut-container" *ngIf="editState">
|
||||
<h2>{{'HOME.SHORTCUTS.SETTINGS' | translate}}</h2>
|
||||
|
||||
<div class="shortcut-list-row">
|
||||
|
||||
<div cdkDropList [cdkDropListData]="allRoutes" class="shortcut-list" (cdkDropListDropped)="drop($event, 'main')">
|
||||
<p *ngIf="editState" class="shortcut-desc">{{'HOME.SHORTCUTS.REORDER' | translate}}</p>
|
||||
<ng-container *ngFor="let shortcut of allRoutes">
|
||||
<ng-template cnslHasRole [hasRole]="shortcut.withRole">
|
||||
<div class="shortcut-box"
|
||||
[ngClass]="{'edit-state': editState && !shortcut.disabled, 'disabled': editState && shortcut.disabled}"
|
||||
cdkDrag [cdkDragDisabled]="shortcut.disabled">
|
||||
<div class="shortcuts-avatar {{shortcut.color}}">
|
||||
<mat-icon *ngIf="shortcut.svgIcon" class="icon" [svgIcon]="shortcut.svgIcon"></mat-icon>
|
||||
<i *ngIf="shortcut.icon" class="icon {{shortcut.icon}}"></i>
|
||||
<span *ngIf="shortcut.label" class="shortcuts-avatar-label">{{shortcut.label}}</span>
|
||||
</div>
|
||||
<div class="shortcut-col">
|
||||
<span *ngIf="shortcut.i18nTitle">{{shortcut.i18nTitle | translate}}</span>
|
||||
<span *ngIf="shortcut.title">{{shortcut.title}}</span>
|
||||
<span class="shortcut-item-desc cnsl-secondary-text" *ngIf="shortcut.i18nDesc">{{shortcut.i18nDesc |
|
||||
translate}}</span>
|
||||
<span class="shortcut-item-desc cnsl-secondary-text" *ngIf="shortcut.desc">{{shortcut.desc}}</span>
|
||||
</div>
|
||||
<span class="fill-space"></span>
|
||||
<div class="shortcut-state-dot" *ngIf="shortcut && shortcut.state !== undefined"
|
||||
matTooltip="{{'PROJECT.STATE.'+shortcut.state | translate}}"
|
||||
[ngClass]="{'active': shortcut.state === ProjectState.PROJECT_STATE_ACTIVE, 'inactive': shortcut.state === ProjectState.PROJECT_STATE_INACTIVE }">
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div cdkDropList [cdkDropListData]="allPolicies" class="shortcut-list"
|
||||
(cdkDropListDropped)="drop($event, 'secondary')">
|
||||
<p *ngIf="editState" class="shortcut-desc">{{'HOME.SHORTCUTS.REORDER' | translate}}</p>
|
||||
<ng-container *ngFor="let shortcut of allPolicies">
|
||||
<ng-template cnslHasRole [hasRole]="shortcut.withRole">
|
||||
<div class="shortcut-box" [ngClass]="{'edit-state': editState && !shortcut.disabled}" cdkDrag
|
||||
[cdkDragDisabled]="shortcut.disabled">
|
||||
<div class="shortcuts-avatar {{shortcut.color}}">
|
||||
<mat-icon *ngIf="shortcut.svgIcon" class="icon" [svgIcon]="shortcut.svgIcon"></mat-icon>
|
||||
<i *ngIf="shortcut.icon" class="icon {{shortcut.icon}}"></i>
|
||||
<span *ngIf="shortcut.label" class="shortcuts-avatar-label">{{shortcut.label}}</span>
|
||||
</div>
|
||||
<div class="shortcut-col">
|
||||
<span *ngIf="shortcut.i18nTitle">{{shortcut.i18nTitle | translate}}</span>
|
||||
<span *ngIf="shortcut.title">{{shortcut.title}}</span>
|
||||
<span class="shortcut-item-desc cnsl-secondary-text" *ngIf="shortcut.i18nDesc">{{shortcut.i18nDesc |
|
||||
translate}}</span>
|
||||
<span class="shortcut-item-desc cnsl-secondary-text" *ngIf="shortcut.desc">{{shortcut.desc}}</span>
|
||||
</div>
|
||||
<span class="fill-space"></span>
|
||||
<div class="shortcut-state-dot" *ngIf="shortcut && shortcut.state !== undefined"
|
||||
matTooltip="{{'PROJECT.STATE.'+shortcut.state | translate}}"
|
||||
[ngClass]="{'active': shortcut.state === ProjectState.PROJECT_STATE_ACTIVE, 'inactive': shortcut.state === ProjectState.PROJECT_STATE_INACTIVE }">
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
|
||||
<div cdkDropList [cdkDropListData]="allProjects" class="shortcut-list"
|
||||
(cdkDropListDropped)="drop($event, 'third')">
|
||||
<p *ngIf="editState" class="shortcut-desc">{{'HOME.SHORTCUTS.REORDER' | translate}}</p>
|
||||
<ng-container *ngFor="let shortcut of allProjects">
|
||||
<ng-template cnslHasRole [hasRole]="shortcut.withRole">
|
||||
<div class="shortcut-box" [ngClass]="{'edit-state': editState && !shortcut.disabled}" cdkDrag
|
||||
[cdkDragDisabled]="shortcut.disabled">
|
||||
<div class="shortcuts-avatar {{shortcut.color}}">
|
||||
<mat-icon *ngIf="shortcut.svgIcon" class="icon" [svgIcon]="shortcut.svgIcon"></mat-icon>
|
||||
<i *ngIf="shortcut.icon" class="icon {{shortcut.icon}}"></i>
|
||||
<span *ngIf="shortcut.label" class="shortcuts-avatar-label">{{shortcut.label}}</span>
|
||||
</div>
|
||||
<div class="shortcut-col">
|
||||
<span *ngIf="shortcut.i18nTitle">{{shortcut.i18nTitle | translate}}</span>
|
||||
<span *ngIf="shortcut.title">{{shortcut.title}}</span>
|
||||
<span class="shortcut-item-desc cnsl-secondary-text" *ngIf="shortcut.i18nDesc">{{shortcut.i18nDesc |
|
||||
translate}}</span>
|
||||
<span class="shortcut-item-desc cnsl-secondary-text" *ngIf="shortcut.desc">{{shortcut.desc}}</span>
|
||||
</div>
|
||||
<span class="fill-space"></span>
|
||||
<div class="shortcut-state-dot" *ngIf="shortcut && shortcut.state !== undefined"
|
||||
matTooltip="{{'PROJECT.STATE.'+shortcut.state | translate}}"
|
||||
[ngClass]="{'active': shortcut.state === ProjectState.PROJECT_STATE_ACTIVE, 'inactive': shortcut.state === ProjectState.PROJECT_STATE_INACTIVE }">
|
||||
</div>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <ng-template #shortcutRef let-shortcut="shortcut">
|
||||
<ng-template cnslHasRole [hasRole]="shortcut.withRole">
|
||||
<div class="shortcut-box edit-state" cdkDrag [cdkDragDisabled]="shortcut.disabled">
|
||||
<div class="shortcuts-avatar {{shortcut.color}}">
|
||||
<mat-icon *ngIf="shortcut.svgIcon" class="icon" [svgIcon]="shortcut.svgIcon"></mat-icon>
|
||||
<i *ngIf="shortcut.icon" class="icon {{shortcut.icon}}"></i>
|
||||
</div>
|
||||
<span *ngIf="shortcut.i18nTitle">{{shortcut.i18nTitle | translate}}</span>
|
||||
<span *ngIf="shortcut.title">{{shortcut.title}}</span>
|
||||
</div>
|
||||
</ng-template>
|
||||
</ng-template> -->
|
||||
@@ -0,0 +1,230 @@
|
||||
@use '@angular/material' as mat;
|
||||
|
||||
@mixin shortcut-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
$warn: map-get($theme, warn);
|
||||
$background: map-get($theme, background);
|
||||
$accent: map-get($theme, accent);
|
||||
$primary-color: mat.get-color-from-palette($primary, 500);
|
||||
|
||||
$warn-color: mat.get-color-from-palette($warn, 500);
|
||||
$accent-color: mat.get-color-from-palette($accent, 500);
|
||||
$foreground: map-get($theme, foreground);
|
||||
$is-dark-theme: map-get($theme, is-dark);
|
||||
$back: map-get($background, background);
|
||||
|
||||
$list-background-color: mat.get-color-from-palette($background, 300);
|
||||
$card-background-color: mat.get-color-from-palette($background, cards);
|
||||
$border-color: if($is-dark-theme, rgba(#8795a1, 0.2), rgba(#8795a1, 0.2));
|
||||
$border-selected-color: if($is-dark-theme, #fff, #000);
|
||||
|
||||
.shortcut-container {
|
||||
width: 100%;
|
||||
margin: 0 25px 25px 0;
|
||||
display: inline-block;
|
||||
vertical-align: top;
|
||||
|
||||
.shortcut-title-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
.shortcut-btn {
|
||||
margin-left: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.shortcut-list-row {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-gap: 1rem;
|
||||
width: 100%;
|
||||
|
||||
@media only screen and (min-width: 800px) {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1200px) {
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
}
|
||||
|
||||
.shortcut-list {
|
||||
border: 1px solid $border-color;
|
||||
min-height: 60px;
|
||||
background-color: $list-background-color;
|
||||
border-radius: 1rem;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
padding: 1rem;
|
||||
}
|
||||
}
|
||||
|
||||
.shortcut-desc {
|
||||
align-self: center;
|
||||
font-size: 14px;
|
||||
color: var(--grey);
|
||||
margin-top: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.shortcut-grid {
|
||||
border: 1px solid $border-color;
|
||||
min-height: 60px;
|
||||
background-color: $list-background-color;
|
||||
border-radius: 1rem;
|
||||
overflow: hidden;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-gap: 1rem;
|
||||
padding: 1rem;
|
||||
|
||||
@media only screen and (min-width: 800px) {
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
|
||||
@media only screen and (min-width: 1200px) {
|
||||
grid-template-columns: 1fr 1fr 1fr;
|
||||
}
|
||||
|
||||
.shortcut-desc {
|
||||
align-self: center;
|
||||
font-size: 14px;
|
||||
color: var(--grey);
|
||||
margin-top: 0;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.shortcut-box {
|
||||
padding: 1rem;
|
||||
color: map-get($foreground, text);
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
box-sizing: border-box;
|
||||
font-size: 14px;
|
||||
background-color: $card-background-color;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: 1rem;
|
||||
margin: 1rem 0;
|
||||
text-decoration: none;
|
||||
|
||||
&.edit-state {
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
&.disabled {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&.no-margin {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.shortcuts-avatar {
|
||||
flex-shrink: 0;
|
||||
height: 40px;
|
||||
width: 40px;
|
||||
margin-right: 1rem;
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: linear-gradient(40deg, rgb(129, 85, 185) 30%, #7b8ada);
|
||||
|
||||
&.purple {
|
||||
background: linear-gradient(40deg, #7c3aed 30%, #6d28d9);
|
||||
}
|
||||
|
||||
&.red {
|
||||
background: linear-gradient(40deg, #dc2626 30%, #db2777);
|
||||
}
|
||||
|
||||
&.green {
|
||||
background: linear-gradient(40deg, #059669 30%, #047857);
|
||||
}
|
||||
|
||||
&.blue {
|
||||
background: linear-gradient(40deg, #3b82f6 30%, #4f46e5);
|
||||
}
|
||||
|
||||
&.yellow {
|
||||
background: linear-gradient(40deg, #f59e0b 30%, #b45309);
|
||||
}
|
||||
|
||||
&.black {
|
||||
background: linear-gradient(40deg, #1f2937, #111827);
|
||||
}
|
||||
|
||||
.icon,
|
||||
i {
|
||||
font-size: 1.5rem;
|
||||
height: 1.2rem;
|
||||
line-height: 1.2rem;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.shortcuts-avatar-label {
|
||||
font-size: 18px;
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
|
||||
.shortcut-col {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.shortcut-item-desc {
|
||||
font-size: 13px;
|
||||
margin-top: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
.fill-space {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.shortcut-state-dot {
|
||||
height: 8px;
|
||||
width: 8px;
|
||||
border-radius: 50%;
|
||||
margin-left: 1rem;
|
||||
flex-shrink: 0;
|
||||
|
||||
&.active {
|
||||
background-color: var(--success);
|
||||
}
|
||||
|
||||
&.inactive {
|
||||
background-color: var(--warn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cdk-drag-preview {
|
||||
box-sizing: border-box;
|
||||
border-radius: 1rem;
|
||||
border: 1px solid $border-color;
|
||||
box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 0 8px 10px 1px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
|
||||
.cdk-drag-placeholder {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.cdk-drag-animating {
|
||||
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.shortcut-list.cdk-drop-list-dragging .shortcut-box:not(.cdk-drag-placeholder) {
|
||||
transition: transform 250ms cubic-bezier(0, 0, 0.2, 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { ShortcutsComponent } from './shortcuts.component';
|
||||
|
||||
describe('ShortcutsComponent', () => {
|
||||
let component: ShortcutsComponent;
|
||||
let fixture: ComponentFixture<ShortcutsComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [ ShortcutsComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(ShortcutsComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,279 @@
|
||||
import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop';
|
||||
import { Component, OnDestroy } from '@angular/core';
|
||||
import { merge, Subject, takeUntil } from 'rxjs';
|
||||
import { Org } from 'src/app/proto/generated/zitadel/org_pb';
|
||||
import { ProjectState } from 'src/app/proto/generated/zitadel/project_pb';
|
||||
import { GrpcAuthService } from 'src/app/services/grpc-auth.service';
|
||||
import { ManagementService } from 'src/app/services/mgmt.service';
|
||||
import { StorageLocation, StorageService } from 'src/app/services/storage.service';
|
||||
|
||||
import { POLICIES } from '../policy-grid/policies';
|
||||
|
||||
export interface ShortcutItem {
|
||||
id: string;
|
||||
type: ShortcutType;
|
||||
title?: string;
|
||||
desc?: string;
|
||||
i18nTitle?: string;
|
||||
i18nDesc?: string;
|
||||
routerLink: any;
|
||||
withRole: string[];
|
||||
icon?: string;
|
||||
label?: string;
|
||||
svgIcon?: string;
|
||||
avatarSrc?: string;
|
||||
color?: string;
|
||||
disabled?: boolean;
|
||||
state?: ProjectState;
|
||||
}
|
||||
|
||||
export enum ShortcutType {
|
||||
ROUTE,
|
||||
POLICY,
|
||||
PROJECT,
|
||||
}
|
||||
|
||||
const PROFILE_SHORTCUT: ShortcutItem = {
|
||||
id: 'profile',
|
||||
type: ShortcutType.ROUTE,
|
||||
routerLink: ['/users', 'me'],
|
||||
i18nTitle: 'USER.TITLE',
|
||||
icon: 'las la-cog',
|
||||
withRole: [''],
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
const CREATE_ORG: ShortcutItem = {
|
||||
id: 'create_org',
|
||||
type: ShortcutType.ROUTE,
|
||||
i18nTitle: 'ORG.PAGES.CREATE',
|
||||
routerLink: ['/org', 'create'],
|
||||
withRole: ['org.create', 'iam.write'],
|
||||
icon: 'las la-plus',
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
const CREATE_PROJECT: ShortcutItem = {
|
||||
id: 'create_project',
|
||||
type: ShortcutType.ROUTE,
|
||||
i18nTitle: 'PROJECT.PAGES.CREATE',
|
||||
routerLink: ['/projects', 'create'],
|
||||
withRole: ['project.create'],
|
||||
icon: 'las la-plus',
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
const CREATE_USER: ShortcutItem = {
|
||||
id: 'create_user',
|
||||
type: ShortcutType.ROUTE,
|
||||
i18nTitle: 'USER.CREATE.TITLE',
|
||||
routerLink: ['/users', 'create'],
|
||||
withRole: ['user.write'],
|
||||
icon: 'las la-plus',
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
@Component({
|
||||
selector: 'cnsl-shortcuts',
|
||||
templateUrl: './shortcuts.component.html',
|
||||
styleUrls: ['./shortcuts.component.scss'],
|
||||
})
|
||||
export class ShortcutsComponent implements OnDestroy {
|
||||
public org!: Org.AsObject;
|
||||
|
||||
public main: ShortcutItem[] = [];
|
||||
public secondary: ShortcutItem[] = [];
|
||||
public third: ShortcutItem[] = [];
|
||||
|
||||
public ALL_SHORTCUTS: ShortcutItem[] = [];
|
||||
public all: ShortcutItem[] = [];
|
||||
|
||||
private destroy$: Subject<void> = new Subject();
|
||||
public editState: boolean = false;
|
||||
public ProjectState: any = ProjectState;
|
||||
constructor(
|
||||
private storageService: StorageService,
|
||||
private auth: GrpcAuthService,
|
||||
private mgmtService: ManagementService,
|
||||
) {
|
||||
const org: Org.AsObject | null = this.storageService.getItem('organization', StorageLocation.session);
|
||||
if (org && org.id) {
|
||||
this.org = org;
|
||||
this.loadProjectShortcuts();
|
||||
}
|
||||
|
||||
merge(this.auth.activeOrgChanged, this.mgmtService.ownedProjects)
|
||||
.pipe(takeUntil(this.destroy$))
|
||||
.subscribe(() => {
|
||||
const org: Org.AsObject | null = this.storageService.getItem('organization', StorageLocation.session);
|
||||
if (org && org.id) {
|
||||
this.org = org;
|
||||
}
|
||||
this.loadProjectShortcuts();
|
||||
});
|
||||
}
|
||||
|
||||
public loadProjectShortcuts(): void {
|
||||
this.mgmtService.ownedProjects.pipe(takeUntil(this.destroy$)).subscribe((projects) => {
|
||||
if (projects) {
|
||||
const mapped: ShortcutItem[] = projects.map((p) => {
|
||||
const policy: ShortcutItem = {
|
||||
id: `project-${p.id}`,
|
||||
type: ShortcutType.PROJECT,
|
||||
title: p.name,
|
||||
i18nDesc: 'PROJECT.PAGES.TYPE.OWNED',
|
||||
routerLink: ['/projects', p.id],
|
||||
withRole: ['project.read', `project.read:${p.id}`],
|
||||
label: 'P',
|
||||
disabled: false,
|
||||
state: p.state,
|
||||
};
|
||||
return policy;
|
||||
});
|
||||
|
||||
const routesShortcuts = [PROFILE_SHORTCUT, CREATE_ORG, CREATE_PROJECT, CREATE_USER];
|
||||
const policyShortcuts = POLICIES.map((p) => {
|
||||
const policy: ShortcutItem = {
|
||||
id: p.i18nTitle,
|
||||
type: ShortcutType.POLICY,
|
||||
i18nTitle: p.i18nTitle,
|
||||
i18nDesc: p.i18nDesc,
|
||||
routerLink: p.orgRouterLink,
|
||||
withRole: p.orgWithRole,
|
||||
icon: p.icon ?? '',
|
||||
svgIcon: p.svgIcon ?? '',
|
||||
color: p.color ?? '',
|
||||
disabled: false,
|
||||
};
|
||||
return policy;
|
||||
});
|
||||
|
||||
this.ALL_SHORTCUTS = [...routesShortcuts, ...policyShortcuts, ...mapped];
|
||||
this.loadShortcuts(this.org);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public loadShortcuts(org: Org.AsObject): void {
|
||||
['main', 'secondary', 'third'].map((listName) => {
|
||||
const joinedShortcuts = this.storageService.getItem(`shortcuts:${listName}:${org.id}`, StorageLocation.local);
|
||||
if (joinedShortcuts) {
|
||||
const parsedIds: string[] = joinedShortcuts.split(',');
|
||||
if (parsedIds && parsedIds.length) {
|
||||
switch (listName) {
|
||||
case 'main':
|
||||
this.main = this.ALL_SHORTCUTS.filter((s) => parsedIds.includes(s.id));
|
||||
break;
|
||||
case 'secondary':
|
||||
this.secondary = this.ALL_SHORTCUTS.filter((s) => parsedIds.includes(s.id));
|
||||
break;
|
||||
case 'third':
|
||||
this.third = this.ALL_SHORTCUTS.filter((s) => parsedIds.includes(s.id));
|
||||
break;
|
||||
}
|
||||
this.organizeAllItems();
|
||||
}
|
||||
} else {
|
||||
switch (listName) {
|
||||
case 'main':
|
||||
this.main = [PROFILE_SHORTCUT, CREATE_ORG, CREATE_PROJECT, CREATE_USER];
|
||||
break;
|
||||
case 'secondary':
|
||||
this.secondary = [];
|
||||
// [LOGIN_POLICY, PRIVATELABEL_POLICY].map((p) => {
|
||||
// const policy: string = {
|
||||
// i18nTitle: p.i18nTitle,
|
||||
// i18nDesc: p.i18nDesc,
|
||||
// routerLink: p.orgRouterLink,
|
||||
// withRole: p.orgWithRole,
|
||||
// icon: p.icon ?? '',
|
||||
// color: p.color ?? '',
|
||||
// disabled: false,
|
||||
// };
|
||||
// return policy;
|
||||
// });
|
||||
break;
|
||||
case 'third':
|
||||
this.third = [];
|
||||
// [LOGIN_TEXTS_POLICY, MESSAGE_TEXTS_POLICY].map((p) => {
|
||||
// const policy: ShortcutItem = {
|
||||
// i18nTitle: p.i18nTitle,
|
||||
// i18nDesc: p.i18nDesc,
|
||||
// routerLink: p.orgRouterLink,
|
||||
// withRole: p.orgWithRole,
|
||||
// icon: p.icon ?? '',
|
||||
// color: p.color ?? '',
|
||||
// disabled: false,
|
||||
// };
|
||||
// return policy;
|
||||
// });
|
||||
break;
|
||||
}
|
||||
this.organizeAllItems();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private organizeAllItems(): void {
|
||||
const list = [this.main, this.secondary, this.third].flat();
|
||||
const filteredPolicies = this.ALL_SHORTCUTS.filter((p) => !list.find((l) => l.id === p.id));
|
||||
this.all = filteredPolicies;
|
||||
|
||||
this.main === this.main.filter((s) => s.id && this.ALL_SHORTCUTS.map((p) => p.id).includes(s.id));
|
||||
this.secondary === this.secondary.filter((s) => s.id && this.ALL_SHORTCUTS.map((p) => p.id).includes(s.id));
|
||||
this.third === this.third.filter((s) => s.id && this.ALL_SHORTCUTS.map((p) => p.id).includes(s.id));
|
||||
}
|
||||
|
||||
public ngOnDestroy(): void {
|
||||
this.destroy$.next();
|
||||
this.destroy$.complete();
|
||||
}
|
||||
|
||||
public drop(event: CdkDragDrop<ShortcutItem[]>, listName: string) {
|
||||
if (event.previousContainer === event.container) {
|
||||
moveItemInArray(event.container.data, event.previousIndex, event.currentIndex);
|
||||
this.saveStateToStorage();
|
||||
this.organizeAllItems();
|
||||
} else {
|
||||
transferArrayItem(event.previousContainer.data, event.container.data, event.previousIndex, event.currentIndex);
|
||||
this.saveStateToStorage();
|
||||
this.organizeAllItems();
|
||||
}
|
||||
}
|
||||
|
||||
public saveStateToStorage(): void {
|
||||
const org: Org.AsObject | null = this.storageService.getItem('organization', StorageLocation.session);
|
||||
if (org && org.id) {
|
||||
this.storageService.setItem(`shortcuts:main:${org.id}`, this.main.map((p) => p.id).join(','), StorageLocation.local);
|
||||
this.storageService.setItem(
|
||||
`shortcuts:secondary:${org.id}`,
|
||||
this.secondary.map((p) => p.id).join(','),
|
||||
StorageLocation.local,
|
||||
);
|
||||
this.storageService.setItem(`shortcuts:third:${org.id}`, this.third.map((p) => p.id).join(','), StorageLocation.local);
|
||||
}
|
||||
}
|
||||
|
||||
public reset(): void {
|
||||
const org: Org.AsObject | null = this.storageService.getItem('organization', StorageLocation.session);
|
||||
if (org && org.id) {
|
||||
['main', 'secondary', 'third'].map((listName) => {
|
||||
this.storageService.removeItem(`shortcuts:${listName}:${org.id}`, StorageLocation.local);
|
||||
});
|
||||
|
||||
this.loadShortcuts(org);
|
||||
}
|
||||
}
|
||||
|
||||
public get allRoutes(): ShortcutItem[] {
|
||||
return this.all.filter((s) => s.type === ShortcutType.ROUTE);
|
||||
}
|
||||
|
||||
public get allPolicies(): ShortcutItem[] {
|
||||
return this.all.filter((s) => s.type === ShortcutType.POLICY);
|
||||
}
|
||||
|
||||
public get allProjects(): ShortcutItem[] {
|
||||
return this.all.filter((s) => s.type === ShortcutType.PROJECT);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
import { DragDropModule } from '@angular/cdk/drag-drop';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { NgModule } from '@angular/core';
|
||||
import { MatButtonModule } from '@angular/material/button';
|
||||
import { MatIconModule } from '@angular/material/icon';
|
||||
import { MatTooltipModule } from '@angular/material/tooltip';
|
||||
import { RouterModule } from '@angular/router';
|
||||
import { TranslateModule } from '@ngx-translate/core';
|
||||
import { HasRoleModule } from 'src/app/directives/has-role/has-role.module';
|
||||
|
||||
import { ShortcutsComponent } from './shortcuts.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [ShortcutsComponent],
|
||||
imports: [
|
||||
CommonModule,
|
||||
MatButtonModule,
|
||||
MatTooltipModule,
|
||||
RouterModule,
|
||||
DragDropModule,
|
||||
HasRoleModule,
|
||||
TranslateModule,
|
||||
MatIconModule,
|
||||
],
|
||||
exports: [ShortcutsComponent],
|
||||
})
|
||||
export class ShortcutsModule {}
|
||||
Reference in New Issue
Block a user