mirror of
https://github.com/fabioformosa/quartz-manager.git
synced 2025-12-30 14:13:16 +09:00
#56 step into layout revamp
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
<app-header></app-header>
|
||||
<div class="content">
|
||||
<router-outlet></router-outlet>
|
||||
<div fxLayout="column" fxLayoutAlign="space-between stretch" fxFill>
|
||||
<app-header fxFlex="0 0 auto"></app-header>
|
||||
<div class="content" fxFlex="100" fxFill>
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
<app-footer fxFlex="0 0 auto"></app-footer>
|
||||
</div>
|
||||
<app-footer></app-footer>
|
||||
|
||||
|
||||
@@ -2,20 +2,9 @@
|
||||
display: block;
|
||||
color: rgba(0,0,0,.54);
|
||||
font-family: Roboto,"Helvetica Neue";
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.content {
|
||||
margin: 50px 70px;
|
||||
}
|
||||
|
||||
@media screen and (min-width: 600px) and (max-width: 1279px) {
|
||||
.content {
|
||||
margin: 20px 30px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 599px) {
|
||||
.content {
|
||||
margin: 8px 12px;
|
||||
}
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ import {MatIconModule} from '@angular/material/icon';
|
||||
import {MatButtonModule} from '@angular/material/button';
|
||||
import {MatCardModule} from '@angular/material/card';
|
||||
import {MatDatepickerModule} from '@angular/material/datepicker';
|
||||
import {MatListModule} from '@angular/material/list';
|
||||
import {MatSidenavModule} from '@angular/material/sidenav';
|
||||
|
||||
import {MatNativeDateModule} from '@angular/material/core';
|
||||
import { NgxMatTimepickerModule, NgxMatDatetimePickerModule} from '@angular-material-components/datetime-picker';
|
||||
@@ -40,7 +42,8 @@ import {
|
||||
SchedulerConfigComponent,
|
||||
SchedulerControlComponent,
|
||||
LogsPanelComponent,
|
||||
ProgressPanelComponent
|
||||
ProgressPanelComponent,
|
||||
TriggerListComponent
|
||||
} from './components';
|
||||
|
||||
import {
|
||||
@@ -51,7 +54,8 @@ import {
|
||||
ConfigService,
|
||||
ProgressWebsocketService,
|
||||
LogsWebsocketService,
|
||||
getHtmlBaseUrl
|
||||
getHtmlBaseUrl,
|
||||
TriggerService
|
||||
} from './services';
|
||||
import { ChangePasswordComponent } from './views/change-password/change-password.component';
|
||||
import { ForbiddenComponent } from './views/forbidden/forbidden.component';
|
||||
@@ -113,7 +117,8 @@ export function jwtOptionsFactory(apiService: ApiService) {
|
||||
LogsPanelComponent,
|
||||
ProgressPanelComponent,
|
||||
ChangePasswordComponent,
|
||||
ForbiddenComponent
|
||||
ForbiddenComponent,
|
||||
TriggerListComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserAnimationsModule,
|
||||
@@ -137,11 +142,13 @@ export function jwtOptionsFactory(apiService: ApiService) {
|
||||
MatInputModule,
|
||||
MatToolbarModule,
|
||||
MatCardModule,
|
||||
MatListModule,
|
||||
MatProgressSpinnerModule,
|
||||
MatProgressBarModule,
|
||||
MatDatepickerModule, MatNativeDateModule,
|
||||
NgxMatMomentModule,
|
||||
NgxMatDatetimePickerModule,
|
||||
MatSidenavModule,
|
||||
FlexLayoutModule
|
||||
],
|
||||
providers: [
|
||||
@@ -159,6 +166,7 @@ export function jwtOptionsFactory(apiService: ApiService) {
|
||||
GuestGuard,
|
||||
AdminGuard,
|
||||
SchedulerService,
|
||||
TriggerService,
|
||||
ProgressWebsocketService,
|
||||
LogsWebsocketService,
|
||||
AuthService,
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<p style="margin: 0px auto; padding: 0px; color: rgba(255, 255, 255, 0.541176); max-width: 356px;">
|
||||
Hand crafted with love by
|
||||
<a href="https://github.com/fabioformosa" style="color: rgba(255, 255, 255, 0.870588);">Fabio Formosa</a>
|
||||
</p>
|
||||
<a style="margin-top: 22px;" mat-icon-button href="https://github.com/fabioformosa/quartz-manager">
|
||||
<img src="assets/image/github.png"/>
|
||||
</a>
|
||||
<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">
|
||||
<img src="assets/image/github.png"/>
|
||||
Quartz Manager
|
||||
</a>
|
||||
<!-- Hand crafted with love by -->
|
||||
<!-- <a href="https://github.com/fabioformosa" style="color: rgba(255, 255, 255, 0.870588);">Fabio Formosa</a>-->
|
||||
</mat-toolbar>
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
:host {
|
||||
display: block;
|
||||
font-weight: 300;
|
||||
font-size: 15px;
|
||||
display: block;
|
||||
:host{
|
||||
//position: absolute;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
height: 64px;
|
||||
}
|
||||
|
||||
#footer{
|
||||
background-color: rgb(33, 33, 33);
|
||||
height: 236px;
|
||||
padding: 72px 24px;
|
||||
font-size: 15px;
|
||||
box-sizing: border-box;
|
||||
text-align: center;
|
||||
a {
|
||||
text-decoration: none;
|
||||
cursor: auto;
|
||||
cursor: pointer;
|
||||
color: #FFFFFF;
|
||||
margin-top: 32px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@@ -21,7 +23,5 @@
|
||||
font-weight: 300;
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<mat-toolbar color="primary" class="app-navbar">
|
||||
<button mat-button mat-ripple routerLink="/">
|
||||
<img alt="Quartz Manager" class="app-angular-logo" src="assets/image/angular-white-transparent.svg">
|
||||
<!-- <img alt="Quartz Manager" class="app-angular-logo" src="assets/image/angular-white-transparent.svg">-->
|
||||
<span>Quartz Manager</span>
|
||||
</button>
|
||||
|
||||
|
||||
@@ -5,3 +5,4 @@ export * from './logs-panel';
|
||||
export * from './scheduler-config';
|
||||
export * from './scheduler-control';
|
||||
export * from './progress-panel';
|
||||
export * from './trigger-list';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<!-- <div class="progress" [hidden]="progress.percentage < 0">
|
||||
<div class="progress-bar"
|
||||
role="progressbar"
|
||||
<div class="progress-bar"
|
||||
role="progressbar"
|
||||
[ngStyle]="{width: percentageStr}">
|
||||
{{percentageStr}}
|
||||
</div>
|
||||
@@ -8,29 +8,29 @@
|
||||
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-title><b>JOB PROGRESS</b></mat-card-title>
|
||||
<mat-card-subtitle><b>JOB PROGRESS</b></mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<div>
|
||||
<mat-progress-bar mode="determinate" value="{{progress.percentage}}"></mat-progress-bar>
|
||||
{{percentageStr}}
|
||||
</div>
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
<div>
|
||||
<mat-chip>counter</mat-chip>
|
||||
<mat-chip>counter</mat-chip>
|
||||
<span class="animated pulse">{{progress.timesTriggered}}</span> <span ng-show="progress.repeatCount > 0">/ {{progress.repeatCount}} </span>
|
||||
|
||||
|
||||
<br/><br/>
|
||||
|
||||
|
||||
<mat-chip>job key</mat-chip> <span class="animated pulse">{{progress.jobKey}}</span><br>
|
||||
<mat-chip>job class</mat-chip> <span class="animated pulse">{{progress.jobClass}}</span><br/>
|
||||
|
||||
|
||||
<br/>
|
||||
<mat-chip>prev fire time</mat-chip> <span class="animated pulse">{{progress.previousFireTime|date:'dd-MM-yyyy HH:mm:ss'}}</span><br/>
|
||||
<mat-chip>next fire time</mat-chip> <span class="animated pulse">{{progress.nextFireTime|date:'dd-MM-yyyy HH:mm:ss'}}</span><br/>
|
||||
<mat-chip>final fire time</mat-chip> <span class="animated pulse">{{progress.finalFireTime|date:'dd-MM-yyyy HH:mm:ss'}}</span><br/>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-card>
|
||||
|
||||
@@ -1,15 +1,26 @@
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-title><b>SCHEDULER CONTROLLER</b></mat-card-title>
|
||||
</mat-card-header>
|
||||
<mat-card-content>
|
||||
<button id="schedulerControllerBtn1" mat-raised-button class="btn btn-default large-btn" (click)="startOrPause()">
|
||||
<span *ngIf = "schedulerState === 'running'">
|
||||
<i class="fas fa-pause red"></i>
|
||||
</span>
|
||||
<span *ngIf = "schedulerState === 'stopped' || schedulerState === 'paused'">
|
||||
<i class="fas fa-play green"></i>
|
||||
</span>
|
||||
</button>
|
||||
<div fxLayout="row" fxLayoutAlign="left stretch" fxLayoutGap="30px">
|
||||
<button id="schedulerControllerBtn" mat-raised-button class="btn btn-default large-btn" (click)="startOrPause()">
|
||||
<span *ngIf = "scheduler?.status === 'RUNNING'">
|
||||
<i class="fas fa-pause red"></i>
|
||||
</span>
|
||||
<span *ngIf = "scheduler?.status === 'STOPPED' || scheduler?.status === 'PAUSED'">
|
||||
<i class="fas fa-play green"></i>
|
||||
</span>
|
||||
</button>
|
||||
<div fxLayout="column center">
|
||||
<mat-card-subtitle style="margin: auto;"><b>SCHEDULER</b></mat-card-subtitle>
|
||||
</div>
|
||||
<mat-divider [vertical]="true"></mat-divider>
|
||||
<div fxLayout="column">
|
||||
<div><label>Name</label></div>
|
||||
<div><span id="scheduler-name">{{scheduler?.name}}</span></div>
|
||||
</div>
|
||||
<div fxLayout="column">
|
||||
<div><label>Instance ID</label></div>
|
||||
<div><span id="scheduler-instance">{{scheduler?.instanceId}}</span></div>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
</mat-card>
|
||||
|
||||
@@ -3,4 +3,15 @@
|
||||
}
|
||||
.green{
|
||||
color: green;
|
||||
}
|
||||
}
|
||||
|
||||
label{
|
||||
color: grey;
|
||||
font-variant: small-caps;
|
||||
font-size: smaller;
|
||||
}
|
||||
|
||||
#scheduler-name{
|
||||
text-transform: capitalize;
|
||||
font-size: larger;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
import {async, ComponentFixture, TestBed} from '@angular/core/testing';
|
||||
import {SchedulerControlComponent} from './scheduler-control.component';
|
||||
import {ApiService, ConfigService, SchedulerService, UserService} from '../../services';
|
||||
import {HttpClient} from '@angular/common/http';
|
||||
import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing';
|
||||
import {RouterTestingModule} from '@angular/router/testing';
|
||||
import {DebugElement} from '@angular/core';
|
||||
import {By} from '@angular/platform-browser';
|
||||
import {Scheduler} from '../../model/scheduler.model';
|
||||
import {MatCardModule} from '@angular/material/card';
|
||||
import {MatIconModule} from '@angular/material/icon';
|
||||
import {MatDividerModule} from '@angular/material/divider';
|
||||
|
||||
describe('SchedulerControlComponent', () => {
|
||||
|
||||
let component: SchedulerControlComponent;
|
||||
let fixture: ComponentFixture<SchedulerControlComponent>;
|
||||
|
||||
let httpClient: HttpClient;
|
||||
let httpTestingController: HttpTestingController;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
imports: [MatCardModule, MatDividerModule, MatIconModule, HttpClientTestingModule, RouterTestingModule],
|
||||
declarations: [SchedulerControlComponent],
|
||||
providers: [UserService, SchedulerService, ApiService, ConfigService]
|
||||
}).compileComponents();
|
||||
|
||||
httpClient = TestBed.inject(HttpClient);
|
||||
httpTestingController = TestBed.inject(HttpTestingController);
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SchedulerControlComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should display the play button at the beginning since the scheduler is stopped', () => {
|
||||
expect(component).toBeDefined();
|
||||
const getSchedulerReq = httpTestingController.expectOne('/quartz-manager/scheduler');
|
||||
const mockScheduler = new Scheduler('test-scheduler', 'test-id', 'STOPPED', []);
|
||||
getSchedulerReq.flush(mockScheduler);
|
||||
|
||||
expect(component.scheduler).toEqual(mockScheduler);
|
||||
expect(component.scheduler.status).toEqual('STOPPED');
|
||||
fixture.detectChanges();
|
||||
|
||||
const schedulerControlComponentDe: DebugElement = fixture.debugElement;
|
||||
const schedulerBtnDe = schedulerControlComponentDe.query(By.css('#schedulerControllerBtn'));
|
||||
expect(schedulerBtnDe).toBeTruthy();
|
||||
|
||||
const playIconDe = schedulerBtnDe.query(By.css('.fa-play'));
|
||||
expect(playIconDe).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should switch the button to pause when the scheduler is started', () => {
|
||||
expect(component).toBeDefined();
|
||||
const getSchedulerReq = httpTestingController.expectOne('/quartz-manager/scheduler');
|
||||
const mockScheduler = new Scheduler('test-scheduler', 'test-id', 'STOPPED', []);
|
||||
getSchedulerReq.flush(mockScheduler);
|
||||
fixture.detectChanges();
|
||||
|
||||
const schedulerControlComponentDe: DebugElement = fixture.debugElement;
|
||||
let schedulerBtnDe = schedulerControlComponentDe.query(By.css('#schedulerControllerBtn'));
|
||||
expect(schedulerBtnDe).toBeTruthy();
|
||||
const playIconDe = schedulerBtnDe.query(By.css('.fa-play'));
|
||||
expect(playIconDe).toBeTruthy();
|
||||
|
||||
schedulerBtnDe.nativeElement.click();
|
||||
const startSchedulerReq = httpTestingController.expectOne('/quartz-manager/scheduler/run');
|
||||
startSchedulerReq.flush(null);
|
||||
fixture.detectChanges();
|
||||
|
||||
schedulerBtnDe = schedulerControlComponentDe.query(By.css('#schedulerControllerBtn'));
|
||||
const pauseIconDe = schedulerBtnDe.query(By.css('.fa-pause'));
|
||||
expect(pauseIconDe).toBeTruthy();
|
||||
|
||||
})
|
||||
|
||||
it('should switch the button to play when the scheduler is stopped', () => {
|
||||
expect(component).toBeDefined();
|
||||
const getSchedulerReq = httpTestingController.expectOne('/quartz-manager/scheduler');
|
||||
const mockScheduler = new Scheduler('test-scheduler', 'test-id', 'RUNNING', []);
|
||||
getSchedulerReq.flush(mockScheduler);
|
||||
fixture.detectChanges();
|
||||
|
||||
const schedulerControlComponentDe: DebugElement = fixture.debugElement;
|
||||
let schedulerBtnDe = schedulerControlComponentDe.query(By.css('#schedulerControllerBtn'));
|
||||
expect(schedulerBtnDe).toBeTruthy();
|
||||
const pauseIconDe = schedulerBtnDe.query(By.css('.fa-pause'));
|
||||
expect(pauseIconDe).toBeTruthy();
|
||||
|
||||
schedulerBtnDe.nativeElement.click();
|
||||
const startSchedulerReq = httpTestingController.expectOne('/quartz-manager/scheduler/pause');
|
||||
startSchedulerReq.flush(null);
|
||||
fixture.detectChanges();
|
||||
|
||||
schedulerBtnDe = schedulerControlComponentDe.query(By.css('#schedulerControllerBtn'));
|
||||
const playIconDe = schedulerBtnDe.query(By.css('.fa-play'));
|
||||
expect(playIconDe).toBeTruthy();
|
||||
|
||||
})
|
||||
|
||||
});
|
||||
@@ -1,54 +1,80 @@
|
||||
import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
|
||||
import { UserService, SchedulerService } from '../../services';
|
||||
import {Component, OnInit} from '@angular/core';
|
||||
import {SchedulerService, UserService} from '../../services';
|
||||
import {Scheduler} from '../../model/scheduler.model';
|
||||
|
||||
@Component({
|
||||
selector: 'scheduler-control',
|
||||
selector: 'qrzmng-scheduler-control',
|
||||
templateUrl: './scheduler-control.component.html',
|
||||
styleUrls: ['./scheduler-control.component.scss']
|
||||
})
|
||||
export class SchedulerControlComponent implements OnInit {
|
||||
|
||||
schedulerState;
|
||||
|
||||
scheduler: Scheduler;
|
||||
|
||||
constructor(
|
||||
private userService: UserService,
|
||||
private schedulerService: SchedulerService
|
||||
) { }
|
||||
) {
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.schedulerService.getStatus().subscribe(res => {this.schedulerState = res.data}, err => {console.log(err)});
|
||||
this._getScheduler();
|
||||
}
|
||||
|
||||
startScheduler = function(){
|
||||
this.schedulerService.startScheduler().subscribe((res) => {this.schedulerState = 'running'}, (res) => {console.log(JSON.stringify(res))});
|
||||
private _getScheduler() {
|
||||
this.schedulerService.getScheduler()
|
||||
.subscribe(resp => this.scheduler = resp);
|
||||
}
|
||||
|
||||
startScheduler = function () {
|
||||
this.schedulerService.startScheduler().subscribe((res) => {
|
||||
this.scheduler.status = 'RUNNING'
|
||||
}, (res) => {
|
||||
console.log(JSON.stringify(res))
|
||||
});
|
||||
};
|
||||
|
||||
stopScheduler = function(){
|
||||
this.schedulerService.stopScheduler().subscribe((res) => {this.schedulerState = 'stopped'}, (res) => {console.log(JSON.stringify(res))});
|
||||
stopScheduler = function () {
|
||||
this.schedulerService.stopScheduler().subscribe((res) => {
|
||||
this.scheduler.status = 'STOPPED'
|
||||
}, (res) => {
|
||||
console.log(JSON.stringify(res))
|
||||
});
|
||||
};
|
||||
|
||||
pauseScheduler = function(){
|
||||
this.schedulerService.pauseScheduler().subscribe((res) => {this.schedulerState = 'paused'}, (res) => {console.log(JSON.stringify(res))});
|
||||
pauseScheduler = function () {
|
||||
this.schedulerService.pauseScheduler().subscribe((res) => {
|
||||
this.scheduler.status = 'PAUSED'
|
||||
}, (res) => {
|
||||
console.log(JSON.stringify(res))
|
||||
});
|
||||
};
|
||||
|
||||
resumeScheduler = function(){
|
||||
this.schedulerService.resumeScheduler().subscribe((res) => {this.schedulerState = 'running'}, (res) => {console.log(JSON.stringify(res))});
|
||||
resumeScheduler = function () {
|
||||
this.schedulerService.resumeScheduler().subscribe((res) => {
|
||||
this.scheduler.status = 'RUNNING'
|
||||
}, (res) => {
|
||||
console.log(JSON.stringify(res))
|
||||
});
|
||||
};
|
||||
|
||||
stop = function(){
|
||||
if(this.schedulerState != 'stopped')
|
||||
stop = function () {
|
||||
if (this.scheduler.status !== 'STOPPED') {
|
||||
this.stopScheduler();
|
||||
}
|
||||
}
|
||||
|
||||
startOrPause = function(){
|
||||
switch (this.schedulerState) {
|
||||
case 'running': this.pauseScheduler();
|
||||
break;
|
||||
case 'paused': this.resumeScheduler();
|
||||
break;
|
||||
default:
|
||||
this.startScheduler();
|
||||
break;
|
||||
startOrPause = function () {
|
||||
switch (this.scheduler.status) {
|
||||
case 'RUNNING':
|
||||
this.pauseScheduler();
|
||||
break;
|
||||
case 'PAUSED':
|
||||
this.resumeScheduler();
|
||||
break;
|
||||
default:
|
||||
this.startScheduler();
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<mat-card>
|
||||
<mat-card-header>
|
||||
<mat-card-title><b>SCHEDULER CONFIG</b></mat-card-title>
|
||||
<mat-card-subtitle><b>TRIGGER DETAILS</b></mat-card-subtitle>
|
||||
</mat-card-header>
|
||||
|
||||
<!-- ADD BUTTON -->
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from './trigger-list.component'
|
||||
@@ -0,0 +1,19 @@
|
||||
<mat-card fxFlex="1 1 auto" style="padding-left: 0; padding-right: 0">
|
||||
<mat-card-header fxLayout="row" fxLayoutAlign="space-between none" style="padding-right: 1em;" >
|
||||
<mat-card-subtitle><b>TRIGGERS</b></mat-card-subtitle>
|
||||
<button mat-raised-button style="top: -0.5em" color="primary" (click)="openNewTriggerForm()">
|
||||
new
|
||||
</button>
|
||||
</mat-card-header>
|
||||
<mat-divider></mat-divider>
|
||||
<mat-card-content style="position: relative; height: 100%">
|
||||
<mat-nav-list style="overflow-y: auto; position: absolute; left: 0; right: 0; top: 0; bottom: 0; overflow: auto; height: calc(100% - 3em)">
|
||||
<mat-list-item *ngFor="let triggerKey of triggerKeys">
|
||||
<a matLine href="...">{{ triggerKey.name }}</a>
|
||||
<!-- <button mat-icon-button (click)="showInfo(link)">-->
|
||||
<!-- <mat-icon>info</mat-icon>-->
|
||||
<!-- </button>-->
|
||||
</mat-list-item>
|
||||
</mat-nav-list>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
||||
@@ -0,0 +1,21 @@
|
||||
/* ===== Scrollbar CSS ===== */
|
||||
/* Firefox */
|
||||
* {
|
||||
scrollbar-width: auto;
|
||||
scrollbar-color: #b8b8b8 #ffffff;
|
||||
}
|
||||
|
||||
/* Chrome, Edge, and Safari */
|
||||
*::-webkit-scrollbar {
|
||||
width: 16px;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-track {
|
||||
background: #ffffff;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
background-color: #b8b8b8;
|
||||
border-radius: 10px;
|
||||
border: 3px solid #ffffff;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import {Component, EventEmitter, OnInit, Output} from '@angular/core';
|
||||
import {TriggerService} from '../../services/trigger.service';
|
||||
import {TriggerKey} from '../../model/triggerKey.model';
|
||||
|
||||
@Component({
|
||||
selector: 'qrzmng-trigger-list',
|
||||
templateUrl: './trigger-list.component.html',
|
||||
styleUrls: ['./trigger-list.component.scss']
|
||||
})
|
||||
export class TriggerListComponent implements OnInit {
|
||||
|
||||
loading = true;
|
||||
triggerKeys: Array<TriggerKey> = [];
|
||||
|
||||
@Output() openedNewTriggerFormEvent = new EventEmitter<boolean>();
|
||||
|
||||
constructor(
|
||||
private triggerService: TriggerService
|
||||
) { }
|
||||
|
||||
ngOnInit() {
|
||||
this.loading = true;
|
||||
this.fetchTriggers();
|
||||
}
|
||||
|
||||
private fetchTriggers() {
|
||||
this.triggerService.fetchTriggers()
|
||||
.subscribe((triggerKeys: Array<TriggerKey>) => {
|
||||
this.triggerKeys = triggerKeys;
|
||||
})
|
||||
}
|
||||
|
||||
openNewTriggerForm() {
|
||||
this.openedNewTriggerFormEvent.emit(true);
|
||||
}
|
||||
}
|
||||
@@ -3,10 +3,12 @@ import {TriggerKey} from './triggerKey.model';
|
||||
export class Scheduler {
|
||||
name: string;
|
||||
instanceId: string;
|
||||
status: string;
|
||||
triggerKeys: TriggerKey[];
|
||||
|
||||
constructor(name: string, instanceId: string, triggerKeys: TriggerKey[]) {
|
||||
constructor(name: string, instanceId: string, status: string, triggerKeys: TriggerKey[]) {
|
||||
this.name = name;
|
||||
this.status = status;
|
||||
this.instanceId = instanceId;
|
||||
this.triggerKeys = triggerKeys;
|
||||
}
|
||||
|
||||
@@ -6,4 +6,5 @@ export * from './scheduler.service';
|
||||
export * from './websocket.service';
|
||||
export * from './progress.websocket.service';
|
||||
export * from './logs.websocket.service';
|
||||
export * from './trigger.service'
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import {Trigger} from '../model/trigger.model';
|
||||
import {Observable} from 'rxjs';
|
||||
import {SimpleTriggerCommand} from '../model/simple-trigger.command';
|
||||
import {SchedulerConfig} from '../model/schedulerConfig.model';
|
||||
import {Scheduler} from '../model/scheduler.model';
|
||||
|
||||
@Injectable()
|
||||
export class SchedulerService {
|
||||
@@ -13,19 +14,19 @@ export class SchedulerService {
|
||||
private apiService: ApiService
|
||||
) { }
|
||||
|
||||
startScheduler = () => {
|
||||
startScheduler = (): Observable<void> => {
|
||||
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/run')
|
||||
}
|
||||
|
||||
stopScheduler = () => {
|
||||
stopScheduler = (): Observable<void> => {
|
||||
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/stop')
|
||||
}
|
||||
|
||||
pauseScheduler = () => {
|
||||
pauseScheduler = (): Observable<void> => {
|
||||
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/pause')
|
||||
}
|
||||
|
||||
resumeScheduler = () => {
|
||||
resumeScheduler = (): Observable<void> => {
|
||||
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/resume')
|
||||
}
|
||||
|
||||
@@ -33,7 +34,7 @@ export class SchedulerService {
|
||||
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler/status')
|
||||
}
|
||||
|
||||
getScheduler = () => {
|
||||
getScheduler = (): Observable<Scheduler> => {
|
||||
return this.apiService.get(getBaseUrl() + '/quartz-manager/scheduler')
|
||||
}
|
||||
|
||||
|
||||
20
quartz-manager-frontend/src/app/services/trigger.service.ts
Normal file
20
quartz-manager-frontend/src/app/services/trigger.service.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import {ApiService} from './api.service';
|
||||
import {Injectable} from '@angular/core';
|
||||
import {Observable} from 'rxjs';
|
||||
import {Trigger} from '../model/trigger.model';
|
||||
import {TriggerKey} from '../model/triggerKey.model';
|
||||
import {getBaseUrl} from './config.service';
|
||||
|
||||
@Injectable()
|
||||
export class TriggerService {
|
||||
|
||||
constructor(
|
||||
private apiService: ApiService) {
|
||||
}
|
||||
|
||||
fetchTriggers = (): Observable<Array<TriggerKey>> => {
|
||||
return this.apiService.get(getBaseUrl() + 'quartz-manager/triggers');
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,19 +1,32 @@
|
||||
<div class="content" fxLayout="row" fxLayoutAlign="center none">
|
||||
<div id="managerViewContainer" class="contenttt" fxLayout="column" fxLayoutAlign="left stretch" fxLayoutGap="10px" fxFill>
|
||||
|
||||
<div fxFlex="1 1 30%" fxFill>
|
||||
<div fxLayout="column">
|
||||
<scheduler-control></scheduler-control>
|
||||
<br/>
|
||||
<qrzmng-simple-trigger-config></qrzmng-simple-trigger-config>
|
||||
</div>
|
||||
<div id="schedulerBarContainer" class="contentttt" fxLayout="column" fxLayoutAlign="left stretch">
|
||||
<qrzmng-scheduler-control></qrzmng-scheduler-control>
|
||||
</div>
|
||||
|
||||
<div fxFlex="1 1 70%" style="margin-left: 20px">
|
||||
<div fxLayout="column">
|
||||
<div fxFlex="1 1 100%"><progress-panel></progress-panel></div>
|
||||
<br/>
|
||||
<div fxFlex="1 1 100%"><logs-panel></logs-panel></div>
|
||||
</div>
|
||||
</div>
|
||||
<div fxLayout="row" fxLayoutGap="20px" fxLayoutAlign="center stretch" fxFlex="1 1 auto">
|
||||
|
||||
<div fxFlex="0 0 300px">
|
||||
<div fxLayout="row" fxLayoutAlign="stretch" fxFill>
|
||||
<qrzmng-trigger-list (openedNewTriggerFormEvent)="setnewTriggerFormOpened($event)" fxFill></qrzmng-trigger-list>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div fxFlex="1 1 500px" >
|
||||
<div fxLayout="column">
|
||||
<qrzmng-simple-trigger-config></qrzmng-simple-trigger-config>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div fxFlex="1 1 auto" style="margin-left: 20px">
|
||||
<div fxLayout="column">
|
||||
<div fxFlex="1 1 100%"><progress-panel></progress-panel></div>
|
||||
<br/>
|
||||
<div fxFlex="1 1 100%"><logs-panel></logs-panel></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ import {
|
||||
})
|
||||
export class ManagerComponent implements OnInit {
|
||||
|
||||
whoamIResponse = {};
|
||||
allUserResponse = {};
|
||||
newTriggerFormOpened = false;
|
||||
|
||||
constructor(
|
||||
private config: ConfigService,
|
||||
private userService: UserService
|
||||
@@ -21,4 +21,8 @@ export class ManagerComponent implements OnInit {
|
||||
ngOnInit() {
|
||||
}
|
||||
|
||||
setnewTriggerFormOpened(opened: boolean){
|
||||
this.newTriggerFormOpened = opened;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
/* You can add global styles to this file, and also import other style files */
|
||||
@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';
|
||||
|
||||
html {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
flex:1;
|
||||
background-color: #f1f1f1;
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ import io.swagger.v3.oas.annotations.security.SecurityRequirement;
|
||||
import it.fabioformosa.quartzmanager.dto.SchedulerConfigParam;
|
||||
import it.fabioformosa.quartzmanager.dto.SchedulerDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.TriggerStatus;
|
||||
import it.fabioformosa.quartzmanager.enums.SchedulerStates;
|
||||
import it.fabioformosa.quartzmanager.services.LegacySchedulerService;
|
||||
import it.fabioformosa.quartzmanager.services.SchedulerService;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.SimpleTrigger;
|
||||
import org.quartz.impl.triggers.SimpleTriggerImpl;
|
||||
@@ -24,8 +24,6 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This controller provides scheduler info about config and status. It provides
|
||||
@@ -42,8 +40,11 @@ public class SchedulerController {
|
||||
|
||||
private LegacySchedulerService legacySchedulerService;
|
||||
|
||||
public SchedulerController(LegacySchedulerService legacySchedulerService, ConversionService conversionService) {
|
||||
private SchedulerService schedulerService;
|
||||
|
||||
public SchedulerController(LegacySchedulerService legacySchedulerService, SchedulerService schedulerService, ConversionService conversionService) {
|
||||
this.legacySchedulerService = legacySchedulerService;
|
||||
this.schedulerService = schedulerService;
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
@@ -82,9 +83,8 @@ public class SchedulerController {
|
||||
schema = @Schema(implementation = SchedulerDTO.class)) })
|
||||
})
|
||||
public SchedulerDTO getScheduler() {
|
||||
log.debug("SCHEDULER - GET Scheduler...");
|
||||
SchedulerDTO schedulerDTO = conversionService.convert(legacySchedulerService.getScheduler(), SchedulerDTO.class);
|
||||
return schedulerDTO;
|
||||
log.trace("SCHEDULER - GET Scheduler...");
|
||||
return schedulerService.getScheduler();
|
||||
}
|
||||
|
||||
//TODO move this to the Trigger Controller
|
||||
@@ -113,24 +113,26 @@ public class SchedulerController {
|
||||
return progress;
|
||||
}
|
||||
|
||||
@GetMapping(value = "/status", produces = "application/json")
|
||||
@Operation(summary = "Get the scheduler status")
|
||||
@ApiResponses(value = {
|
||||
@ApiResponse(responseCode = "200", description = "Return the scheduler status",
|
||||
content = { @Content(mediaType = "application/json",
|
||||
schema = @Schema(implementation = SchedulerStates.class)) })
|
||||
})
|
||||
public Map<String, String> getStatus() throws SchedulerException {
|
||||
log.trace("SCHEDULER - GET STATUS");
|
||||
String schedulerState = "";
|
||||
if (legacySchedulerService.getScheduler().isShutdown() || !legacySchedulerService.getScheduler().isStarted())
|
||||
schedulerState = SchedulerStates.STOPPED.toString();
|
||||
else if (legacySchedulerService.getScheduler().isStarted() && legacySchedulerService.getScheduler().isInStandbyMode())
|
||||
schedulerState = SchedulerStates.PAUSED.toString();
|
||||
else
|
||||
schedulerState = SchedulerStates.RUNNING.toString();
|
||||
return Collections.singletonMap("data", schedulerState.toLowerCase());
|
||||
}
|
||||
|
||||
//REMOVEME
|
||||
// @GetMapping(value = "/status", produces = "application/json")
|
||||
// @Operation(summary = "Get the scheduler status")
|
||||
// @ApiResponses(value = {
|
||||
// @ApiResponse(responseCode = "200", description = "Return the scheduler status",
|
||||
// content = { @Content(mediaType = "application/json",
|
||||
// schema = @Schema(implementation = SchedulerStates.class)) })
|
||||
// })
|
||||
// public Map<String, String> getStatus() throws SchedulerException {
|
||||
// log.trace("SCHEDULER - GET STATUS");
|
||||
// String schedulerState = "";
|
||||
// if (legacySchedulerService.getScheduler().isShutdown() || !legacySchedulerService.getScheduler().isStarted())
|
||||
// schedulerState = SchedulerStates.STOPPED.toString();
|
||||
// else if (legacySchedulerService.getScheduler().isStarted() && legacySchedulerService.getScheduler().isInStandbyMode())
|
||||
// schedulerState = SchedulerStates.PAUSED.toString();
|
||||
// else
|
||||
// schedulerState = SchedulerStates.RUNNING.toString();
|
||||
// return Collections.singletonMap("data", schedulerState.toLowerCase());
|
||||
// }
|
||||
|
||||
@GetMapping("/pause")
|
||||
@Operation(summary = "Get paused the scheduler")
|
||||
|
||||
@@ -10,12 +10,14 @@ import it.fabioformosa.quartzmanager.dto.SchedulerConfigParam;
|
||||
import it.fabioformosa.quartzmanager.dto.TriggerDTO;
|
||||
import it.fabioformosa.quartzmanager.exceptions.TriggerNotFoundException;
|
||||
import it.fabioformosa.quartzmanager.services.LegacySchedulerService;
|
||||
import it.fabioformosa.quartzmanager.services.TriggerService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.List;
|
||||
|
||||
@Slf4j
|
||||
@RequestMapping(TriggerController.TRIGGER_CONTROLLER_BASE_URL)
|
||||
@@ -26,11 +28,19 @@ public class TriggerController extends AbstractTriggerController {
|
||||
static public final String TRIGGER_CONTROLLER_BASE_URL = "/quartz-manager/triggers";
|
||||
|
||||
private LegacySchedulerService schedulerService;
|
||||
private TriggerService triggerService;
|
||||
|
||||
public TriggerController(LegacySchedulerService schedulerService) {
|
||||
public TriggerController(LegacySchedulerService schedulerService, TriggerService triggerService) {
|
||||
this.schedulerService = schedulerService;
|
||||
this.triggerService = triggerService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public List<TriggerDTO> listTriggers() throws SchedulerException {
|
||||
return triggerService.fetchTriggers();
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/{name}")
|
||||
public TriggerDTO getTrigger(@PathVariable String name) throws SchedulerException, TriggerNotFoundException {
|
||||
return schedulerService.getLegacyTriggerByName(name);
|
||||
|
||||
@@ -2,8 +2,10 @@ package it.fabioformosa.quartzmanager.converters;
|
||||
|
||||
import it.fabioformosa.metamorphosis.core.converters.AbstractBaseConverterToDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.SchedulerDTO;
|
||||
import it.fabioformosa.quartzmanager.enums.SchedulerStatus;
|
||||
import lombok.SneakyThrows;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.impl.matchers.GroupMatcher;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -16,6 +18,15 @@ public class SchedulerToSchedulerDTO extends AbstractBaseConverterToDTO<Schedule
|
||||
target.setName(source.getSchedulerName());
|
||||
target.setInstanceId(source.getSchedulerInstanceId());
|
||||
target.setTriggerKeys(source.getTriggerKeys(GroupMatcher.anyTriggerGroup()));
|
||||
target.setStatus(buildTheSchedulerStatus(source));
|
||||
}
|
||||
|
||||
private SchedulerStatus buildTheSchedulerStatus(Scheduler scheduler) throws SchedulerException {
|
||||
if (scheduler.isShutdown() || !scheduler.isStarted())
|
||||
return SchedulerStatus.STOPPED;
|
||||
else if (scheduler.isStarted() && scheduler.isInStandbyMode())
|
||||
return SchedulerStatus.PAUSED;
|
||||
return SchedulerStatus.RUNNING;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,35 +1,19 @@
|
||||
package it.fabioformosa.quartzmanager.dto;
|
||||
|
||||
import it.fabioformosa.quartzmanager.enums.SchedulerStatus;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.quartz.TriggerKey;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
@Data
|
||||
public class SchedulerDTO {
|
||||
private String name;
|
||||
private String instanceId;
|
||||
private SchedulerStatus status;
|
||||
private Set<TriggerKey> triggerKeys;
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setInstanceId(String instanceId) {
|
||||
this.instanceId = instanceId;
|
||||
}
|
||||
|
||||
public String getInstanceId() {
|
||||
return instanceId;
|
||||
}
|
||||
|
||||
public void setTriggerKeys(Set<TriggerKey> triggerKeys) {
|
||||
this.triggerKeys = triggerKeys;
|
||||
}
|
||||
|
||||
public Set<TriggerKey> getTriggerKeys() {
|
||||
return triggerKeys;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
package it.fabioformosa.quartzmanager.enums;
|
||||
|
||||
public enum SchedulerStates {
|
||||
public enum SchedulerStatus {
|
||||
RUNNING, STOPPED, PAUSED
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package it.fabioformosa.quartzmanager.services;
|
||||
|
||||
import it.fabioformosa.quartzmanager.dto.SchedulerDTO;
|
||||
import org.quartz.Scheduler;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
@Service
|
||||
public class SchedulerService extends AbstractSchedulerService{
|
||||
|
||||
public SchedulerService(Scheduler scheduler, ConversionService conversionService) {
|
||||
super(scheduler, conversionService);
|
||||
}
|
||||
|
||||
public SchedulerDTO getScheduler() {
|
||||
return conversionService.convert(scheduler, SchedulerDTO.class);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package it.fabioformosa.quartzmanager.services;
|
||||
|
||||
import it.fabioformosa.quartzmanager.dto.TriggerDTO;
|
||||
import it.fabioformosa.quartzmanager.dto.TriggerKeyDTO;
|
||||
import org.quartz.Scheduler;
|
||||
import org.quartz.SchedulerException;
|
||||
import org.quartz.TriggerKey;
|
||||
import org.quartz.impl.matchers.GroupMatcher;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@Service
|
||||
public class TriggerService {
|
||||
|
||||
private Scheduler scheduler;
|
||||
private ConversionService conversionService;
|
||||
|
||||
public TriggerService(Scheduler scheduler, ConversionService conversionService) {
|
||||
this.scheduler = scheduler;
|
||||
this.conversionService = conversionService;
|
||||
}
|
||||
|
||||
public List<TriggerDTO> fetchTriggers() throws SchedulerException {
|
||||
Set<TriggerKey> triggerKeys = scheduler.getTriggerKeys(GroupMatcher.anyTriggerGroup());
|
||||
return (List<TriggerDTO>) conversionService.convert(triggerKeys,
|
||||
TypeDescriptor.collection(Set.class, TypeDescriptor.valueOf(TriggerKey.class)),
|
||||
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(TriggerKeyDTO.class)));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user