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:
Max Peintner
2022-04-28 10:35:02 +00:00
committed by GitHub
co-authored by Livio Amstutz
parent 00f7dbe875
commit 08ae39ae19
668 changed files with 47746 additions and 19117 deletions
@@ -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 {}