feat: console flat navigation, settings (#3581)

* instance routing

* instance naming

* org list

* rm isonsystem

* breadcrumb  type

* routing

* instance members

* fragment refresh org

* settings pages

* settings list, sidenav grouping, i18n

* org-settings, policy changes

* lint

* grid

* rename grid

* fallback to general

* cleanup

* general settings, remove cards

* sidenav for settings, label policy

* i18n

* header, nav backbuild

* general, project nav rehaul

* login text background adapt

* org nav anim

* org, instance settings, fix policy layout, roles

* i18n, active route for project

* lint
This commit is contained in:
Max Peintner
2022-05-09 15:01:36 +02:00
committed by GitHub
parent 94e420bb24
commit 06e3330d2e
188 changed files with 4046 additions and 3639 deletions
@@ -1,6 +1,9 @@
<div class="sidenav-container">
<div class="sidenav-settings-list">
<div class="sidenav-settings-list" [ngClass]="{ indented: indented }">
<div class="sidenav-sticky-rel">
<h1 *ngIf="title">{{ title }}</h1>
<p *ngIf="description" class="cnsl-secondary-text">{{ description }}</p>
<button
*ngIf="currentSetting !== undefined"
(click)="value = undefined"
@@ -10,8 +13,19 @@
<i class="las la-angle-left"></i>
<span>{{ 'USER.SETTINGS.TITLE' | translate }}</span>
</button>
<ng-container *ngFor="let setting of settingsList">
<ng-container *ngFor="let setting of settingsList; index as i">
<ng-container>
<span
class="sidenav-setting-group hide-on-mobile"
[ngClass]="{ show: currentSetting === undefined }"
*ngIf="
(setting.groupI18nKey && i > 0 && setting.groupI18nKey !== settingsList[i - 1].groupI18nKey) ||
(i === 0 && setting.groupI18nKey)
"
>{{ setting.groupI18nKey | translate }}</span
>
<button
(click)="value = setting.id"
class="sidenav-setting-list-element hide-on-mobile"
@@ -34,8 +48,6 @@
</div>
<div class="sidenav-content">
<div class="max-width-container">
<ng-content></ng-content>
</div>
<ng-content></ng-content>
</div>
</div>
@@ -2,10 +2,10 @@
@mixin sidenav-theme($theme) {
$foreground: map-get($theme, foreground);
$background: map-get($theme, background);
$is-dark-theme: map-get($theme, is-dark);
.sidenav-container {
padding-top: 1rem;
display: grid;
position: relative;
grid-template-columns: 1fr;
@@ -13,12 +13,54 @@
.sidenav-settings-list {
position: relative;
&.indented {
margin-right: 2rem;
.sidenav-sticky-rel {
margin-left: -2rem;
padding-left: 2rem;
background: map-get($background, footer);
}
}
.sidenav-sticky-rel {
display: flex;
flex-direction: column;
position: sticky;
top: 50px;
padding: 1rem 2rem 1rem 0;
top: 36px;
padding: 20px 2rem 20px 0;
.sidenav-setting-group {
font-size: 11px;
letter-spacing: 0.05em;
text-transform: uppercase;
color: if($is-dark-theme, #ffffff60, #00000060);
margin-top: 1rem;
font-weight: 600;
margin-bottom: 0.5rem;
padding-top: 1rem;
border-top: 1px solid if($is-dark-theme, rgba(#8795a1, 0.2), rgba(#8795a1, 0.2));
&:nth-child(2) {
border-top: none;
padding-top: 0;
margin-top: 0;
}
&.hide-on-mobile {
@media only screen and (max-width: 500px) {
display: none;
}
}
&.show {
display: none;
@media only screen and (max-width: 500px) {
display: flex;
}
}
}
.sidenav-setting-list-element {
border: none;
@@ -1,30 +1,63 @@
import { Component, forwardRef, Input } from '@angular/core';
import { NG_VALUE_ACCESSOR } from '@angular/forms';
import { Component, Input, OnInit } from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { PolicyComponentServiceType } from '../policies/policy-component-types.enum';
export interface SidenavSetting {
id: string;
i18nKey: string;
groupI18nKey?: string;
requiredRoles?: { [serviceType in PolicyComponentServiceType]: string[] };
}
@Component({
selector: 'cnsl-sidenav',
templateUrl: './sidenav.component.html',
styleUrls: ['./sidenav.component.scss'],
providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => SidenavComponent), multi: true }],
providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: SidenavComponent, multi: true }],
})
export class SidenavComponent {
@Input() public currentSetting: string | undefined = 'general';
export class SidenavComponent implements ControlValueAccessor, OnInit {
@Input() public title: string = '';
@Input() public description: string = '';
@Input() public indented: boolean = false;
@Input() public currentSetting?: string | undefined = undefined;
@Input() public settingsList: SidenavSetting[] = [];
@Input() public queryParam: string = '';
constructor() {}
constructor(private router: Router, private route: ActivatedRoute) {}
private onChange: any = () => {};
private onTouch: any = () => {};
ngOnInit(): void {
if (!this.value) {
this.value = this.settingsList[0].id;
}
}
private onChange = (current: string | undefined) => {};
private onTouch = (current: string | undefined) => {};
@Input() get value(): string | undefined {
return this.currentSetting;
}
set value(setting: string | undefined) {
this.currentSetting = setting;
this.onChange(setting);
this.onTouch(setting);
if (setting || setting === undefined) {
this.onChange(setting);
this.onTouch(setting);
}
if (this.queryParam && setting) {
this.router.navigate([], {
relativeTo: this.route,
queryParams: {
[this.queryParam]: setting,
},
queryParamsHandling: 'merge',
skipLocationChange: false,
});
}
}
public writeValue(value: any) {
@@ -1,13 +1,15 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { MatIconModule } from '@angular/material/icon';
import { RouterModule } from '@angular/router';
import { TranslateModule } from '@ngx-translate/core';
import { SidenavComponent } from './sidenav.component';
@NgModule({
declarations: [SidenavComponent],
imports: [CommonModule, MatIconModule, TranslateModule],
imports: [CommonModule, FormsModule, RouterModule, MatIconModule, TranslateModule],
exports: [SidenavComponent],
})
export class SidenavModule {}