feat: As a user I want to have a sidenav in order to select the current step of my Pentest
Co-authored-by: Marcel Haag <marcel.haag@novatec-gmbh.de>
This commit is contained in:
parent
5d5dbe95fa
commit
abddd00451
File diff suppressed because it is too large
Load Diff
|
@ -1 +1,5 @@
|
||||||
<p>pentest-categories works!</p>
|
<div>
|
||||||
|
<nb-menu class="menu-style" tag="menu" [items]="categories"></nb-menu>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
@import '../../../assets/@theme/styles/themes';
|
|
@ -1,6 +1,17 @@
|
||||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||||
|
|
||||||
import { PentestCategoriesComponent } from './pentest-categories.component';
|
import { PentestCategoriesComponent } from './pentest-categories.component';
|
||||||
|
import {NbMenuModule, NbMenuService} from '@nebular/theme';
|
||||||
|
import {NgxsModule} from '@ngxs/store';
|
||||||
|
import {ProjectState} from '@shared/stores/project-state/project-state';
|
||||||
|
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
|
||||||
|
import {HttpLoaderFactory} from '../../common-app.module';
|
||||||
|
import {HttpClient, HttpClientModule} from '@angular/common/http';
|
||||||
|
import {HttpClientTestingModule} from '@angular/common/http/testing';
|
||||||
|
import {CommonModule} from '@angular/common';
|
||||||
|
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
|
||||||
|
import {ThemeModule} from '@assets/@theme/theme.module';
|
||||||
|
import {RouterTestingModule} from '@angular/router/testing';
|
||||||
|
|
||||||
describe('PentestCategoriesComponent', () => {
|
describe('PentestCategoriesComponent', () => {
|
||||||
let component: PentestCategoriesComponent;
|
let component: PentestCategoriesComponent;
|
||||||
|
@ -8,7 +19,29 @@ describe('PentestCategoriesComponent', () => {
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
await TestBed.configureTestingModule({
|
await TestBed.configureTestingModule({
|
||||||
declarations: [ PentestCategoriesComponent ]
|
declarations: [
|
||||||
|
PentestCategoriesComponent
|
||||||
|
],
|
||||||
|
imports: [
|
||||||
|
CommonModule,
|
||||||
|
BrowserAnimationsModule,
|
||||||
|
NbMenuModule.forRoot(),
|
||||||
|
ThemeModule.forRoot(),
|
||||||
|
TranslateModule.forRoot({
|
||||||
|
loader: {
|
||||||
|
provide: TranslateLoader,
|
||||||
|
useFactory: HttpLoaderFactory,
|
||||||
|
deps: [HttpClient]
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
NgxsModule.forRoot([ProjectState]),
|
||||||
|
RouterTestingModule.withRoutes([]),
|
||||||
|
HttpClientModule,
|
||||||
|
HttpClientTestingModule
|
||||||
|
],
|
||||||
|
providers: [
|
||||||
|
NbMenuService
|
||||||
|
]
|
||||||
})
|
})
|
||||||
.compileComponents();
|
.compileComponents();
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,15 +1,77 @@
|
||||||
import { Component, OnInit } from '@angular/core';
|
import {Component, OnDestroy, OnInit} from '@angular/core';
|
||||||
|
import {NbMenuItem, NbMenuService} from '@nebular/theme';
|
||||||
|
import {Subject} from 'rxjs';
|
||||||
|
import {Store} from '@ngxs/store';
|
||||||
|
import {ChangeCategory} from '@shared/stores/project-state/project-state.actions';
|
||||||
|
import {Category} from '@shared/models/category.model';
|
||||||
|
import {untilDestroyed} from 'ngx-take-until-destroy';
|
||||||
|
import {TranslateService} from '@ngx-translate/core';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-pentest-categories',
|
selector: 'app-pentest-categories',
|
||||||
templateUrl: './pentest-categories.component.html',
|
templateUrl: './pentest-categories.component.html',
|
||||||
styleUrls: ['./pentest-categories.component.scss']
|
styleUrls: ['./pentest-categories.component.scss']
|
||||||
})
|
})
|
||||||
export class PentestCategoriesComponent implements OnInit {
|
export class PentestCategoriesComponent implements OnInit, OnDestroy {
|
||||||
|
categories: NbMenuItem[] = [];
|
||||||
|
selectedCategory: Category = 0;
|
||||||
|
|
||||||
constructor() { }
|
private destroy$ = new Subject<void>();
|
||||||
|
|
||||||
ngOnInit(): void {
|
constructor(private store: Store,
|
||||||
|
private menuService: NbMenuService,
|
||||||
|
private translateService: TranslateService) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.initTranslation();
|
||||||
|
// Set first item in list as selected
|
||||||
|
this.categories[0].selected = true;
|
||||||
|
this.menuService.onItemClick()
|
||||||
|
.pipe(
|
||||||
|
untilDestroyed(this)
|
||||||
|
)
|
||||||
|
.subscribe((menuBag) => {
|
||||||
|
this.selectedCategory = menuBag.item.data;
|
||||||
|
this.categories.forEach(category => {
|
||||||
|
category.selected = false;
|
||||||
|
});
|
||||||
|
menuBag.item.selected = true;
|
||||||
|
this.store.dispatch(new ChangeCategory(this.selectedCategory));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private initTranslation(): void {
|
||||||
|
for (const cat in Category) {
|
||||||
|
if (isNaN(Number(cat))) {
|
||||||
|
// initialize category menu
|
||||||
|
this.translateService.get('categories.' + cat)
|
||||||
|
.pipe(
|
||||||
|
untilDestroyed(this)
|
||||||
|
)
|
||||||
|
.subscribe((text: string) => {
|
||||||
|
this.categories.push({title: text, data: Category[cat as keyof typeof Category]});
|
||||||
|
});
|
||||||
|
// set up continuous translation
|
||||||
|
this.translateService.stream('categories.' + cat)
|
||||||
|
.pipe(
|
||||||
|
untilDestroyed(this)
|
||||||
|
)
|
||||||
|
.subscribe((text: string) => {
|
||||||
|
this.categories.forEach(item => {
|
||||||
|
if (item.data === Category[cat as keyof typeof Category]) {
|
||||||
|
item.title = text;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnDestroy(): void {
|
||||||
|
this.destroy$.next();
|
||||||
|
this.destroy$.complete();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,11 +3,12 @@ import {CommonModule} from '@angular/common';
|
||||||
import {PentestHeaderComponent} from './pentest-header/pentest-header.component';
|
import {PentestHeaderComponent} from './pentest-header/pentest-header.component';
|
||||||
import {PentestCategoriesComponent} from './pentest-categories/pentest-categories.component';
|
import {PentestCategoriesComponent} from './pentest-categories/pentest-categories.component';
|
||||||
import {PentestTableComponent} from './pentest-table/pentest-table.component';
|
import {PentestTableComponent} from './pentest-table/pentest-table.component';
|
||||||
import {NbCardModule, NbLayoutModule, NbTreeGridModule} from '@nebular/theme';
|
import {NbCardModule, NbLayoutModule, NbTreeGridModule, NbMenuModule, NbSidebarModule, NbListModule} from '@nebular/theme';
|
||||||
import {TranslateModule} from '@ngx-translate/core';
|
import {TranslateModule} from '@ngx-translate/core';
|
||||||
import {StatusTagModule} from '@shared/widgets/status-tag/status-tag.module';
|
import {StatusTagModule} from '@shared/widgets/status-tag/status-tag.module';
|
||||||
import {FindigWidgetModule} from '@shared/widgets/findig-widget/findig-widget.module';
|
import {FindigWidgetModule} from '@shared/widgets/findig-widget/findig-widget.module';
|
||||||
import {RouterModule} from '@angular/router';
|
import {RouterModule} from '@angular/router';
|
||||||
|
import {FormsModule} from '@angular/forms';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
|
@ -24,11 +25,15 @@ import {RouterModule} from '@angular/router';
|
||||||
CommonModule,
|
CommonModule,
|
||||||
NbLayoutModule,
|
NbLayoutModule,
|
||||||
NbCardModule,
|
NbCardModule,
|
||||||
|
NbMenuModule.forRoot(),
|
||||||
NbTreeGridModule,
|
NbTreeGridModule,
|
||||||
TranslateModule,
|
TranslateModule,
|
||||||
StatusTagModule,
|
StatusTagModule,
|
||||||
FindigWidgetModule,
|
FindigWidgetModule,
|
||||||
RouterModule
|
RouterModule,
|
||||||
|
NbMenuModule,
|
||||||
|
FormsModule,
|
||||||
|
NbListModule
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class PentestOverviewModule {
|
export class PentestOverviewModule {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {getTitleKeyForRefNumber} from '@shared/functions/categories/get-title-ke
|
||||||
templateUrl: './pentest-table.component.html',
|
templateUrl: './pentest-table.component.html',
|
||||||
styleUrls: ['./pentest-table.component.scss']
|
styleUrls: ['./pentest-table.component.scss']
|
||||||
})
|
})
|
||||||
|
|
||||||
export class PentestTableComponent implements OnInit, OnDestroy {
|
export class PentestTableComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
columns: Array<PentestColumns> = [PentestColumns.TEST_ID, PentestColumns.TITLE, PentestColumns.STATUS, PentestColumns.FINDINGS];
|
columns: Array<PentestColumns> = [PentestColumns.TEST_ID, PentestColumns.TITLE, PentestColumns.STATUS, PentestColumns.FINDINGS];
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {NgModule} from '@angular/core';
|
||||||
import {CommonModule} from '@angular/common';
|
import {CommonModule} from '@angular/common';
|
||||||
import {ProjectOverviewComponent} from './project-overview.component';
|
import {ProjectOverviewComponent} from './project-overview.component';
|
||||||
import {ProjectOverviewRoutingModule} from './project-overview-routing.module';
|
import {ProjectOverviewRoutingModule} from './project-overview-routing.module';
|
||||||
import {NbButtonModule, NbCardModule, NbProgressBarModule, NbSpinnerModule} from '@nebular/theme';
|
import {NbButtonModule, NbCardModule, NbMenuModule, NbProgressBarModule, NbSidebarModule, NbSpinnerModule} from '@nebular/theme';
|
||||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||||
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
|
||||||
import {TranslateModule} from '@ngx-translate/core';
|
import {TranslateModule} from '@ngx-translate/core';
|
||||||
|
|
|
@ -1,22 +1,24 @@
|
||||||
<div fxFlex class="pentest-overview">
|
<div fxFlex class="pentest-overview">
|
||||||
<nb-layout>
|
<nb-layout fxFlex>
|
||||||
|
|
||||||
<nb-layout-header fxFlexAlign="center" class="header-column">
|
<nb-layout-header fxFlexAlign="center" class="header-column">
|
||||||
<app-pentest-header></app-pentest-header>
|
<app-pentest-header></app-pentest-header>
|
||||||
</nb-layout-header>
|
</nb-layout-header>
|
||||||
|
|
||||||
<nb-layout-column fxFlexFill fxLayout="row" fxLayoutGap="2rem">
|
<nb-layout-column fxFlex="1 1 max-content" class="column-wrapper">
|
||||||
<nb-card class="categories-column">
|
<nb-card class="categories-column">
|
||||||
<nb-card-body>
|
<app-pentest-categories></app-pentest-categories>
|
||||||
<app-pentest-categories></app-pentest-categories>
|
|
||||||
</nb-card-body>
|
|
||||||
</nb-card>
|
</nb-card>
|
||||||
|
</nb-layout-column>
|
||||||
|
|
||||||
|
<nb-layout-column class="table-wrapper" fxFlex="4 1 85%">
|
||||||
<nb-card class="table-column">
|
<nb-card class="table-column">
|
||||||
<nb-card-body>
|
<nb-card-body>
|
||||||
<app-pentest-table></app-pentest-table>
|
<app-pentest-table></app-pentest-table>
|
||||||
</nb-card-body>
|
</nb-card-body>
|
||||||
</nb-card>
|
</nb-card>
|
||||||
</nb-layout-column>
|
</nb-layout-column>
|
||||||
|
|
||||||
</nb-layout>
|
</nb-layout>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -7,17 +7,24 @@
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
.header-column {
|
.header-column {
|
||||||
width: 100%
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.categories-column {
|
.column-wrapper {
|
||||||
width: 20%;
|
padding-left: 0 !important;
|
||||||
height: calc(100vh - #{$pentest-header-height});
|
|
||||||
|
.categories-column {
|
||||||
|
height: calc(100vh - #{$pentest-header-height});
|
||||||
|
height: 80vh;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-column {
|
.table-wrapper{
|
||||||
overflow: auto !important;
|
padding-right: 0 !important;
|
||||||
width: 80%;
|
|
||||||
height: 80vh;
|
.table-column {
|
||||||
|
overflow: auto !important;
|
||||||
|
height: 80vh;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import {Project} from '@shared/models/project.model';
|
||||||
templateUrl: './project.component.html',
|
templateUrl: './project.component.html',
|
||||||
styleUrls: ['./project.component.scss']
|
styleUrls: ['./project.component.scss']
|
||||||
})
|
})
|
||||||
|
|
||||||
export class ProjectComponent implements OnInit, OnDestroy {
|
export class ProjectComponent implements OnInit, OnDestroy {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {NgModule} from '@angular/core';
|
||||||
import {CommonModule} from '@angular/common';
|
import {CommonModule} from '@angular/common';
|
||||||
import {RouterModule} from '@angular/router';
|
import {RouterModule} from '@angular/router';
|
||||||
import {ProjectComponent} from './project.component';
|
import {ProjectComponent} from './project.component';
|
||||||
import {NbCardModule, NbLayoutModule} from '@nebular/theme';
|
import {NbCardModule, NbLayoutModule, NbMenuModule, NbSidebarModule} from '@nebular/theme';
|
||||||
import {FlexLayoutModule} from '@angular/flex-layout';
|
import {FlexLayoutModule} from '@angular/flex-layout';
|
||||||
import {TranslateModule} from '@ngx-translate/core';
|
import {TranslateModule} from '@ngx-translate/core';
|
||||||
import {ProjectDialogModule} from '@shared/modules/project-dialog/project-dialog.module';
|
import {ProjectDialogModule} from '@shared/modules/project-dialog/project-dialog.module';
|
||||||
|
@ -13,6 +13,9 @@ import {PentestOverviewModule} from '../../pentest-overview';
|
||||||
declarations: [
|
declarations: [
|
||||||
ProjectComponent
|
ProjectComponent
|
||||||
],
|
],
|
||||||
|
exports: [
|
||||||
|
ProjectComponent
|
||||||
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
NbCardModule,
|
NbCardModule,
|
||||||
|
|
|
@ -8,4 +8,44 @@
|
||||||
right: 0.41rem !important;
|
right: 0.41rem !important;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nb-menu {
|
||||||
|
background-color: nb-theme(menu-background-color);
|
||||||
|
|
||||||
|
ul.menu-items {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item a {
|
||||||
|
font-family: Roboto, "Helvetica Neue", sans-serif;
|
||||||
|
font-size: 0.95rem;
|
||||||
|
font-weight: nb-theme(text-font-weight);;
|
||||||
|
line-height: nb-theme(menu-text-line-height);
|
||||||
|
padding: nb-theme(menu-item-padding);
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-item {
|
||||||
|
a {
|
||||||
|
color: nb-theme(menu-text-color);
|
||||||
|
border-radius: nb-theme(menu-item-border-radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
a.active {
|
||||||
|
background-color: nb-theme(color-primary-hover) !important;
|
||||||
|
color: nb-theme(text-control-color) !important;
|
||||||
|
font-weight: nb-theme(menu-text-font-weight);
|
||||||
|
}
|
||||||
|
|
||||||
|
a:hover {
|
||||||
|
background-color: nb-theme(color-basic-transparent-focus);
|
||||||
|
color: nb-theme(menu-text-color);
|
||||||
|
cursor: nb-theme(menu-item-hover-cursor);
|
||||||
|
// Increases element size on hover
|
||||||
|
transform: scale(1.025);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@
|
||||||
@import '~@nebular/theme/styles/theming';
|
@import '~@nebular/theme/styles/theming';
|
||||||
// @nebular out of the box themes
|
// @nebular out of the box themes
|
||||||
@import '~@nebular/theme/styles/themes';
|
@import '~@nebular/theme/styles/themes';
|
||||||
|
// enable custom css properties
|
||||||
|
$nb-enable-css-custom-properties: true;
|
||||||
|
|
||||||
$nb-themes: nb-register-theme((
|
$nb-themes: nb-register-theme((
|
||||||
layout-padding-top: 2.25rem,
|
layout-padding-top: 2.25rem,
|
||||||
|
@ -44,3 +46,4 @@ $nb-themes: nb-register-theme((
|
||||||
slide-out-shadow-color: 0 4px 14px 0 #8f9bb3,
|
slide-out-shadow-color: 0 4px 14px 0 #8f9bb3,
|
||||||
slide-out-shadow-color-rtl: 0 4px 14px 0 #8f9bb3,
|
slide-out-shadow-color-rtl: 0 4px 14px 0 #8f9bb3,
|
||||||
), dark, dark);
|
), dark, dark);
|
||||||
|
|
||||||
|
|
|
@ -207,5 +207,19 @@
|
||||||
"011": "Testen von Web-Messaging",
|
"011": "Testen von Web-Messaging",
|
||||||
"012": "Lokalen Speicher testen"
|
"012": "Lokalen Speicher testen"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"categories": {
|
||||||
|
"INFORMATION_GATHERING": "Informationsbeschaffung",
|
||||||
|
"CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING": "Konfig- & Einsatzmanagement-Testing",
|
||||||
|
"IDENTITY_MANAGEMENT_TESTING": "Identitätsmanagement-Testing",
|
||||||
|
"AUTHENTICATION_TESTING": "Authentifizierungs-Testing",
|
||||||
|
"AUTHORIZATION_TESTING": "Autorisations-Testing",
|
||||||
|
"SESSION_MANAGEMENT_TESTING": "Sitzungsmanagement-Testing",
|
||||||
|
"INPUT_VALIDATION_TESTING": "Eingabevalidierungs-Testing",
|
||||||
|
"ERROR_HANDLING": "Fehlerbehandlung",
|
||||||
|
"CRYPTOGRAPHY": "Kryptographie",
|
||||||
|
"BUSINESS_LOGIC_TESTING": "Business-Logik-Testing",
|
||||||
|
"CLIENT_SIDE_TESTING": "Clientseitiges-Testing"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -207,5 +207,18 @@
|
||||||
"011": "Test Web Messaging",
|
"011": "Test Web Messaging",
|
||||||
"012": "Test Local Storage"
|
"012": "Test Local Storage"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"categories": {
|
||||||
|
"INFORMATION_GATHERING": "Information Gathering",
|
||||||
|
"CONFIGURATION_AND_DEPLOY_MANAGEMENT_TESTING": "Config & Deploy Management Testing",
|
||||||
|
"IDENTITY_MANAGEMENT_TESTING": "Identity Management Testing",
|
||||||
|
"AUTHENTICATION_TESTING": "Authentication Testing",
|
||||||
|
"AUTHORIZATION_TESTING": "Authorization Testing",
|
||||||
|
"SESSION_MANAGEMENT_TESTING": "Session Management Testing",
|
||||||
|
"INPUT_VALIDATION_TESTING": "Input Validation Testing",
|
||||||
|
"ERROR_HANDLING": "Error Handling",
|
||||||
|
"CRYPTOGRAPHY": "Cryptography",
|
||||||
|
"BUSINESS_LOGIC_TESTING": "Business Logic Testing",
|
||||||
|
"CLIENT_SIDE_TESTING": "Client Side Testing"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue