From 77f4b83fb77ddcd515a6d38da5b5e4527a85dc52 Mon Sep 17 00:00:00 2001 From: Vladyslav Pavlenko <30902180+vpavlenko-cv@users.noreply.github.com> Date: Sat, 21 Dec 2024 20:14:32 +0200 Subject: [PATCH] [CYB - 195][UI] Parser job configuration. (#89) --- .../src/app/app-routing.module.ts | 2 + .../chain-list-page.component.spec.ts | 4 +- .../pipeline-create.component.html | 8 +- .../pipeline-create.component.ts | 17 +- .../pipeline-stepper.component.html | 187 +++++++++++++++- .../pipeline-stepper.component.scss | 36 ++++ .../pipeline-stepper.component.spec.ts | 48 ++++- .../pipeline-stepper.component.ts | 200 +++++++++++++++++- .../app/cluster/pipelines/pipelines.module.ts | 7 +- .../styled-chips-list.component.ts | 4 +- .../app/shared/pipes/contains.pipe.spec.ts | 8 + .../src/app/shared/pipes/contains.pipe.ts | 15 ++ .../src/app/shared/pipes/filter.pipe.spec.ts | 8 + .../src/app/shared/pipes/filter.pipe.ts | 15 ++ .../src/app/shared/share.module.ts | 8 +- .../parser-chains-client/src/styles.scss | 6 + 16 files changed, 555 insertions(+), 18 deletions(-) create mode 100644 flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/contains.pipe.spec.ts create mode 100644 flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/contains.pipe.ts create mode 100644 flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/filter.pipe.spec.ts create mode 100644 flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/filter.pipe.ts diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/app-routing.module.ts b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/app-routing.module.ts index 390254808..914044bad 100644 --- a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/app-routing.module.ts +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/app-routing.module.ts @@ -24,6 +24,7 @@ import {ClusterPageComponent} from "./cluster/cluster-page/cluster-page.componen import {PipelinesComponent} from 'src/app/cluster/pipelines/pipelines.component'; import {PipelineCreateComponent} from 'src/app/cluster/pipelines/pipeline-create/pipeline-create.component'; import {PipelineSubmitComponent} from 'src/app/cluster/pipelines/pipeline-submit/pipeline-submit.component'; +import {PipelineStepperComponent} from 'src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component'; export const routes: Routes = [ { path: '404', component: PageNotFoundComponent }, @@ -37,6 +38,7 @@ export const routes: Routes = [ { path: 'clusters', component: ClusterListPageComponent }, { path: 'clusters/pipelines', component: PipelinesComponent }, { path: 'clusters/pipelines/create', component: PipelineCreateComponent }, + { path: 'clusters/pipelines/stepper', component: PipelineStepperComponent }, { path: 'clusters/pipelines/submit', component: PipelineSubmitComponent }, { path: 'clusters/:clusterId', component: ClusterPageComponent}, diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/chain-list-page/chain-list-page.component.spec.ts b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/chain-list-page/chain-list-page.component.spec.ts index c4bce5122..b2e4fc34c 100644 --- a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/chain-list-page/chain-list-page.component.spec.ts +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/chain-list-page/chain-list-page.component.spec.ts @@ -41,8 +41,8 @@ const mockChains: ChainModel[] = [{id: '1', name: 'test1'}, {id: '2', name: 'tes describe('PipelinesComponent', () => { let component: ChainListPageComponent; let fixture: ComponentFixture; - let pipelineService: jasmine.SpyObj - let chainListPageService: jasmine.SpyObj + let pipelineService: jasmine.SpyObj; + let chainListPageService: jasmine.SpyObj; beforeEach(waitForAsync(() => { TestBed.configureTestingModule({ diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-create/pipeline-create.component.html b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-create/pipeline-create.component.html index 34ba8e7a2..eacb10a88 100644 --- a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-create/pipeline-create.component.html +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-create/pipeline-create.component.html @@ -69,16 +69,16 @@
- {{ jobsEnum.PARSER.label }} - {{ jobsEnum.TRIAGE.label }} - {{ jobsEnum.PROFILE.label }} - {{ jobsEnum.INDEX.label }}
diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-create/pipeline-create.component.ts b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-create/pipeline-create.component.ts index 7bd492f64..792e1b922 100644 --- a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-create/pipeline-create.component.ts +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-create/pipeline-create.component.ts @@ -16,7 +16,7 @@ const BUTTONS_CONST = [ {label: 'Archive', value: 'Archive', disabled: false}, {label: 'Git', value: 'Git', disabled: false}, {label: 'Empty', value: 'Empty', disabled: false}, - {label: 'Manual', value: 'Manual', disabled: true} + {label: 'Manual', value: 'Manual', disabled: false} ] as const; const BUTTON_LABELS = BUTTONS_CONST.map(b => b.value); @@ -107,6 +107,8 @@ export class PipelineCreateComponent { this.fileControl.clearValidators(); break case 'Manual': + this.jobs = [JOBS_ENUM.PARSER.value]; + break; default: } this.fileControl.updateValueAndValidity(); @@ -128,7 +130,13 @@ export class PipelineCreateComponent { jobs: this.jobs, sourceMap: this.sourceMap, } - this._router.navigate(['clusters/pipelines/submit'], {state: {data}}); + if (this.mode === 'Manual') { + this._router.navigate(['clusters/pipelines/stepper'], {state: {data}}); + + } else { + this._router.navigate(['clusters/pipelines/submit'], {state: {data}}); + + } } onFileDropped(fileList: FileList) { @@ -182,4 +190,9 @@ export class PipelineCreateComponent { })) ); } + + slideToggleDisabled(value) { + return this.mode === 'Manual' && value !== JOBS_ENUM.PARSER; + + } } diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.html b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.html index a4f36b7bc..233f8dd2e 100644 --- a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.html +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.html @@ -1,3 +1,188 @@ -

