mirror of
https://github.com/fabioformosa/quartz-manager.git
synced 2026-05-15 06:10:29 +09:00
Merge branch 'feature/#101_angular15_update' into develop
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -1,3 +1,4 @@
|
|||||||
/.project
|
/.project
|
||||||
.idea
|
.idea
|
||||||
*.iml
|
*.iml
|
||||||
|
.DS_Store
|
||||||
|
|||||||
@@ -26,7 +26,8 @@
|
|||||||
"src/favicon.ico"
|
"src/favicon.ico"
|
||||||
],
|
],
|
||||||
"styles": [
|
"styles": [
|
||||||
"src/styles.css"
|
"src/styles.css",
|
||||||
|
"node_modules/roboto-fontface/css/roboto/roboto-fontface.css"
|
||||||
],
|
],
|
||||||
"scripts": []
|
"scripts": []
|
||||||
},
|
},
|
||||||
|
|||||||
21542
quartz-manager-frontend/package-lock.json
generated
21542
quartz-manager-frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -14,20 +14,20 @@
|
|||||||
},
|
},
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular-material-components/datetime-picker": "8.0.0",
|
"@angular-material-components/datetime-picker": "15.0.0",
|
||||||
"@angular-material-components/moment-adapter": "8.0.0",
|
"@angular-material-components/moment-adapter": "15.0.0",
|
||||||
"@angular/animations": "14.2.12",
|
"@angular/animations": "15.2.10",
|
||||||
"@angular/cdk": "^14.0.1",
|
"@angular/cdk": "15.0.1",
|
||||||
"@angular/common": "14.2.12",
|
"@angular/common": "15.2.10",
|
||||||
"@angular/compiler": "14.2.12",
|
"@angular/compiler": "15.2.10",
|
||||||
"@angular/core": "14.2.12",
|
"@angular/core": "15.2.10",
|
||||||
"@angular/flex-layout": "14.0.0-beta.41",
|
"@angular/flex-layout": "15.0.0-beta.42",
|
||||||
"@angular/forms": "14.2.12",
|
"@angular/forms": "15.2.10",
|
||||||
"@angular/material": "^14.0.1",
|
"@angular/material": "15.0.1",
|
||||||
"@angular/platform-browser": "14.2.12",
|
"@angular/platform-browser": "15.2.10",
|
||||||
"@angular/platform-browser-dynamic": "14.2.12",
|
"@angular/platform-browser-dynamic": "15.2.10",
|
||||||
"@angular/platform-server": "14.2.12",
|
"@angular/platform-server": "15.2.10",
|
||||||
"@angular/router": "14.2.12",
|
"@angular/router": "15.2.10",
|
||||||
"@auth0/angular-jwt": "5.1.0",
|
"@auth0/angular-jwt": "5.1.0",
|
||||||
"@fortawesome/fontawesome": "^1.1.4",
|
"@fortawesome/fontawesome": "^1.1.4",
|
||||||
"@fortawesome/fontawesome-free-regular": "^5.0.8",
|
"@fortawesome/fontawesome-free-regular": "^5.0.8",
|
||||||
@@ -37,6 +37,7 @@
|
|||||||
"hammerjs": "2.0.8",
|
"hammerjs": "2.0.8",
|
||||||
"moment": "^2.29.1",
|
"moment": "^2.29.1",
|
||||||
"net": "^1.0.2",
|
"net": "^1.0.2",
|
||||||
|
"roboto-fontface": "^0.10.0",
|
||||||
"rxjs": "6.5.5",
|
"rxjs": "6.5.5",
|
||||||
"sockjs-client": "^1.1.1",
|
"sockjs-client": "^1.1.1",
|
||||||
"stompjs": "^2.3.3",
|
"stompjs": "^2.3.3",
|
||||||
@@ -44,16 +45,16 @@
|
|||||||
"zone.js": "~0.12.0"
|
"zone.js": "~0.12.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@angular-devkit/build-angular": "14.2.10",
|
"@angular-devkit/build-angular": "^15.2.10",
|
||||||
"@angular-devkit/core": "^14.2.10",
|
"@angular-devkit/core": "^15.2.10",
|
||||||
"@angular-eslint/builder": "14.4.0",
|
"@angular-eslint/builder": "15.2.1",
|
||||||
"@angular-eslint/eslint-plugin": "14.4.0",
|
"@angular-eslint/eslint-plugin": "15.2.1",
|
||||||
"@angular-eslint/eslint-plugin-template": "14.4.0",
|
"@angular-eslint/eslint-plugin-template": "15.2.1",
|
||||||
"@angular-eslint/schematics": "14.4.0",
|
"@angular-eslint/schematics": "15.2.1",
|
||||||
"@angular-eslint/template-parser": "14.4.0",
|
"@angular-eslint/template-parser": "15.2.1",
|
||||||
"@angular/cli": "14.2.10",
|
"@angular/cli": "^15.2.10",
|
||||||
"@angular/compiler-cli": "14.2.12",
|
"@angular/compiler-cli": "15.2.10",
|
||||||
"@angular/language-service": "14.2.12",
|
"@angular/language-service": "15.2.10",
|
||||||
"@types/hammerjs": "2.0.34",
|
"@types/hammerjs": "2.0.34",
|
||||||
"@types/jasmine": "2.5.54",
|
"@types/jasmine": "2.5.54",
|
||||||
"@types/jasminewd2": "2.0.3",
|
"@types/jasminewd2": "2.0.3",
|
||||||
@@ -62,7 +63,7 @@
|
|||||||
"@typescript-eslint/eslint-plugin": "5.43.0",
|
"@typescript-eslint/eslint-plugin": "5.43.0",
|
||||||
"@typescript-eslint/eslint-plugin-tslint": "^5.46.0",
|
"@typescript-eslint/eslint-plugin-tslint": "^5.46.0",
|
||||||
"@typescript-eslint/parser": "5.43.0",
|
"@typescript-eslint/parser": "5.43.0",
|
||||||
"codelyzer": "~6.0.2",
|
"codelyzer": "6.0.2",
|
||||||
"eslint": "^8.28.0",
|
"eslint": "^8.28.0",
|
||||||
"eslint-config-prettier": "^8.5.0",
|
"eslint-config-prettier": "^8.5.0",
|
||||||
"eslint-plugin-import": "^2.26.0",
|
"eslint-plugin-import": "^2.26.0",
|
||||||
@@ -80,9 +81,9 @@
|
|||||||
"karma-jasmine-html-reporter": "~2.0.0",
|
"karma-jasmine-html-reporter": "~2.0.0",
|
||||||
"prettier": "^2.8.1",
|
"prettier": "^2.8.1",
|
||||||
"prettier-eslint": "^15.0.1",
|
"prettier-eslint": "^15.0.1",
|
||||||
"protractor": "~7.0.0",
|
"protractor": "^7.0.0",
|
||||||
"ts-node": "10.9.1",
|
"ts-node": "10.9.1",
|
||||||
"typescript": "4.6.4"
|
"typescript": "4.9.5"
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"preset": "jest-preset-angular",
|
"preset": "jest-preset-angular",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<div fxLayout="column" fxLayoutAlign="space-between stretch" fxFill>
|
<div fxLayout="column" fxLayoutAlign="space-between stretch" fxFill>
|
||||||
<app-header fxFlex="0 0 auto"></app-header>
|
<app-header fxFlex="0 0 auto"></app-header>
|
||||||
<div class="content" fxFlex="100" fxFill>
|
<div class="content flex h-100">
|
||||||
<router-outlet></router-outlet>
|
<router-outlet></router-outlet>
|
||||||
</div>
|
</div>
|
||||||
<app-footer fxFlex="0 0 auto"></app-footer>
|
<app-footer fxFlex="0 0 auto"></app-footer>
|
||||||
|
|||||||
@@ -7,4 +7,5 @@
|
|||||||
|
|
||||||
.content {
|
.content {
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
|
max-height: calc(100vh - 169px);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {MatDatepickerModule} from '@angular/material/datepicker';
|
|||||||
import {MatSelectModule} from '@angular/material/select';
|
import {MatSelectModule} from '@angular/material/select';
|
||||||
import {MatListModule} from '@angular/material/list';
|
import {MatListModule} from '@angular/material/list';
|
||||||
import {MatSidenavModule} from '@angular/material/sidenav';
|
import {MatSidenavModule} from '@angular/material/sidenav';
|
||||||
|
import {MatDialogModule} from '@angular/material/dialog';
|
||||||
|
|
||||||
import {MatNativeDateModule} from '@angular/material/core';
|
import {MatNativeDateModule} from '@angular/material/core';
|
||||||
import { NgxMatTimepickerModule, NgxMatDatetimePickerModule} from '@angular-material-components/datetime-picker';
|
import { NgxMatTimepickerModule, NgxMatDatetimePickerModule} from '@angular-material-components/datetime-picker';
|
||||||
@@ -108,6 +109,7 @@ export function jwtOptionsFactory(apiService: ApiService) {
|
|||||||
deps: [ApiService]
|
deps: [ApiService]
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
MatDialogModule,
|
||||||
MatMenuModule,
|
MatMenuModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
MatButtonModule,
|
MatButtonModule,
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
<mat-toolbar id="footer" style="color: rgba(255, 255, 255, 0.541176);" fxLayout="row" fxLayoutAlign="center center">
|
<mat-toolbar id="footer" style="color: rgba(255, 255, 255, 0.541176);" fxLayout="row" fxLayoutAlign="center center">
|
||||||
<a mat-icon-button href="https://github.com/fabioformosa/quartz-manager">
|
<a href="https://github.com/fabioformosa/quartz-manager" class="flex flex-row align-items-center" style="gap: 6px">
|
||||||
<img src="assets/image/github.png"/>
|
<div class="flex"><img src="assets/image/github.png"/></div>
|
||||||
Quartz Manager
|
<div class="font-size-14 font-weight-500 display-block line-height-100">Quartz Manager</div>
|
||||||
</a>
|
</a>
|
||||||
<!-- Hand crafted with love by -->
|
<!-- Hand crafted with love by -->
|
||||||
<!-- <a href="https://github.com/fabioformosa" style="color: rgba(255, 255, 255, 0.870588);">Fabio Formosa</a>-->
|
<!-- <a href="https://github.com/fabioformosa" style="color: rgba(255, 255, 255, 0.870588);">Fabio Formosa</a>-->
|
||||||
</mat-toolbar>
|
</mat-toolbar>
|
||||||
|
|||||||
@@ -1,39 +1,65 @@
|
|||||||
<mat-card fxFlex="1 1 auto">
|
<mat-card class="flex flex-1 max-h-100">
|
||||||
<mat-card-header fxLayout="row" fxLayoutAlign="space-between none" style="padding-right: 1em;">
|
<mat-card-header class="pb-16">
|
||||||
<mat-card-subtitle><b>JOB LOGS</b></mat-card-subtitle>
|
<mat-card-subtitle ><b>JOB LOGS</b></mat-card-subtitle>
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content style="position: relative; height: calc(100% - 3em);">
|
<mat-card-content class="flex flex-1 overflow-y-auto">
|
||||||
<div *ngIf="!selectedTriggerName && (!logs || logs.length == 0)" fxLayout="row" fxFlexAlign="center stretch" style="text-align: center">
|
<div class="flex-1">
|
||||||
<div fxFill style="height: 100%;">
|
<div *ngIf="!selectedTriggerName && (!logs || logs.length == 0)" fxFill class="h-100" style="text-align: center;">
|
||||||
<img src="assets/image/logs.svg" alt="no logs" width="320" style="margin-top: 6em;" />
|
<img
|
||||||
</div>
|
src="assets/image/logs.svg"
|
||||||
|
alt="no logs"
|
||||||
|
width="320"
|
||||||
|
style="margin-top: 6em" />
|
||||||
</div>
|
</div>
|
||||||
<div *ngIf="isWaitingForLogs()" class="waitingLogs" fxLayout="column" fxLayoutAlign="center center" fxLayoutGap="12px">
|
<div *ngIf="isWaitingForLogs()" class="waitingLogs" fxLayout="column" fxLayoutAlign="center center" fxLayoutGap="12px">
|
||||||
<mat-spinner diameter="36"></mat-spinner>
|
<mat-spinner diameter="36"></mat-spinner>
|
||||||
<div>Waiting for logs from {{selectedTriggerName}}...</div>
|
<div>Waiting for logs from {{selectedTriggerName}}...</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="logs" style="overflow-y: auto; position: absolute; left: 0; right: 0; top: 0; bottom: 0; overflow: auto;">
|
|
||||||
|
<div id="logs" fxFill style="height: 100%">
|
||||||
<div
|
<div
|
||||||
*ngFor = "let log of logs; let first = first" fxLayout="row" fxLayout.xs="column" fxLayoutAlign="start" fxLayoutGap="10px">
|
*ngFor="let log of logs; let first = first"
|
||||||
<div fxFlex="0 1 300px">
|
fxLayout="row"
|
||||||
<span [ngClass]="{'animate__animated animate__zoomIn zoomIn firstLog': first}"> [{{log.time|date:'medium'}}]</span>
|
fxLayout.xs="column"
|
||||||
</div>
|
fxLayoutAlign="start"
|
||||||
<div fxFlex="1 1 16px">
|
fxLayoutGap="10px">
|
||||||
<span [ngClass]="{'animated zoomIn firstLog': first}">
|
<div style="flex: 1; max-width: 300px">
|
||||||
<i class = "fas" [ngClass]="{'fa-check-circle green': log.type == 'INFO',
|
<span
|
||||||
'fa-exclamation-triangle yellow': log.type == 'WARN',
|
[ngClass]="{
|
||||||
'fa-times-circle red': log.type == 'ERROR'}"></i>
|
'animate__animated animate__zoomIn zoomIn firstLog': first
|
||||||
</span>
|
}">
|
||||||
</div>
|
[{{ log.time | date : 'medium' }}]</span
|
||||||
<div fxFlex="0 1 250px">
|
>
|
||||||
<span [ngClass]="{'animate__animated animate__zoomIn zoomIn firstLog': first}">
|
</div>
|
||||||
{{log.threadName}}
|
<div style="flex: 1; max-width: 16px">
|
||||||
</span>
|
<span [ngClass]="{ 'animated zoomIn firstLog': first }">
|
||||||
</div>
|
<i
|
||||||
<div fxFlex="1 1">
|
class="fas"
|
||||||
<span [ngClass]="{'animate__animated animate__zoomIn zoomIn firstLog': first}"> {{log.msg}}</span>
|
[ngClass]="{
|
||||||
</div>
|
'fa-check-circle green': log.type == 'INFO',
|
||||||
|
'fa-exclamation-triangle yellow': log.type == 'WARN',
|
||||||
|
'fa-times-circle red': log.type == 'ERROR'
|
||||||
|
}"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div style="flex: 1; max-width: 250px">
|
||||||
|
<span
|
||||||
|
[ngClass]="{
|
||||||
|
'animate__animated animate__zoomIn zoomIn firstLog': first
|
||||||
|
}">
|
||||||
|
{{ log.threadName }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div style="flex: 1">
|
||||||
|
<span
|
||||||
|
[ngClass]="{
|
||||||
|
'animate__animated animate__zoomIn zoomIn firstLog': first
|
||||||
|
}">
|
||||||
|
{{ log.msg }}</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</mat-card-content>
|
</div>
|
||||||
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
|
|||||||
@@ -1,3 +1,9 @@
|
|||||||
|
:host {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
.red{
|
.red{
|
||||||
color: red;
|
color: red;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,12 +5,16 @@ import {jest} from '@jest/globals';
|
|||||||
|
|
||||||
describe('LogsPanelComponent', () => {
|
describe('LogsPanelComponent', () => {
|
||||||
|
|
||||||
|
const ngZone = {run: jest.fn((fn: () => void) => fn())};
|
||||||
|
|
||||||
|
beforeEach(() => ngZone.run.mockClear());
|
||||||
|
|
||||||
it('should subscribe to the selected trigger logs topic', () => {
|
it('should subscribe to the selected trigger logs topic', () => {
|
||||||
const messages = new Subject<any>();
|
const messages = new Subject<any>();
|
||||||
const logsRxWebsocketService = {
|
const logsRxWebsocketService = {
|
||||||
watch: jest.fn(() => messages.asObservable())
|
watch: jest.fn(() => messages.asObservable())
|
||||||
};
|
};
|
||||||
const component = new LogsPanelComponent(logsRxWebsocketService as any, null);
|
const component = new LogsPanelComponent(logsRxWebsocketService as any, null, ngZone as any);
|
||||||
|
|
||||||
component.triggerKey = new TriggerKey('trigger-1', null);
|
component.triggerKey = new TriggerKey('trigger-1', null);
|
||||||
|
|
||||||
@@ -26,6 +30,7 @@ describe('LogsPanelComponent', () => {
|
|||||||
};
|
};
|
||||||
messages.next({body: JSON.stringify(logRecord)});
|
messages.next({body: JSON.stringify(logRecord)});
|
||||||
|
|
||||||
|
expect(ngZone.run).toHaveBeenCalled();
|
||||||
expect(component.logs[0]).toEqual({
|
expect(component.logs[0]).toEqual({
|
||||||
time: logRecord.date.toISOString(),
|
time: logRecord.date.toISOString(),
|
||||||
type: 'INFO',
|
type: 'INFO',
|
||||||
@@ -43,7 +48,7 @@ describe('LogsPanelComponent', () => {
|
|||||||
.mockReturnValueOnce(firstMessages.asObservable())
|
.mockReturnValueOnce(firstMessages.asObservable())
|
||||||
.mockReturnValueOnce(secondMessages.asObservable())
|
.mockReturnValueOnce(secondMessages.asObservable())
|
||||||
};
|
};
|
||||||
const component = new LogsPanelComponent(logsRxWebsocketService as any, null);
|
const component = new LogsPanelComponent(logsRxWebsocketService as any, null, ngZone as any);
|
||||||
|
|
||||||
component.triggerKey = new TriggerKey('trigger-1', null);
|
component.triggerKey = new TriggerKey('trigger-1', null);
|
||||||
const firstSubscription = component.topicSubscription;
|
const firstSubscription = component.topicSubscription;
|
||||||
@@ -64,7 +69,7 @@ describe('LogsPanelComponent', () => {
|
|||||||
.mockReturnValueOnce(secondMessages.asObservable())
|
.mockReturnValueOnce(secondMessages.asObservable())
|
||||||
.mockReturnValueOnce(firstMessages.asObservable())
|
.mockReturnValueOnce(firstMessages.asObservable())
|
||||||
};
|
};
|
||||||
const component = new LogsPanelComponent(logsRxWebsocketService as any, null);
|
const component = new LogsPanelComponent(logsRxWebsocketService as any, null, ngZone as any);
|
||||||
|
|
||||||
component.triggerKey = new TriggerKey('trigger-1', null);
|
component.triggerKey = new TriggerKey('trigger-1', null);
|
||||||
firstMessages.next({body: JSON.stringify({date: new Date(), type: 'INFO', message: 'first log', threadName: 'worker-1'})});
|
firstMessages.next({body: JSON.stringify({date: new Date(), type: 'INFO', message: 'first log', threadName: 'worker-1'})});
|
||||||
@@ -89,7 +94,7 @@ describe('LogsPanelComponent', () => {
|
|||||||
const logsRxWebsocketService = {
|
const logsRxWebsocketService = {
|
||||||
watch: jest.fn(() => messages.asObservable())
|
watch: jest.fn(() => messages.asObservable())
|
||||||
};
|
};
|
||||||
const component = new LogsPanelComponent(logsRxWebsocketService as any, null);
|
const component = new LogsPanelComponent(logsRxWebsocketService as any, null, ngZone as any);
|
||||||
|
|
||||||
component.triggerKey = new TriggerKey('trigger-1', null);
|
component.triggerKey = new TriggerKey('trigger-1', null);
|
||||||
messages.next({body: JSON.stringify({date: new Date(), type: 'INFO', message: 'first log', threadName: 'worker-1'})});
|
messages.next({body: JSON.stringify({date: new Date(), type: 'INFO', message: 'first log', threadName: 'worker-1'})});
|
||||||
@@ -105,7 +110,7 @@ describe('LogsPanelComponent', () => {
|
|||||||
const logsRxWebsocketService = {
|
const logsRxWebsocketService = {
|
||||||
watch: jest.fn()
|
watch: jest.fn()
|
||||||
};
|
};
|
||||||
const component = new LogsPanelComponent(logsRxWebsocketService as any, null);
|
const component = new LogsPanelComponent(logsRxWebsocketService as any, null, ngZone as any);
|
||||||
|
|
||||||
expect(() => component.ngOnDestroy()).not.toThrow();
|
expect(() => component.ngOnDestroy()).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {Component, Input, OnDestroy, OnInit} from '@angular/core';
|
import {Component, Input, NgZone, OnDestroy, OnInit} from '@angular/core';
|
||||||
|
|
||||||
import {ApiService} from '../../services';
|
import {ApiService} from '../../services';
|
||||||
import {LogsRxWebsocketService} from '../../services/logs.rx-websocket.service';
|
import {LogsRxWebsocketService} from '../../services/logs.rx-websocket.service';
|
||||||
@@ -25,7 +25,8 @@ export class LogsPanelComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private logsRxWebsocketService: LogsRxWebsocketService,
|
private logsRxWebsocketService: LogsRxWebsocketService,
|
||||||
private apiService: ApiService
|
private apiService: ApiService,
|
||||||
|
private ngZone: NgZone
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,7 +59,7 @@ export class LogsPanelComponent implements OnInit, OnDestroy {
|
|||||||
this._unsubscribeFromTopic();
|
this._unsubscribeFromTopic();
|
||||||
this.topicSubscription = this.logsRxWebsocketService.watch(`/topic/logs/${triggerKey.name}`)
|
this.topicSubscription = this.logsRxWebsocketService.watch(`/topic/logs/${triggerKey.name}`)
|
||||||
.pipe(map((msg: any) => JSON.parse(msg.body)))
|
.pipe(map((msg: any) => JSON.parse(msg.body)))
|
||||||
.subscribe(this._showNewLog, (err) => {
|
.subscribe(logRecord => this.ngZone.run(() => this._showNewLog(logRecord)), (err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
// TODO in case of 401
|
// TODO in case of 401
|
||||||
// this.apiService.get('/quartz-manager/session/refresh');
|
// this.apiService.get('/quartz-manager/session/refresh');
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
</div> -->
|
</div> -->
|
||||||
|
|
||||||
<mat-card style="padding-bottom: 0" [ngClass]="{'progress-updated': progressUpdated}">
|
<mat-card style="padding-bottom: 0" [ngClass]="{'progress-updated': progressUpdated}">
|
||||||
<mat-card-header>
|
<mat-card-header style="padding-bottom: 16px;">
|
||||||
<mat-card-subtitle><b>JOB PROGRESS</b></mat-card-subtitle>
|
<mat-card-subtitle><b>JOB PROGRESS</b></mat-card-subtitle>
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
|
|||||||
@@ -5,13 +5,17 @@ import {jest} from '@jest/globals';
|
|||||||
|
|
||||||
describe('ProgressPanelComponent', () => {
|
describe('ProgressPanelComponent', () => {
|
||||||
|
|
||||||
|
const ngZone = {run: jest.fn((fn: () => void) => fn())};
|
||||||
|
|
||||||
|
beforeEach(() => ngZone.run.mockClear());
|
||||||
|
|
||||||
it('should subscribe to the selected trigger progress topic', () => {
|
it('should subscribe to the selected trigger progress topic', () => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
const messages = new Subject<any>();
|
const messages = new Subject<any>();
|
||||||
const progressRxWebsocketService = {
|
const progressRxWebsocketService = {
|
||||||
watch: jest.fn(() => messages.asObservable())
|
watch: jest.fn(() => messages.asObservable())
|
||||||
};
|
};
|
||||||
const component = new ProgressPanelComponent(progressRxWebsocketService as any);
|
const component = new ProgressPanelComponent(progressRxWebsocketService as any, ngZone as any);
|
||||||
|
|
||||||
component.triggerKey = new TriggerKey('trigger-1', null);
|
component.triggerKey = new TriggerKey('trigger-1', null);
|
||||||
|
|
||||||
@@ -20,6 +24,7 @@ describe('ProgressPanelComponent', () => {
|
|||||||
messages.next({body: JSON.stringify({percentage: 75, timesTriggered: 3})});
|
messages.next({body: JSON.stringify({percentage: 75, timesTriggered: 3})});
|
||||||
jest.runOnlyPendingTimers();
|
jest.runOnlyPendingTimers();
|
||||||
|
|
||||||
|
expect(ngZone.run).toHaveBeenCalled();
|
||||||
expect(component.progress.percentage).toEqual(75);
|
expect(component.progress.percentage).toEqual(75);
|
||||||
expect(component.percentageStr).toEqual('75%');
|
expect(component.percentageStr).toEqual('75%');
|
||||||
expect(component.progressUpdated).toBeTruthy();
|
expect(component.progressUpdated).toBeTruthy();
|
||||||
@@ -34,7 +39,7 @@ describe('ProgressPanelComponent', () => {
|
|||||||
.mockReturnValueOnce(firstMessages.asObservable())
|
.mockReturnValueOnce(firstMessages.asObservable())
|
||||||
.mockReturnValueOnce(secondMessages.asObservable())
|
.mockReturnValueOnce(secondMessages.asObservable())
|
||||||
};
|
};
|
||||||
const component = new ProgressPanelComponent(progressRxWebsocketService as any);
|
const component = new ProgressPanelComponent(progressRxWebsocketService as any, ngZone as any);
|
||||||
|
|
||||||
component.triggerKey = new TriggerKey('trigger-1', null);
|
component.triggerKey = new TriggerKey('trigger-1', null);
|
||||||
const firstSubscription = component.topicSubscription;
|
const firstSubscription = component.topicSubscription;
|
||||||
@@ -55,7 +60,7 @@ describe('ProgressPanelComponent', () => {
|
|||||||
.mockReturnValueOnce(secondMessages.asObservable())
|
.mockReturnValueOnce(secondMessages.asObservable())
|
||||||
.mockReturnValueOnce(firstMessages.asObservable())
|
.mockReturnValueOnce(firstMessages.asObservable())
|
||||||
};
|
};
|
||||||
const component = new ProgressPanelComponent(progressRxWebsocketService as any);
|
const component = new ProgressPanelComponent(progressRxWebsocketService as any, ngZone as any);
|
||||||
|
|
||||||
component.triggerKey = new TriggerKey('trigger-1', null);
|
component.triggerKey = new TriggerKey('trigger-1', null);
|
||||||
firstMessages.next({body: JSON.stringify({percentage: 75, timesTriggered: 3})});
|
firstMessages.next({body: JSON.stringify({percentage: 75, timesTriggered: 3})});
|
||||||
@@ -78,7 +83,7 @@ describe('ProgressPanelComponent', () => {
|
|||||||
const progressRxWebsocketService = {
|
const progressRxWebsocketService = {
|
||||||
watch: jest.fn(() => messages.asObservable())
|
watch: jest.fn(() => messages.asObservable())
|
||||||
};
|
};
|
||||||
const component = new ProgressPanelComponent(progressRxWebsocketService as any);
|
const component = new ProgressPanelComponent(progressRxWebsocketService as any, ngZone as any);
|
||||||
|
|
||||||
component.triggerKey = new TriggerKey('trigger-1', null);
|
component.triggerKey = new TriggerKey('trigger-1', null);
|
||||||
messages.next({body: JSON.stringify({percentage: 75, timesTriggered: 3})});
|
messages.next({body: JSON.stringify({percentage: 75, timesTriggered: 3})});
|
||||||
@@ -94,7 +99,7 @@ describe('ProgressPanelComponent', () => {
|
|||||||
const progressRxWebsocketService = {
|
const progressRxWebsocketService = {
|
||||||
watch: jest.fn()
|
watch: jest.fn()
|
||||||
};
|
};
|
||||||
const component = new ProgressPanelComponent(progressRxWebsocketService as any);
|
const component = new ProgressPanelComponent(progressRxWebsocketService as any, ngZone as any);
|
||||||
|
|
||||||
expect(() => component.ngOnDestroy()).not.toThrow();
|
expect(() => component.ngOnDestroy()).not.toThrow();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {Component, Input, OnDestroy, OnInit} from '@angular/core'
|
import {Component, Input, NgZone, OnDestroy, OnInit} from '@angular/core'
|
||||||
import TriggerFiredBundle from '../../model/trigger-fired-bundle.model';
|
import TriggerFiredBundle from '../../model/trigger-fired-bundle.model';
|
||||||
import {TriggerKey} from '../../model/triggerKey.model';
|
import {TriggerKey} from '../../model/triggerKey.model';
|
||||||
import {ProgressRxWebsocketService} from '../../services/progress.rx-websocket.service';
|
import {ProgressRxWebsocketService} from '../../services/progress.rx-websocket.service';
|
||||||
@@ -19,7 +19,8 @@ export class ProgressPanelComponent implements OnInit, OnDestroy {
|
|||||||
private selectedTriggerKey: TriggerKey;
|
private selectedTriggerKey: TriggerKey;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private progressRxWebsocketService: ProgressRxWebsocketService
|
private progressRxWebsocketService: ProgressRxWebsocketService,
|
||||||
|
private ngZone: NgZone
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
@@ -44,7 +45,7 @@ export class ProgressPanelComponent implements OnInit, OnDestroy {
|
|||||||
this._unsubscribeFromTopic();
|
this._unsubscribeFromTopic();
|
||||||
this.topicSubscription = this.progressRxWebsocketService.watch(`/topic/progress/${triggerKey.name}`)
|
this.topicSubscription = this.progressRxWebsocketService.watch(`/topic/progress/${triggerKey.name}`)
|
||||||
.pipe(map((msg: any) => JSON.parse(msg.body)))
|
.pipe(map((msg: any) => JSON.parse(msg.body)))
|
||||||
.subscribe(this.onNewProgressMsg, (err) => {
|
.subscribe(progress => this.ngZone.run(() => this.onNewProgressMsg(progress)), (err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
// TODO in case of 401
|
// TODO in case of 401
|
||||||
// this.apiService.get('/quartz-manager/session/refresh');
|
// this.apiService.get('/quartz-manager/session/refresh');
|
||||||
|
|||||||
@@ -13,11 +13,11 @@
|
|||||||
<mat-card-subtitle style="margin: auto;"><b>SCHEDULER</b></mat-card-subtitle>
|
<mat-card-subtitle style="margin: auto;"><b>SCHEDULER</b></mat-card-subtitle>
|
||||||
</div>
|
</div>
|
||||||
<mat-divider [vertical]="true"></mat-divider>
|
<mat-divider [vertical]="true"></mat-divider>
|
||||||
<div fxLayout="column">
|
<div fxLayout="column" class="justify-space-between">
|
||||||
<div><label>Name</label></div>
|
<div><label>Name</label></div>
|
||||||
<div><span id="scheduler-name">{{scheduler?.name}}</span></div>
|
<div><span id="scheduler-name">{{scheduler?.name}}</span></div>
|
||||||
</div>
|
</div>
|
||||||
<div fxLayout="column">
|
<div fxLayout="column" class="justify-space-between">
|
||||||
<div><label>Instance ID</label></div>
|
<div><label>Instance ID</label></div>
|
||||||
<div><span id="scheduler-instance">{{scheduler?.instanceId}}</span></div>
|
<div><span id="scheduler-instance">{{scheduler?.instanceId}}</span></div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,5 +13,10 @@ label{
|
|||||||
|
|
||||||
#scheduler-name{
|
#scheduler-name{
|
||||||
text-transform: capitalize;
|
text-transform: capitalize;
|
||||||
font-size: larger;
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#scheduler-instance {
|
||||||
|
text-transform: capitalize;
|
||||||
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<mat-card fxFlex="1 1 auto">
|
<mat-card fxFlex="1 1 auto">
|
||||||
<mat-card-header>
|
<mat-card-header style="padding-bottom: 16px;">
|
||||||
<mat-card-subtitle><b>TRIGGER DETAILS</b></mat-card-subtitle>
|
<mat-card-subtitle><b>TRIGGER DETAILS</b></mat-card-subtitle>
|
||||||
</mat-card-header>
|
</mat-card-header>
|
||||||
<mat-divider></mat-divider>
|
<mat-divider></mat-divider>
|
||||||
<mat-card-content *ngIf="shouldShowTheTriggerCardContent()" style="position: relative; height: 100%">
|
<mat-card-content *ngIf="shouldShowTheTriggerCardContent()" style="position: relative; height: 100%">
|
||||||
<div fxLayout="column" style="overflow-y: auto; position: absolute; left: 0; right: 0; top: 0; bottom: 0;
|
<div fxLayout="column" style="overflow-y: auto; position: absolute; left: 0; right: 0; top: 0; bottom: 0;
|
||||||
overflow: auto;height: calc(100% - 3em); padding-top: 1em;">
|
overflow: auto;padding: 1em;">
|
||||||
<mat-card id="noEligibleJobsAlert" *ngIf="jobs?.length === 0" style="background-color: #ff6385">
|
<mat-card id="noEligibleJobsAlert" *ngIf="jobs?.length === 0" style="background-color: #ff6385">
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<i class="fas fa-exclamation-circle" style="color: #fff"></i> <strong>WARNING</strong>
|
<i class="fas fa-exclamation-circle" style="color: #fff"></i> <strong>WARNING</strong>
|
||||||
@@ -14,15 +14,13 @@
|
|||||||
app prop <i>quartz-manager.jobClassPackages</i> with the correct java package </p>
|
app prop <i>quartz-manager.jobClassPackages</i> with the correct java package </p>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
<form name="triggerConfigForm" fxFlex="1 1 100%"
|
<form name="triggerConfigForm" class="trigger-config-form" fxFlex="1 1 100%"
|
||||||
[formGroup]="simpleTriggerReactiveForm" (ngSubmit)="onSubmitTriggerConfig()">
|
[formGroup]="simpleTriggerReactiveForm" (ngSubmit)="onSubmitTriggerConfig()">
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field
|
<mat-form-field
|
||||||
[appearance]="enabledTriggerForm && !trigger ? 'standard': 'none'"
|
|
||||||
class="full-size-input">
|
class="full-size-input">
|
||||||
<mat-label>Trigger Name</mat-label>
|
<mat-label>Trigger Name</mat-label>
|
||||||
<input id="triggerName"
|
<input id="triggerName"
|
||||||
[readonly]="!enabledTriggerForm || trigger"
|
|
||||||
matInput placeholder="name of the trigger (unique)"
|
matInput placeholder="name of the trigger (unique)"
|
||||||
formControlName="triggerName" name="triggerName">
|
formControlName="triggerName" name="triggerName">
|
||||||
<mat-error *ngIf="simpleTriggerReactiveForm.controls.triggerName.errors?.required">
|
<mat-error *ngIf="simpleTriggerReactiveForm.controls.triggerName.errors?.required">
|
||||||
@@ -33,12 +31,11 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field
|
<mat-form-field
|
||||||
[appearance]="enabledTriggerForm ? 'standard': 'none'"
|
|
||||||
class="full-size-input"
|
class="full-size-input"
|
||||||
>
|
>
|
||||||
<mat-label>Job Class</mat-label>
|
<mat-label>Job Class</mat-label>
|
||||||
<mat-select id="jobClass" name="jobClass" formControlName="jobClass" [disabled]="!enabledTriggerForm">
|
<mat-select id="jobClass" name="jobClass" formControlName="jobClass">
|
||||||
<mat-option *ngFor="let job of jobs" [value]="job" style="font-size: 0.8em">
|
<mat-option *ngFor="let job of jobs" [value]="job" class="font-13">
|
||||||
{{job}}
|
{{job}}
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
@@ -50,23 +47,21 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field
|
<mat-form-field
|
||||||
[appearance]="enabledTriggerForm ? 'standard': 'none'"
|
|
||||||
class="full-size-input"
|
class="full-size-input"
|
||||||
>
|
>
|
||||||
<mat-label>Misfire Instruction</mat-label>
|
<mat-label>Misfire Instruction</mat-label>
|
||||||
<mat-select id="misfireInstruction" name="misfireInstruction" formControlName="misfireInstruction"
|
<mat-select id="misfireInstruction" name="misfireInstruction" formControlName="misfireInstruction">
|
||||||
[disabled]="!enabledTriggerForm" style="font-size: 0.8em">
|
<mat-option class="font-13" value="MISFIRE_INSTRUCTION_FIRE_NOW">FIRE NOW</mat-option>
|
||||||
<mat-option value="MISFIRE_INSTRUCTION_FIRE_NOW">FIRE NOW</mat-option>
|
<mat-option class="font-13" value="MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT">RESCHEDULE NOW WITH
|
||||||
<mat-option value="MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT">RESCHEDULE NOW WITH
|
|
||||||
EXISTING REPEAT COUNT
|
EXISTING REPEAT COUNT
|
||||||
</mat-option>
|
</mat-option>
|
||||||
<mat-option value="MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT">RESCHEDULE NOW WITH
|
<mat-option class="font-13" value="MISFIRE_INSTRUCTION_RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT">RESCHEDULE NOW WITH
|
||||||
REMAINING REPEAT COUNT
|
REMAINING REPEAT COUNT
|
||||||
</mat-option>
|
</mat-option>
|
||||||
<mat-option value="MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT">RESCHEDULE NEXT WITH
|
<mat-option class="font-13" value="MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT">RESCHEDULE NEXT WITH
|
||||||
REMAINING COUNT
|
REMAINING COUNT
|
||||||
</mat-option>
|
</mat-option>
|
||||||
<mat-option value="MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT">RESCHEDULE NEXT WITH EXISTING
|
<mat-option class="font-13" value="MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_EXISTING_COUNT">RESCHEDULE NEXT WITH EXISTING
|
||||||
COUNT
|
COUNT
|
||||||
</mat-option>
|
</mat-option>
|
||||||
</mat-select>
|
</mat-select>
|
||||||
@@ -82,12 +77,10 @@
|
|||||||
<div formGroupName="triggerPeriod">
|
<div formGroupName="triggerPeriod">
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field
|
<mat-form-field
|
||||||
[appearance]="enabledTriggerForm ? 'standard': 'none'"
|
|
||||||
class="full-size-input"
|
class="full-size-input"
|
||||||
>
|
>
|
||||||
<mat-label>Start Date (optional)</mat-label>
|
<mat-label>Start Date (optional)</mat-label>
|
||||||
<input id="startDate"
|
<input id="startDate"
|
||||||
[readonly]="!enabledTriggerForm"
|
|
||||||
matInput
|
matInput
|
||||||
[ngxMatDatetimePicker]="startDatePicker" placeholder="Choose a start date"
|
[ngxMatDatetimePicker]="startDatePicker" placeholder="Choose a start date"
|
||||||
formControlName="startDate" name="startDate">
|
formControlName="startDate" name="startDate">
|
||||||
@@ -99,12 +92,10 @@
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field
|
<mat-form-field
|
||||||
[appearance]="enabledTriggerForm ? 'standard': 'none'"
|
|
||||||
class="full-size-input"
|
class="full-size-input"
|
||||||
>
|
>
|
||||||
<mat-label>End Date (optional)</mat-label>
|
<mat-label>End Date (optional)</mat-label>
|
||||||
<input id="endDate"
|
<input id="endDate"
|
||||||
[readonly]="!enabledTriggerForm"
|
|
||||||
matInput
|
matInput
|
||||||
[ngxMatDatetimePicker]="endDatePicker" placeholder="Choose a end date"
|
[ngxMatDatetimePicker]="endDatePicker" placeholder="Choose a end date"
|
||||||
formControlName="endDate" name="endDate"
|
formControlName="endDate" name="endDate"
|
||||||
@@ -122,12 +113,10 @@
|
|||||||
<div formGroupName="triggerRecurrence">
|
<div formGroupName="triggerRecurrence">
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field
|
<mat-form-field
|
||||||
[appearance]="enabledTriggerForm ? 'standard': 'none'"
|
|
||||||
class="full-size-input"
|
class="full-size-input"
|
||||||
>
|
>
|
||||||
<mat-label>Repeat Interval [in mills]</mat-label>
|
<mat-label>Repeat Interval [in mills]</mat-label>
|
||||||
<input id="repeatInterval"
|
<input id="repeatInterval"
|
||||||
[readonly]="!enabledTriggerForm"
|
|
||||||
matInput placeholder="Repeat Interval [in mills]" type="number"
|
matInput placeholder="Repeat Interval [in mills]" type="number"
|
||||||
formControlName="repeatInterval" name="repeatInterval"
|
formControlName="repeatInterval" name="repeatInterval"
|
||||||
>
|
>
|
||||||
@@ -138,12 +127,10 @@
|
|||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<mat-form-field
|
<mat-form-field
|
||||||
[appearance]="enabledTriggerForm ? 'standard': 'none'"
|
|
||||||
class="full-size-input"
|
class="full-size-input"
|
||||||
>
|
>
|
||||||
<mat-label>Repeat Count</mat-label>
|
<mat-label>Repeat Count</mat-label>
|
||||||
<input id="repeatCount"
|
<input id="repeatCount"
|
||||||
[readonly]="!enabledTriggerForm"
|
|
||||||
matInput placeholder="Repeat Count (-1 REPEAT INDEFINITELY)" type="number"
|
matInput placeholder="Repeat Count (-1 REPEAT INDEFINITELY)" type="number"
|
||||||
formControlName="repeatCount" name="repeatCount"
|
formControlName="repeatCount" name="repeatCount"
|
||||||
>
|
>
|
||||||
@@ -158,26 +145,23 @@
|
|||||||
<br/>
|
<br/>
|
||||||
|
|
||||||
<div fxLayout="row" fxFlexAlign="space-evenly center" style="padding-bottom: 1em;">
|
<div fxLayout="row" fxFlexAlign="space-evenly center" style="padding-bottom: 1em;">
|
||||||
<div fxFlex="1 1 auto" style="text-align: center" *ngIf="enabledTriggerForm">
|
<div fxFlex="1 1 auto" style="text-align: center" *ngIf="simpleTriggerReactiveForm.enabled">
|
||||||
<button mat-raised-button
|
<button mat-raised-button
|
||||||
type="button"
|
type="button"
|
||||||
*ngIf="enabledTriggerForm"
|
|
||||||
(click)="onResetReactiveForm()">
|
(click)="onResetReactiveForm()">
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div fxFlex="1 1 auto" style="text-align: center" *ngIf="enabledTriggerForm">
|
<div fxFlex="1 1 auto" style="text-align: center" *ngIf="simpleTriggerReactiveForm.enabled">
|
||||||
<button mat-raised-button
|
<button mat-raised-button
|
||||||
type="submit" color="primary"
|
type="submit" color="primary"
|
||||||
[disabled]="simpleTriggerReactiveForm.invalid"
|
[disabled]="simpleTriggerReactiveForm.invalid">
|
||||||
*ngIf="enabledTriggerForm">
|
|
||||||
Submit
|
Submit
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div fxFlex="1 1 auto" style="text-align: center" *ngIf="!enabledTriggerForm">
|
<div fxFlex="1 1 auto" style="text-align: center" *ngIf="!simpleTriggerReactiveForm.enabled">
|
||||||
<button mat-raised-button type="button"
|
<button mat-raised-button type="button"
|
||||||
*ngIf="!enabledTriggerForm"
|
(click)="openTriggerForm();simpleTriggerReactiveForm.controls['triggerName'].disable();">
|
||||||
(click)="enabledTriggerForm = true">
|
|
||||||
Reschedule
|
Reschedule
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -5,6 +5,22 @@
|
|||||||
.full-size-input{
|
.full-size-input{
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
:host ::ng-deep .trigger-config-form .mat-mdc-form-field {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host ::ng-deep .trigger-config-form .mat-mdc-select-value,
|
||||||
|
:host ::ng-deep .trigger-config-form .mat-mdc-select-value-text,
|
||||||
|
:host ::ng-deep .trigger-config-form .mat-mdc-input-element,
|
||||||
|
:host ::ng-deep .trigger-config-form .mdc-floating-label {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
:host ::ng-deep .trigger-config-form .mat-mdc-select-trigger {
|
||||||
|
min-height: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ===== Scrollbar CSS ===== */
|
/* ===== Scrollbar CSS ===== */
|
||||||
/* Firefox */
|
/* Firefox */
|
||||||
* {
|
* {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing';
|
import {ComponentFixture, fakeAsync, flush, TestBed, waitForAsync} from '@angular/core/testing';
|
||||||
import {MatCardModule} from '@angular/material/card';
|
import {MatCardModule} from '@angular/material/card';
|
||||||
import {SimpleTriggerConfigComponent} from './simple-trigger-config.component';
|
import {SimpleTriggerConfigComponent} from './simple-trigger-config.component';
|
||||||
import {ApiService, ConfigService, CONTEXT_PATH, SchedulerService} from '../../services';
|
import {ApiService, ConfigService, CONTEXT_PATH, SchedulerService} from '../../services';
|
||||||
@@ -86,7 +86,7 @@ describe('SimpleTriggerConfig', () => {
|
|||||||
const dropdownDe = componentDe.query(By.css(dropdownSelector));
|
const dropdownDe = componentDe.query(By.css(dropdownSelector));
|
||||||
dropdownDe.nativeElement.click();
|
dropdownDe.nativeElement.click();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const matOptionDe = componentDe.query(By.css('.mat-select-panel')).queryAll(By.css('.mat-option'));
|
const matOptionDe = componentDe.query(By.css('.mat-mdc-select-panel')).queryAll(By.css('.mat-mdc-option'));
|
||||||
matOptionDe[index].nativeElement.click();
|
matOptionDe[index].nativeElement.click();
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
}
|
}
|
||||||
@@ -124,7 +124,7 @@ describe('SimpleTriggerConfig', () => {
|
|||||||
openFormAndFillAllMandatoryFields();
|
openFormAndFillAllMandatoryFields();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should emit an event when a new trigger is submitted', () => {
|
it('should emit an event when a new trigger is submitted', fakeAsync(() => {
|
||||||
const componentDe: DebugElement = fixture.debugElement;
|
const componentDe: DebugElement = fixture.debugElement;
|
||||||
const mockTrigger = new Trigger();
|
const mockTrigger = new Trigger();
|
||||||
mockTrigger.triggerKeyDTO = new TriggerKey(testTriggerName, null);
|
mockTrigger.triggerKeyDTO = new TriggerKey(testTriggerName, null);
|
||||||
@@ -143,14 +143,18 @@ describe('SimpleTriggerConfig', () => {
|
|||||||
|
|
||||||
let actualNewTrigger;
|
let actualNewTrigger;
|
||||||
component.onNewTrigger.subscribe(simpleTrigger => actualNewTrigger = simpleTrigger);
|
component.onNewTrigger.subscribe(simpleTrigger => actualNewTrigger = simpleTrigger);
|
||||||
|
let submittedTriggerKey: TriggerKey;
|
||||||
|
component.onTriggerSubmitting.subscribe(triggerKey => submittedTriggerKey = triggerKey);
|
||||||
|
|
||||||
submitButton.nativeElement.click();
|
submitButton.nativeElement.click();
|
||||||
|
expect(submittedTriggerKey).toEqual(new TriggerKey(testTriggerName, null));
|
||||||
|
flush();
|
||||||
|
|
||||||
const postSimpleTriggerReq = httpTestingController.expectOne(`${CONTEXT_PATH}/simple-triggers/${testTriggerName}`);
|
const postSimpleTriggerReq = httpTestingController.expectOne(`${CONTEXT_PATH}/simple-triggers/${testTriggerName}`);
|
||||||
postSimpleTriggerReq.flush(mockTrigger);
|
postSimpleTriggerReq.flush(mockTrigger);
|
||||||
|
|
||||||
expect(actualNewTrigger).toEqual(mockTrigger);
|
expect(actualNewTrigger).toEqual(mockTrigger);
|
||||||
});
|
}));
|
||||||
|
|
||||||
it('should not emit an event when an existing trigger is edited', () => {
|
it('should not emit an event when an existing trigger is edited', () => {
|
||||||
const mockTriggerKey = new TriggerKey(testTriggerName, null);
|
const mockTriggerKey = new TriggerKey(testTriggerName, null);
|
||||||
@@ -207,14 +211,14 @@ describe('SimpleTriggerConfig', () => {
|
|||||||
component.trigger = new SimpleTrigger();
|
component.trigger = new SimpleTrigger();
|
||||||
component.trigger.triggerKeyDTO = mockTriggerKey;
|
component.trigger.triggerKeyDTO = mockTriggerKey;
|
||||||
|
|
||||||
fixture.detectChanges();
|
|
||||||
|
|
||||||
const mockTrigger = new Trigger();
|
const mockTrigger = new Trigger();
|
||||||
mockTrigger.triggerKeyDTO = mockTriggerKey;
|
mockTrigger.triggerKeyDTO = mockTriggerKey;
|
||||||
mockTrigger.jobDetailDTO = <JobDetail>{jobClassName: 'TestJob', description: null};
|
mockTrigger.jobDetailDTO = <JobDetail>{jobClassName: 'TestJob', description: null};
|
||||||
const getSimpleTriggerReq = httpTestingController.expectOne(`${CONTEXT_PATH}/simple-triggers/my-simple-trigger`);
|
const getSimpleTriggerReq = httpTestingController.expectOne(`${CONTEXT_PATH}/simple-triggers/my-simple-trigger`);
|
||||||
getSimpleTriggerReq.flush(mockTrigger);
|
getSimpleTriggerReq.flush(mockTrigger);
|
||||||
|
|
||||||
|
fixture.detectChanges();
|
||||||
|
|
||||||
const componentDe: DebugElement = fixture.debugElement;
|
const componentDe: DebugElement = fixture.debugElement;
|
||||||
const submitButton = componentDe.query(By.css('form button'));
|
const submitButton = componentDe.query(By.css('form button'));
|
||||||
expect(submitButton.nativeElement.textContent.trim()).toEqual('Reschedule');
|
expect(submitButton.nativeElement.textContent.trim()).toEqual('Reschedule');
|
||||||
@@ -247,7 +251,7 @@ describe('SimpleTriggerConfig', () => {
|
|||||||
|
|
||||||
expect(component.simpleTriggerReactiveForm.value.triggerName).toEqual(testTriggerName);
|
expect(component.simpleTriggerReactiveForm.value.triggerName).toEqual(testTriggerName);
|
||||||
|
|
||||||
component.triggerKey = null;
|
component.openNewTriggerForm();
|
||||||
|
|
||||||
expect(component.simpleTriggerReactiveForm.value.triggerName).toBeNull();
|
expect(component.simpleTriggerReactiveForm.value.triggerName).toBeNull();
|
||||||
expect(component.simpleTriggerReactiveForm.value.jobClass).toBeNull();
|
expect(component.simpleTriggerReactiveForm.value.jobClass).toBeNull();
|
||||||
@@ -255,6 +259,16 @@ describe('SimpleTriggerConfig', () => {
|
|||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should not emit form open changes while applying a null trigger input', () => {
|
||||||
|
let formOpenChangeEmitted = false;
|
||||||
|
component.triggerFormOpenChange.subscribe(() => formOpenChangeEmitted = true);
|
||||||
|
|
||||||
|
component.triggerKey = null;
|
||||||
|
|
||||||
|
expect(formOpenChangeEmitted).toBeFalsy();
|
||||||
|
expect(component.shouldShowTheTriggerCardContent()).toBeFalsy();
|
||||||
|
});
|
||||||
|
|
||||||
it('should display the warning if there are no eligible jobs', () => {
|
it('should display the warning if there are no eligible jobs', () => {
|
||||||
fixture.detectChanges();
|
fixture.detectChanges();
|
||||||
const getJobsReq = httpTestingController.expectOne(`${CONTEXT_PATH}/jobs`);
|
const getJobsReq = httpTestingController.expectOne(`${CONTEXT_PATH}/jobs`);
|
||||||
|
|||||||
@@ -42,14 +42,15 @@ export class SimpleTriggerConfigComponent implements OnInit {
|
|||||||
|
|
||||||
private jobs: Array<String>;
|
private jobs: Array<String>;
|
||||||
|
|
||||||
enabledTriggerForm = false;
|
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
onNewTrigger = new EventEmitter<SimpleTrigger>();
|
onNewTrigger = new EventEmitter<SimpleTrigger>();
|
||||||
|
|
||||||
@Output()
|
@Output()
|
||||||
triggerFormOpenChange = new EventEmitter<boolean>();
|
triggerFormOpenChange = new EventEmitter<boolean>();
|
||||||
|
|
||||||
|
@Output()
|
||||||
|
onTriggerSubmitting = new EventEmitter<TriggerKey>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private formBuilder: UntypedFormBuilder,
|
private formBuilder: UntypedFormBuilder,
|
||||||
private schedulerService: SchedulerService,
|
private schedulerService: SchedulerService,
|
||||||
@@ -58,6 +59,7 @@ export class SimpleTriggerConfigComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
|
this.simpleTriggerReactiveForm.disable();
|
||||||
this.fetchJobs();
|
this.fetchJobs();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,24 +68,24 @@ export class SimpleTriggerConfigComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
openTriggerForm() {
|
openTriggerForm() {
|
||||||
this.enabledTriggerForm = true;
|
this.simpleTriggerReactiveForm.enable();
|
||||||
this.triggerFormOpenChange.emit(this.enabledTriggerForm);
|
this.triggerFormOpenChange.emit(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private closeTriggerForm() {
|
private closeTriggerForm() {
|
||||||
this.enabledTriggerForm = false;
|
this.simpleTriggerReactiveForm.disable();
|
||||||
this.triggerFormOpenChange.emit(this.enabledTriggerForm);
|
this.triggerFormOpenChange.emit(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Input()
|
@Input()
|
||||||
set triggerKey(triggerKey: TriggerKey) {
|
set triggerKey(triggerKey: TriggerKey) {
|
||||||
if (!triggerKey) {
|
if (!triggerKey) {
|
||||||
this.openNewTriggerForm();
|
return;
|
||||||
} else if (!this.selectedTriggerKey || this.selectedTriggerKey.name !== triggerKey.name) {
|
} else if (!this.selectedTriggerKey || this.selectedTriggerKey.name !== triggerKey.name) {
|
||||||
this._resetTheTrigger();
|
this._resetTheTrigger();
|
||||||
this.selectedTriggerKey = {...triggerKey} as TriggerKey;
|
this.selectedTriggerKey = {...triggerKey} as TriggerKey;
|
||||||
this.fetchSelectedTrigger();
|
this.fetchSelectedTrigger();
|
||||||
this.closeTriggerForm();
|
this.simpleTriggerReactiveForm.disable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,10 +109,11 @@ export class SimpleTriggerConfigComponent implements OnInit {
|
|||||||
this.simpleTriggerReactiveForm.setValue(this._fromTriggerToReactiveForm(retTrigger))
|
this.simpleTriggerReactiveForm.setValue(this._fromTriggerToReactiveForm(retTrigger))
|
||||||
this.triggerLoading = false;
|
this.triggerLoading = false;
|
||||||
this.triggerInProgress = this.trigger.mayFireAgain;
|
this.triggerInProgress = this.trigger.mayFireAgain;
|
||||||
|
this.simpleTriggerReactiveForm.disable();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldShowTheTriggerCardContent = (): boolean => this.trigger !== null || this.enabledTriggerForm;
|
shouldShowTheTriggerCardContent = (): boolean => this.trigger !== null || this.simpleTriggerReactiveForm.enabled;
|
||||||
|
|
||||||
existsATriggerInProgress = (): boolean => this.trigger && this.triggerInProgress;
|
existsATriggerInProgress = (): boolean => this.trigger && this.triggerInProgress;
|
||||||
|
|
||||||
@@ -128,6 +131,17 @@ export class SimpleTriggerConfigComponent implements OnInit {
|
|||||||
this.schedulerService.updateSimpleTriggerConfig : this.schedulerService.saveSimpleTriggerConfig;
|
this.schedulerService.updateSimpleTriggerConfig : this.schedulerService.saveSimpleTriggerConfig;
|
||||||
|
|
||||||
const simpleTriggerCommand = this._fromReactiveFormToCommand();
|
const simpleTriggerCommand = this._fromReactiveFormToCommand();
|
||||||
|
if (!this.trigger) {
|
||||||
|
this.onTriggerSubmitting.emit(new TriggerKey(simpleTriggerCommand.triggerName, null));
|
||||||
|
setTimeout(() => this.submitTriggerConfig(schedulerServiceCall, simpleTriggerCommand));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.submitTriggerConfig(schedulerServiceCall, simpleTriggerCommand);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private submitTriggerConfig(schedulerServiceCall, simpleTriggerCommand: SimpleTriggerCommand) {
|
||||||
this.triggerLoading = true;
|
this.triggerLoading = true;
|
||||||
schedulerServiceCall(simpleTriggerCommand)
|
schedulerServiceCall(simpleTriggerCommand)
|
||||||
.subscribe((retTrigger: SimpleTrigger) => {
|
.subscribe((retTrigger: SimpleTrigger) => {
|
||||||
@@ -148,9 +162,8 @@ export class SimpleTriggerConfigComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
this.triggerLoading = false;
|
this.triggerLoading = false;
|
||||||
}, () => {
|
}, () => {
|
||||||
this.triggerLoading = false
|
this.triggerLoading = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private _triggerPeriodValidator(control: AbstractControl): ValidationErrors | null {
|
private _triggerPeriodValidator(control: AbstractControl): ValidationErrors | null {
|
||||||
@@ -191,7 +204,7 @@ this.triggerLoading = false
|
|||||||
};
|
};
|
||||||
|
|
||||||
private _fromReactiveFormToCommand = (): SimpleTriggerCommand => {
|
private _fromReactiveFormToCommand = (): SimpleTriggerCommand => {
|
||||||
const reactiveFormValue = this.simpleTriggerReactiveForm.value;
|
const reactiveFormValue = this.simpleTriggerReactiveForm.getRawValue();
|
||||||
const simpleTriggerCommand = new SimpleTriggerCommand();
|
const simpleTriggerCommand = new SimpleTriggerCommand();
|
||||||
simpleTriggerCommand.triggerName = reactiveFormValue.triggerName;
|
simpleTriggerCommand.triggerName = reactiveFormValue.triggerName;
|
||||||
simpleTriggerCommand.jobClass = reactiveFormValue.jobClass;
|
simpleTriggerCommand.jobClass = reactiveFormValue.jobClass;
|
||||||
|
|||||||
@@ -6,12 +6,14 @@ import {MatDialog, MatDialogRef} from '@angular/material/dialog';
|
|||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
template: `
|
template: `
|
||||||
<h3 mat-dialog-title>Coming Soon</h3>
|
<div style="padding:16px">
|
||||||
<div mat-dialog-content>
|
<h3 mat-dialog-title>Coming Soon</h3>
|
||||||
<p>This feature is in roadmap and it will come with the next releases</p>
|
<div mat-dialog-content>
|
||||||
</div>
|
<p>This feature is in roadmap and it will come with the next releases</p>
|
||||||
<div mat-dialog-actions>
|
</div>
|
||||||
<button mat-button (click)="closeDialog()" style="padding: 0.5em;width: 5em;">Ok</button>
|
<div mat-dialog-actions>
|
||||||
|
<button mat-button (click)="closeDialog()" style="padding: 0.5em;width: 5em;">Ok</button>
|
||||||
|
</div>
|
||||||
</div>`,
|
</div>`,
|
||||||
})
|
})
|
||||||
// tslint:disable-next-line:component-class-suffix
|
// tslint:disable-next-line:component-class-suffix
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
:host {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +1,48 @@
|
|||||||
<div id="managerViewContainer" fxLayout="column" fxLayoutAlign="left stretch" fxLayoutGap="10px" fxFill>
|
<div id="managerViewContainer" class="flex flex-column flex-1 gap-6 h-100">
|
||||||
|
<div id="schedulerBarContainer">
|
||||||
<div id="schedulerBarContainer" fxLayout="column" fxLayoutAlign="left stretch">
|
|
||||||
<qrzmng-scheduler-control></qrzmng-scheduler-control>
|
<qrzmng-scheduler-control></qrzmng-scheduler-control>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxLayout="row" fxLayoutGap="8px" fxLayoutAlign="center stretch" fxFlex="1 1 auto">
|
<div id="manager-content-container" class="flex flex-row flex-1 gap-6">
|
||||||
|
<div class="flex-1" style="max-width: 250px">
|
||||||
<div fxFlex="0 0 250px">
|
|
||||||
<div fxLayout="row" fxLayoutAlign="stretch" fxFill>
|
<div fxLayout="row" fxLayoutAlign="stretch" fxFill>
|
||||||
<qrzmng-trigger-list
|
<qrzmng-trigger-list
|
||||||
(onNewTriggerClicked)="onNewTriggerRequested()"
|
(onNewTriggerClicked)="onNewTriggerRequested()"
|
||||||
[openedNewTriggerForm]="newTriggerFormOpened"
|
[openedNewTriggerForm]="newTriggerFormOpened"
|
||||||
(onSelectedTrigger)="setSelectedTrigger($event)"
|
(onSelectedTrigger)="setSelectedTrigger($event)"
|
||||||
fxFill></qrzmng-trigger-list>
|
fxFill></qrzmng-trigger-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="1 1 350px">
|
<div class="flex-1" style="max-width: 350px">
|
||||||
<div fxLayout="row" fxFill>
|
<div fxLayout="row" fxFill>
|
||||||
<div fxLayout="column" fxFill>
|
<div fxLayout="column" fxFill>
|
||||||
<qrzmng-simple-trigger-config fxFill
|
<qrzmng-simple-trigger-config
|
||||||
|
fxFill
|
||||||
[triggerKey]="selectedTriggerKey"
|
[triggerKey]="selectedTriggerKey"
|
||||||
(triggerFormOpenChange)="setNewTriggerFormOpened($event)"
|
(triggerFormOpenChange)="setNewTriggerFormOpened($event)"
|
||||||
|
(onTriggerSubmitting)="monitorTrigger($event)"
|
||||||
(onNewTrigger)="onNewTriggerCreated($event)">
|
(onNewTrigger)="onNewTriggerCreated($event)">
|
||||||
</qrzmng-simple-trigger-config>
|
</qrzmng-simple-trigger-config>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div fxFlex="1 1 auto" style="margin-left: 20px;">
|
<div class="flex-1">
|
||||||
<div fxFlex="1 1 auto" fxLayout="column" fxLayoutAlign="start stretch" fxLayoutGap="6px">
|
<div class="h-100 min-h-100 flex flex-column gap-6">
|
||||||
<progress-panel
|
<div class="flex flex-column" >
|
||||||
[triggerKey]=selectedTriggerKey
|
<progress-panel class="flex-1"
|
||||||
>
|
[triggerKey]=monitoredTriggerKey
|
||||||
</progress-panel>
|
>
|
||||||
<logs-panel fxFlex="1 1 auto" fxFill
|
</progress-panel>
|
||||||
[triggerKey]=selectedTriggerKey
|
</div>
|
||||||
>
|
<div class="flex flex-column flex-1" style="max-height: calc(100% - 136px); min-height: calc(100% - 210px);">
|
||||||
</logs-panel>
|
<logs-panel class="flex flex-1 h-100 max-h-100"
|
||||||
|
[triggerKey]=monitoredTriggerKey
|
||||||
|
>
|
||||||
|
</logs-panel>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1 +1,10 @@
|
|||||||
|
:host {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#manager-content-container {
|
||||||
|
height: calc(100% - 80px);
|
||||||
|
max-height: calc(100% - 80px);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import {Component, OnInit, ViewChild} from '@angular/core';
|
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||||
import {SimpleTrigger} from '../../model/simple-trigger.model';
|
import { SimpleTrigger } from '../../model/simple-trigger.model';
|
||||||
import {TriggerKey} from '../../model/triggerKey.model';
|
import { TriggerKey } from '../../model/triggerKey.model';
|
||||||
import {SimpleTriggerConfigComponent} from '../../components/simple-trigger-config';
|
import { SimpleTriggerConfigComponent } from '../../components/simple-trigger-config';
|
||||||
import {TriggerListComponent} from '../../components';
|
import { TriggerListComponent } from '../../components';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'manager',
|
selector: 'manager',
|
||||||
@@ -10,7 +10,6 @@ import {TriggerListComponent} from '../../components';
|
|||||||
styleUrls: ['./manager.component.scss']
|
styleUrls: ['./manager.component.scss']
|
||||||
})
|
})
|
||||||
export class ManagerComponent implements OnInit {
|
export class ManagerComponent implements OnInit {
|
||||||
|
|
||||||
@ViewChild(SimpleTriggerConfigComponent)
|
@ViewChild(SimpleTriggerConfigComponent)
|
||||||
private triggerConfigComponent!: SimpleTriggerConfigComponent;
|
private triggerConfigComponent!: SimpleTriggerConfigComponent;
|
||||||
|
|
||||||
@@ -21,14 +20,15 @@ export class ManagerComponent implements OnInit {
|
|||||||
|
|
||||||
selectedTriggerKey: TriggerKey;
|
selectedTriggerKey: TriggerKey;
|
||||||
|
|
||||||
constructor(
|
monitoredTriggerKey: TriggerKey;
|
||||||
) { }
|
|
||||||
|
|
||||||
ngOnInit() {
|
constructor() {}
|
||||||
}
|
|
||||||
|
ngOnInit() {}
|
||||||
|
|
||||||
onNewTriggerRequested() {
|
onNewTriggerRequested() {
|
||||||
this.selectedTriggerKey = null;
|
this.selectedTriggerKey = null;
|
||||||
|
this.monitoredTriggerKey = null;
|
||||||
this.newTriggerFormOpened = true;
|
this.newTriggerFormOpened = true;
|
||||||
if (this.triggerConfigComponent) {
|
if (this.triggerConfigComponent) {
|
||||||
this.triggerConfigComponent.openNewTriggerForm();
|
this.triggerConfigComponent.openNewTriggerForm();
|
||||||
@@ -42,11 +42,15 @@ export class ManagerComponent implements OnInit {
|
|||||||
|
|
||||||
setSelectedTrigger(triggerKey: TriggerKey) {
|
setSelectedTrigger(triggerKey: TriggerKey) {
|
||||||
this.selectedTriggerKey = triggerKey;
|
this.selectedTriggerKey = triggerKey;
|
||||||
|
this.monitoredTriggerKey = triggerKey;
|
||||||
this.newTriggerFormOpened = false;
|
this.newTriggerFormOpened = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
monitorTrigger(triggerKey: TriggerKey) {
|
||||||
|
this.monitoredTriggerKey = triggerKey;
|
||||||
|
}
|
||||||
|
|
||||||
setNewTriggerFormOpened(opened: boolean) {
|
setNewTriggerFormOpened(opened: boolean) {
|
||||||
this.newTriggerFormOpened = opened;
|
this.newTriggerFormOpened = opened;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,3 +12,91 @@ body {
|
|||||||
flex:1;
|
flex:1;
|
||||||
background-color: #f1f1f1;
|
background-color: #f1f1f1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
TODO: Remove the below utility classes once tailwind is integrated.
|
||||||
|
*/
|
||||||
|
.font-13 {
|
||||||
|
font-size: 13px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-large {
|
||||||
|
font-size: large;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-larger {
|
||||||
|
font-size: larger;
|
||||||
|
}
|
||||||
|
|
||||||
|
.justify-space-between {
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-row {
|
||||||
|
flex-direction: row;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-column {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.flex-1 {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.h-100 {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.min-h-100 {
|
||||||
|
min-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.max-h-100 {
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.w-100 {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gap-6 {
|
||||||
|
gap: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overflow-hidden {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overflow-y-auto {
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pb-16 {
|
||||||
|
padding-bottom: 16px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mdc-list-item__primary-text {
|
||||||
|
font-size: 0.8em !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.font-size-14 {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.font-weight-500 {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
.display-block {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.line-height-100 {
|
||||||
|
line-height: 100%;
|
||||||
|
}
|
||||||
|
.align-items-center {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
"moduleResolution": "node",
|
"moduleResolution": "node",
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"target": "es2020",
|
"target": "ES2022",
|
||||||
"typeRoots": [
|
"typeRoots": [
|
||||||
"node_modules/@types"
|
"node_modules/@types"
|
||||||
],
|
],
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
"es2016",
|
"es2016",
|
||||||
"dom"
|
"dom"
|
||||||
],
|
],
|
||||||
"module": "es2020"
|
"module": "es2020",
|
||||||
|
"useDefineForClassFields": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user