Skip to content

Commit 77f4b83

Browse files
authored
[CYB - 195][UI] Parser job configuration. (#89)
1 parent b973766 commit 77f4b83

File tree

16 files changed

+555
-18
lines changed

16 files changed

+555
-18
lines changed

flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/app-routing.module.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {ClusterPageComponent} from "./cluster/cluster-page/cluster-page.componen
2424
import {PipelinesComponent} from 'src/app/cluster/pipelines/pipelines.component';
2525
import {PipelineCreateComponent} from 'src/app/cluster/pipelines/pipeline-create/pipeline-create.component';
2626
import {PipelineSubmitComponent} from 'src/app/cluster/pipelines/pipeline-submit/pipeline-submit.component';
27+
import {PipelineStepperComponent} from 'src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component';
2728

2829
export const routes: Routes = [
2930
{ path: '404', component: PageNotFoundComponent },
@@ -37,6 +38,7 @@ export const routes: Routes = [
3738
{ path: 'clusters', component: ClusterListPageComponent },
3839
{ path: 'clusters/pipelines', component: PipelinesComponent },
3940
{ path: 'clusters/pipelines/create', component: PipelineCreateComponent },
41+
{ path: 'clusters/pipelines/stepper', component: PipelineStepperComponent },
4042
{ path: 'clusters/pipelines/submit', component: PipelineSubmitComponent },
4143
{ path: 'clusters/:clusterId', component: ClusterPageComponent},
4244

flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/chain-list-page/chain-list-page.component.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ const mockChains: ChainModel[] = [{id: '1', name: 'test1'}, {id: '2', name: 'tes
4141
describe('PipelinesComponent', () => {
4242
let component: ChainListPageComponent;
4343
let fixture: ComponentFixture<ChainListPageComponent>;
44-
let pipelineService: jasmine.SpyObj<PipelineService>
45-
let chainListPageService: jasmine.SpyObj<ChainListPageService>
44+
let pipelineService: jasmine.SpyObj<PipelineService>;
45+
let chainListPageService: jasmine.SpyObj<ChainListPageService>;
4646

4747
beforeEach(waitForAsync(() => {
4848
TestBed.configureTestingModule({

flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-create/pipeline-create.component.html

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,16 @@
6969

7070
<div *ngIf="mode !== 'Empty'">
7171
<div class="flex-row-jsb-ac horizontal-wrapper" [style.min-height.px]="70">
72-
<mat-slide-toggle color="primary" [checked]="jobs.indexOf(jobsEnum.PARSER.value) !== -1"
72+
<mat-slide-toggle [disabled]="slideToggleDisabled(jobsEnum.PARSER)" color="primary" [checked]="jobs.indexOf(jobsEnum.PARSER.value) !== -1"
7373
(change)="toggleValueInArray( jobs , jobsEnum.PARSER.value)">{{ jobsEnum.PARSER.label }}
7474
</mat-slide-toggle>
75-
<mat-slide-toggle color="primary" [checked]="jobs.indexOf(jobsEnum.TRIAGE.value) !== -1"
75+
<mat-slide-toggle [disabled]="slideToggleDisabled(jobsEnum.TRIAGE)" color="primary" [checked]="jobs.indexOf(jobsEnum.TRIAGE.value) !== -1"
7676
(change)="toggleValueInArray( jobs , jobsEnum.TRIAGE.value)">{{ jobsEnum.TRIAGE.label }}
7777
</mat-slide-toggle>
78-
<mat-slide-toggle color="primary" [checked]="jobs.indexOf(jobsEnum.PROFILE.value) !== -1"
78+
<mat-slide-toggle [disabled]="slideToggleDisabled(jobsEnum.PROFILE)" color="primary" [checked]="jobs.indexOf(jobsEnum.PROFILE.value) !== -1"
7979
(change)="toggleValueInArray( jobs , jobsEnum.PROFILE.value)">{{ jobsEnum.PROFILE.label }}
8080
</mat-slide-toggle>
81-
<mat-slide-toggle color="primary" [checked]="jobs.indexOf(jobsEnum.INDEX.value) !== -1"
81+
<mat-slide-toggle [disabled]="slideToggleDisabled(jobsEnum.INDEX)" color="primary" [checked]="jobs.indexOf(jobsEnum.INDEX.value) !== -1"
8282
(change)="toggleValueInArray( jobs , jobsEnum.INDEX.value)">{{ jobsEnum.INDEX.label }}
8383
</mat-slide-toggle>
8484
</div>

flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-create/pipeline-create.component.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const BUTTONS_CONST = [
1616
{label: 'Archive', value: 'Archive', disabled: false},
1717
{label: 'Git', value: 'Git', disabled: false},
1818
{label: 'Empty', value: 'Empty', disabled: false},
19-
{label: 'Manual', value: 'Manual', disabled: true}
19+
{label: 'Manual', value: 'Manual', disabled: false}
2020
] as const;
2121

2222
const BUTTON_LABELS = BUTTONS_CONST.map(b => b.value);
@@ -107,6 +107,8 @@ export class PipelineCreateComponent {
107107
this.fileControl.clearValidators();
108108
break
109109
case 'Manual':
110+
this.jobs = [JOBS_ENUM.PARSER.value];
111+
break;
110112
default:
111113
}
112114
this.fileControl.updateValueAndValidity();
@@ -128,7 +130,13 @@ export class PipelineCreateComponent {
128130
jobs: this.jobs,
129131
sourceMap: this.sourceMap,
130132
}
131-
this._router.navigate(['clusters/pipelines/submit'], {state: {data}});
133+
if (this.mode === 'Manual') {
134+
this._router.navigate(['clusters/pipelines/stepper'], {state: {data}});
135+
136+
} else {
137+
this._router.navigate(['clusters/pipelines/submit'], {state: {data}});
138+
139+
}
132140
}
133141

134142
onFileDropped(fileList: FileList) {
@@ -182,4 +190,9 @@ export class PipelineCreateComponent {
182190
}))
183191
);
184192
}
193+
194+
slideToggleDisabled(value) {
195+
return this.mode === 'Manual' && value !== JOBS_ENUM.PARSER;
196+
197+
}
185198
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,188 @@
1-
<p>pipeline-stepper works!</p>
21
<mat-stepper #stepper>
2+
<mat-step [stepControl]="parserFormGroup">
3+
<form [formGroup]="parserFormGroup">
4+
<ng-template matStepLabel>Parser config</ng-template>
5+
<mat-tab-group color="primary" class="parser-chain-step">
6+
<mat-tab label="General Config">
7+
<div class="general-section">
8+
<h1>Kafka Topic config: </h1>
9+
<span>Configuration of Kafka topic for parser job</span>
10+
<div style="display: flex; flex-direction: column">
11+
<div style="display: flex; flex-direction: row">
12+
<mat-form-field class="input-form" color="primary" appearance="outline">
13+
<mat-label>Topic output</mat-label>
14+
<input matInput
15+
type="text"
16+
formControlName="topicOutput"
17+
id="topicOutput"
18+
label="topic Output"
19+
placeholder="topic Output"
20+
>
21+
</mat-form-field>
22+
<mat-form-field class="input-form" color="primary" appearance="outline" [style.margin-left.px]="15">
23+
<mat-label>Error Topic</mat-label>
24+
<input matInput
25+
type="text"
26+
formControlName="errorTopic"
27+
id="errorTopic"
28+
label="error topic name"
29+
placeholder="error topic">
30+
</mat-form-field>
31+
</div>
32+
<mat-slide-toggle color="primary" formControlName="sourceFlag" [style.margin-bottom.px]="15">Enable source
33+
</mat-slide-toggle>
34+
<div *ngIf="parserFormGroup.controls.sourceFlag.value" class="general-section">
35+
<mat-form-field class="input-form" color="primary"
36+
appearance="outline">
37+
<mat-label>Original base path</mat-label>
38+
<input matInput
39+
type="text"
40+
formControlName="origBasePath"
41+
id="origBasePath"
42+
label="original base path"
43+
placeholder="orig Base Path name">
44+
</mat-form-field>
45+
</div>
46+
</div>
47+
</div>
48+
49+
</mat-tab>
50+
51+
<div formArrayName="chains">
52+
<mat-tab *ngFor="let chain of chains.controls; let index = index" formGroupName="{{index}}">
53+
<ng-template mat-tab-label>
54+
<ng-container *ngIf="!chain.getRawValue().editMode">
55+
<div (dblclick)="dbClick(chain)">{{ chain.getRawValue().chainName }}</div>
56+
</ng-container>
57+
58+
<ng-container *ngIf="chain.getRawValue().editMode">
59+
<input style="max-width: 100px" formControlName="chainName"/>
60+
<mat-icon class="save-tab-icon" (click)="dbClick(chain)">save</mat-icon>
61+
<mat-icon *ngIf="chains.length > 1" class="delete-tab-icon" (click)="deleteChain(index)">delete
62+
</mat-icon>
63+
</ng-container>
64+
</ng-template>
65+
<mat-form-field *ngIf="vm$ | async as vm" class="source-list" appearance="outline">
66+
<mat-label>Source</mat-label>
67+
<mat-chip-list #chipList aria-label="Source selection" selectable="false">
68+
<mat-chip
69+
*ngFor="let selectedPipeline of getSelectedSource(index)"
70+
(removed)="remove(selectedPipeline, index)"
71+
>
72+
{{ selectedPipeline }}
73+
<button matChipRemove>
74+
<mat-icon>cancel</mat-icon>
75+
</button>
76+
</mat-chip>
77+
<input
78+
placeholder="Select source..."
79+
#sourceInput
80+
formControlName="source"
81+
[style.width.%]="85"
82+
[matAutocomplete]="auto"
83+
[matChipInputFor]="chipList"
84+
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
85+
(matChipInputTokenEnd)="add($event, index)">
86+
<mat-autocomplete #auto="matAutocomplete"
87+
(optionSelected)="selected($event, index)">
88+
<mat-option
89+
*ngFor="let searchedPipeline of vm.pipelines | filter:getSelectedSource(index) | contains:getSource(index)"
90+
[value]="searchedPipeline">
91+
{{ searchedPipeline }}
92+
</mat-option>
93+
</mat-autocomplete>
94+
</mat-chip-list>
95+
96+
</mat-form-field>
97+
98+
<!-- Chains list -->
99+
100+
<div *ngIf="vm$ | async as vm">
101+
<app-custom-list *ngIf="vm.currentChains.length > 0">
102+
<app-custom-list-line *ngFor="let chain of vm.currentChains">
103+
<mat-icon customListIcon>link</mat-icon>
104+
<div customListLine>{{ chain.name }}</div>
105+
<app-styled-chips-list customListChips
106+
[chips]="topicMap.get(index)?.get(chain.id) ? [topicMap.get(index).get(chain.id)] : [] "
107+
[forceStyleDisplay]="true"></app-styled-chips-list>
108+
<button
109+
customListAction
110+
mat-button
111+
color="primary"
112+
class="flex-row-jc-ac"
113+
data-qe-id="view-fields-button"
114+
matTooltip="Add topic to the chain"
115+
matTooltipPosition="above"
116+
(click)="assignTopic(assignTopicDialog, chain.id, index)">
117+
<mat-chip selected>ASSIGN TOPIC
118+
<mat-icon [style.color]="'white'">add</mat-icon>
119+
</mat-chip>
120+
</button>
121+
<button
122+
customListAction
123+
mat-button
124+
color="primary"
125+
class="flex-row-jc-ac"
126+
data-qe-id="view-fields-button"
127+
matTooltip="Edit"
128+
matTooltipPosition="below"
129+
[routerLink]="['/parserconfig', 'chains', chain.id]"
130+
[queryParams]="{pipeline: chain.pipeline}"
131+
132+
>
133+
<mat-icon class="edit-action-color">edit</mat-icon>
134+
</button>
135+
<button
136+
customListAction
137+
mat-button
138+
color="primary"
139+
class="flex-row-jc-ac"
140+
data-qe-id="delete-field-type-btn"
141+
matTooltip="Delete"
142+
matTooltipPosition="below"
143+
(click)="deleteItem(chain.id)">
144+
<mat-icon class="delete-action-color">delete</mat-icon>
145+
</button>
146+
</app-custom-list-line>
147+
</app-custom-list>
148+
<button [style.margin.px]="10" mat-raised-button routerLink="/parserconfig"
149+
color="primary">ADD CHAIN
150+
</button>
151+
</div>
152+
</mat-tab>
153+
</div>
154+
<mat-tab disabled>
155+
<ng-template mat-tab-label>
156+
<button mat-icon-button (click)="addTab()">
157+
<mat-icon>add_circle</mat-icon>
158+
</button>
159+
</ng-template>
160+
</mat-tab>
161+
</mat-tab-group>
162+
<div>
163+
<button mat-raised-button color="primary" (click)="navigateToReceiver()" matStepperNext>Next
164+
</button>
165+
</div>
166+
</form>
167+
</mat-step>
3168
</mat-stepper>
169+
170+
171+
<ng-template #assignTopicDialog let-data>
172+
<h2 mat-dialog-title>Assign Topic</h2>
173+
<div mat-dialog-content [style.display]="'inline'">
174+
<div class="inner-assign-wrapper">
175+
<span class="inner-assign-wrapper-span">
176+
Topic or Topic pattern that would associated with this chain.
177+
</span>
178+
<mat-form-field appearance="outline">
179+
<mat-label>Topic Name</mat-label>
180+
<input matInput [(ngModel)]="data.name">
181+
</mat-form-field>
182+
</div>
183+
</div>
184+
<div mat-dialog-actions align="end">
185+
<button mat-raised-button color="accent" [mat-dialog-close]="false">Cancel</button>
186+
<button mat-raised-button color="primary" [mat-dialog-close]="data">Assign</button>
187+
</div>
188+
</ng-template>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
@use '@angular/material' as mat;
2+
@import "./styles.scss";
3+
4+
.save-tab-icon {
5+
color: mat.get-color-from-palette($theme-primary);
6+
}
7+
8+
.delete-tab-icon {
9+
color: mat.get-color-from-palette(mat.$red-palette, 300);
10+
}
11+
12+
.source-list {
13+
min-width: 300px;
14+
width: 70%;
15+
margin-top: 10px;
16+
margin-bottom: 10px;
17+
}
18+
19+
.inner-assign-wrapper {
20+
display: flex;
21+
flex-direction: column;
22+
flex-wrap: wrap;
23+
align-content: flex-start;
24+
justify-content: space-around;
25+
align-items: flex-start;
26+
}
27+
28+
.inner-assign-wrapper-span {
29+
font-size: 20px;
30+
margin-bottom: 15px;
31+
}
32+
33+
.general-section {
34+
display: flex;
35+
flex-direction: column
36+
}

flink-cyber/metron-parser-chain/parser-chains-config-service/frontend/parser-chains-client/src/app/cluster/pipelines/pipeline-stepper/pipeline-stepper.component.spec.ts

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import {ComponentFixture, TestBed} from '@angular/core/testing';
22

33
import {PipelineStepperComponent} from './pipeline-stepper.component';
4-
import {FormsModule} from '@angular/forms';
4+
import {FormsModule, ReactiveFormsModule} from '@angular/forms';
55
import {SharedModule} from 'src/app/shared/share.module';
66
import {MatCardModule} from '@angular/material/card';
77
import {MatDividerModule} from '@angular/material/divider';
@@ -16,10 +16,26 @@ import {AsyncPipe, NgComponentOutlet, NgForOf, NgIf, NgTemplateOutlet} from '@an
1616
import {MatSelectModule} from '@angular/material/select';
1717
import {MatStepperModule} from '@angular/material/stepper';
1818
import {NoopAnimationsModule} from '@angular/platform-browser/animations';
19+
import {PipelineService} from 'src/app/services/pipeline.service';
20+
import {of} from 'rxjs';
21+
import {ChainListPageService} from 'src/app/services/chain-list-page.service';
22+
import {ChainModel} from 'src/app/chain-list-page/chain.model';
23+
import {Router} from '@angular/router';
24+
import {RouterTestingModule} from '@angular/router/testing';
25+
import {MatTabsModule} from '@angular/material/tabs';
26+
import {MatSlideToggleModule} from '@angular/material/slide-toggle';
27+
import {MatChipsModule} from '@angular/material/chips';
28+
import {MatAutocompleteModule} from '@angular/material/autocomplete';
29+
30+
const mockPipeline = ['foo-pipeline1', 'foo-pipeline2'];
31+
const mockChains: ChainModel[] = [{id: '1', name: 'test1'}, {id: '2', name: 'test2'}];
1932

2033
describe('PipelineStepperComponent', () => {
2134
let component: PipelineStepperComponent;
2235
let fixture: ComponentFixture<PipelineStepperComponent>;
36+
let pipelineService: jasmine.SpyObj<PipelineService>;
37+
let chainListPageService: jasmine.SpyObj<ChainListPageService>;
38+
let router: Router;
2339

2440
beforeEach(async () => {
2541
await TestBed.configureTestingModule({ imports: [
@@ -41,13 +57,43 @@ describe('PipelineStepperComponent', () => {
4157
FormsModule,
4258
NgForOf,
4359
MatStepperModule,
60+
RouterTestingModule.withRoutes([]),
61+
MatTabsModule,
62+
ReactiveFormsModule,
63+
MatSlideToggleModule,
64+
MatChipsModule,
65+
MatAutocompleteModule,
4466
NoopAnimationsModule
4567
],
68+
providers: [
69+
{
70+
provide: PipelineService,
71+
useValue: jasmine.createSpyObj('PipelineService', ['getPipelines', 'createPipeline', 'renamePipeline', 'deletePipeline'])
72+
},
73+
{
74+
provide: ChainListPageService,
75+
useValue: jasmine.createSpyObj('ChainListPageService', ['createChain', 'getChains', 'deleteChain', 'getPipelines'])
76+
},
77+
],
4678

4779
declarations: [ PipelineStepperComponent ]
4880
})
4981
.compileComponents();
5082

83+
pipelineService = TestBed.inject(PipelineService) as jasmine.SpyObj<PipelineService>;
84+
pipelineService.getPipelines.and.returnValue(of(mockPipeline));
85+
chainListPageService = TestBed.inject(ChainListPageService) as jasmine.SpyObj<ChainListPageService>;
86+
chainListPageService.getChains.and.returnValue(of(mockChains));
87+
88+
router = TestBed.inject(Router);
89+
spyOn(router, 'getCurrentNavigation').and.returnValue({
90+
extras: {state: {data: {clusterId: 'test1', pipelineName: 'foo-pipe', branch: 'testbranch'}}},
91+
id: 0,
92+
initialUrl: null,
93+
extractedUrl: null,
94+
trigger: null,
95+
previousNavigation: null
96+
})
5197
fixture = TestBed.createComponent(PipelineStepperComponent);
5298
component = fixture.componentInstance;
5399
fixture.detectChanges();

0 commit comments

Comments
 (0)