pipeline-stepper works!

+ +
+ Parser config + + +
+

Kafka Topic config:

+ Configuration of Kafka topic for parser job +
+
+ + Topic output + + + + Error Topic + + +
+ Enable source + +
+ + Original base path + + +
+
+
+ +
+ +
+ + + +
{{ chain.getRawValue().chainName }}
+
+ + + + save + delete + + +
+ + Source + + + {{ selectedPipeline }} + + + + + + {{ searchedPipeline }} + + + + + + + + +
+ + + link +
{{ chain.name }}
+ + + + +
+
+ +
+
+
+ + + + + +
+
+ +
+
+
+ + + +

Assign Topic

+
+
+ + Topic or Topic pattern that would associated with this chain. + + + Topic Name + + +
+
+
+ + +
+
diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.scss b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.scss index e69de29bb..2dfb3d6da 100644 --- a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.scss +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.scss @@ -0,0 +1,36 @@ +@use '@angular/material' as mat; +@import "./styles.scss"; + +.save-tab-icon { + color: mat.get-color-from-palette($theme-primary); +} + +.delete-tab-icon { + color: mat.get-color-from-palette(mat.$red-palette, 300); +} + +.source-list { + min-width: 300px; + width: 70%; + margin-top: 10px; + margin-bottom: 10px; +} + +.inner-assign-wrapper { + display: flex; + flex-direction: column; + flex-wrap: wrap; + align-content: flex-start; + justify-content: space-around; + align-items: flex-start; +} + +.inner-assign-wrapper-span { + font-size: 20px; + margin-bottom: 15px; +} + +.general-section { + display: flex; + flex-direction: column +} diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.spec.ts b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.spec.ts index 0f72808a0..cb2c72693 100644 --- a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.spec.ts +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.spec.ts @@ -1,7 +1,7 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; import {PipelineStepperComponent} from './pipeline-stepper.component'; -import {FormsModule} from '@angular/forms'; +import {FormsModule, ReactiveFormsModule} from '@angular/forms'; import {SharedModule} from 'src/app/shared/share.module'; import {MatCardModule} from '@angular/material/card'; import {MatDividerModule} from '@angular/material/divider'; @@ -16,10 +16,26 @@ import {AsyncPipe, NgComponentOutlet, NgForOf, NgIf, NgTemplateOutlet} from '@an import {MatSelectModule} from '@angular/material/select'; import {MatStepperModule} from '@angular/material/stepper'; import {NoopAnimationsModule} from '@angular/platform-browser/animations'; +import {PipelineService} from 'src/app/services/pipeline.service'; +import {of} from 'rxjs'; +import {ChainListPageService} from 'src/app/services/chain-list-page.service'; +import {ChainModel} from 'src/app/chain-list-page/chain.model'; +import {Router} from '@angular/router'; +import {RouterTestingModule} from '@angular/router/testing'; +import {MatTabsModule} from '@angular/material/tabs'; +import {MatSlideToggleModule} from '@angular/material/slide-toggle'; +import {MatChipsModule} from '@angular/material/chips'; +import {MatAutocompleteModule} from '@angular/material/autocomplete'; + +const mockPipeline = ['foo-pipeline1', 'foo-pipeline2']; +const mockChains: ChainModel[] = [{id: '1', name: 'test1'}, {id: '2', name: 'test2'}]; describe('PipelineStepperComponent', () => { let component: PipelineStepperComponent; let fixture: ComponentFixture; + let pipelineService: jasmine.SpyObj; + let chainListPageService: jasmine.SpyObj; + let router: Router; beforeEach(async () => { await TestBed.configureTestingModule({ imports: [ @@ -41,13 +57,43 @@ describe('PipelineStepperComponent', () => { FormsModule, NgForOf, MatStepperModule, + RouterTestingModule.withRoutes([]), + MatTabsModule, + ReactiveFormsModule, + MatSlideToggleModule, + MatChipsModule, + MatAutocompleteModule, NoopAnimationsModule ], + providers: [ + { + provide: PipelineService, + useValue: jasmine.createSpyObj('PipelineService', ['getPipelines', 'createPipeline', 'renamePipeline', 'deletePipeline']) + }, + { + provide: ChainListPageService, + useValue: jasmine.createSpyObj('ChainListPageService', ['createChain', 'getChains', 'deleteChain', 'getPipelines']) + }, + ], declarations: [ PipelineStepperComponent ] }) .compileComponents(); + pipelineService = TestBed.inject(PipelineService) as jasmine.SpyObj; + pipelineService.getPipelines.and.returnValue(of(mockPipeline)); + chainListPageService = TestBed.inject(ChainListPageService) as jasmine.SpyObj; + chainListPageService.getChains.and.returnValue(of(mockChains)); + + router = TestBed.inject(Router); + spyOn(router, 'getCurrentNavigation').and.returnValue({ + extras: {state: {data: {clusterId: 'test1', pipelineName: 'foo-pipe', branch: 'testbranch'}}}, + id: 0, + initialUrl: null, + extractedUrl: null, + trigger: null, + previousNavigation: null + }) fixture = TestBed.createComponent(PipelineStepperComponent); component = fixture.componentInstance; fixture.detectChanges(); diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.ts b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.ts index 378f88e73..5b55c1571 100644 --- a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.ts +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.ts @@ -1,10 +1,206 @@ -import { Component} from '@angular/core'; +import {Component, ElementRef, inject, TemplateRef, ViewChild} from '@angular/core'; +import {FormBuilder, FormGroup} from '@angular/forms'; +import {PipelineService} from 'src/app/services/pipeline.service'; +import {filter, map, scan, shareReplay, startWith, switchMap} from 'rxjs/operators'; +import {MatChipInputEvent} from '@angular/material/chips'; +import {COMMA, ENTER} from '@angular/cdk/keycodes'; +import {MatAutocomplete, MatAutocompleteSelectedEvent} from '@angular/material/autocomplete'; +import {BehaviorSubject, combineLatest, merge, Observable} from 'rxjs'; +import {ChainListPageService} from 'src/app/services/chain-list-page.service'; +import {ChainModel} from 'src/app/chain-list-page/chain.model'; +import {changeStateFn} from 'src/app/shared/utils'; +import {MatDialog} from '@angular/material/dialog'; +import {CustomChip} from 'src/app/shared/components/styled-chips-list/styled-chips-list.component'; +import {PipelineSubmitState} from 'src/app/cluster/pipelines/pipeline-submit/pipeline-submit.component'; +import {Router} from '@angular/router'; + @Component({ selector: 'app-pipeline-stepper', templateUrl: './pipeline-stepper.component.html', - styleUrls: ['./pipeline-stepper.component.scss'] + styleUrls: ['./pipeline-stepper.component.scss'], }) export class PipelineStepperComponent { + separatorKeysCodes: readonly number[] = [ENTER, COMMA]; + @ViewChild('sourceInput') sourceInput: ElementRef; + @ViewChild('auto') autocomplete!: MatAutocomplete; + + private _formBuilder = inject(FormBuilder); + private _pipelineService = inject(PipelineService); + private _chainService = inject(ChainListPageService); + // Chains Event triggers + private _addChainSubject = new BehaviorSubject(null); + private _deleteChainByPipelineSubject = new BehaviorSubject(null); + private _deleteChainByIdSubject = new BehaviorSubject(null); + private _dialog = inject(MatDialog); + private _router = inject(Router); + + // Chains Event + private _addChainEvent$: Observable<(state: PipedChainModel[]) => PipedChainModel[]> = this._addChainSubject.pipe( + filter(value => value !== null), // Filter out initial null emission + switchMap(pipeline => + this._chainService.getChains(pipeline).pipe( + map(ch => ch.map(c => ({...c, pipeline}))) + ) + ), + map((chain: PipedChainModel[]) => (state: PipedChainModel[]) => [...state, ...chain])); + private _deleteChainByPipelineEvent$ = this._deleteChainByPipelineSubject.pipe( + filter(value => value !== null), // Filter out initial null emission + map(pipeline => (state: PipedChainModel[]) => state.filter(pipedChain => pipedChain.pipeline !== pipeline))); + private _deleteChainByIdEvent$ = this._deleteChainByIdSubject.pipe( + filter(value => value !== null), // Filter out initial null emission + map(id => changeStateFn(id, 'id'))); + + + private _currentChains$: Observable = this._chainService.getChains().pipe( + map(ch => ch.map(c => ({...c, pipeline: ''}))), + switchMap(chains => { + return merge( + this._addChainEvent$, + this._deleteChainByPipelineEvent$, + this._deleteChainByIdEvent$ + ).pipe( + startWith(lab => lab), + scan((state, reducer) => reducer(state), chains), + ) + }), + shareReplay(1) + ); + + + // constructor() { + // const navigation = this._router.getCurrentNavigation(); + // this.state = navigation?.extras.state.data as PipelineSubmitState; + // } + + state: PipelineSubmitState = this._router.getCurrentNavigation().extras.state.data as PipelineSubmitState; + + allPipeline$ = this._pipelineService.getPipelines().pipe(shareReplay()); + + + topicMap: Map> = new Map(); + + + parserFormGroup = this._formBuilder.group({ + topicOutput: [''], + errorTopic: [''], + sourceFlag: false, + origBasePath: [''], + storage: [null], + chains: this._formBuilder.array( + [this._formBuilder.group({ + chainName: 'Chain', + source: '', + selectedSource: this._formBuilder.control([]), + editMode: false, + })] + ) + }); + + get vm$() { + return combineLatest([ + this.allPipeline$, + this._currentChains$ + ]).pipe( + map(([pipelines, currentChains]) => ({pipelines, currentChains})), + shareReplay() + ); + } + + get chains() { + return this.parserFormGroup.controls.chains; // Getter for the FormArray + } + getSelectedSource(i: number) { + return this.chains.controls[i].controls.selectedSource.getRawValue() + } + + + addTab(): void { + const defaultChain = this._formBuilder.group({ + chainName: `Chain ${this.chains.length}`, + source: '', + selectedSource: this._formBuilder.control([]), + editMode: false, + }); + this.chains.push(defaultChain); + + } + + deleteChain(index: number): void { + this.chains.removeAt(index) + } + + dbClick(val: FormGroup) { + val.setValue({...val.getRawValue(), editMode: !val.getRawValue().editMode}) + } + + add(event: MatChipInputEvent, index: number): void { + const value = (event.value || '').trim(); + + // Add our fruit + if (value) { + this._addChainSubject.next(value); + } + + event.chipInput!.clear(); + const conf = this.chains.controls[index].getRawValue(); + const selectedSource = this.chains.controls[index].getRawValue().selectedSource; + this.chains.controls[index].setValue({...conf, source: '', selectedSource: [...selectedSource, value]}); + } + + remove(value: string, index: number): void { + const conf = this.chains.controls[index].getRawValue(); + const selectedSource = this.chains.controls[index].getRawValue().selectedSource.filter(v => v !== value); + this.chains.controls[index].setValue({...conf, selectedSource}); + this._deleteChainByPipelineSubject.next(value); + } + + selected(event: MatAutocompleteSelectedEvent, index: number) { + const value = event.option.viewValue; + this._addChainSubject.next(value); + this.sourceInput.nativeElement.value = ''; + const conf = this.chains.controls[index].getRawValue(); + const selectedSource = this.chains.controls[index].getRawValue().selectedSource; + this.chains.controls[index].setValue({...conf, source: '', selectedSource: [...selectedSource, value]}); + } + + deleteItem(id: string) { + this._deleteChainByIdSubject.next(id); + } + + assignTopic(ref: TemplateRef, chainId: string, index: number) { + this._dialog.open(ref, { + minWidth: '30vw', + data: { + id: chainId, + name: this.topicMap.get(index)?.get(chainId)?.name, + } + }).afterClosed().subscribe((data: { id: string, name: string }) => { + if (data) { + const tmp: Map = new Map(); + tmp.set(chainId, {name: data.name, allowMapping: false, selected: true, removable: false}); + this.topicMap.set(index, tmp); + } + }); + } + + getSource(index: number): string { + return this.chains.controls[index].controls.source.getRawValue(); + } + + navigateToReceiver() { + this._currentChains$.subscribe(value => { + const newState = { + ...this.state, + chainModel: value, + chains: this.chains.getRawValue(), + } + this._router.navigate(['clusters/pipelines/submit'], { + state: {data: newState} + }); + }); + } } + +type PipedChainModel = ChainModel & { pipeline: string} diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipelines.module.ts b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipelines.module.ts index f861e2572..34465eb57 100644 --- a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipelines.module.ts +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipelines.module.ts @@ -36,6 +36,8 @@ import {MatSlideToggleModule} from '@angular/material/slide-toggle'; import {FileUploadModule} from 'src/app/cluster/component/file-upload/file-upload.module'; import {MatProgressSpinnerModule} from '@angular/material/progress-spinner'; import {MatCheckboxModule} from '@angular/material/checkbox'; +import {MatTabsModule} from '@angular/material/tabs'; +import {MatChipsModule} from '@angular/material/chips'; @NgModule({ @@ -67,7 +69,10 @@ import {MatCheckboxModule} from '@angular/material/checkbox'; FileUploadModule, MatProgressSpinnerModule, MatCheckboxModule, - KeyValuePipe + KeyValuePipe, + MatTabsModule, + MatChipsModule, + SharedModule ], providers: [], exports: [PipelinesComponent] diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/components/styled-chips-list/styled-chips-list.component.ts b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/components/styled-chips-list/styled-chips-list.component.ts index c0c9466f9..e37eea9b6 100644 --- a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/components/styled-chips-list/styled-chips-list.component.ts +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/components/styled-chips-list/styled-chips-list.component.ts @@ -29,11 +29,11 @@ export class StyledChipsListComponent { click(chipHash: MatChip, name: string) { if (this.selectable) { this.chips = this.chips.map(c => { - if (c.name === name ) { + if (c.name === name) { console.log(chipHash); this.selectionField.emit(c); - return {...c, selected: !c.selected}; + return {...c, selected: !c.selected}; } return c; }) diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/contains.pipe.spec.ts b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/contains.pipe.spec.ts new file mode 100644 index 000000000..e51beec36 --- /dev/null +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/contains.pipe.spec.ts @@ -0,0 +1,8 @@ +import { ContainsPipe } from './contains.pipe'; + +describe('ContainsPipe', () => { + it('create an instance', () => { + const pipe = new ContainsPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/contains.pipe.ts b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/contains.pipe.ts new file mode 100644 index 000000000..95eeb640e --- /dev/null +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/contains.pipe.ts @@ -0,0 +1,15 @@ +import {Pipe, PipeTransform} from '@angular/core'; + +@Pipe({ + name: 'contains' +}) +export class ContainsPipe implements PipeTransform { + + transform(items: string[], term: string): string[] { + if (items === null || items.length === 0 || term === null || term.length === 0) { + return items; + } + return items.filter(item => item.toLowerCase().includes(term.toLowerCase())); + } + +} diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/filter.pipe.spec.ts b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/filter.pipe.spec.ts new file mode 100644 index 000000000..1427de361 --- /dev/null +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/filter.pipe.spec.ts @@ -0,0 +1,8 @@ +import { FilterPipe } from './filter.pipe'; + +describe('FilterPipe', () => { + it('create an instance', () => { + const pipe = new FilterPipe(); + expect(pipe).toBeTruthy(); + }); +}); diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/filter.pipe.ts b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/filter.pipe.ts new file mode 100644 index 000000000..0158a019e --- /dev/null +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/pipes/filter.pipe.ts @@ -0,0 +1,15 @@ +import {Pipe, PipeTransform} from '@angular/core'; + +@Pipe({ + name: 'filter' +}) +export class FilterPipe implements PipeTransform { + + transform(items: string[], term: string[]): string[] { + if (items === null || items.length === 0 || term === null || term.length === 0) { + return items; + } + return items.filter(item => term.indexOf(item) === -1); + } + +} diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/share.module.ts b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/share.module.ts index 894fc669a..b27418415 100644 --- a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/share.module.ts +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/shared/share.module.ts @@ -27,11 +27,13 @@ import {UploadComponent} from './components/upload/upload/upload.component'; import {FileUploadModule} from 'src/app/cluster/component/file-upload/file-upload.module'; import {UploadProgressComponent} from 'src/app/shared/components/upload/upload/progress/progress.component'; import {FormsModule} from '@angular/forms'; +import {FilterPipe} from './pipes/filter.pipe'; +import { ContainsPipe } from './pipes/contains.pipe'; @NgModule({ - imports: [CommonModule, MatButtonToggleModule, A11yModule, MatDialogModule, MatButtonModule, MatProgressSpinnerModule, MatProgressBarModule, MatIconModule, MatChipsModule, MatTooltipModule, FileUploadModule, FormsModule], - declarations: [SortPipe, WithLoadingPipe, MultiButtonComponent, ConfirmDeleteDialogComponent, CustomListComponent, CustomListItemComponent, CustomListIconDirective, CustomListActionDirective, CustomListLineDirective, CustomListSubheaderDirective, CustomListChipsDirective, StyledChipsListComponent, UploadComponent, UploadProgressComponent], - exports: [SortPipe, WithLoadingPipe, MultiButtonComponent, ConfirmDeleteDialogComponent, CustomListItemComponent, CustomListComponent, CustomListIconDirective, CustomListActionDirective, CustomListLineDirective, CustomListSubheaderDirective, CustomListChipsDirective, StyledChipsListComponent, UploadComponent] + imports: [CommonModule, MatButtonToggleModule, A11yModule, MatDialogModule, MatButtonModule, MatProgressSpinnerModule, MatProgressBarModule, MatIconModule, MatChipsModule, MatTooltipModule, FileUploadModule, FormsModule], + declarations: [SortPipe, FilterPipe, WithLoadingPipe, MultiButtonComponent, ConfirmDeleteDialogComponent, CustomListComponent, CustomListItemComponent, CustomListIconDirective, CustomListActionDirective, CustomListLineDirective, CustomListSubheaderDirective, CustomListChipsDirective, StyledChipsListComponent, UploadComponent, UploadProgressComponent, ContainsPipe], + exports: [SortPipe, FilterPipe, WithLoadingPipe, MultiButtonComponent, ConfirmDeleteDialogComponent, CustomListItemComponent, CustomListComponent, CustomListIconDirective, CustomListActionDirective, CustomListLineDirective, CustomListSubheaderDirective, CustomListChipsDirective, StyledChipsListComponent, UploadComponent, ContainsPipe] }) export class SharedModule { } diff --git a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/styles.scss b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/styles.scss index 3d6a3a30b..78931583d 100644 --- a/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/styles.scss +++ b/flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/styles.scss @@ -371,3 +371,9 @@ flex-column-jfs-ac { .delete-icon { color: mat.get-color-from-palette(mat.define-palette(mat.$red-palette), 300); } +.parser-chain-step .mat-tab-labels :last-child.mat-tab-label { + min-width: 0; + padding: 0 12px; + color: mat.get-color-from-palette($theme-primary); + opacity: 87%; +}