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:
Stipe Knez 2022-06-13 21:08:29 +02:00 committed by Marcel Haag
parent 5d5dbe95fa
commit abddd00451
16 changed files with 632 additions and 670 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1 +1,5 @@
<p>pentest-categories works!</p>
<div>
<nb-menu class="menu-style" tag="menu" [items]="categories"></nb-menu>
</div>

View File

@ -0,0 +1 @@
@import '../../../assets/@theme/styles/themes';

View File

@ -1,6 +1,17 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
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', () => {
let component: PentestCategoriesComponent;
@ -8,7 +19,29 @@ describe('PentestCategoriesComponent', () => {
beforeEach(async () => {
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();
});

View File

@ -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({
selector: 'app-pentest-categories',
templateUrl: './pentest-categories.component.html',
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();
}
}

View File

@ -3,11 +3,12 @@ import {CommonModule} from '@angular/common';
import {PentestHeaderComponent} from './pentest-header/pentest-header.component';
import {PentestCategoriesComponent} from './pentest-categories/pentest-categories.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 {StatusTagModule} from '@shared/widgets/status-tag/status-tag.module';
import {FindigWidgetModule} from '@shared/widgets/findig-widget/findig-widget.module';
import {RouterModule} from '@angular/router';
import {FormsModule} from '@angular/forms';
@NgModule({
declarations: [
@ -24,11 +25,15 @@ import {RouterModule} from '@angular/router';
CommonModule,
NbLayoutModule,
NbCardModule,
NbMenuModule.forRoot(),
NbTreeGridModule,
TranslateModule,
StatusTagModule,
FindigWidgetModule,
RouterModule
RouterModule,
NbMenuModule,
FormsModule,
NbListModule
]
})
export class PentestOverviewModule {

View File

@ -14,6 +14,7 @@ import {getTitleKeyForRefNumber} from '@shared/functions/categories/get-title-ke
templateUrl: './pentest-table.component.html',
styleUrls: ['./pentest-table.component.scss']
})
export class PentestTableComponent implements OnInit, OnDestroy {
columns: Array<PentestColumns> = [PentestColumns.TEST_ID, PentestColumns.TITLE, PentestColumns.STATUS, PentestColumns.FINDINGS];

View File

@ -2,7 +2,7 @@ import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {ProjectOverviewComponent} from './project-overview.component';
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 {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
import {TranslateModule} from '@ngx-translate/core';

View File

@ -1,22 +1,24 @@
<div fxFlex class="pentest-overview">
<nb-layout>
<nb-layout fxFlex>
<nb-layout-header fxFlexAlign="center" class="header-column">
<app-pentest-header></app-pentest-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-body>
<app-pentest-categories></app-pentest-categories>
</nb-card-body>
</nb-card>
</nb-layout-column>
<nb-layout-column class="table-wrapper" fxFlex="4 1 85%">
<nb-card class="table-column">
<nb-card-body>
<app-pentest-table></app-pentest-table>
</nb-card-body>
</nb-card>
</nb-layout-column>
</nb-layout>
</div>

View File

@ -7,17 +7,24 @@
overflow: hidden;
.header-column {
width: 100%
width: 100%;
}
.column-wrapper {
padding-left: 0 !important;
.categories-column {
width: 20%;
height: calc(100vh - #{$pentest-header-height});
height: 80vh;
}
}
.table-wrapper{
padding-right: 0 !important;
.table-column {
overflow: auto !important;
width: 80%;
height: 80vh;
}
}
}

View File

@ -11,6 +11,7 @@ import {Project} from '@shared/models/project.model';
templateUrl: './project.component.html',
styleUrls: ['./project.component.scss']
})
export class ProjectComponent implements OnInit, OnDestroy {
constructor(

View File

@ -2,7 +2,7 @@ import {NgModule} from '@angular/core';
import {CommonModule} from '@angular/common';
import {RouterModule} from '@angular/router';
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 {TranslateModule} from '@ngx-translate/core';
import {ProjectDialogModule} from '@shared/modules/project-dialog/project-dialog.module';
@ -13,6 +13,9 @@ import {PentestOverviewModule} from '../../pentest-overview';
declarations: [
ProjectComponent
],
exports: [
ProjectComponent
],
imports: [
CommonModule,
NbCardModule,

View File

@ -8,4 +8,44 @@
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);
}
}
}
}

View File

@ -2,6 +2,8 @@
@import '~@nebular/theme/styles/theming';
// @nebular out of the box themes
@import '~@nebular/theme/styles/themes';
// enable custom css properties
$nb-enable-css-custom-properties: true;
$nb-themes: nb-register-theme((
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-rtl: 0 4px 14px 0 #8f9bb3,
), dark, dark);

View File

@ -207,5 +207,19 @@
"011": "Testen von Web-Messaging",
"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"
}
}

View File

@ -207,5 +207,18 @@
"011": "Test Web Messaging",
"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"
}
}