From 54c4933b630cd1438f4460cb3566338a92ad752f Mon Sep 17 00:00:00 2001 From: Iurii Panarin Date: Thu, 25 Jun 2020 23:36:46 +0200 Subject: [PATCH 01/17] feat(incident): add rules modal --- src/app/app.component.ts | 5 ++ src/app/shared/enums/rules.type.ts | 6 ++ .../add-rule.component.html | 60 +++++++++++++++++ .../add-rule.component.scss | 22 ++++++ .../add-rule-component/add-rule.component.ts | 67 +++++++++++++++++++ .../modals/add-rule/add-rule.service.ts | 19 ++++++ .../add-rule/validators/rule.validator.ts | 40 +++++++++++ .../shared/modules/modals/modals.module.ts | 12 +++- src/app/shared/services/app.service.ts | 4 +- src/app/shared/services/rules.service.ts | 33 +++++++++ src/app/shared/services/storage.service.ts | 4 +- src/app/shared/shared.module.ts | 2 + src/assets/i18n/en.json | 12 +++- 13 files changed, 276 insertions(+), 10 deletions(-) create mode 100644 src/app/shared/enums/rules.type.ts create mode 100644 src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.html create mode 100644 src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.scss create mode 100644 src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts create mode 100644 src/app/shared/modules/modals/add-rule/add-rule.service.ts create mode 100644 src/app/shared/modules/modals/add-rule/validators/rule.validator.ts create mode 100644 src/app/shared/services/rules.service.ts diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 7ab47a6..5840174 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -5,6 +5,8 @@ import { MatSelectChange } from '@angular/material/select'; import { Subject, BehaviorSubject } from 'rxjs'; import { takeUntil, startWith, tap } from 'rxjs/operators'; import { StorageService } from './shared/services/storage.service'; +import { AddRuleService } from './shared/modules/modals/add-rule/add-rule.service'; +import { OwnerType } from './shared/enums/rules.type'; @Component({ selector: 'sqd-root', @@ -44,6 +46,7 @@ export class AppComponent implements OnInit, OnDestroy { private appService: AppService, private translateService: TranslateService, private storageService: StorageService, + private addRuleService: AddRuleService, ) {} ngOnInit() { @@ -54,6 +57,8 @@ export class AppComponent implements OnInit, OnDestroy { takeUntil(this.destroyed$), ) .subscribe(); + + this.addRuleService.open(OwnerType.INCIDENT_OWNER_TYPE_AGENT, 'asf'); } ngOnDestroy() { diff --git a/src/app/shared/enums/rules.type.ts b/src/app/shared/enums/rules.type.ts new file mode 100644 index 0000000..30bef4a --- /dev/null +++ b/src/app/shared/enums/rules.type.ts @@ -0,0 +1,6 @@ +export enum OwnerType { + INCIDENT_OWNER_TYPE_UNSPECIFIED = 0, + INCIDENT_OWNER_TYPE_SCHEDULER = 1, + INCIDENT_OWNER_TYPE_AGENT = 2, + INCIDENT_OWNER_TYPE_APPLICATION = 3, +} diff --git a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.html b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.html new file mode 100644 index 0000000..5b93e0f --- /dev/null +++ b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.html @@ -0,0 +1,60 @@ + +
+ + {{ 'MODULES.MODALS.ADD_RULE.TITLE' | translate }} + + + + + {{ 'MODULES.MODALS.ADD_RULE.NAME_HINT' | translate }} + + {{ + 'ERRORS.REQUIRED' | translate + }} + + + + + + {{ 'MODULES.MODALS.ADD_RULE.RULE_HINT' | translate }}: + + {{ + 'MODULES.MODALS.ADD_RULE.RULE_URL' | translate + }} + + + + {{ + 'ERRORS.REQUIRED' | translate + }} + + + {{ + 'ERRORS.ruleNotValid' | translate + }} + + +
{{ errorValidation | json }}
+ + {{ + 'MODULES.MODALS.ADD_RULE.AUTOCLOSE' | translate + }} + +
+ + + +
+
diff --git a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.scss b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.scss new file mode 100644 index 0000000..f769e84 --- /dev/null +++ b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.scss @@ -0,0 +1,22 @@ +mat-card-content { + display: flex; + flex-direction: column; +} +mat-card-actions { + padding-bottom: 0; +} + +pre { + width: 100%; + overflow-x: scroll; +} + +mat-card { + min-width: 300px; + box-shadow: none !important; + padding-bottom: 0; + .selector-form { + margin-top: 10px; + display: flex; + } +} diff --git a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts new file mode 100644 index 0000000..de50fc8 --- /dev/null +++ b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts @@ -0,0 +1,67 @@ +import { Component, ChangeDetectionStrategy, Inject, OnDestroy } from '@angular/core'; +import { OwnerType } from 'src/app/shared/enums/rules.type'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { FormBuilder, Validators } from '@angular/forms'; +import { RuleValidator } from '../validators/rule.validator'; +import { Subject } from 'rxjs'; +import { RulesService } from 'src/app/shared/services/rules.service'; +import { takeUntil } from 'rxjs/operators'; + +export interface AddRuleData { + ownerType: OwnerType; + ownerId: string; +} + +@Component({ + selector: 'sqd-dialog-add-rule', + templateUrl: './add-rule.component.html', + styleUrls: ['./add-rule.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AddRuleFormComponent implements OnDestroy { + private destroyed$ = new Subject(); + + private ruleValidationErrMsg = new Subject(); + + validationErrors$ = this.ruleValidationErrMsg.asObservable(); + + form = this.fb.group({ + name: ['', Validators.compose([Validators.required])], + rule: [ + '', + { + validators: Validators.compose([Validators.required]), + asyncValidators: [ + new RuleValidator( + this.data.ownerType, + this.ruleValidationErrMsg, + this.rulesService, + this.destroyed$, + ), + ], + }, + ], + autoClose: [false], + }); + + constructor( + @Inject(MAT_DIALOG_DATA) public data: AddRuleData, + private dialogRef: MatDialogRef, + private fb: FormBuilder, + private rulesService: RulesService, + ) {} + + onSubmit() { + const { rule, name, autoClose } = this.form.value; + this.rulesService + .createRule(this.data.ownerId, this.data.ownerType, rule, name, autoClose) + .pipe(takeUntil(this.destroyed$)) + .subscribe((res) => { + this.dialogRef.close(res); + }); + } + + ngOnDestroy() { + this.destroyed$.next(); + } +} diff --git a/src/app/shared/modules/modals/add-rule/add-rule.service.ts b/src/app/shared/modules/modals/add-rule/add-rule.service.ts new file mode 100644 index 0000000..3a6d6cd --- /dev/null +++ b/src/app/shared/modules/modals/add-rule/add-rule.service.ts @@ -0,0 +1,19 @@ +import { Injectable } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { AddRuleFormComponent, AddRuleData } from './add-rule-component/add-rule.component'; +import { OwnerType } from 'src/app/shared/enums/rules.type'; + +@Injectable() +export class AddRuleService { + constructor(private dialog: MatDialog) {} + open(ownerType: OwnerType, ownerId: string) { + return this.dialog + .open(AddRuleFormComponent, { + data: { + ownerId, + ownerType, + }, + }) + .afterClosed(); + } +} diff --git a/src/app/shared/modules/modals/add-rule/validators/rule.validator.ts b/src/app/shared/modules/modals/add-rule/validators/rule.validator.ts new file mode 100644 index 0000000..df65ff2 --- /dev/null +++ b/src/app/shared/modules/modals/add-rule/validators/rule.validator.ts @@ -0,0 +1,40 @@ +import { AsyncValidator, AbstractControl } from '@angular/forms'; +import { of, Subject, timer } from 'rxjs'; +import { map, switchMap, filter, catchError, tap, takeUntil } from 'rxjs/operators'; +import { RulesService } from 'src/app/shared/services/rules.service'; +import { OwnerType } from 'src/app/shared/enums/rules.type'; + +export class RuleValidator implements AsyncValidator { + constructor( + private ownerType: OwnerType, + private errors$: Subject, + private rulesService: RulesService, + private destoryed$: Subject, + ) {} + + validate(control: AbstractControl) { + return timer(500).pipe( + switchMap(() => of(control.value)), + map((value) => (value ? `${value}`.trim() : null)), + filter((v) => !!v), + tap(() => this.errors$.next(null)), + switchMap((trimmedValue) => + this.rulesService.validateRule(this.ownerType, trimmedValue).pipe( + catchError((err) => { + this.errors$.next(err); + return of(false); + }), + ), + ), + tap((value) => (value ? this.errors$.next(null) : void 0)), + map((value) => + !value + ? { + ruleNotValid: true, + } + : null, + ), + takeUntil(this.destoryed$), + ); + } +} diff --git a/src/app/shared/modules/modals/modals.module.ts b/src/app/shared/modules/modals/modals.module.ts index 384396c..7729a02 100644 --- a/src/app/shared/modules/modals/modals.module.ts +++ b/src/app/shared/modules/modals/modals.module.ts @@ -12,6 +12,11 @@ import { ReactiveFormsModule } from '@angular/forms'; import { MatSelectModule } from '@angular/material/select'; import { MatInputModule } from '@angular/material/input'; import { TranslateModule } from '@ngx-translate/core'; +import { AddRuleService } from './add-rule/add-rule.service'; +import { AddRuleFormComponent } from './add-rule/add-rule-component/add-rule.component'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { RuleValidator } from './add-rule/validators/rule.validator'; + @NgModule({ imports: [ CommonModule, @@ -24,11 +29,12 @@ import { TranslateModule } from '@ngx-translate/core'; MatButtonModule, MatChipsModule, MatIconModule, + MatCheckboxModule, TranslateModule.forChild({}), ], exports: [], - providers: [AddCheckerService], - declarations: [AddCheckerFormComponent], - entryComponents: [AddCheckerFormComponent], + providers: [AddCheckerService, AddRuleService], + declarations: [AddCheckerFormComponent, AddRuleFormComponent], + entryComponents: [AddCheckerFormComponent, AddRuleFormComponent], }) export class ModalsModule {} diff --git a/src/app/shared/services/app.service.ts b/src/app/shared/services/app.service.ts index 4e816fd..97aa4be 100644 --- a/src/app/shared/services/app.service.ts +++ b/src/app/shared/services/app.service.ts @@ -3,9 +3,7 @@ import { HttpClient } from '@angular/common/http'; import { map, catchError } from 'rxjs/operators'; import { of } from 'rxjs'; -@Injectable({ - providedIn: 'root', -}) +@Injectable() export class AppService { constructor(private httpClient: HttpClient) {} diff --git a/src/app/shared/services/rules.service.ts b/src/app/shared/services/rules.service.ts new file mode 100644 index 0000000..a21475b --- /dev/null +++ b/src/app/shared/services/rules.service.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import { map, catchError } from 'rxjs/operators'; +import { of } from 'rxjs'; +import { OwnerType } from '../enums/rules.type'; + +@Injectable() +export class RulesService { + constructor(private httpClient: HttpClient) {} + + validateRule(ownerType: OwnerType, rule: string) { + return this.httpClient.post('/api/rule/validate', { + ownerType, + rule, + }); + } + + createRule( + ownerId: string, + ownerType: OwnerType, + rule: string, + name: string, + autoClose: boolean, + ) { + return this.httpClient.post('/api/rules', { + ownerId, + ownerType, + rule, + name, + autoClose, + }); + } +} diff --git a/src/app/shared/services/storage.service.ts b/src/app/shared/services/storage.service.ts index 672ba70..723d3fc 100644 --- a/src/app/shared/services/storage.service.ts +++ b/src/app/shared/services/storage.service.ts @@ -1,8 +1,6 @@ import { Injectable } from '@angular/core'; -@Injectable({ - providedIn: 'root', -}) +@Injectable() export class StorageService { set(key: string, value: any): boolean { try { diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index a18f900..1a73eab 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -13,6 +13,7 @@ import { StorageService } from './services/storage.service'; import { MatPaginatorIntl } from '@angular/material/paginator'; import { TranslateService } from '@ngx-translate/core'; import { PaginatorI18n } from './services/paginatorIntl.service'; +import { RulesService } from './services/rules.service'; const sharedModules = [ CommonModule, @@ -37,6 +38,7 @@ const sharedModules = [ deps: [TranslateService], useClass: PaginatorI18n, }, + RulesService, ], }) export class SharedModule {} diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 9463d62..019d9f9 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -31,7 +31,8 @@ "notValidUrl": "Not valid url", "minConcurrency": "Should be more than 0", "minStatusCode": "Should be more than 0", - "maxStatusCode": "Should be more less 503" + "maxStatusCode": "Should be more less 503", + "ruleNotValid": "Rule is not valid" }, "MENU": { "AGENTS": "Agents", @@ -123,6 +124,15 @@ }, "MODULES": { "MODALS": { + "ADD_RULE": { + "TITLE": "Add rule", + "SELECT_NAME": "Provide name", + "NAME_HINT": "Better provide uniq name", + "PROVIDE_RULE": "Provide rule", + "RULE_HINT": "Rules example you can find here", + "RULE_URL": "Rules examples", + "AUTOCLOSE": "Auto-close incident" + }, "ADD_CHECKER": { "TITLE": "Add checker", "SELECT_TYPE": "Select type of checker", From c3c734c7bf5726cb70a99c335d11283f0d0f973b Mon Sep 17 00:00:00 2001 From: Iurii Panarin Date: Mon, 29 Jun 2020 00:02:21 +0200 Subject: [PATCH 02/17] feat(rules): add rules --- src/app/app.component.ts | 8 +- src/app/app.module.ts | 1 + src/app/modules/checkers/checkers.module.ts | 2 + .../components/checker/checker.component.html | 6 + .../components/checker/checker.component.ts | 3 + src/app/shared/enums/rules.type.ts | 7 ++ src/app/shared/interfaces/rules.interfaces.ts | 11 ++ .../components/rule-list/list.component.html | 31 +++++ .../components/rule-list/list.component.scss | 0 .../components/rule-list/list.component.ts | 111 ++++++++++++++++++ src/app/shared/modules/rules/rules.module.ts | 26 ++++ src/app/shared/services/rules.service.ts | 30 ++++- src/app/shared/utils/http.utils.ts | 1 - src/assets/i18n/en.json | 15 +++ 14 files changed, 240 insertions(+), 12 deletions(-) create mode 100644 src/app/shared/interfaces/rules.interfaces.ts create mode 100644 src/app/shared/modules/rules/components/rule-list/list.component.html create mode 100644 src/app/shared/modules/rules/components/rule-list/list.component.scss create mode 100644 src/app/shared/modules/rules/components/rule-list/list.component.ts create mode 100644 src/app/shared/modules/rules/rules.module.ts diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 5840174..7722c71 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,12 +1,9 @@ import { Component, ChangeDetectionStrategy, OnDestroy, OnInit } from '@angular/core'; import { AppService } from './shared/services/app.service'; import { TranslateService } from '@ngx-translate/core'; -import { MatSelectChange } from '@angular/material/select'; import { Subject, BehaviorSubject } from 'rxjs'; -import { takeUntil, startWith, tap } from 'rxjs/operators'; +import { takeUntil, tap } from 'rxjs/operators'; import { StorageService } from './shared/services/storage.service'; -import { AddRuleService } from './shared/modules/modals/add-rule/add-rule.service'; -import { OwnerType } from './shared/enums/rules.type'; @Component({ selector: 'sqd-root', @@ -46,7 +43,6 @@ export class AppComponent implements OnInit, OnDestroy { private appService: AppService, private translateService: TranslateService, private storageService: StorageService, - private addRuleService: AddRuleService, ) {} ngOnInit() { @@ -57,8 +53,6 @@ export class AppComponent implements OnInit, OnDestroy { takeUntil(this.destroyed$), ) .subscribe(); - - this.addRuleService.open(OwnerType.INCIDENT_OWNER_TYPE_AGENT, 'asf'); } ngOnDestroy() { diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 951d02b..ec0b597 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -8,6 +8,7 @@ import { TranslateModule, TranslateLoader } from '@ngx-translate/core'; import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { HttpClient } from '@angular/common/http'; import { MatMenuModule } from '@angular/material/menu'; +import { RulesModule } from './shared/modules/rules/rules.module'; export function HttpLoaderFactory(http: HttpClient) { return new TranslateHttpLoader(http); diff --git a/src/app/modules/checkers/checkers.module.ts b/src/app/modules/checkers/checkers.module.ts index e48a26f..9163b92 100644 --- a/src/app/modules/checkers/checkers.module.ts +++ b/src/app/modules/checkers/checkers.module.ts @@ -22,6 +22,7 @@ import { SchedulerConfigComponent } from './components/checker/config/config.com import { SchedulerSnapshotComponent } from './components/checker/snapshot/snapshot.component'; import { MatSelectModule } from '@angular/material/select'; import { TranslateModule } from '@ngx-translate/core'; +import { RulesModule } from 'src/app/shared/modules/rules/rules.module'; const routes: Routes = [ { @@ -59,6 +60,7 @@ const routes: Routes = [ MatIconModule, MatCheckboxModule, MatProgressSpinnerModule, + RulesModule, TranslateModule.forChild({}), ], providers: [CheckersService], diff --git a/src/app/modules/checkers/components/checker/checker.component.html b/src/app/modules/checkers/components/checker/checker.component.html index 09824d5..907a3c1 100644 --- a/src/app/modules/checkers/components/checker/checker.component.html +++ b/src/app/modules/checkers/components/checker/checker.component.html @@ -111,6 +111,12 @@ + + + + + +
diff --git a/src/app/modules/checkers/components/checker/checker.component.ts b/src/app/modules/checkers/components/checker/checker.component.ts index 5da7b56..ef66ddf 100644 --- a/src/app/modules/checkers/components/checker/checker.component.ts +++ b/src/app/modules/checkers/components/checker/checker.component.ts @@ -25,6 +25,7 @@ import { SchedulerSnapshotComponent } from './snapshot/snapshot.component'; import { CheckerDataSource } from './datasource/checker.datasource'; import { SortSchedulerList, angularSortDirectionMap } from 'src/app/shared/enums/sort.table'; import { SchedulerStatus, SchedulerResponseCode } from 'src/app/shared/enums/schedulers.type'; +import { OwnerType } from 'src/app/shared/enums/rules.type'; class CrossFieldErrorMatcher implements ErrorStateMatcher { isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { @@ -90,6 +91,8 @@ export class CheckerComponent implements OnInit, OnDestroy { currentId$ = this.route.params.pipe(map((p) => p.id as string)); + SCHDEDULER_TYPE = OwnerType.INCIDENT_OWNER_TYPE_SCHEDULER; + dataSource = new CheckerDataSource(this.checkersService); checkInfo$ = combineLatest(this.refresh$, this.currentId$).pipe( diff --git a/src/app/shared/enums/rules.type.ts b/src/app/shared/enums/rules.type.ts index 30bef4a..08a4b57 100644 --- a/src/app/shared/enums/rules.type.ts +++ b/src/app/shared/enums/rules.type.ts @@ -4,3 +4,10 @@ export enum OwnerType { INCIDENT_OWNER_TYPE_AGENT = 2, INCIDENT_OWNER_TYPE_APPLICATION = 3, } + +export enum RuleStatus { + RULE_STATUS_UNSPECIFIED = 0, + RULE_STATUS_ACTIVE = 1, + RULE_STATUS_INACTIVE = 2, + RULE_STATUS_REMOVED = 3, +} diff --git a/src/app/shared/interfaces/rules.interfaces.ts b/src/app/shared/interfaces/rules.interfaces.ts new file mode 100644 index 0000000..9dc4836 --- /dev/null +++ b/src/app/shared/interfaces/rules.interfaces.ts @@ -0,0 +1,11 @@ +import { OwnerType, RuleStatus } from '../enums/rules.type'; + +export interface Rule { + id: string; + rule: string; + name: string; + auto_close: boolean; + status: RuleStatus; + ownerType: OwnerType; + ownerId: string; +} diff --git a/src/app/shared/modules/rules/components/rule-list/list.component.html b/src/app/shared/modules/rules/components/rule-list/list.component.html new file mode 100644 index 0000000..4683059 --- /dev/null +++ b/src/app/shared/modules/rules/components/rule-list/list.component.html @@ -0,0 +1,31 @@ +
+ +
+ + + +
+ + {{ 'MODULES.RULES.TABLE.STATUS' | translate }}: + {{ 'ENUMS.RULES.STATUS.' + rule.status | translate }} + + {{ rule.name }} + + +
+
{{ rule.rule }}
+
+
diff --git a/src/app/shared/modules/rules/components/rule-list/list.component.scss b/src/app/shared/modules/rules/components/rule-list/list.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/shared/modules/rules/components/rule-list/list.component.ts b/src/app/shared/modules/rules/components/rule-list/list.component.ts new file mode 100644 index 0000000..6ebb19b --- /dev/null +++ b/src/app/shared/modules/rules/components/rule-list/list.component.ts @@ -0,0 +1,111 @@ +import { + Component, + ChangeDetectionStrategy, + Input, + OnChanges, + SimpleChanges, + OnDestroy, +} from '@angular/core'; +import { OwnerType, RuleStatus } from 'src/app/shared/enums/rules.type'; +import { BehaviorSubject, Subject, combineLatest, of } from 'rxjs'; +import { RulesService } from 'src/app/shared/services/rules.service'; +import { takeUntil, switchMap, tap, finalize, startWith } from 'rxjs/operators'; +import { Rule } from 'src/app/shared/interfaces/rules.interfaces'; +import { MatSlideToggleChange } from '@angular/material/slide-toggle'; +import { AddRuleService } from '../../../modals/add-rule/add-rule.service'; + +@Component({ + selector: 'sqd-rule-list', + templateUrl: './list.component.html', + styleUrls: ['./list.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class RuleListComponent implements OnChanges, OnDestroy { + private destroyed$ = new Subject(); + + @Input() ownerId: string; + @Input() ownerType: OwnerType; + + private ownerID$ = new BehaviorSubject(this.ownerId); + + loading$ = new BehaviorSubject(false); + + private refresh$ = new Subject(); + + private ownerType$ = new BehaviorSubject(this.ownerType); + + rulesList$ = combineLatest( + this.ownerID$, + this.ownerType$, + this.refresh$.pipe(startWith(null)), + ).pipe( + switchMap(([id, type]) => this.rulesService.getRulesByOwnerId(id, type)), + takeUntil(this.destroyed$), + ); + + ACTIVE_STATUS = RuleStatus.RULE_STATUS_ACTIVE; + + REMOVED = RuleStatus.RULE_STATUS_REMOVED; + + UNCPECIFIED = RuleStatus.RULE_STATUS_UNSPECIFIED; + + constructor(private rulesService: RulesService, private addRulesService: AddRuleService) {} + + ngOnChanges(changes: SimpleChanges) { + if ('ownerId' in changes) { + this.ownerID$.next(changes.ownerId.currentValue); + } + + if ('ownerType' in changes) { + this.ownerType$.next(changes.ownerType.currentValue); + } + } + + addRule() { + this.addRulesService + .open(this.ownerType, this.ownerId) + .pipe(takeUntil(this.destroyed$)) + .subscribe((res) => { + if (res && res.id) { + this.refresh$.next(); + } + }); + } + + trackByFn(rule: Rule) { + return rule.id; + } + + toggleRule(event: MatSlideToggleChange, ruleId: string) { + of(event.checked) + .pipe( + tap(() => this.loading$.next(true)), + finalize(() => this.loading$.next(false)), + switchMap((checked) => + checked ? this.rulesService.activate(ruleId) : this.rulesService.deactivate(ruleId), + ), + takeUntil(this.destroyed$), + ) + .subscribe(() => { + this.refresh$.next(); + }); + } + + remove(ruleId: string) { + this.rulesService + .remove(ruleId) + .pipe( + tap(() => this.loading$.next(true)), + finalize(() => this.loading$.next(false)), + takeUntil(this.destroyed$), + ) + .subscribe(() => { + this.refresh$.next(); + }); + } + + ngOnDestroy() { + this.destroyed$.next(); + this.destroyed$.complete(); + } +} diff --git a/src/app/shared/modules/rules/rules.module.ts b/src/app/shared/modules/rules/rules.module.ts new file mode 100644 index 0000000..7b63915 --- /dev/null +++ b/src/app/shared/modules/rules/rules.module.ts @@ -0,0 +1,26 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { RuleListComponent } from './components/rule-list/list.component'; +import { MatListModule } from '@angular/material/list'; +import { MatSlideToggleModule } from '@angular/material/slide-toggle'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { TranslateModule } from '@ngx-translate/core'; +import { MatTooltipModule } from '@angular/material/tooltip'; +import { MatIconModule } from '@angular/material/icon'; +import { MatButtonModule } from '@angular/material/button'; + +@NgModule({ + imports: [ + CommonModule, + MatListModule, + MatSlideToggleModule, + MatCheckboxModule, + MatTooltipModule, + MatIconModule, + MatButtonModule, + TranslateModule.forChild({}), + ], + declarations: [RuleListComponent], + exports: [RuleListComponent], +}) +export class RulesModule {} diff --git a/src/app/shared/services/rules.service.ts b/src/app/shared/services/rules.service.ts index a21475b..a5c98b4 100644 --- a/src/app/shared/services/rules.service.ts +++ b/src/app/shared/services/rules.service.ts @@ -1,20 +1,42 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; -import { map, catchError } from 'rxjs/operators'; -import { of } from 'rxjs'; import { OwnerType } from '../enums/rules.type'; +import { Rule } from '../interfaces/rules.interfaces'; +import { setQueryParams, queryParam } from '../utils/http.utils'; @Injectable() export class RulesService { constructor(private httpClient: HttpClient) {} validateRule(ownerType: OwnerType, rule: string) { - return this.httpClient.post('/api/rule/validate', { + return this.httpClient.post('/api/rule/validate', { ownerType, rule, }); } + getRulesByOwnerId(ownerId: string, ownerType: OwnerType) { + return this.httpClient.get>(`/api/v1/rules`, { + params: setQueryParams(queryParam('ownerType', ownerType), queryParam('ownerId', ownerId)), + }); + } + + activate(ruleId: string) { + return this.httpClient.put(`/api/v1/rules/${ruleId}/activate`, {}); + } + + getById(ruleId: string) { + return this.httpClient.get(`/api/v1/rules/${ruleId}`); + } + + remove(ruleId: string) { + return this.httpClient.delete(`/api/v1/rules/${ruleId}`); + } + + deactivate(ruleId: string) { + return this.httpClient.put(`/api/v1/rules/${ruleId}/deactivate`, {}); + } + createRule( ownerId: string, ownerType: OwnerType, @@ -22,7 +44,7 @@ export class RulesService { name: string, autoClose: boolean, ) { - return this.httpClient.post('/api/rules', { + return this.httpClient.post('/api/v1/rules', { ownerId, ownerType, rule, diff --git a/src/app/shared/utils/http.utils.ts b/src/app/shared/utils/http.utils.ts index f27602f..677fe33 100644 --- a/src/app/shared/utils/http.utils.ts +++ b/src/app/shared/utils/http.utils.ts @@ -5,7 +5,6 @@ export type queryFn = (params: HttpParams) => HttpParams; export function queryParam( name: string, value: string | number, - strictNumber: boolean = false, ): (params: HttpParams) => HttpParams { return (params: HttpParams) => { if (!value) { diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 019d9f9..9545e42 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -40,6 +40,14 @@ "APPLICATIONS": "Applications" }, "ENUMS": { + "RULES": { + "STATUS": { + "0": "Unspecified", + "1": "Active", + "2": "Inactive", + "3": "Removed" + } + }, "AGENTS": { "STATUS": { "0": "Unspecified", @@ -259,6 +267,13 @@ "STATUS": "Status" } }, + "RULES": { + "TABLE": { + "STATUS": "Status", + "REMOVE": "Remove", + "ADD": "Add" + } + }, "CHECKERS": { "TABLE": { "ID": "Id", From bd6c769862d0905b09537250561e211ec93f73e8 Mon Sep 17 00:00:00 2001 From: Iurii Panarin Date: Wed, 1 Jul 2020 00:54:29 +0200 Subject: [PATCH 03/17] feat(rule): add style for rule + incident module --- src/app/app-routing.module.ts | 5 ++ src/app/app.component.ts | 4 ++ src/app/modules/agents/agents.module.ts | 2 + .../components/overview/agents.component.html | 46 ++++++++++++------- .../components/overview/agents.component.ts | 3 ++ .../applications/applications.module.ts | 2 + .../application/application.component.html | 9 ++++ .../application/application.component.ts | 3 ++ .../components/checker/checker.component.html | 7 ++- .../components/checker/checker.component.scss | 4 +- .../incident/incident.component.html | 1 + .../incident/incident.component.scss | 0 .../components/incident/incident.component.ts | 9 ++++ .../components/list/list.component.html | 1 + .../components/list/list.component.scss | 0 .../components/list/list.component.ts | 9 ++++ src/app/modules/incidents/incidents.module.ts | 26 +++++++++++ .../add-rule/validators/rule.validator.ts | 26 ++++------- .../components/rule-list/list.component.html | 24 ++++++++-- .../components/rule-list/list.component.scss | 18 ++++++++ .../components/rule-list/list.component.ts | 30 +++++++++--- src/app/shared/services/rules.service.ts | 18 ++++++-- src/assets/i18n/en.json | 9 +++- 23 files changed, 204 insertions(+), 52 deletions(-) create mode 100644 src/app/modules/incidents/components/incident/incident.component.html create mode 100644 src/app/modules/incidents/components/incident/incident.component.scss create mode 100644 src/app/modules/incidents/components/incident/incident.component.ts create mode 100644 src/app/modules/incidents/components/list/list.component.html create mode 100644 src/app/modules/incidents/components/list/list.component.scss create mode 100644 src/app/modules/incidents/components/list/list.component.ts create mode 100644 src/app/modules/incidents/incidents.module.ts diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 940ea2b..35528e9 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -20,6 +20,11 @@ const routes: Routes = [ loadChildren: () => import('./modules/transaction/transaction.module').then((m) => m.TransactionModule), }, + { + path: 'incidents', + loadChildren: () => + import('./modules/incidents/incidents.module').then((m) => m.IncidentsModule), + }, ]; @NgModule({ diff --git a/src/app/app.component.ts b/src/app/app.component.ts index 7722c71..e5de4e7 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -31,6 +31,10 @@ export class AppComponent implements OnInit, OnDestroy { path: 'applications', text: 'MENU.APPLICATIONS', }, + { + path: 'incidents', + text: 'MENU.INCIDNETS', + }, ]; private readonly STORAGE_KEY = 'LANG'; diff --git a/src/app/modules/agents/agents.module.ts b/src/app/modules/agents/agents.module.ts index 6c9a403..2b8c516 100644 --- a/src/app/modules/agents/agents.module.ts +++ b/src/app/modules/agents/agents.module.ts @@ -13,6 +13,7 @@ import { OwlDateTimeModule, OwlNativeDateTimeModule } from '@busacca/ng-pick-dat import { ReactiveFormsModule } from '@angular/forms'; import { MatInputModule } from '@angular/material/input'; import { TranslateModule } from '@ngx-translate/core'; +import { RulesModule } from 'src/app/shared/modules/rules/rules.module'; const routes: Routes = [ { @@ -49,6 +50,7 @@ const routes: Routes = [ OwlNativeDateTimeModule, ReactiveFormsModule, MatInputModule, + RulesModule, TranslateModule.forChild({}), ], declarations: [AgentsComponent], diff --git a/src/app/modules/agents/components/overview/agents.component.html b/src/app/modules/agents/components/overview/agents.component.html index 9edbd95..f13ab05 100644 --- a/src/app/modules/agents/components/overview/agents.component.html +++ b/src/app/modules/agents/components/overview/agents.component.html @@ -15,10 +15,11 @@
- - - + + @@ -44,9 +44,11 @@ [errorStateMatcher]="errorMatcher" > - {{ 'ERRORS.dateToLessThenFrom' | translate }} + + {{ + 'ERRORS.dateToLessThenFrom' | translate + }} + @@ -59,9 +61,11 @@ [errorStateMatcher]="errorMatcher" > - {{ 'ERRORS.dateToLessThenFrom' | translate }} + + {{ + 'ERRORS.dateToLessThenFrom' | translate + }} + @@ -73,7 +77,17 @@
- - {{ 'MODULES.AGENT.PAGE.HOME_LABEL' | translate }} -
+ + + + {{ 'MODULES.CHECKERS.PAGE.INCIDENT_RULES' | translate }} + + + + + + + + {{ 'MODULES.AGENT.PAGE.HOME_LABEL' | translate }} + diff --git a/src/app/modules/agents/components/overview/agents.component.ts b/src/app/modules/agents/components/overview/agents.component.ts index 3c85ae5..2e089f8 100644 --- a/src/app/modules/agents/components/overview/agents.component.ts +++ b/src/app/modules/agents/components/overview/agents.component.ts @@ -9,6 +9,7 @@ import { ErrorStateMatcher } from '@angular/material/core'; import { FormControl, FormGroupDirective, NgForm, Validators, FormBuilder } from '@angular/forms'; import { minusMinute, FormRangeValue } from 'src/app/shared/date/date'; import { dateFromToValidator } from 'src/app/shared/validators/date.validators'; +import { OwnerType } from 'src/app/shared/enums/rules.type'; class CrossFieldErrorMatcher implements ErrorStateMatcher { isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { @@ -97,6 +98,8 @@ export class AgentsComponent implements OnDestroy { [AgentsService.CPU]: 'laptop', }; + AGENT_TYPE = OwnerType.INCIDENT_OWNER_TYPE_AGENT; + constructor( private agentService: AgentsService, private route: ActivatedRoute, diff --git a/src/app/modules/applications/applications.module.ts b/src/app/modules/applications/applications.module.ts index c17bc59..c4ee07a 100644 --- a/src/app/modules/applications/applications.module.ts +++ b/src/app/modules/applications/applications.module.ts @@ -24,6 +24,7 @@ import { MatSidenavModule } from '@angular/material/sidenav'; import { QueryParamModule } from '@ngqp/core'; import { ApplicationsService } from './services/applications.service'; import { TranslateModule } from '@ngx-translate/core'; +import { RulesModule } from 'src/app/shared/modules/rules/rules.module'; const routes: Routes = [ { @@ -83,6 +84,7 @@ const routes: Routes = [ MatIconModule, MatSidenavModule, QueryParamModule, + RulesModule, TranslateModule.forChild({}), ], entryComponents: [], diff --git a/src/app/modules/applications/components/application/application.component.html b/src/app/modules/applications/components/application/application.component.html index d00c3c0..ca103eb 100644 --- a/src/app/modules/applications/components/application/application.component.html +++ b/src/app/modules/applications/components/application/application.component.html @@ -25,6 +25,15 @@ + + + {{ 'MODULES.CHECKERS.PAGE.INCIDENT_RULES' | translate }} + + + + + + {{ 'MODULES.APPLICATIONS.PAGE.TRANSACTIONS' | translate }} diff --git a/src/app/modules/applications/components/application/application.component.ts b/src/app/modules/applications/components/application/application.component.ts index 9d95ebc..b21a7b0 100644 --- a/src/app/modules/applications/components/application/application.component.ts +++ b/src/app/modules/applications/components/application/application.component.ts @@ -5,6 +5,7 @@ import { ApplicationsService } from '../../services/applications.service'; import { ApplicationStatus } from 'src/app/shared/enums/application.type'; import { Subject } from 'rxjs'; import { TranslateService } from '@ngx-translate/core'; +import { OwnerType } from 'src/app/shared/enums/rules.type'; @Component({ selector: 'sqd-application', @@ -36,6 +37,8 @@ export class ApplicationComponent implements OnDestroy { }, ]; + APPLICATION_TYPE = OwnerType.INCIDENT_OWNER_TYPE_APPLICATION; + constructor(private route: ActivatedRoute, private applicationService: ApplicationsService) {} ngOnDestroy() { diff --git a/src/app/modules/checkers/components/checker/checker.component.html b/src/app/modules/checkers/components/checker/checker.component.html index 907a3c1..aa3c2dc 100644 --- a/src/app/modules/checkers/components/checker/checker.component.html +++ b/src/app/modules/checkers/components/checker/checker.component.html @@ -1,7 +1,7 @@
- {{ 'MODULES.CHECKERS.PAGE.CONFIGURATION' | translate }} + {{ 'MODULES.CHECKERS.PAGE.CONFIGURATION' | translate }} +

+
+
+

+ {{ 'MODULES.INCIDENT.PAGE.TIME_HISTORY_ITEM' | translate }} + : {{ toDate(item.timestamp) | date: 'd/M/yyyy HH:mm:ss' }}, + {{ 'MODULES.INCIDENT.PAGE.STATUS' | translate }} + : {{ 'ENUMS.INCIDENTS.STATUS.' + item.status }} +

+
+ + + + + + + +
+ +
+
+
diff --git a/src/app/modules/incidents/components/incident/incident.component.scss b/src/app/modules/incidents/components/incident/incident.component.scss index e69de29..b83d642 100644 --- a/src/app/modules/incidents/components/incident/incident.component.scss +++ b/src/app/modules/incidents/components/incident/incident.component.scss @@ -0,0 +1,29 @@ +$padding: 40px; + +:host { + padding: $padding; + display: flex; + flex-direction: column; + mat-card { + margin-bottom: $padding/2; + + mat-card-header::ng-deep { + .mat-card-header-text { + margin: 0; + } + } + mat-card-content { + display: flex; + > div { + width: 50%; + &.history { + > p { + strong { + margin-left: $padding/4; + } + } + } + } + } + } +} diff --git a/src/app/modules/incidents/components/incident/incident.component.ts b/src/app/modules/incidents/components/incident/incident.component.ts index 0ad8315..cdf3455 100644 --- a/src/app/modules/incidents/components/incident/incident.component.ts +++ b/src/app/modules/incidents/components/incident/incident.component.ts @@ -1,8 +1,12 @@ import { Component, ChangeDetectionStrategy, OnDestroy } from '@angular/core'; -import { map, takeUntil, switchMap } from 'rxjs/operators'; -import { ActivatedRoute } from '@angular/router'; +import { map, takeUntil, switchMap, startWith } from 'rxjs/operators'; +import { ActivatedRoute, Router } from '@angular/router'; import { IncidentService } from '../../services/incident.service'; -import { Subject } from 'rxjs'; +import { Subject, combineLatest } from 'rxjs'; +import { IncidentStatus } from 'src/app/shared/enums/incident.type'; +import { RulesService } from 'src/app/shared/services/rules.service'; +import { OwnerType } from 'src/app/shared/enums/rules.type'; +import { Time, timeToDate } from 'src/app/shared/date/date'; @Component({ selector: 'sqd-incident', @@ -12,18 +16,67 @@ import { Subject } from 'rxjs'; }) export class IncidentComponent implements OnDestroy { private destoryed$ = new Subject(); + private refresh$ = new Subject(); currentId$ = this.route.params.pipe( map((p) => p.id as string), takeUntil(this.destoryed$), ); - currentIncident$ = this.currentId$.pipe( - switchMap((id: string) => this.incidentService.getById(id)), + currentIncident$ = combineLatest(this.currentId$, this.refresh$.pipe(startWith(null))).pipe( + switchMap(([id, _]) => this.incidentService.getById(id)), takeUntil(this.destoryed$), ); - constructor(private route: ActivatedRoute, private incidentService: IncidentService) {} + OPENED = IncidentStatus.INCIDENT_STATUS_OPENED; + CLOSED = IncidentStatus.INCIDENT_STATUS_CLOSED; + + constructor( + private route: ActivatedRoute, + private incidentService: IncidentService, + private rulesService: RulesService, + private router: Router, + ) {} + + close(id: string) { + this.incidentService + .close(id) + .pipe(takeUntil(this.destoryed$)) + .subscribe(() => { + this.refresh$.next(null); + }); + } + + study(id: string) { + this.incidentService + .study(id) + .pipe(takeUntil(this.destoryed$)) + .subscribe(() => { + this.refresh$.next(null); + }); + } + + goToRulePage(ruleId: string) { + this.rulesService + .getById(ruleId) + .pipe(takeUntil(this.destoryed$)) + .subscribe((rule) => { + switch (rule.ownerType) { + case OwnerType.INCIDENT_OWNER_TYPE_AGENT: + this.router.navigate(['agents', rule.ownerId]); + break; + case OwnerType.INCIDENT_OWNER_TYPE_SCHEDULER: + this.router.navigate(['checkers', rule.ownerId]); + break; + case OwnerType.INCIDENT_OWNER_TYPE_APPLICATION: + this.router.navigate(['applications', rule.ownerId]); + break; + } + }); + } + toDate(time: Time) { + return timeToDate(time); + } ngOnDestroy() { this.destoryed$.next(); diff --git a/src/app/modules/incidents/incidents.module.ts b/src/app/modules/incidents/incidents.module.ts index d23a356..40ebf67 100644 --- a/src/app/modules/incidents/incidents.module.ts +++ b/src/app/modules/incidents/incidents.module.ts @@ -14,6 +14,9 @@ import { MatFormFieldModule } from '@angular/material/form-field'; import { QueryParamModule } from '@ngqp/core'; import { MatCardModule } from '@angular/material/card'; import { MatSortModule } from '@angular/material/sort'; +import { MatProgressSpinnerModule } from '@angular/material/progress-spinner'; +import { MatButtonModule } from '@angular/material/button'; +import { MatIconModule } from '@angular/material/icon'; const routes: Routes = [ { @@ -47,6 +50,9 @@ const routes: Routes = [ MatPaginatorModule, MatFormFieldModule, QueryParamModule, + MatProgressSpinnerModule, + MatButtonModule, + MatIconModule, ], declarations: [ListComponent, IncidentComponent], }) diff --git a/src/app/modules/incidents/services/incident.service.ts b/src/app/modules/incidents/services/incident.service.ts index 015b44b..6a0fc39 100644 --- a/src/app/modules/incidents/services/incident.service.ts +++ b/src/app/modules/incidents/services/incident.service.ts @@ -40,6 +40,14 @@ export class IncidentService { }); } + close(incidentId: string) { + return this.httpClient.put(`/api/v1/incidents/${incidentId}/close`, {}); + } + + study(incidentId: string) { + return this.httpClient.put(`/api/v1/incidents/${incidentId}/study`, {}); + } + getById(incidentId: string) { return this.httpClient.get(`/api/v1/incidents/${incidentId}`); } From e582601633cfe3b9a1fb7748b5c09ec5517e9edc Mon Sep 17 00:00:00 2001 From: Iurii Panarin Date: Sun, 5 Jul 2020 01:59:21 +0200 Subject: [PATCH 10/17] scss --- .../incidents/components/incident/incident.component.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/modules/incidents/components/incident/incident.component.scss b/src/app/modules/incidents/components/incident/incident.component.scss index b83d642..9b14e50 100644 --- a/src/app/modules/incidents/components/incident/incident.component.scss +++ b/src/app/modules/incidents/components/incident/incident.component.scss @@ -26,4 +26,8 @@ $padding: 40px; } } } + .spinner-container { + display: flex; + justify-content: center; + } } From 40b740b98f94f5c66fba031cdfa578690b23fc6d Mon Sep 17 00:00:00 2001 From: Iurii Panarin Date: Sun, 5 Jul 2020 02:17:25 +0200 Subject: [PATCH 11/17] feat(incident) --- .../incidents/components/incident/incident.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/modules/incidents/components/incident/incident.component.html b/src/app/modules/incidents/components/incident/incident.component.html index 99f4b46..25c38e3 100644 --- a/src/app/modules/incidents/components/incident/incident.component.html +++ b/src/app/modules/incidents/components/incident/incident.component.html @@ -7,7 +7,7 @@

{{ 'MODULES.INCIDENT.PAGE.STATUS' | translate }} - : {{ 'ENUMS.INCIDENTS.STATUS.' + incident.status }} + : {{ 'ENUMS.INCIDENTS.STATUS.' + (incident.status || 0) }}

{{ 'MODULES.INCIDENT.PAGE.RULE_ID' | translate }} @@ -28,7 +28,7 @@ {{ 'MODULES.INCIDENT.PAGE.TIME_HISTORY_ITEM' | translate }} : {{ toDate(item.timestamp) | date: 'd/M/yyyy HH:mm:ss' }}, {{ 'MODULES.INCIDENT.PAGE.STATUS' | translate }} - : {{ 'ENUMS.INCIDENTS.STATUS.' + item.status }} + : {{ 'ENUMS.INCIDENTS.STATUS.' + (item.status || 0) }}

From 3408328abd7dc6fcd911c1f6b9d02c7e9324ec65 Mon Sep 17 00:00:00 2001 From: Iurii Panarin Date: Sun, 5 Jul 2020 18:43:34 +0200 Subject: [PATCH 12/17] feat(translate): add translation --- src/assets/i18n/en.json | 8 ++++++ src/assets/i18n/ru.json | 60 +++++++++++++++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index f18f800..04a238e 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -288,6 +288,14 @@ } }, "INCIDENTS": { + "PAGE": { + "TITLE": "Incident", + "STATUS": "Status", + "RULE_ID": "Rule Id", + "TIME_HISTORY_ITEM": "Timestamp", + "BTN_STUDY": "Study incident", + "BTN_CLOSE": "Close incident" + }, "LIST": { "TABLE_TITLE": "Table of incidents", "ID": "Id", diff --git a/src/assets/i18n/ru.json b/src/assets/i18n/ru.json index 5453e1f..3877c14 100644 --- a/src/assets/i18n/ru.json +++ b/src/assets/i18n/ru.json @@ -31,14 +31,33 @@ "notValidUrl": "Не валидный url", "minConcurrency": "Должно быть больше нуля", "minStatusCode": "Статус код должен быть больше нуля", - "maxStatusCode": "Статус код должен быть меньше 503" + "maxStatusCode": "Статус код должен быть меньше 503", + "ruleNotValid": "Правило не правильно" }, "MENU": { "AGENTS": "Агенты", "CHECKERS": "Чекеры", - "APPLICATIONS": "Приложения" + "APPLICATIONS": "Приложения", + "INCIDNETS": "Инциденты" }, "ENUMS": { + "INCIDENTS": { + "STATUS": { + "0": "Неопределенный", + "1": "Открытый", + "2": "Узучаемый", + "3": "Можно закрыть", + "4": "Закрытый" + } + }, + "RULES": { + "STATUS": { + "0": "Неопределенный", + "1": "Активный", + "2": "Неактивный", + "3": "Удаленный" + } + }, "AGENTS": { "STATUS": { "0": "Неопределенный", @@ -143,6 +162,25 @@ "ADD_BUTTON": "Добавить", "PUT_PATH": "Добавить селектор", "NEW_HEADER": "Добавить заголовки" + }, + "ADD_RULE": { + "AUTOCLOSE": "Закрывать автоматически инцидент", + "NAME_HINT": "Лучше выбирать уникальное имя", + "PROVIDE_RULE": "Укажите правило инцидента", + "RULE_HINT": "Примеры можете найти здесь", + "RULE_URL": "Примеры правил", + "SELECT_NAME": "Укажите имя", + "TITLE": "Добавить правило" + } + }, + "RULES": { + "TABLE": { + "ADD": " Добавить", + "AUTO_CLOSE": "Автозакрытие", + "INCIDENTS_LIST": "Список инцидентов", + "NAME": "Имя", + "REMOVE": "Удалить", + "STATUS": "Статус" } }, "STATS": { @@ -249,6 +287,23 @@ "STATUS": "Статус" } }, + "INCIDENTS": { + "LIST": { + "DURATION": "Продолжительность", + "ID": "Идентификатор", + "RULE_ID": "Идентификатор правила", + "STATUS": "Статус", + "TABLE_TITLE": "Таблица инцидентов" + }, + "PAGE": { + "BTN_CLOSE": "Закрыть инцидент", + "BTN_STUDY": "Изучить инцидент", + "RULE_ID": "Идентификатор правила", + "STATUS": "Стутус", + "TIME_HISTORY_ITEM": "Время", + "TITLE": "Инцидент" + } + }, "CHECKERS": { "TABLE": { "ID": "Идентификатор", @@ -267,6 +322,7 @@ "STOP": "Остановить", "REMOVE": "Удалить", "ID": "Идентификатор", + "INCIDENT_RULES": "Правила для инцидентов", "NAME": "Имя", "TYPE": "Тип", "STATUS": "Статус", From 1d838258794b56a81cfb074cb15bdcfbe83f535c Mon Sep 17 00:00:00 2001 From: Iurii Panarin Date: Mon, 6 Jul 2020 00:06:35 +0200 Subject: [PATCH 13/17] feat(rule): add examples --- .../add-rule.component.html | 21 +++++++++++++++- .../add-rule.component.scss | 14 +++++++++++ .../add-rule-component/add-rule.component.ts | 24 +++++++++++++++++++ .../shared/modules/modals/modals.module.ts | 2 ++ src/app/shared/numbers/numbers.ts | 2 +- src/assets/i18n/en.json | 7 ++++-- src/assets/i18n/ru.json | 7 ++++-- 7 files changed, 71 insertions(+), 6 deletions(-) diff --git a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.html b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.html index 5b93e0f..ef13e3b 100644 --- a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.html +++ b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.html @@ -25,7 +25,10 @@ > {{ 'MODULES.MODALS.ADD_RULE.RULE_HINT' | translate }}: - + {{ 'MODULES.MODALS.ADD_RULE.RULE_URL' | translate }} @@ -42,6 +45,22 @@ }} + +
{{ 'MODULES.MODALS.ADD_RULE.EXAMPLES' | translate }}
+ + done +
{{example.value}}
+
{{example.description | translate}}
+
+
{{ errorValidation | json }}
{{ diff --git a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.scss b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.scss index f769e84..1f3809f 100644 --- a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.scss +++ b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.scss @@ -1,3 +1,5 @@ +@import 'src/theme/colors.scss'; + mat-card-content { display: flex; flex-direction: column; @@ -19,4 +21,16 @@ mat-card { margin-top: 10px; display: flex; } + .example-item { + &:hover { + background-color: mat-color($primary, 50); + cursor: pointer; + } + .example-value { + font-weight: bold; + } + .example-description { + color: mat-color($accent, 800); + } + } } diff --git a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts index de50fc8..bdc4601 100644 --- a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts +++ b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts @@ -12,6 +12,11 @@ export interface AddRuleData { ownerId: string; } +interface Example { + description: string; + value: string; +} + @Component({ selector: 'sqd-dialog-add-rule', templateUrl: './add-rule.component.html', @@ -25,6 +30,19 @@ export class AddRuleFormComponent implements OnDestroy { validationErrors$ = this.ruleValidationErrMsg.asObservable(); + examples: { [key: string]: Array } = { + [`${OwnerType.INCIDENT_OWNER_TYPE_SCHEDULER}`]: [ + { + description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_SCHEDULER_LAST_TWO_OK', + value: 'all(map(Last(2), {.Code}), { # == Error })', + }, + { + description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_SCHEDULER_LAST_SIX_OK', + value: 'count(map(Last(6), {.Code}), { # == Error}) > 3', + }, + ], + }; + form = this.fb.group({ name: ['', Validators.compose([Validators.required])], rule: [ @@ -61,6 +79,12 @@ export class AddRuleFormComponent implements OnDestroy { }); } + applyRule(ruleValue: string) { + this.form.patchValue({ + rule: ruleValue, + }); + } + ngOnDestroy() { this.destroyed$.next(); } diff --git a/src/app/shared/modules/modals/modals.module.ts b/src/app/shared/modules/modals/modals.module.ts index 7729a02..3de303d 100644 --- a/src/app/shared/modules/modals/modals.module.ts +++ b/src/app/shared/modules/modals/modals.module.ts @@ -16,6 +16,7 @@ import { AddRuleService } from './add-rule/add-rule.service'; import { AddRuleFormComponent } from './add-rule/add-rule-component/add-rule.component'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { RuleValidator } from './add-rule/validators/rule.validator'; +import { MatListModule } from '@angular/material/list'; @NgModule({ imports: [ @@ -31,6 +32,7 @@ import { RuleValidator } from './add-rule/validators/rule.validator'; MatIconModule, MatCheckboxModule, TranslateModule.forChild({}), + MatListModule, ], exports: [], providers: [AddCheckerService, AddRuleService], diff --git a/src/app/shared/numbers/numbers.ts b/src/app/shared/numbers/numbers.ts index 91a4f1d..90cefd1 100644 --- a/src/app/shared/numbers/numbers.ts +++ b/src/app/shared/numbers/numbers.ts @@ -5,7 +5,7 @@ export const roundNumber = (value: number, countNumber = 2) => { export const getRoundedPercent = (value: number, count = 2) => { if (isNaN(value)) { - return `100 %`; + return `NaN`; } return `${roundNumber(value, count) * 100} %`; }; diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 04a238e..389c274 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -143,12 +143,15 @@ "MODULES": { "MODALS": { "ADD_RULE": { + "EXAMPLES": "Examples", + "EXAMPLE_SCHEDULER_LAST_TWO_OK": "Last two schedulers(both) return success", + "EXAMPLE_SCHEDULER_LAST_SIX_OK": "Errors in last 6 schedulers record > 3", "TITLE": "Add rule", "SELECT_NAME": "Provide name", "NAME_HINT": "Better provide uniq name", "PROVIDE_RULE": "Provide rule", - "RULE_HINT": "Rules example you can find here", - "RULE_URL": "Rules examples", + "RULE_HINT": "Language Definition you can find by link", + "RULE_URL": "Here", "AUTOCLOSE": "Auto-close incident" }, "ADD_CHECKER": { diff --git a/src/assets/i18n/ru.json b/src/assets/i18n/ru.json index 3877c14..d5ed7e1 100644 --- a/src/assets/i18n/ru.json +++ b/src/assets/i18n/ru.json @@ -164,11 +164,14 @@ "NEW_HEADER": "Добавить заголовки" }, "ADD_RULE": { + "EXAMPLES": "Примеры", + "EXAMPLE_SCHEDULER_LAST_TWO_OK": "Две последних проверки вернули success(обе)", + "EXAMPLE_SCHEDULER_LAST_SIX_OK": "В последних 6 записях больше 3 ошибок", "AUTOCLOSE": "Закрывать автоматически инцидент", "NAME_HINT": "Лучше выбирать уникальное имя", "PROVIDE_RULE": "Укажите правило инцидента", - "RULE_HINT": "Примеры можете найти здесь", - "RULE_URL": "Примеры правил", + "RULE_HINT": "Описание языка можете найти по ссылке", + "RULE_URL": "Здесь", "SELECT_NAME": "Укажите имя", "TITLE": "Добавить правило" } From ed917ddcb61888b50c5d0714defa4a4c038ef55a Mon Sep 17 00:00:00 2001 From: Iurii Panarin Date: Mon, 6 Jul 2020 00:08:15 +0200 Subject: [PATCH 14/17] fix(transalte) --- .../modals/add-rule/add-rule-component/add-rule.component.ts | 4 ++-- src/assets/i18n/en.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts index bdc4601..643a4f7 100644 --- a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts +++ b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts @@ -33,11 +33,11 @@ export class AddRuleFormComponent implements OnDestroy { examples: { [key: string]: Array } = { [`${OwnerType.INCIDENT_OWNER_TYPE_SCHEDULER}`]: [ { - description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_SCHEDULER_LAST_TWO_OK', + description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_SCHEDULER_LAST_TWO', value: 'all(map(Last(2), {.Code}), { # == Error })', }, { - description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_SCHEDULER_LAST_SIX_OK', + description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_SCHEDULER_LAST_SIX', value: 'count(map(Last(6), {.Code}), { # == Error}) > 3', }, ], diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 389c274..17248dc 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -144,8 +144,8 @@ "MODALS": { "ADD_RULE": { "EXAMPLES": "Examples", - "EXAMPLE_SCHEDULER_LAST_TWO_OK": "Last two schedulers(both) return success", - "EXAMPLE_SCHEDULER_LAST_SIX_OK": "Errors in last 6 schedulers record > 3", + "EXAMPLE_SCHEDULER_LAST_TWO": "Last two schedulers(both) return error", + "EXAMPLE_SCHEDULER_LAST_SIX": "Errors in last 6 schedulers record > 3", "TITLE": "Add rule", "SELECT_NAME": "Provide name", "NAME_HINT": "Better provide uniq name", From 5df46c43f8058e5af5b6d84f249943cf3dec6512 Mon Sep 17 00:00:00 2001 From: Iurii Panarin Date: Tue, 7 Jul 2020 01:39:29 +0200 Subject: [PATCH 15/17] feat(incident): fix table --- .../components/overview/agents.component.html | 122 +++++++++--------- .../transaction-list/list.component.scss | 1 + .../incident/incident.component.html | 18 +-- .../components/incident/incident.component.ts | 8 +- .../components/list/list.component.html | 44 +++---- .../components/list/list.component.scss | 3 + .../components/list/list.component.ts | 27 +++- src/app/shared/interfaces/rules.interfaces.ts | 4 +- .../add-rule.component.html | 2 + .../add-rule.component.scss | 1 + .../add-rule-component/add-rule.component.ts | 30 +++++ src/assets/i18n/en.json | 7 + src/assets/i18n/ru.json | 7 + 13 files changed, 170 insertions(+), 104 deletions(-) diff --git a/src/app/modules/agents/components/overview/agents.component.html b/src/app/modules/agents/components/overview/agents.component.html index f13ab05..a61b60a 100644 --- a/src/app/modules/agents/components/overview/agents.component.html +++ b/src/app/modules/agents/components/overview/agents.component.html @@ -15,11 +15,10 @@
- - -
- - - - - - {{ - 'ERRORS.dateToLessThenFrom' | translate - }} - - - - - - - - {{ - 'ERRORS.dateToLessThenFrom' | translate - }} - - -
+
+ + +
+ + + + + {{ 'ERRORS.dateToLessThenFrom' | translate }} + + + + + + {{ 'ERRORS.dateToLessThenFrom' | translate }} + +
-
- - - - - -
-
-
- - - {{ 'MODULES.CHECKERS.PAGE.INCIDENT_RULES' | translate }} - - - - - +
+ + + + + +
+ + + + + {{ 'MODULES.CHECKERS.PAGE.INCIDENT_RULES' | translate }} + + + + + +
+ {{ 'MODULES.AGENT.PAGE.HOME_LABEL' | translate }} diff --git a/src/app/modules/applications/components/transaction-list/list.component.scss b/src/app/modules/applications/components/transaction-list/list.component.scss index 2000812..cf8dc88 100644 --- a/src/app/modules/applications/components/transaction-list/list.component.scss +++ b/src/app/modules/applications/components/transaction-list/list.component.scss @@ -1,5 +1,6 @@ table { display: block; + overflow-x: scroll; .mat-row { &:hover { cursor: pointer; diff --git a/src/app/modules/incidents/components/incident/incident.component.html b/src/app/modules/incidents/components/incident/incident.component.html index 25c38e3..fdb9434 100644 --- a/src/app/modules/incidents/components/incident/incident.component.html +++ b/src/app/modules/incidents/components/incident/incident.component.html @@ -1,16 +1,16 @@ - {{ 'MODULES.INCIDENT.PAGE.TITLE' | translate }} #{{ incident.id }} + {{ 'MODULES.INCIDENTS.PAGE.TITLE' | translate }} #{{ incident.id }}

- {{ 'MODULES.INCIDENT.PAGE.STATUS' | translate }} - : {{ 'ENUMS.INCIDENTS.STATUS.' + (incident.status || 0) }} + {{ 'MODULES.INCIDENTS.PAGE.STATUS' | translate }} + : {{ 'ENUMS.INCIDENTS.STATUS.' + (incident.status || 0) | translate}}

- {{ 'MODULES.INCIDENT.PAGE.RULE_ID' | translate }} + {{ 'MODULES.INCIDENTS.PAGE.RULE_ID' | translate }} : {{ incident.rule_id }} + >{{ 'MODULES.INCIDENTS.PAGE.BTN_STUDY' | translate }} + >{{ 'MODULES.INCIDENTS.PAGE.BTN_CLOSE' | translate }} diff --git a/src/app/modules/incidents/components/incident/incident.component.ts b/src/app/modules/incidents/components/incident/incident.component.ts index cdf3455..f1825e2 100644 --- a/src/app/modules/incidents/components/incident/incident.component.ts +++ b/src/app/modules/incidents/components/incident/incident.component.ts @@ -61,15 +61,15 @@ export class IncidentComponent implements OnDestroy { .getById(ruleId) .pipe(takeUntil(this.destoryed$)) .subscribe((rule) => { - switch (rule.ownerType) { + switch (rule.owner_type) { case OwnerType.INCIDENT_OWNER_TYPE_AGENT: - this.router.navigate(['agents', rule.ownerId]); + this.router.navigate(['agents', rule.owner_id]); break; case OwnerType.INCIDENT_OWNER_TYPE_SCHEDULER: - this.router.navigate(['checkers', rule.ownerId]); + this.router.navigate(['checkers', rule.owner_id]); break; case OwnerType.INCIDENT_OWNER_TYPE_APPLICATION: - this.router.navigate(['applications', rule.ownerId]); + this.router.navigate(['applications', rule.owner_id]); break; } }); diff --git a/src/app/modules/incidents/components/list/list.component.html b/src/app/modules/incidents/components/list/list.component.html index 6baafa2..9d6b284 100644 --- a/src/app/modules/incidents/components/list/list.component.html +++ b/src/app/modules/incidents/components/list/list.component.html @@ -24,10 +24,11 @@ - {{ toDate(element.start_time) | date: 'd/M/yyyy HH:mm:ss' }} + + {{ toDate(startTime) | date: 'd/M/yyyy HH:mm:ss' }} + @@ -44,20 +45,11 @@ - {{ toDate(element.end_time) | date: 'd/M/yyyy HH:mm:ss' }} - - - - - - {{ 'MODULES.INCIDENTS.LIST.RULE_ID' | translate}} - - - - {{ element.name }} + + {{ toDate(endTime) | date: 'd/M/yyyy HH:mm:ss' }} + @@ -79,14 +71,20 @@ - {{ 'MODULES.INCIDENTS.LIST.DURATION' | translate}} + {{ 'MODULES.INCIDENTS.LIST.DURATION' | translate}} {{ getDuration(element) }} + + + + {{ 'MODULES.INCIDENTS.LIST.RULE_ID' | translate}} + + + + {{ element.rule_id }} + + diff --git a/src/app/modules/incidents/components/list/list.component.scss b/src/app/modules/incidents/components/list/list.component.scss index d79ec89..06469a0 100644 --- a/src/app/modules/incidents/components/list/list.component.scss +++ b/src/app/modules/incidents/components/list/list.component.scss @@ -5,6 +5,9 @@ $padding: 40px; display: flex; justify-content: center; flex-direction: column; + mat-form-field { + width: 100%; + } table { display: block; .mat-row { diff --git a/src/app/modules/incidents/components/list/list.component.ts b/src/app/modules/incidents/components/list/list.component.ts index b0c33ec..19c6255 100644 --- a/src/app/modules/incidents/components/list/list.component.ts +++ b/src/app/modules/incidents/components/list/list.component.ts @@ -21,9 +21,10 @@ import { takeUntil, switchMap } from 'rxjs/operators'; import { IncidentListDataSource } from './datasources/list.datasource'; import { IncidentService } from '../../services/incident.service'; import { MatSelectChange } from '@angular/material/select'; -import { timeToDate, Time, diffInSec } from 'src/app/shared/date/date'; +import { timeToDate, Time, diffInSec, SECOND } from 'src/app/shared/date/date'; import { Incident } from 'src/app/shared/interfaces/incident.interfaces'; import { TranslateService } from '@ngx-translate/core'; +import { roundNumber } from 'src/app/shared/numbers/numbers'; @Component({ selector: 'sqd-incident-list', @@ -63,7 +64,7 @@ export class ListComponent implements AfterViewInit, OnInit, OnDestroy { IncidentStatus.INCIDENT_STATUS_STUDIED, ]; - displayedColumns: string[] = ['Id', 'StartTime', 'EndTime', 'RuleId', 'Status', 'Duration']; + displayedColumns: string[] = ['Id', 'StartTime', 'EndTime', 'Status', 'Duration', 'RuleId']; @ViewChild(MatPaginator, { static: true }) paginator: MatPaginator; @ViewChild(MatSort, { static: true }) sort: MatSort; @@ -215,6 +216,20 @@ export class ListComponent implements AfterViewInit, OnInit, OnDestroy { return timeToDate(time); } + getStartTime(incident: Incident): Time | false { + return incident.histories && incident.histories[0] && incident.histories[0].timestamp; + } + + getEndTime(incident: Incident): Time | false { + const index = (incident.histories || []).findIndex( + (item) => item.status === IncidentStatus.INCIDENT_STATUS_CLOSED, + ); + if (index !== -1) { + return incident.histories[index].timestamp; + } + return false; + } + getDuration(incident: Incident) { const index = (incident.histories || []).findIndex( (e) => e.status === IncidentStatus.INCIDENT_STATUS_CLOSED, @@ -222,10 +237,10 @@ export class ListComponent implements AfterViewInit, OnInit, OnDestroy { if (index === -1) { return '-'; } - return `${diffInSec( - incident.histories[index].timestamp, - incident.histories[0].timestamp, - )} ${this.translateService.instant('LABELS.SEC')}`; + return `${roundNumber( + diffInSec(incident.histories[index].timestamp, incident.histories[0].timestamp) / SECOND, + 3, + )} ${this.translateService.instant('LABELS.SECOND')}`; } clickRow(incident: Incident) { diff --git a/src/app/shared/interfaces/rules.interfaces.ts b/src/app/shared/interfaces/rules.interfaces.ts index 9dc4836..aced19a 100644 --- a/src/app/shared/interfaces/rules.interfaces.ts +++ b/src/app/shared/interfaces/rules.interfaces.ts @@ -6,6 +6,6 @@ export interface Rule { name: string; auto_close: boolean; status: RuleStatus; - ownerType: OwnerType; - ownerId: string; + owner_type: OwnerType; + owner_id: string; } diff --git a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.html b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.html index ef13e3b..12d30ea 100644 --- a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.html +++ b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.html @@ -24,6 +24,8 @@ formControlName="rule" > + {{ 'MODULES.MODALS.ADD_RULE.RULE_HINT_BOOL' | translate }} +
{{ 'MODULES.MODALS.ADD_RULE.RULE_HINT' | translate }}: 3', }, + { + description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_SCHEDULER_DURATION', + value: 'any(map(Last(2), { Duration(#)}), { # > 30 })', + }, + ], + [`${OwnerType.INCIDENT_OWNER_TYPE_AGENT}`]: [ + { + description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_AGENT_CPU_LOAD', + value: 'any(map(Last(1, UseType(CPU)), {.CpuInfo.Cpus})[0], {.Load > 20})', + }, + { + value: 'any(map(Last(1, UseType(Memory)), {.MemoryInfo.Mem.UsedPercent}), { # > 50})', + description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_AGENT_MEMORY_LOAD', + }, + { + value: + 'any(map(Last(1, UseType(Disk)), {.DiskInfo.Disks["/System/Volumes/Data"].UsedPercent}), { # > 50})', + description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_AGENT_DISK_LOAD', + }, + ], + [`${OwnerType.INCIDENT_OWNER_TYPE_APPLICATION}`]: [ + { + description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_APPLICATION_FAILED_TRANSACTION', + value: 'all(map(Last(2, UseName(\'/times\')), {.Status}), { # == Failed})', + }, + { + value: + 'all(map(Last(2, UseMethod(\'GET\'), UseName(\'/times\')), { Duration(#)}), { # > 3000})', + description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_APPLICATION_DURATION_TRANSACTION', + }, ], }; diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 17248dc..19ad9c7 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -146,11 +146,18 @@ "EXAMPLES": "Examples", "EXAMPLE_SCHEDULER_LAST_TWO": "Last two schedulers(both) return error", "EXAMPLE_SCHEDULER_LAST_SIX": "Errors in last 6 schedulers record > 3", + "EXAMPLE_SCHEDULER_DURATION": "In last two schedulers one and more element have duration more > 30 msec", + "EXAMPLE_AGENT_CPU_LOAD": "Any CPU have load more than 0.2", + "EXAMPLE_AGENT_MEMORY_LOAD": "Memory used percent more than 50%", + "EXAMPLE_AGENT_DISK_LOAD": "Disk '/System/Volumes/Data' used percent more than 50%", + "EXAMPLE_APPLICATION_FAILED_TRANSACTION": "Last two transaction with name '/times' was failed", + "EXAMPLE_APPLICATION_DURATION_TRANSACTION": "Last two transation with name '/times' and method 'GET' was more than 3000msec", "TITLE": "Add rule", "SELECT_NAME": "Provide name", "NAME_HINT": "Better provide uniq name", "PROVIDE_RULE": "Provide rule", "RULE_HINT": "Language Definition you can find by link", + "RULE_HINT_BOOL": "Rule should be expression which return boolean", "RULE_URL": "Here", "AUTOCLOSE": "Auto-close incident" }, diff --git a/src/assets/i18n/ru.json b/src/assets/i18n/ru.json index d5ed7e1..d64e2ef 100644 --- a/src/assets/i18n/ru.json +++ b/src/assets/i18n/ru.json @@ -167,10 +167,17 @@ "EXAMPLES": "Примеры", "EXAMPLE_SCHEDULER_LAST_TWO_OK": "Две последних проверки вернули success(обе)", "EXAMPLE_SCHEDULER_LAST_SIX_OK": "В последних 6 записях больше 3 ошибок", + "EXAMPLE_SCHEDULER_DURATION": "В двух последних записях хотя бы одна проверлась дольше 30 мсек", + "EXAMPLE_AGENT_CPU_LOAD": "Любой процессор имеет нагрузку больше чем 0.2", + "EXAMPLE_AGENT_MEMORY_LOAD": "Занято памяти больше 50%", + "EXAMPLE_AGENT_DISK_LOAD": "Диск '/System/Volumes/Data' заполнен больше чем на 50 процентов", + "EXAMPLE_APPLICATION_FAILED_TRANSACTION": "Две последнии транзакции с именем '/times' были с ошибкой", + "EXAMPLE_APPLICATION_DURATION_TRANSACTION": "Две последнии транзакции с именем '/times' и методов 'GET' были дольше чем 3000мсек", "AUTOCLOSE": "Закрывать автоматически инцидент", "NAME_HINT": "Лучше выбирать уникальное имя", "PROVIDE_RULE": "Укажите правило инцидента", "RULE_HINT": "Описание языка можете найти по ссылке", + "RULE_HINT_BOOL": "Правило должно возвращать boolean", "RULE_URL": "Здесь", "SELECT_NAME": "Укажите имя", "TITLE": "Добавить правило" From 9df7a41b92bc4f8988c1af3dfa4db2fc43842590 Mon Sep 17 00:00:00 2001 From: Iurii Panarin Date: Tue, 7 Jul 2020 19:58:13 +0200 Subject: [PATCH 16/17] feat(rules) --- .../add-rule-component/add-rule.component.ts | 18 ++++++++++++++++-- src/assets/i18n/en.json | 6 ++++-- src/assets/i18n/ru.json | 8 +++++--- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts index 6187cef..fb92f9f 100644 --- a/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts +++ b/src/app/shared/modules/modals/add-rule/add-rule-component/add-rule.component.ts @@ -36,6 +36,10 @@ export class AddRuleFormComponent implements OnDestroy { description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_SCHEDULER_LAST_TWO', value: 'all(map(Last(2), {.Code}), { # == Error })', }, + { + description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_SCHEDULER_LAST_TWO_STRICT', + value: 'len(filter(map(Last(2), {.Code}), { # == Error })) == 2', + }, { description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_SCHEDULER_LAST_SIX', value: 'count(map(Last(6), {.Code}), { # == Error}) > 3', @@ -48,7 +52,12 @@ export class AddRuleFormComponent implements OnDestroy { [`${OwnerType.INCIDENT_OWNER_TYPE_AGENT}`]: [ { description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_AGENT_CPU_LOAD', - value: 'any(map(Last(1, UseType(CPU)), {.CpuInfo.Cpus})[0], {.Load > 20})', + value: 'any(Last(3, UseType(CPU)), {any(.CpuInfo.Cpus, {.Load > 10})})', + }, + { + description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_AGENT_CPU_LOAD_STRICT', + value: + 'len(filter(map(Last(3, UseType(CPU)), {all(.CpuInfo.Cpus, {.Load > 10})}), { # == true })) == 3', }, { value: 'any(map(Last(1, UseType(Memory)), {.MemoryInfo.Mem.UsedPercent}), { # > 50})', @@ -56,7 +65,12 @@ export class AddRuleFormComponent implements OnDestroy { }, { value: - 'any(map(Last(1, UseType(Disk)), {.DiskInfo.Disks["/System/Volumes/Data"].UsedPercent}), { # > 50})', + 'any(Last(1, UseType(Disk)), {.DiskInfo.Disks["/System/Volumes/Data"].UsedPercent}), { # > 50})', + description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_AGENT_DISK_LOAD', + }, + { + value: + 'any(Last(1, UseType(Disk)), {.DiskInfo.Disks["/System/Volumes/Data"].UsedPercent > 50})', description: 'MODULES.MODALS.ADD_RULE.EXAMPLE_AGENT_DISK_LOAD', }, ], diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json index 19ad9c7..ec4346e 100644 --- a/src/assets/i18n/en.json +++ b/src/assets/i18n/en.json @@ -145,11 +145,13 @@ "ADD_RULE": { "EXAMPLES": "Examples", "EXAMPLE_SCHEDULER_LAST_TWO": "Last two schedulers(both) return error", + "EXAMPLE_SCHEDULER_LAST_TWO_STRICT": "Last strict two schedulers(both) return error", "EXAMPLE_SCHEDULER_LAST_SIX": "Errors in last 6 schedulers record > 3", "EXAMPLE_SCHEDULER_DURATION": "In last two schedulers one and more element have duration more > 30 msec", - "EXAMPLE_AGENT_CPU_LOAD": "Any CPU have load more than 0.2", + "EXAMPLE_AGENT_CPU_LOAD": "Any CPU in last 3 checks have load more than 10%", + "EXAMPLE_AGENT_CPU_LOAD_STRICT": "All CPU in last 3 checks have load more than 10% and check was done more than 3(in all time)", "EXAMPLE_AGENT_MEMORY_LOAD": "Memory used percent more than 50%", - "EXAMPLE_AGENT_DISK_LOAD": "Disk '/System/Volumes/Data' used percent more than 50%", + "EXAMPLE_AGENT_DISK_LOAD": "In last 1 check disk '/System/Volumes/Data' used percent more than 50%", "EXAMPLE_APPLICATION_FAILED_TRANSACTION": "Last two transaction with name '/times' was failed", "EXAMPLE_APPLICATION_DURATION_TRANSACTION": "Last two transation with name '/times' and method 'GET' was more than 3000msec", "TITLE": "Add rule", diff --git a/src/assets/i18n/ru.json b/src/assets/i18n/ru.json index d64e2ef..c615450 100644 --- a/src/assets/i18n/ru.json +++ b/src/assets/i18n/ru.json @@ -165,12 +165,14 @@ }, "ADD_RULE": { "EXAMPLES": "Примеры", - "EXAMPLE_SCHEDULER_LAST_TWO_OK": "Две последних проверки вернули success(обе)", + "EXAMPLE_SCHEDULER_LAST_TWO_OK": "Две последних проверки вернули ошибку(обе)", + "EXAMPLE_SCHEDULER_LAST_TWO_STRICT": "Строго две последнии проверки вернули ошибку(обе)", "EXAMPLE_SCHEDULER_LAST_SIX_OK": "В последних 6 записях больше 3 ошибок", "EXAMPLE_SCHEDULER_DURATION": "В двух последних записях хотя бы одна проверлась дольше 30 мсек", - "EXAMPLE_AGENT_CPU_LOAD": "Любой процессор имеет нагрузку больше чем 0.2", + "EXAMPLE_AGENT_CPU_LOAD": "Любой процессор в последнии 3 проверки имеет нагрузку больше чем 10%", + "EXAMPLE_AGENT_CPU_LOAD_STRICT": "Все процессоры в посленднии 3 проверки имеет нагрузку больше чем 10% и было сделано проверок больше 3(за все время)", "EXAMPLE_AGENT_MEMORY_LOAD": "Занято памяти больше 50%", - "EXAMPLE_AGENT_DISK_LOAD": "Диск '/System/Volumes/Data' заполнен больше чем на 50 процентов", + "EXAMPLE_AGENT_DISK_LOAD": "В последней проверке диск '/System/Volumes/Data' заполнен больше чем на 50%", "EXAMPLE_APPLICATION_FAILED_TRANSACTION": "Две последнии транзакции с именем '/times' были с ошибкой", "EXAMPLE_APPLICATION_DURATION_TRANSACTION": "Две последнии транзакции с именем '/times' и методов 'GET' были дольше чем 3000мсек", "AUTOCLOSE": "Закрывать автоматически инцидент", From f6f24c10e7f2dc1b2ce4139aa59ae3fc8150cc3e Mon Sep 17 00:00:00 2001 From: Iurii Panarin Date: Tue, 7 Jul 2020 21:16:15 +0200 Subject: [PATCH 17/17] fix(nan): owerview --- src/app/shared/numbers/numbers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/shared/numbers/numbers.ts b/src/app/shared/numbers/numbers.ts index 90cefd1..cfa9212 100644 --- a/src/app/shared/numbers/numbers.ts +++ b/src/app/shared/numbers/numbers.ts @@ -5,7 +5,7 @@ export const roundNumber = (value: number, countNumber = 2) => { export const getRoundedPercent = (value: number, count = 2) => { if (isNaN(value)) { - return `NaN`; + return `0 %`; } return `${roundNumber(value, count) * 100} %`; };