Compare commits

...

1 Commits

Author SHA1 Message Date
Marcel Haag 8e2cfd81fa feat: As an user I want to have an additional pentest-header 2022-06-24 21:55:50 +02:00
30 changed files with 4610 additions and 1641 deletions

View File

@ -97,7 +97,9 @@
"test": {
"builder": "@angular-builders/jest:run",
"options": {
"polyfills": "src/polyfills.ts",
"polyfills": [
"src/polyfills.ts"
],
"tsConfig": "tsconfig.spec.json",
"assets": [
"src/assets/images/favicons/favicon.ico",

File diff suppressed because it is too large Load Diff

View File

@ -28,8 +28,8 @@
"@fortawesome/fontawesome-svg-core": "^1.2.36",
"@fortawesome/free-regular-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@nebular/eva-icons": "^8.0.0",
"@nebular/theme": "^8.0.0",
"@nebular/theme": "^9.0.0",
"@ngneat/until-destroy": "~8.0.4",
"@ngx-translate/core": "^13.0.0",
"@ngx-translate/http-loader": "^6.0.0",
"@ngxs/store": "^3.7.3",
@ -51,20 +51,21 @@
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-builders/jest": "10.0.1",
"@angular-builders/jest": "14.0.0",
"@angular-devkit/build-angular": "~12.2.16",
"@angular/cli": "~12.2.16",
"@angular/compiler-cli": "~12.2.16",
"@schematics/angular": "^10.2.4",
"@types/jasmine": "~3.6.0",
"@types/jasminewd2": "^2.0.10",
"@types/jest": "26.0.15",
"@types/jest": "28.1.1",
"@types/node": "^12.20.47",
"codelyzer": "^6.0.2",
"font-awesome": "^4.7.0",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~5.0.0",
"jest": "26.6.1",
"jest": "28.1.1",
"jest-environment-jsdom": "^28.1.1",
"protractor": "~7.0.0",
"ts-node": "~8.3.0",
"tslint": "~6.1.0",

View File

@ -1,4 +1,5 @@
<nb-layout>
<!--ToDo: add '*ngIf="$authState.getValue()"' after session store works again-->
<nb-layout-header *ngIf="$authState.getValue()">
<app-header class="header"></app-header>
</nb-layout-header>

View File

@ -2,7 +2,6 @@ import {TestBed} from '@angular/core/testing';
import {RouterTestingModule} from '@angular/router/testing';
import {AppComponent} from './app.component';
import {NbLayoutModule, NbThemeModule} from '@nebular/theme';
import {NbEvaIconsModule} from '@nebular/eva-icons';
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {HttpLoaderFactory} from './common-app.module';
import {HttpClient} from '@angular/common/http';
@ -27,7 +26,6 @@ describe('AppComponent', () => {
deps: [HttpClient]
}
}),
NbEvaIconsModule,
ThemeModule,
HeaderModule,
NgxsModule.forRoot([SessionState]),

View File

@ -5,11 +5,12 @@ import {registerLocale} from 'i18n-iso-countries';
import {registerLocaleData} from '@angular/common';
import {Store} from '@ngxs/store';
import {BehaviorSubject, Subscription} from 'rxjs';
import {SessionState, SessionStateModel} from '../shared/stores/session-state/session-state';
import {untilDestroyed} from 'ngx-take-until-destroy';
import {SessionState, SessionStateModel} from '@shared/stores/session-state/session-state';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
import {isNotNullOrUndefined} from 'codelyzer/util/isNotNullOrUndefined';
import {filter} from 'rxjs/operators';
@UntilDestroy()
@Component({
selector: 'app-root',
templateUrl: './app.component.html',

View File

@ -6,9 +6,8 @@ import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {
NbLayoutModule,
NbToastrModule,
NbIconModule, NbCardModule, NbButtonModule, NbDialogService, NbDialogModule, NbSelectModule,
NbIconModule, NbCardModule, NbButtonModule, NbDialogService, NbDialogModule, NbSelectModule
} from '@nebular/theme';
import {NbEvaIconsModule} from '@nebular/eva-icons';
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {HttpClient, HttpClientModule} from '@angular/common/http';
import {HttpLoaderFactory} from './common-app.module';
@ -49,7 +48,6 @@ import {ProjectState} from '@shared/stores/project-state/project-state';
FontAwesomeModule,
BrowserAnimationsModule,
ThemeModule.forRoot(),
NbEvaIconsModule,
NbSelectModule,
ConfirmDialogModule,
NgxsModule.forRoot([SessionState, ProjectState], {developmentMode: !environment.production}),

View File

@ -2,16 +2,17 @@ import {Component, OnDestroy, OnInit} from '@angular/core';
import * as FA from '@fortawesome/free-solid-svg-icons';
import {NbThemeService} from '@nebular/theme';
import {map} from 'rxjs/operators';
import {untilDestroyed} from 'ngx-take-until-destroy';
import {GlobalTitlesVariables} from '@shared/config/global-variables';
import {TranslateService} from '@ngx-translate/core';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
@UntilDestroy()
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.scss']
})
export class HeaderComponent implements OnInit, OnDestroy{
export class HeaderComponent implements OnInit{
readonly fa = FA;
readonly SECURITYC4PO_TITLE = GlobalTitlesVariables.SECURITYC4PO_TITLE;
@ -43,9 +44,4 @@ export class HeaderComponent implements OnInit, OnDestroy{
onClickLanguage(language: string): void {
this.translateService.use(language);
}
ngOnDestroy(): void {
// This method must be present when using ngx-take-until-destroy
// even when empty
}
}

View File

@ -1,9 +1,9 @@
import {Component, OnDestroy, OnInit} from '@angular/core';
import {Component, OnInit} from '@angular/core';
import {AbstractControl, FormBuilder, FormGroup, Validators} from '@angular/forms';
import {Router} from '@angular/router';
import {Store} from '@ngxs/store';
import {NotificationService, PopupType} from '../../shared/services/notification.service';
import {untilDestroyed} from 'ngx-take-until-destroy';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
import {User} from '../../shared/models/user.model';
import {throwError} from 'rxjs';
import {UpdateIsAuthenticated, UpdateUser} from '../../shared/stores/session-state/session-state.actions';
@ -12,13 +12,14 @@ import {HttpClient} from '@angular/common/http';
import {FieldStatus} from '../../shared/models/form-field-status.model';
import {KeycloakService} from 'keycloak-angular';
@UntilDestroy()
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
// ToDo: Exchange default Keycloak login with self made login
export class LoginComponent implements OnInit, OnDestroy {
export class LoginComponent implements OnInit {
readonly MIN_LENGTH: number = 2;
readonly SECURITYC4PO_TITLE = GlobalTitlesVariables.SECURITYC4PO_TITLE;
readonly NOVATEC_NAME = GlobalTitlesVariables.NOVATEC_NAME;
@ -108,11 +109,6 @@ export class LoginComponent implements OnInit, OnDestroy {
return ctrlValue === '';
}
ngOnDestroy(): void {
// This method must be present when using ngx-take-until-destroy
// even when empty
}
readAppVersion(): void {
this.httpClient.get<Version>('assets/version.json', {responseType: 'json'})
.subscribe((data: Version) => {

View File

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

View File

@ -1 +1,5 @@
@import '../../../assets/@theme/styles/themes';
.pentest-categories {
width: 22vw;
}

View File

@ -1,3 +1,28 @@
<div>
<p>header for "{{selectedProjectTitle}}" works!</p>
<div class="pentest-header" fxLayout="row" fxLayoutGap="2rem" fxLayoutAlign="space-between center">
<div class="back-button-container">
<button nbButton
shape="round"
title="{{ 'global.action.return' | translate }}"
(click)="onClickRouteBack()">
<fa-icon [icon]="fa.faLongArrowAltLeft"
class="back-element-icon fa-lg"></fa-icon>
</button>
</div>
<h4>{{selectedProjectTitle$.getValue()}}</h4>
<div class="export-button-container">
<nb-actions size="medium">
<nb-action>
<button nbButton hero
status="primary"
shape="round"
(click)="onClickExportPentest()">
<fa-icon [icon]="fa.faFileExport"
class="export-element-icon fa-lg"></fa-icon>
<span class="export-element-text">{{ 'global.action.export' | translate }}</span>
</button>
</nb-action>
</nb-actions>
</div>
</div>

View File

@ -0,0 +1,21 @@
.pentest-header {
width: calc(100vw - 14%);
.back-button-container {
.back-element-icon {
}
}
.export-button-container {
display: flex;
align-content: flex-end;
.export-element-icon {
}
.export-element-text {
padding-left: 0.5rem;
font-size: 0.85rem;
}
}
}

View File

@ -1,6 +1,15 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {ComponentFixture, TestBed} from '@angular/core/testing';
import { PentestHeaderComponent } from './pentest-header.component';
import {PentestHeaderComponent} from './pentest-header.component';
import {BrowserAnimationsModule} from '@angular/platform-browser/animations';
import {HttpClientTestingModule} from '@angular/common/http/testing';
import {ThemeModule} from '@assets/@theme/theme.module';
import {TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {HttpLoaderFactory} from '../../common-app.module';
import {HttpClient} from '@angular/common/http';
import {RouterTestingModule} from '@angular/router/testing';
import {NgxsModule} from '@ngxs/store';
import {ProjectState} from '@shared/stores/project-state/project-state';
describe('PentestHeaderComponent', () => {
let component: PentestHeaderComponent;
@ -8,9 +17,23 @@ describe('PentestHeaderComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ PentestHeaderComponent ]
declarations: [PentestHeaderComponent],
imports: [
BrowserAnimationsModule,
HttpClientTestingModule,
ThemeModule.forRoot(),
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
}),
RouterTestingModule.withRoutes([]),
NgxsModule.forRoot([ProjectState])
]
})
.compileComponents();
.compileComponents();
});
beforeEach(() => {

View File

@ -1,5 +1,14 @@
import { Component, OnInit } from '@angular/core';
import {Component, OnInit} from '@angular/core';
import * as FA from '@fortawesome/free-solid-svg-icons';
import {Route} from '@shared/models/route.enum';
import {Store} from '@ngxs/store';
import {Router} from '@angular/router';
import {PROJECT_STATE_NAME, ProjectState} from '@shared/stores/project-state/project-state';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
import {BehaviorSubject} from 'rxjs';
import {Project} from '@shared/models/project.model';
@UntilDestroy()
@Component({
selector: 'app-pentest-header',
templateUrl: './pentest-header.component.html',
@ -7,11 +16,38 @@ import { Component, OnInit } from '@angular/core';
})
export class PentestHeaderComponent implements OnInit {
selectedProjectTitle: string = history?.state?.selectedProject ? history?.state?.selectedProject.title : '';
readonly fa = FA;
selectedProjectTitle$: BehaviorSubject<string> = new BehaviorSubject<string>('');
constructor() { }
ngOnInit(): void {
constructor(private store: Store,
private readonly router: Router) {
}
ngOnInit(): void {
this.store.select(ProjectState.project).pipe(
untilDestroyed(this)
).subscribe({
next: (selectedProject: Project) => {
this.selectedProjectTitle$.next(selectedProject?.title);
},
error: err => {
console.error(err);
}
});
}
onClickRouteBack(): void {
this.router.navigate([Route.PROJECT_OVERVIEW])
.then(
() => this.store.reset({
...this.store.snapshot(),
[PROJECT_STATE_NAME]: undefined
})
).finally();
}
onClickExportPentest(): void {
// tslint:disable-next-line:no-console
console.info('To be implemented..');
}
}

View File

@ -3,12 +3,23 @@ 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, NbMenuModule, NbSidebarModule, NbListModule} from '@nebular/theme';
import {
NbCardModule,
NbLayoutModule,
NbTreeGridModule,
NbMenuModule,
NbListModule,
NbButtonModule,
NbTooltipModule,
NbActionsModule
} 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';
import {FontAwesomeModule} from '@fortawesome/angular-fontawesome';
import {FlexLayoutModule} from '@angular/flex-layout';
@NgModule({
declarations: [
@ -26,6 +37,10 @@ import {FormsModule} from '@angular/forms';
NbLayoutModule,
NbCardModule,
NbMenuModule.forRoot(),
NbButtonModule,
// nbTooltip crashes app right now if used in component,
// workaround: use title in html for now
NbTooltipModule,
NbTreeGridModule,
TranslateModule,
StatusTagModule,
@ -33,7 +48,10 @@ import {FormsModule} from '@angular/forms';
RouterModule,
NbMenuModule,
FormsModule,
NbListModule
NbListModule,
FontAwesomeModule,
FlexLayoutModule,
NbActionsModule
]
})
export class PentestOverviewModule {

View File

@ -5,6 +5,7 @@
class="pentest-cell"
routerLink="pentest"
fragment="{{pentest.data['refNumber']}}"
(click)="selectPentest(pentest.data)"
[skipLocationChange]="true">
</tr>
<!-- Test ID -->

View File

@ -1,6 +1,7 @@
@import '../../../assets/@theme/styles/themes';
.pentest-table {
width: calc(78vw - 18%);
.pentest-cell {
// Add style here

View File

@ -1,21 +1,24 @@
import {Component, OnDestroy, OnInit} from '@angular/core';
import {Component, OnInit} from '@angular/core';
import {NbGetters, NbTreeGridDataSource, NbTreeGridDataSourceBuilder} from '@nebular/theme';
import {Pentest, PentestEntry, transformPentestsToEntries} from '@shared/models/pentest.model';
import {PentestService} from '@shared/services/pentest.service';
import {Store} from '@ngxs/store';
import {ProjectState} from '@shared/stores/project-state/project-state';
import {untilDestroyed} from 'ngx-take-until-destroy';
import {PROJECT_STATE_NAME, ProjectState} from '@shared/stores/project-state/project-state';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
import {catchError, switchMap} from 'rxjs/operators';
import {of} from 'rxjs';
import {getTitleKeyForRefNumber} from '@shared/functions/categories/get-title-key-for-ref-number.function';
import {Route} from '@shared/models/route.enum';
import {Router} from '@angular/router';
import {ChangePentest} from '@shared/stores/project-state/project-state.actions';
@UntilDestroy()
@Component({
selector: 'app-pentest-table',
templateUrl: './pentest-table.component.html',
styleUrls: ['./pentest-table.component.scss']
})
export class PentestTableComponent implements OnInit, OnDestroy {
export class PentestTableComponent implements OnInit {
columns: Array<PentestColumns> = [PentestColumns.TEST_ID, PentestColumns.TITLE, PentestColumns.STATUS, PentestColumns.FINDINGS];
dataSource: NbTreeGridDataSource<PentestEntry>;
@ -31,7 +34,8 @@ export class PentestTableComponent implements OnInit, OnDestroy {
constructor(
private store: Store,
private pentestService: PentestService,
private dataSourceBuilder: NbTreeGridDataSourceBuilder<PentestEntry>
private dataSourceBuilder: NbTreeGridDataSourceBuilder<PentestEntry>,
private readonly router: Router
) {
this.dataSource = dataSourceBuilder.create(this.data, this.getters);
}
@ -56,15 +60,24 @@ export class PentestTableComponent implements OnInit, OnDestroy {
});
}
selectPentest(pentest: Pentest): void {
/* ToDo: Include again after fixing pentest route
this.router.navigate([Route.PENTEST])
.then(
() => this.store.reset({
...this.store.snapshot(),
[PROJECT_STATE_NAME]: undefined
})
).finally();
*/
this.store.dispatch(new ChangePentest(pentest.id));
}
// HTML only
getTitle(refNumber: string): string {
return getTitleKeyForRefNumber(refNumber);
}
ngOnDestroy(): void {
// This method must be present when using ngx-take-until-destroy
// even when empty
}
}
enum PentestColumns {

View File

@ -1,8 +1,8 @@
import {Component, OnDestroy, OnInit} from '@angular/core';
import {Component, OnInit} from '@angular/core';
import * as FA from '@fortawesome/free-solid-svg-icons';
import {Project, ProjectDialogBody} from '@shared/models/project.model';
import {BehaviorSubject, Observable} from 'rxjs';
import {untilDestroyed} from 'ngx-take-until-destroy';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
import {ProjectService} from '@shared/services/project.service';
import {NotificationService, PopupType} from '@shared/services/notification.service';
import {catchError, filter, mergeMap, switchMap, tap} from 'rxjs/operators';
@ -10,12 +10,13 @@ import {DialogService} from '@shared/services/dialog-service/dialog.service';
import {ProjectDialogComponent} from '@shared/modules/project-dialog/project-dialog.component';
import {ProjectDialogService} from '@shared/modules/project-dialog/service/project-dialog.service';
@UntilDestroy()
@Component({
selector: 'app-project-overview',
templateUrl: './project-overview.component.html',
styleUrls: ['./project-overview.component.scss']
})
export class ProjectOverviewComponent implements OnInit, OnDestroy {
export class ProjectOverviewComponent implements OnInit {
readonly fa = FA;
@ -40,7 +41,7 @@ export class ProjectOverviewComponent implements OnInit, OnDestroy {
tap(() => this.loading$.next(true))
)
.subscribe({
next: (projects) => {
next: (projects: Project[]) => {
this.projects.next(projects);
this.loading$.next(false);
},
@ -133,9 +134,4 @@ export class ProjectOverviewComponent implements OnInit, OnDestroy {
isLoading(): Observable<boolean> {
return this.loading$.asObservable();
}
ngOnDestroy(): void {
// This method must be present when using ngx-take-until-destroy
// even when empty
}
}

View File

@ -1,17 +1,17 @@
<div fxFlex class="pentest-overview">
<nb-layout fxFlex>
<nb-layout-header fxFlexAlign="center" class="header-column">
<nb-layout-header fxFlex="0 1 max-content" class="header-column">
<app-pentest-header></app-pentest-header>
</nb-layout-header>
<nb-layout-column fxFlex="1 1 max-content" class="column-wrapper">
<nb-layout-column fxFlex="0 1 max-content" class="column-wrapper">
<nb-card class="categories-column">
<app-pentest-categories></app-pentest-categories>
</nb-card>
</nb-layout-column>
<nb-layout-column class="table-wrapper" fxFlex="4 1 85%">
<nb-layout-column fxFlex="0 1 max-content" class="table-wrapper" >
<nb-card class="table-column">
<nb-card-body>
<app-pentest-table></app-pentest-table>

View File

@ -7,7 +7,7 @@
overflow: hidden;
.header-column {
width: 100%;
width: 100vw;
}
.column-wrapper {
@ -15,7 +15,6 @@
.categories-column {
height: calc(100vh - #{$pentest-header-height});
height: 80vh;
}
}
@ -24,7 +23,7 @@
.table-column {
overflow: auto !important;
height: 80vh;
height: calc(100vh - #{$pentest-header-height});
}
}
}

View File

@ -1,18 +1,18 @@
import {Component, OnDestroy, OnInit} from '@angular/core';
import {Component, OnInit} from '@angular/core';
import {Store} from '@ngxs/store';
import {InitProjectState} from '@shared/stores/project-state/project-state.actions';
import {Router} from '@angular/router';
import {Route} from '@shared/models/route.enum';
import {untilDestroyed} from 'ngx-take-until-destroy';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
import {Project} from '@shared/models/project.model';
@UntilDestroy()
@Component({
selector: 'app-project',
templateUrl: './project.component.html',
styleUrls: ['./project.component.scss']
})
export class ProjectComponent implements OnInit, OnDestroy {
export class ProjectComponent implements OnInit {
constructor(
private store: Store,
@ -35,9 +35,4 @@ export class ProjectComponent implements OnInit, OnDestroy {
[]
)).pipe(untilDestroyed(this)).subscribe();
}
ngOnDestroy(): void {
// This method must be present when using ngx-take-until-destroy
// even when empty
}
}

View File

@ -12,7 +12,7 @@
}
.dialog-button {
width: 4.5rem;
width: 5.25rem;
height: 2.5rem;
font-size: 1.5rem;
// font-size: 0.85rem;
}

View File

@ -13,7 +13,6 @@ import {
NbIconModule,
NbThemeModule,
} from '@nebular/theme';
import { NbEvaIconsModule } from '@nebular/eva-icons';
import { CORPORATE_THEME } from './styles/theme.corporate';
import { DARK_THEME } from './styles/theme.dark';
@ -27,8 +26,7 @@ const NB_MODULES = [
NbContextMenuModule,
NbButtonModule,
NbSelectModule,
NbIconModule,
NbEvaIconsModule,
NbIconModule
];
const COMPONENTS = [
];

View File

@ -3,9 +3,11 @@
"action.login": "Einloggen",
"action.retry": "Erneut Versuchen",
"action.save": "Speichern",
"action.update": "Aktualisieren",
"action.confirm": "Bestätigen",
"action.cancel": "Abbrechen",
"action.return": "Zurück",
"action.update": "Speichern",
"action.export": "Exportieren",
"action.yes": "Ja",
"action.no": "Nein",
"username": "Nutzername",

View File

@ -4,8 +4,10 @@
"action.retry": "Try again",
"action.confirm": "Confirm",
"action.save": "Save",
"action.update": "Update",
"action.cancel": "Cancel",
"action.return": "Return",
"action.update": "Update",
"action.export": "Export",
"action.yes": "Yes",
"action.no": "No",
"username": "Username",

View File

@ -1,4 +1,5 @@
export enum Route {
HOME = 'home',
PROJECT_OVERVIEW = 'projects'
PROJECT_OVERVIEW = 'projects',
PENTEST = 'pentest'
}

View File

@ -1,15 +1,17 @@
import {Component, Inject, OnDestroy, OnInit} from '@angular/core';
import {Component, Inject, OnInit} from '@angular/core';
import {NB_DIALOG_CONFIG, NbDialogRef} from '@nebular/theme';
import {FormBuilder, FormGroup} from '@angular/forms';
import {GenericFormFieldConfig, ProjectDialogData} from '@shared/models/project-dialog-data';
import deepEqual from 'deep-equal';
import {UntilDestroy} from '@ngneat/until-destroy';
@UntilDestroy()
@Component({
selector: 'app-project-dialog',
templateUrl: './project-dialog.component.html',
styleUrls: ['./project-dialog.component.scss']
})
export class ProjectDialogComponent implements OnInit, OnDestroy {
export class ProjectDialogComponent implements OnInit {
// form control elements
projectFormGroup: FormGroup;
formArray: GenericFormFieldConfig[];
@ -82,8 +84,4 @@ export class ProjectDialogComponent implements OnInit, OnDestroy {
});
return projectData;
}
ngOnDestroy(): void {
// ToDo: Remove this after Angular upgrade and use @UnitDestroy() instead
}
}

View File

@ -1,13 +1,14 @@
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
import {Component, Input, OnInit} from '@angular/core';
import {Observable, of} from 'rxjs';
import {untilDestroyed} from 'ngx-take-until-destroy';
import {UntilDestroy, untilDestroyed} from '@ngneat/until-destroy';
@UntilDestroy()
@Component({
selector: 'app-loading-spinner',
templateUrl: './loading-spinner.component.html',
styleUrls: ['./loading-spinner.component.scss']
})
export class LoadingSpinnerComponent implements OnInit, OnDestroy {
export class LoadingSpinnerComponent implements OnInit {
@Input() isLoading$: Observable<boolean> = of(false);
loading: boolean;
@ -20,7 +21,4 @@ export class LoadingSpinnerComponent implements OnInit, OnDestroy {
this.loading = value;
});
}
ngOnDestroy(): void {
}
}