+
{{percentageStr}}
diff --git a/quartz-manager-frontend/src/app/components/progress-panel/progress-panel.component.scss b/quartz-manager-frontend/src/app/components/progress-panel/progress-panel.component.scss
index 7aa05ec..51c57ca 100644
--- a/quartz-manager-frontend/src/app/components/progress-panel/progress-panel.component.scss
+++ b/quartz-manager-frontend/src/app/components/progress-panel/progress-panel.component.scss
@@ -31,3 +31,21 @@
.fireBoxContent{
text-align: center;
}
+
+.progress-updated {
+ animation: progressUpdatePulse 700ms ease-out;
+}
+
+@keyframes progressUpdatePulse {
+ 0% {
+ box-shadow: 0 0 0 0 rgba(63, 81, 181, 0.35);
+ }
+
+ 45% {
+ box-shadow: 0 0 0 6px rgba(63, 81, 181, 0.16);
+ }
+
+ 100% {
+ box-shadow: 0 0 0 0 rgba(63, 81, 181, 0);
+ }
+}
diff --git a/quartz-manager-frontend/src/app/components/progress-panel/progress-panel.component.spec.ts b/quartz-manager-frontend/src/app/components/progress-panel/progress-panel.component.spec.ts
new file mode 100644
index 0000000..05b3f86
--- /dev/null
+++ b/quartz-manager-frontend/src/app/components/progress-panel/progress-panel.component.spec.ts
@@ -0,0 +1,102 @@
+import {Subject} from 'rxjs';
+import {ProgressPanelComponent} from './progress-panel.component';
+import {TriggerKey} from '../../model/triggerKey.model';
+import {jest} from '@jest/globals';
+
+describe('ProgressPanelComponent', () => {
+
+ it('should subscribe to the selected trigger progress topic', () => {
+ jest.useFakeTimers();
+ const messages = new Subject
();
+ const progressRxWebsocketService = {
+ watch: jest.fn(() => messages.asObservable())
+ };
+ const component = new ProgressPanelComponent(progressRxWebsocketService as any);
+
+ component.triggerKey = new TriggerKey('trigger-1', null);
+
+ expect(progressRxWebsocketService.watch).toHaveBeenCalledWith('/topic/progress/trigger-1');
+
+ messages.next({body: JSON.stringify({percentage: 75, timesTriggered: 3})});
+ jest.runOnlyPendingTimers();
+
+ expect(component.progress.percentage).toEqual(75);
+ expect(component.percentageStr).toEqual('75%');
+ expect(component.progressUpdated).toBeTruthy();
+ jest.useRealTimers();
+ });
+
+ it('should unsubscribe from the previous topic when the trigger changes', () => {
+ const firstMessages = new Subject();
+ const secondMessages = new Subject();
+ const progressRxWebsocketService = {
+ watch: jest.fn()
+ .mockReturnValueOnce(firstMessages.asObservable())
+ .mockReturnValueOnce(secondMessages.asObservable())
+ };
+ const component = new ProgressPanelComponent(progressRxWebsocketService as any);
+
+ component.triggerKey = new TriggerKey('trigger-1', null);
+ const firstSubscription = component.topicSubscription;
+ jest.spyOn(firstSubscription, 'unsubscribe');
+
+ component.triggerKey = new TriggerKey('trigger-2', null);
+
+ expect(firstSubscription.unsubscribe).toHaveBeenCalled();
+ expect(progressRxWebsocketService.watch).toHaveBeenCalledWith('/topic/progress/trigger-2');
+ });
+
+ it('should reset progress when the trigger changes', () => {
+ const firstMessages = new Subject();
+ const secondMessages = new Subject();
+ const progressRxWebsocketService = {
+ watch: jest.fn()
+ .mockReturnValueOnce(firstMessages.asObservable())
+ .mockReturnValueOnce(secondMessages.asObservable())
+ .mockReturnValueOnce(firstMessages.asObservable())
+ };
+ const component = new ProgressPanelComponent(progressRxWebsocketService as any);
+
+ component.triggerKey = new TriggerKey('trigger-1', null);
+ firstMessages.next({body: JSON.stringify({percentage: 75, timesTriggered: 3})});
+ expect(component.progress.percentage).toEqual(75);
+
+ component.triggerKey = new TriggerKey('trigger-2', null);
+ expect(component.progress.percentage).toEqual(-1);
+ expect(component.percentageStr).toBeNull();
+ expect(component.progressUpdated).toBeFalsy();
+
+ secondMessages.next({body: JSON.stringify({percentage: 20, timesTriggered: 1})});
+ expect(component.progress.percentage).toEqual(20);
+
+ component.triggerKey = new TriggerKey('trigger-1', null);
+ expect(component.progress.percentage).toEqual(-1);
+ });
+
+ it('should reset progress when no trigger is selected', () => {
+ const messages = new Subject();
+ const progressRxWebsocketService = {
+ watch: jest.fn(() => messages.asObservable())
+ };
+ const component = new ProgressPanelComponent(progressRxWebsocketService as any);
+
+ component.triggerKey = new TriggerKey('trigger-1', null);
+ messages.next({body: JSON.stringify({percentage: 75, timesTriggered: 3})});
+
+ component.triggerKey = null;
+
+ expect(component.progress.percentage).toEqual(-1);
+ expect(component.percentageStr).toBeNull();
+ expect(component.progressUpdated).toBeFalsy();
+ });
+
+ it('should ignore destroy when no topic was selected', () => {
+ const progressRxWebsocketService = {
+ watch: jest.fn()
+ };
+ const component = new ProgressPanelComponent(progressRxWebsocketService as any);
+
+ expect(() => component.ngOnDestroy()).not.toThrow();
+ });
+
+});
diff --git a/quartz-manager-frontend/src/app/components/progress-panel/progress-panel.component.ts b/quartz-manager-frontend/src/app/components/progress-panel/progress-panel.component.ts
index 0d50777..550305a 100644
--- a/quartz-manager-frontend/src/app/components/progress-panel/progress-panel.component.ts
+++ b/quartz-manager-frontend/src/app/components/progress-panel/progress-panel.component.ts
@@ -1,84 +1,91 @@
-import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core'
-import {ProgressWebsocketService, QuartzManagerWebsocketMessage} from '../../services';
-
-import { Observable } from 'rxjs';
+import {Component, Input, OnDestroy, OnInit} from '@angular/core'
import TriggerFiredBundle from '../../model/trigger-fired-bundle.model';
-// import {Message} from '@stomp/stompjs';
-
-// import { Subscription } from 'rxjs/Subscription';
-// import {StompService} from '@stomp/ng2-stompjs';
-
-// import { QueueingSubject } from 'queueing-subject'
-// import websocketConnect from 'rxjs-websockets'
-// import 'rxjs/add/operator/share'
-// import {ServerSocket} from '../../services/qz.socket.service'
+import {TriggerKey} from '../../model/triggerKey.model';
+import {ProgressRxWebsocketService} from '../../services/progress.rx-websocket.service';
+import {map} from 'rxjs/operators';
@Component({
selector: 'progress-panel',
templateUrl: './progress-panel.component.html',
styleUrls: ['./progress-panel.component.scss']
})
-export class ProgressPanelComponent implements OnInit {
-
- progress: TriggerFiredBundle = new TriggerFiredBundle();
- percentageStr: string;
-
- // // Stream of messages
- // private subscription: Subscription;
- // public messages: Observable;
- // // Subscription status
- // public subscribed: boolean;
- // // Array of historic message (bodies)
- // public mq: Array = [];
+export class ProgressPanelComponent implements OnInit, OnDestroy {
+
+ progress: TriggerFiredBundle = ProgressPanelComponent._buildEmptyProgress();
+ percentageStr: string;
+ progressUpdated = false;
+ topicSubscription;
+ private selectedTriggerKey: TriggerKey;
constructor(
- private progressWebsocketService: ProgressWebsocketService,
- // private _stompService: StompService,
- // private serverSocket : ServerSocket
+ private progressRxWebsocketService: ProgressRxWebsocketService
) { }
- onNewProgressMsg = (receivedMsg: QuartzManagerWebsocketMessage) => {
- if (receivedMsg.type === 'SUCCESS') {
- const newStatus = receivedMsg.message;
- this.progress = newStatus;
- this.percentageStr = this.progress.percentage + '%';
- }
- }
+ @Input()
+ set triggerKey(triggerKey: TriggerKey) {
+ if (!triggerKey || !triggerKey.name) {
+ this._unsubscribeFromTopic();
+ this.selectedTriggerKey = null;
+ this._resetProgress();
+ return;
+ }
+
+ if (this.selectedTriggerKey?.name === triggerKey.name) {
+ return;
+ }
+
+ this._resetProgress();
+ this.selectedTriggerKey = {...triggerKey} as TriggerKey;
+ this._subscribeToTheTopic(this.selectedTriggerKey);
+ }
+
+ private _subscribeToTheTopic = (triggerKey: TriggerKey) => {
+ this._unsubscribeFromTopic();
+ this.topicSubscription = this.progressRxWebsocketService.watch(`/topic/progress/${triggerKey.name}`)
+ .pipe(map((msg: any) => JSON.parse(msg.body)))
+ .subscribe(this.onNewProgressMsg, (err) => {
+ console.log(err);
+ // TODO in case of 401
+ // this.apiService.get('/quartz-manager/session/refresh');
+ });
+ };
+
+ onNewProgressMsg = (receivedMsg) => {
+ this.progress = receivedMsg;
+ this.percentageStr = this.progress.percentage + '%';
+ this._markProgressUpdated();
+ }
ngOnInit() {
- const obs = this.progressWebsocketService.getObservable()
- obs.subscribe({
- 'next' : this.onNewProgressMsg,
- 'error' : (err) => {console.log(err)}
- });
-
- // this.subscribed = false;
- // this.subscribe();
-
- // this.serverSocket.connect()
- // this.socketSubscription = this.serverSocket.messages.subscribe((message: string) => {
- // console.log('received message from server: ', message)
- // })
- }
-
- // public subscribe() {
- // if (this.subscribed) {
- // return;
- // }
-
- // // Stream of messages
- // this.messages = this._stompService.subscribe('/topic/progress');
-
- // // Subscribe a function to be run on_next message
- // this.subscription = this.messages.subscribe(this.on_next);
-
- // this.subscribed = true;
- // }
-
- // public on_next = (message: Message) => {
- // this.mq.push(message.body + '\n');
- // console.log(message);
- // }
-
-}
+ }
+
+ ngOnDestroy() {
+ this._unsubscribeFromTopic();
+ }
+
+ private _unsubscribeFromTopic() {
+ if (this.topicSubscription) {
+ this.topicSubscription.unsubscribe();
+ this.topicSubscription = null;
+ }
+ }
+
+ private _resetProgress() {
+ this.progress = ProgressPanelComponent._buildEmptyProgress();
+ this.percentageStr = null;
+ this.progressUpdated = false;
+ }
+
+ private _markProgressUpdated() {
+ this.progressUpdated = false;
+ setTimeout(() => this.progressUpdated = true);
+ }
+
+ private static _buildEmptyProgress() {
+ const progress = new TriggerFiredBundle();
+ progress.percentage = -1;
+ return progress;
+ }
+
+}
diff --git a/quartz-manager-frontend/src/app/components/scheduler-control/scheduler-control.component.spec.ts b/quartz-manager-frontend/src/app/components/scheduler-control/scheduler-control.component.spec.ts
index 266fe11..2245bb0 100644
--- a/quartz-manager-frontend/src/app/components/scheduler-control/scheduler-control.component.spec.ts
+++ b/quartz-manager-frontend/src/app/components/scheduler-control/scheduler-control.component.spec.ts
@@ -13,6 +13,12 @@ import {MatDividerModule} from '@angular/material/divider';
describe('SchedulerControlComponent', () => {
+ const schedulerUrl = '/quartz-manager/scheduler';
+ const schedulerButtonSelector = '#schedulerControllerBtn';
+ const schedulerName = 'test-scheduler';
+ const schedulerId = 'test-id';
+ const stoppedStatus = 'STOPPED';
+
let component: SchedulerControlComponent;
let fixture: ComponentFixture;
@@ -38,16 +44,16 @@ describe('SchedulerControlComponent', () => {
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', []);
+ const getSchedulerReq = httpTestingController.expectOne(schedulerUrl);
+ const mockScheduler = new Scheduler(schedulerName, schedulerId, stoppedStatus, []);
getSchedulerReq.flush(mockScheduler);
expect(component.scheduler).toEqual(mockScheduler);
- expect(component.scheduler.status).toEqual('STOPPED');
+ expect(component.scheduler.status).toEqual(stoppedStatus);
fixture.detectChanges();
const schedulerControlComponentDe: DebugElement = fixture.debugElement;
- const schedulerBtnDe = schedulerControlComponentDe.query(By.css('#schedulerControllerBtn'));
+ const schedulerBtnDe = schedulerControlComponentDe.query(By.css(schedulerButtonSelector));
expect(schedulerBtnDe).toBeTruthy();
const playIconDe = schedulerBtnDe.query(By.css('.fa-play'));
@@ -56,13 +62,13 @@ describe('SchedulerControlComponent', () => {
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', []);
+ const getSchedulerReq = httpTestingController.expectOne(schedulerUrl);
+ const mockScheduler = new Scheduler(schedulerName, schedulerId, stoppedStatus, []);
getSchedulerReq.flush(mockScheduler);
fixture.detectChanges();
const schedulerControlComponentDe: DebugElement = fixture.debugElement;
- let schedulerBtnDe = schedulerControlComponentDe.query(By.css('#schedulerControllerBtn'));
+ let schedulerBtnDe = schedulerControlComponentDe.query(By.css(schedulerButtonSelector));
expect(schedulerBtnDe).toBeTruthy();
const playIconDe = schedulerBtnDe.query(By.css('.fa-play'));
expect(playIconDe).toBeTruthy();
@@ -72,7 +78,7 @@ describe('SchedulerControlComponent', () => {
startSchedulerReq.flush(null);
fixture.detectChanges();
- schedulerBtnDe = schedulerControlComponentDe.query(By.css('#schedulerControllerBtn'));
+ schedulerBtnDe = schedulerControlComponentDe.query(By.css(schedulerButtonSelector));
const pauseIconDe = schedulerBtnDe.query(By.css('.fa-pause'));
expect(pauseIconDe).toBeTruthy();
@@ -80,13 +86,13 @@ describe('SchedulerControlComponent', () => {
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', []);
+ const getSchedulerReq = httpTestingController.expectOne(schedulerUrl);
+ const mockScheduler = new Scheduler(schedulerName, schedulerId, 'RUNNING', []);
getSchedulerReq.flush(mockScheduler);
fixture.detectChanges();
const schedulerControlComponentDe: DebugElement = fixture.debugElement;
- let schedulerBtnDe = schedulerControlComponentDe.query(By.css('#schedulerControllerBtn'));
+ let schedulerBtnDe = schedulerControlComponentDe.query(By.css(schedulerButtonSelector));
expect(schedulerBtnDe).toBeTruthy();
const pauseIconDe = schedulerBtnDe.query(By.css('.fa-pause'));
expect(pauseIconDe).toBeTruthy();
@@ -96,7 +102,7 @@ describe('SchedulerControlComponent', () => {
startSchedulerReq.flush(null);
fixture.detectChanges();
- schedulerBtnDe = schedulerControlComponentDe.query(By.css('#schedulerControllerBtn'));
+ schedulerBtnDe = schedulerControlComponentDe.query(By.css(schedulerButtonSelector));
const playIconDe = schedulerBtnDe.query(By.css('.fa-play'));
expect(playIconDe).toBeTruthy();
diff --git a/quartz-manager-frontend/src/app/components/simple-trigger-config/simple-trigger-config.component.spec.ts b/quartz-manager-frontend/src/app/components/simple-trigger-config/simple-trigger-config.component.spec.ts
index 1f66f48..422752f 100644
--- a/quartz-manager-frontend/src/app/components/simple-trigger-config/simple-trigger-config.component.spec.ts
+++ b/quartz-manager-frontend/src/app/components/simple-trigger-config/simple-trigger-config.component.spec.ts
@@ -23,6 +23,11 @@ import {MisfireInstruction} from '../../model/misfire-instruction.model';
describe('SimpleTriggerConfig', () => {
+ const submitButtonSelector = 'form button[color="primary"]';
+ const repeatIntervalSelector = '#repeatInterval';
+ const testTriggerName = 'test-trigger';
+ const testJobName = 'TestJob';
+
let component: SimpleTriggerConfigComponent;
let fixture: ComponentFixture;
@@ -91,16 +96,16 @@ describe('SimpleTriggerConfig', () => {
fixture.detectChanges();
const getJobsReq = httpTestingController.expectOne(`${CONTEXT_PATH}/jobs`);
- getJobsReq.flush(['TestJob']);
+ getJobsReq.flush([testJobName]);
const componentDe: DebugElement = fixture.debugElement;
- const submitButton = componentDe.query(By.css('form button[color="primary"]'));
+ const submitButton = componentDe.query(By.css(submitButtonSelector));
expect(submitButton.nativeElement.textContent.trim()).toEqual('Submit');
expect(submitButton.nativeElement.getAttribute('disabled')).toEqual('');
- setInputValue(componentDe, '#triggerName', 'test-trigger');
- expect(component.simpleTriggerReactiveForm.controls.triggerName.value).toEqual('test-trigger');
+ setInputValue(componentDe, '#triggerName', testTriggerName);
+ expect(component.simpleTriggerReactiveForm.controls.triggerName.value).toEqual(testTriggerName);
expect(submitButton.nativeElement.getAttribute('disabled')).toEqual('');
setMatSelectValueByIndex(componentDe, '#misfireInstruction', 0);
expect(component.simpleTriggerReactiveForm.controls.misfireInstruction.value).toEqual('MISFIRE_INSTRUCTION_FIRE_NOW');
@@ -111,7 +116,7 @@ describe('SimpleTriggerConfig', () => {
setInputValue(componentDe, '#repeatCount', '1000');
expect(submitButton.nativeElement.getAttribute('disabled')).toEqual('');
- setInputValue(componentDe, '#repeatInterval', '2000');
+ setInputValue(componentDe, repeatIntervalSelector, '2000');
expect(submitButton.nativeElement.getAttribute('disabled')).toEqual(null);
}
@@ -122,18 +127,18 @@ describe('SimpleTriggerConfig', () => {
it('should emit an event when a new trigger is submitted', () => {
const componentDe: DebugElement = fixture.debugElement;
const mockTrigger = new Trigger();
- mockTrigger.triggerKeyDTO = new TriggerKey('test-trigger', null);
- mockTrigger.jobDetailDTO = {jobClassName: 'TestJob', description: null};
+ mockTrigger.triggerKeyDTO = new TriggerKey(testTriggerName, null);
+ mockTrigger.jobDetailDTO = {jobClassName: testJobName, description: null};
mockTrigger.misfireInstruction = MisfireInstruction.MISFIRE_INSTRUCTION_FIRE_NOW;
openFormAndFillAllMandatoryFields();
- setInputValue(componentDe, '#repeatInterval', '2000');
+ setInputValue(componentDe, repeatIntervalSelector, '2000');
expect(component.simpleTriggerReactiveForm.controls.triggerRecurrence.value.repeatInterval).toEqual(2000);
setInputValue(componentDe, '#repeatCount', '100');
expect(component.simpleTriggerReactiveForm.controls.triggerRecurrence.value.repeatCount).toEqual(100);
- const submitButton = componentDe.query(By.css('form button[color="primary"]'));
+ const submitButton = componentDe.query(By.css(submitButtonSelector));
expect(submitButton.nativeElement.textContent.trim()).toEqual('Submit');
let actualNewTrigger;
@@ -141,28 +146,28 @@ describe('SimpleTriggerConfig', () => {
submitButton.nativeElement.click();
- const postSimpleTriggerReq = httpTestingController.expectOne(`${CONTEXT_PATH}/simple-triggers/test-trigger`);
+ const postSimpleTriggerReq = httpTestingController.expectOne(`${CONTEXT_PATH}/simple-triggers/${testTriggerName}`);
postSimpleTriggerReq.flush(mockTrigger);
expect(actualNewTrigger).toEqual(mockTrigger);
});
it('should not emit an event when an existing trigger is edited', () => {
- const mockTriggerKey = new TriggerKey('test-trigger', null);
+ const mockTriggerKey = new TriggerKey(testTriggerName, null);
component.triggerKey = mockTriggerKey;
fixture.detectChanges();
const mockTrigger = new SimpleTrigger();
- mockTrigger.triggerKeyDTO = new TriggerKey('test-trigger', null);
- mockTrigger.jobDetailDTO = {jobClassName: 'TestJob', description: null};
+ mockTrigger.triggerKeyDTO = new TriggerKey(testTriggerName, null);
+ mockTrigger.jobDetailDTO = {jobClassName: testJobName, description: null};
mockTrigger.mayFireAgain = true;
mockTrigger.misfireInstruction = MisfireInstruction.MISFIRE_INSTRUCTION_FIRE_NOW;
- const getSimpleTriggerReq = httpTestingController.expectOne(`${CONTEXT_PATH}/simple-triggers/test-trigger`);
+ const getSimpleTriggerReq = httpTestingController.expectOne(`${CONTEXT_PATH}/simple-triggers/${testTriggerName}`);
getSimpleTriggerReq.flush(mockTrigger);
component.simpleTriggerReactiveForm.setValue({
- triggerName: 'test-trigger',
- jobClass: 'TestJob',
+ triggerName: testTriggerName,
+ jobClass: testJobName,
triggerRecurrence: {
repeatInterval: 2000,
repeatCount: 100,
@@ -178,10 +183,10 @@ describe('SimpleTriggerConfig', () => {
fixture.detectChanges();
const componentDe: DebugElement = fixture.debugElement;
- setInputValue(componentDe, '#repeatInterval', '4000');
+ setInputValue(componentDe, repeatIntervalSelector, '4000');
expect(component.simpleTriggerReactiveForm.controls.triggerRecurrence.value.repeatInterval).toEqual(4000);
- const submitButton = componentDe.query(By.css('form button[color="primary"]'));
+ const submitButton = componentDe.query(By.css(submitButtonSelector));
expect(submitButton.nativeElement.textContent.trim()).toEqual('Submit');
let actualNewTrigger;
@@ -189,7 +194,7 @@ describe('SimpleTriggerConfig', () => {
submitButton.nativeElement.click();
- const putSimpleTriggerReq = httpTestingController.expectOne(`${CONTEXT_PATH}/simple-triggers/test-trigger`);
+ const putSimpleTriggerReq = httpTestingController.expectOne(`${CONTEXT_PATH}/simple-triggers/${testTriggerName}`);
putSimpleTriggerReq.flush(mockTrigger);
expect(actualNewTrigger).toBeUndefined();
@@ -220,8 +225,34 @@ describe('SimpleTriggerConfig', () => {
fixture.detectChanges();
const componentDe: DebugElement = fixture.debugElement;
- const submitButton = componentDe.query(By.css('form button[color="primary"]'));
+ const submitButton = componentDe.query(By.css(submitButtonSelector));
expect(submitButton.nativeElement.textContent.trim()).toEqual('Submit');
+
+ expect(component.simpleTriggerReactiveForm.value.triggerName).toBeNull();
+
+ });
+
+ it('should reset the form when a new trigger is selected', () => {
+ const mockTriggerKey = new TriggerKey(testTriggerName, null);
+ component.triggerKey = mockTriggerKey;
+
+ const mockTrigger = new SimpleTrigger();
+ mockTrigger.triggerKeyDTO = mockTriggerKey;
+ mockTrigger.jobDetailDTO = {jobClassName: testJobName, description: null};
+ mockTrigger.mayFireAgain = true;
+ mockTrigger.misfireInstruction = MisfireInstruction.MISFIRE_INSTRUCTION_FIRE_NOW;
+
+ const getSimpleTriggerReq = httpTestingController.expectOne(`${CONTEXT_PATH}/simple-triggers/${testTriggerName}`);
+ getSimpleTriggerReq.flush(mockTrigger);
+
+ expect(component.simpleTriggerReactiveForm.value.triggerName).toEqual(testTriggerName);
+
+ component.triggerKey = null;
+
+ expect(component.simpleTriggerReactiveForm.value.triggerName).toBeNull();
+ expect(component.simpleTriggerReactiveForm.value.jobClass).toBeNull();
+ expect(component.shouldShowTheTriggerCardContent()).toBeTruthy();
+
});
it('should display the warning if there are no eligible jobs', () => {
diff --git a/quartz-manager-frontend/src/app/components/simple-trigger-config/simple-trigger-config.component.ts b/quartz-manager-frontend/src/app/components/simple-trigger-config/simple-trigger-config.component.ts
index 1b643ae..99ae80f 100644
--- a/quartz-manager-frontend/src/app/components/simple-trigger-config/simple-trigger-config.component.ts
+++ b/quartz-manager-frontend/src/app/components/simple-trigger-config/simple-trigger-config.component.ts
@@ -34,9 +34,8 @@ export class SimpleTriggerConfigComponent implements OnInit {
scheduler: Scheduler;
- triggerLoading = true;
+ triggerLoading = false;
- private fetchedTriggers = false;
private triggerInProgress = false;
private selectedTriggerKey: TriggerKey;
@@ -48,6 +47,9 @@ export class SimpleTriggerConfigComponent implements OnInit {
@Output()
onNewTrigger = new EventEmitter();
+ @Output()
+ triggerFormOpenChange = new EventEmitter();
+
constructor(
private formBuilder: UntypedFormBuilder,
private schedulerService: SchedulerService,
@@ -65,18 +67,37 @@ export class SimpleTriggerConfigComponent implements OnInit {
openTriggerForm() {
this.enabledTriggerForm = true;
+ this.triggerFormOpenChange.emit(this.enabledTriggerForm);
}
private closeTriggerForm() {
this.enabledTriggerForm = false;
+ this.triggerFormOpenChange.emit(this.enabledTriggerForm);
}
@Input()
set triggerKey(triggerKey: TriggerKey) {
- this.selectedTriggerKey = {...triggerKey} as TriggerKey;
- this.fetchSelectedTrigger();
+ if (!triggerKey) {
+ this.openNewTriggerForm();
+ } else if (!this.selectedTriggerKey || this.selectedTriggerKey.name !== triggerKey.name) {
+ this._resetTheTrigger();
+ this.selectedTriggerKey = {...triggerKey} as TriggerKey;
+ this.fetchSelectedTrigger();
+ this.closeTriggerForm();
+ }
}
+ openNewTriggerForm() {
+ this._resetTheTrigger();
+ this.openTriggerForm();
+ }
+
+ private _resetTheTrigger() {
+ this.trigger = null;
+ this.triggerInProgress = false;
+ this.selectedTriggerKey = null;
+ this.simpleTriggerReactiveForm.reset(new SimpleTriggerReactiveForm());
+ }
fetchSelectedTrigger = () => {
this.triggerLoading = true;
@@ -94,7 +115,11 @@ export class SimpleTriggerConfigComponent implements OnInit {
existsATriggerInProgress = (): boolean => this.trigger && this.triggerInProgress;
onResetReactiveForm = () => {
- this.simpleTriggerReactiveForm.setValue(this._fromTriggerToReactiveForm(this.trigger));
+ if (this.trigger) {
+ this.simpleTriggerReactiveForm.setValue(this._fromTriggerToReactiveForm(this.trigger));
+ } else {
+ this.simpleTriggerReactiveForm.reset(new SimpleTriggerReactiveForm());
+ }
this.closeTriggerForm();
};
@@ -103,13 +128,13 @@ export class SimpleTriggerConfigComponent implements OnInit {
this.schedulerService.updateSimpleTriggerConfig : this.schedulerService.saveSimpleTriggerConfig;
const simpleTriggerCommand = this._fromReactiveFormToCommand();
+ this.triggerLoading = true;
schedulerServiceCall(simpleTriggerCommand)
.subscribe((retTrigger: SimpleTrigger) => {
this.trigger = retTrigger;
this.simpleTriggerReactiveForm.setValue(this._fromTriggerToReactiveForm(retTrigger));
- this.fetchedTriggers = true;
this.triggerInProgress = this.trigger.mayFireAgain;
if (schedulerServiceCall === this.schedulerService.saveSimpleTriggerConfig) {
@@ -118,8 +143,13 @@ export class SimpleTriggerConfigComponent implements OnInit {
this.closeTriggerForm();
}, error => {
- this.simpleTriggerReactiveForm.setValue(this._fromTriggerToReactiveForm(this.trigger));
- });
+ if (this.trigger) {
+ this.simpleTriggerReactiveForm.setValue(this._fromTriggerToReactiveForm(this.trigger));
+ }
+ this.triggerLoading = false;
+ }, () => {
+this.triggerLoading = false
+});
}
diff --git a/quartz-manager-frontend/src/app/components/trigger-list/trigger-list.component.html b/quartz-manager-frontend/src/app/components/trigger-list/trigger-list.component.html
index 88677dd..7718dfb 100644
--- a/quartz-manager-frontend/src/app/components/trigger-list/trigger-list.component.html
+++ b/quartz-manager-frontend/src/app/components/trigger-list/trigger-list.component.html
@@ -9,7 +9,9 @@
+ [ngClass]="{'selectedTrigger': selectedTrigger && selectedTrigger.name==triggerKey.name}"
+ (click)="selectTrigger(triggerKey)"
+ >
{{ triggerKey.name }}
diff --git a/quartz-manager-frontend/src/app/components/trigger-list/trigger-list.component.ts b/quartz-manager-frontend/src/app/components/trigger-list/trigger-list.component.ts
index 9e98f91..3a41163 100644
--- a/quartz-manager-frontend/src/app/components/trigger-list/trigger-list.component.ts
+++ b/quartz-manager-frontend/src/app/components/trigger-list/trigger-list.component.ts
@@ -81,16 +81,17 @@ export class TriggerListComponent implements OnInit {
}
onNewTriggerBtnClicked() {
- if (this.getTriggerKeyList() && this.getTriggerKeyList().length > 0) {
- this.dialog.open(UnsupportedMultipleJobsDialog)
- } else {
- this.onNewTriggerClicked.emit();
- }
+ this.onNewTriggerClicked.emit();
+ // if (this.getTriggerKeyList() && this.getTriggerKeyList().length > 0) {
+ // this.dialog.open(UnsupportedMultipleJobsDialog)
+ // } else {
+ // this.onNewTriggerClicked.emit();
+ // }
}
onNewTrigger(newTrigger: SimpleTrigger) {
this.newTriggers = [newTrigger, ...this.newTriggers];
- this.selectedTrigger = newTrigger.triggerKeyDTO;
+ this.selectTrigger(newTrigger.triggerKeyDTO);
}
}
diff --git a/quartz-manager-frontend/src/app/polyfills.ts b/quartz-manager-frontend/src/app/polyfills.ts
index 622efa0..766305d 100644
--- a/quartz-manager-frontend/src/app/polyfills.ts
+++ b/quartz-manager-frontend/src/app/polyfills.ts
@@ -14,7 +14,7 @@
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
*/
-/***************************************************************************************************
+/** *************************************************************************************************
* BROWSER POLYFILLS
*/
@@ -51,14 +51,14 @@ import 'core-js/es7/reflect';
-/***************************************************************************************************
+/** *************************************************************************************************
* Zone JS is required by Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
-/***************************************************************************************************
+/** *************************************************************************************************
* APPLICATION IMPORTS
*/
@@ -68,7 +68,7 @@ import 'zone.js/dist/zone'; // Included with Angular CLI.
*/
// import 'intl'; // Run `npm install --save intl`.
-/***************************************************************************************************
+/** *************************************************************************************************
* MATERIAL 2
*/
import 'hammerjs/hammer';
diff --git a/quartz-manager-frontend/src/app/services/index.ts b/quartz-manager-frontend/src/app/services/index.ts
index a3e5802..81435d0 100644
--- a/quartz-manager-frontend/src/app/services/index.ts
+++ b/quartz-manager-frontend/src/app/services/index.ts
@@ -3,9 +3,8 @@ export * from './user.service';
export * from './config.service';
export * from './auth.service';
export * from './scheduler.service';
-export * from './websocket.service';
-export * from './progress.websocket.service';
-export * from './logs.websocket.service';
+export * from './progress.rx-websocket.service';
+export * from './logs.rx-websocket.service';
export * from './trigger.service'
export * from './job.service'
diff --git a/quartz-manager-frontend/src/app/services/logs.rx-websocket.service.spec.ts b/quartz-manager-frontend/src/app/services/logs.rx-websocket.service.spec.ts
new file mode 100644
index 0000000..64fa05e
--- /dev/null
+++ b/quartz-manager-frontend/src/app/services/logs.rx-websocket.service.spec.ts
@@ -0,0 +1,39 @@
+import { TestBed } from '@angular/core/testing';
+
+import { LogsRxWebsocketService } from './logs.rx-websocket.service';
+import {ApiService} from './api.service';
+import {RxStomp} from '@stomp/rx-stomp';
+import {jest} from '@jest/globals';
+
+describe('LogsRxWebsocketService', () => {
+ let service: LogsRxWebsocketService;
+ let configureSpy;
+ let activateSpy;
+
+ beforeEach(() => {
+ configureSpy = jest.spyOn(RxStomp.prototype, 'configure');
+ activateSpy = jest.spyOn(RxStomp.prototype, 'activate').mockImplementation(() => undefined);
+
+ TestBed.configureTestingModule({
+ providers: [
+ {provide: ApiService, useValue: {getToken: () => 'test-token'}}
+ ]
+ });
+ service = TestBed.inject(LogsRxWebsocketService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+
+ it('should configure rx-stomp with the logs websocket endpoint', () => {
+ expect(configureSpy).toHaveBeenCalled();
+ expect(activateSpy).toHaveBeenCalled();
+
+ const config = configureSpy.mock.calls[configureSpy.mock.calls.length - 1][0];
+ expect(config.heartbeatIncoming).toEqual(0);
+ expect(config.heartbeatOutgoing).toEqual(20000);
+ expect(config.reconnectDelay).toEqual(200);
+ expect(config.webSocketFactory.toString()).toContain('/logs?access_token=');
+ });
+});
diff --git a/quartz-manager-frontend/src/app/services/logs.rx-websocket.service.ts b/quartz-manager-frontend/src/app/services/logs.rx-websocket.service.ts
new file mode 100644
index 0000000..76a07b4
--- /dev/null
+++ b/quartz-manager-frontend/src/app/services/logs.rx-websocket.service.ts
@@ -0,0 +1,23 @@
+import { Injectable } from '@angular/core';
+import {RxStompService} from './rx-stomp.service';
+import {ApiService} from './api.service';
+import SockJS from 'sockjs-client';
+import {CONTEXT_PATH, getBaseUrl} from './config.service';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class LogsRxWebsocketService extends RxStompService {
+
+ constructor(private apiService: ApiService) {
+ super({
+ webSocketFactory: () => new SockJS(`${getBaseUrl()}${CONTEXT_PATH}/logs?access_token=${this.apiService.getToken()}`),
+ heartbeatIncoming: 0,
+ heartbeatOutgoing: 20000,
+ reconnectDelay: 200,
+ debug: (msg: string): void => {
+ console.log(new Date(), msg);
+ }
+ });
+ }
+}
diff --git a/quartz-manager-frontend/src/app/services/logs.websocket.service.ts b/quartz-manager-frontend/src/app/services/logs.websocket.service.ts
deleted file mode 100644
index 97e77dd..0000000
--- a/quartz-manager-frontend/src/app/services/logs.websocket.service.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import {Injectable} from '@angular/core';
-import {WebsocketService, ApiService, getBaseUrl, CONTEXT_PATH} from '.';
-import {SocketOption} from '../model/SocketOption.model';
-
-@Injectable()
-export class LogsWebsocketService extends WebsocketService {
-
- constructor(private apiService: ApiService) {
- super(new SocketOption(getBaseUrl() + `${CONTEXT_PATH}/logs`, '/topic/logs', apiService.getToken))
- }
-
-}
diff --git a/quartz-manager-frontend/src/app/services/progress.rx-websocket.service.spec.ts b/quartz-manager-frontend/src/app/services/progress.rx-websocket.service.spec.ts
new file mode 100644
index 0000000..cf32c29
--- /dev/null
+++ b/quartz-manager-frontend/src/app/services/progress.rx-websocket.service.spec.ts
@@ -0,0 +1,39 @@
+import { TestBed } from '@angular/core/testing';
+import {RxStomp} from '@stomp/rx-stomp';
+import {jest} from '@jest/globals';
+
+import { ProgressRxWebsocketService } from './progress.rx-websocket.service';
+import {ApiService} from './api.service';
+
+describe('ProgressRxWebsocketService', () => {
+ let service: ProgressRxWebsocketService;
+ let configureSpy;
+ let activateSpy;
+
+ beforeEach(() => {
+ configureSpy = jest.spyOn(RxStomp.prototype, 'configure');
+ activateSpy = jest.spyOn(RxStomp.prototype, 'activate').mockImplementation(() => undefined);
+
+ TestBed.configureTestingModule({
+ providers: [
+ {provide: ApiService, useValue: {getToken: () => 'test-token'}}
+ ]
+ });
+ service = TestBed.inject(ProgressRxWebsocketService);
+ });
+
+ it('should be created', () => {
+ expect(service).toBeTruthy();
+ });
+
+ it('should configure rx-stomp with the progress websocket endpoint', () => {
+ expect(configureSpy).toHaveBeenCalled();
+ expect(activateSpy).toHaveBeenCalled();
+
+ const config = configureSpy.mock.calls[configureSpy.mock.calls.length - 1][0];
+ expect(config.heartbeatIncoming).toEqual(0);
+ expect(config.heartbeatOutgoing).toEqual(20000);
+ expect(config.reconnectDelay).toEqual(200);
+ expect(config.webSocketFactory.toString()).toContain('/progress?access_token=');
+ });
+});
diff --git a/quartz-manager-frontend/src/app/services/progress.rx-websocket.service.ts b/quartz-manager-frontend/src/app/services/progress.rx-websocket.service.ts
new file mode 100644
index 0000000..647f668
--- /dev/null
+++ b/quartz-manager-frontend/src/app/services/progress.rx-websocket.service.ts
@@ -0,0 +1,23 @@
+import { Injectable } from '@angular/core';
+import {RxStompService} from './rx-stomp.service';
+import {ApiService} from './api.service';
+import SockJS from 'sockjs-client';
+import {CONTEXT_PATH, getBaseUrl} from './config.service';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class ProgressRxWebsocketService extends RxStompService {
+
+ constructor(private apiService: ApiService) {
+ super({
+ webSocketFactory: () => new SockJS(`${getBaseUrl()}${CONTEXT_PATH}/progress?access_token=${this.apiService.getToken()}`),
+ heartbeatIncoming: 0,
+ heartbeatOutgoing: 20000,
+ reconnectDelay: 200,
+ debug: (msg: string): void => {
+ console.log(new Date(), msg);
+ }
+ });
+ }
+}
diff --git a/quartz-manager-frontend/src/app/services/progress.websocket.service.ts b/quartz-manager-frontend/src/app/services/progress.websocket.service.ts
deleted file mode 100644
index 7322e6f..0000000
--- a/quartz-manager-frontend/src/app/services/progress.websocket.service.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-import {Injectable} from '@angular/core';
-import {WebsocketService, ApiService, getBaseUrl, CONTEXT_PATH} from '.';
-import {SocketOption} from '../model/SocketOption.model';
-
-@Injectable()
-export class ProgressWebsocketService extends WebsocketService {
-
- constructor(private apiService: ApiService) {
- super(new SocketOption(getBaseUrl() + `${CONTEXT_PATH}/progress`, '/topic/progress', apiService.getToken))
- }
-
-}
diff --git a/quartz-manager-frontend/src/app/services/rx-stomp.service.ts b/quartz-manager-frontend/src/app/services/rx-stomp.service.ts
new file mode 100644
index 0000000..dfdd16a
--- /dev/null
+++ b/quartz-manager-frontend/src/app/services/rx-stomp.service.ts
@@ -0,0 +1,12 @@
+import {RxStomp} from '@stomp/rx-stomp';
+import {RxStompConfig} from '@stomp/rx-stomp/esm6/rx-stomp-config';
+
+export class RxStompService extends RxStomp {
+
+ constructor(rxStompConfig: RxStompConfig) {
+ super();
+ super.configure(rxStompConfig);
+ super.activate();
+ }
+
+}
diff --git a/quartz-manager-frontend/src/app/services/user.service.ts b/quartz-manager-frontend/src/app/services/user.service.ts
index ae0bf61..224953f 100644
--- a/quartz-manager-frontend/src/app/services/user.service.ts
+++ b/quartz-manager-frontend/src/app/services/user.service.ts
@@ -35,7 +35,7 @@ export class UserService {
this.currentUser = user;
this.router.initialNavigation();
}, err => {
- console.log(`error retrieving current user due to ` + JSON.stringify(err));
+ console.log('error retrieving current user due to ' + JSON.stringify(err));
const httpErrorResponse = err as HttpErrorResponse;
if (httpErrorResponse.status === 404) {
this.isAnAnonymousUser = true;
diff --git a/quartz-manager-frontend/src/app/services/websocket.service.ts b/quartz-manager-frontend/src/app/services/websocket.service.ts
deleted file mode 100644
index 599f936..0000000
--- a/quartz-manager-frontend/src/app/services/websocket.service.ts
+++ /dev/null
@@ -1,136 +0,0 @@
-import {Observable, Subscriber} from 'rxjs';
-import {SocketEndpoint} from '../model/SocketEndpoint.model'
-
-
-import Stomp from 'stompjs';
-import SockJS from 'sockjs-client';
-import {SocketOption} from '../model/SocketOption.model';
-
-interface WebsocketSubscriber {
- index: number,
- observer: Subscriber
-}
-
-export interface QuartzManagerWebsocketMessage {
- type: string;
- message: any;
- headers: any;
- self: boolean;
-}
-
-export class WebsocketService {
-
- _options: SocketOption;
-
- _socket: SocketEndpoint = new SocketEndpoint();
-
- observableStompConnection: Observable;
- subscribers: Array = [];
- subscriberIndex = 0;
-
- _messageIds: Array = [];
-
- reconnectionPromise: any;
-
- constructor(options: SocketOption) {
- this._options = options
- this.createObservableSocket();
- this.connect();
- }
-
- getOptions = () => {
- }
-
- private createObservableSocket = () => {
- this.observableStompConnection = new Observable((observer) => {
- const subscriberIndex = this.subscriberIndex++;
- this.addToSubscribers({index: subscriberIndex, observer});
- return () => this.removeFromSubscribers(subscriberIndex);
- });
- }
-
- private addToSubscribers = (subscriber) => {
- this.subscribers.push(subscriber);
- }
-
- private removeFromSubscribers = (index) => {
- this.subscribers = this.subscribers.filter(subscriber => subscriber.index !== index);
- }
-
- getObservable = () => {
- return this.observableStompConnection;
- };
-
- getMessage = function (data): QuartzManagerWebsocketMessage {
- const out: QuartzManagerWebsocketMessage = {};
- out.type = 'SUCCESS';
- out.message = JSON.parse(data.body);
- out.headers = {};
- out.headers.messageId = data.headers['message-id'];
-
- const messageIdIndex = this._messageIds.indexOf(out.headers.messageId);
- if (messageIdIndex > -1) {
- out.self = true;
- this._messageIds = this._messageIds.splice(messageIdIndex, 1);
- }
- return out;
- };
-
- _socketListener = (frame) => {
- console.log('Connected: ' + frame);
- this._socket.stomp.subscribe(
- this._options.topicName,
- data => this.subscribers.forEach(subscriber => subscriber.observer.next(this.getMessage(data)))
- );
- }
-
- _onSocketError = (errorMsg) => {
- const out: any = {};
- out.type = 'ERROR';
- out.message = errorMsg;
- this.subscribers.forEach(subscriber => subscriber.observer.error(out));
- this.scheduleReconnection();
- }
-
- scheduleReconnection = () => {
- this.reconnectionPromise = setTimeout(() => {
- console.log('Socket reconnecting... (if it fails, next attempt in ' + this._options.reconnectionTimeout + ' msec)');
- this.connect();
- }, this._options.reconnectionTimeout);
- }
-
- reconnectNow = function () {
- this._socket.stomp.disconnect();
- if (this.reconnectionPromise && this.reconnectionPromise.cancel) {
- this.reconnectionPromise.cancel();
- }
- this.connect();
- };
-
- send = (message) => {
- const id = Math.floor(Math.random() * 1000000);
- this._socket.stomp.send(this._options.brokerName, {
- priority: 9
- }, JSON.stringify({
- message: message,
- id: id
- }));
- this._messageIds.push(id);
- };
-
- connect = () => {
- const headers = {};
-
- let socketUrl = this._options.socketUrl;
- if (this._options.getAccessToken()) {
- socketUrl += `?access_token=${this._options.getAccessToken()}`;
- }
-
- this._socket.client = new SockJS(socketUrl);
- this._socket.stomp = Stomp.over(this._socket.client);
- this._socket.stomp.connect(headers, this._socketListener, this._onSocketError);
- this._socket.stomp.onclose = this.scheduleReconnection;
- }
-
-
-}
diff --git a/quartz-manager-frontend/src/app/views/manager/manager.component.html b/quartz-manager-frontend/src/app/views/manager/manager.component.html
index 05b11c9..1428332 100644
--- a/quartz-manager-frontend/src/app/views/manager/manager.component.html
+++ b/quartz-manager-frontend/src/app/views/manager/manager.component.html
@@ -19,18 +19,25 @@
diff --git a/quartz-manager-frontend/src/app/views/manager/manager.component.ts b/quartz-manager-frontend/src/app/views/manager/manager.component.ts
index 01ce9f1..20a9a7d 100644
--- a/quartz-manager-frontend/src/app/views/manager/manager.component.ts
+++ b/quartz-manager-frontend/src/app/views/manager/manager.component.ts
@@ -1,8 +1,4 @@
import {Component, OnInit, ViewChild} from '@angular/core';
-import {
- ConfigService,
- UserService
-} from '../../services';
import {SimpleTrigger} from '../../model/simple-trigger.model';
import {TriggerKey} from '../../model/triggerKey.model';
import {SimpleTriggerConfigComponent} from '../../components/simple-trigger-config';
@@ -32,15 +28,25 @@ export class ManagerComponent implements OnInit {
}
onNewTriggerRequested() {
- this.triggerConfigComponent.openTriggerForm();
+ this.selectedTriggerKey = null;
+ this.newTriggerFormOpened = true;
+ if (this.triggerConfigComponent) {
+ this.triggerConfigComponent.openNewTriggerForm();
+ }
}
onNewTriggerCreated(newTrigger: SimpleTrigger) {
this.triggerListComponent.onNewTrigger(newTrigger);
+ this.newTriggerFormOpened = false;
}
setSelectedTrigger(triggerKey: TriggerKey) {
this.selectedTriggerKey = triggerKey;
+ this.newTriggerFormOpened = false;
+ }
+
+ setNewTriggerFormOpened(opened: boolean) {
+ this.newTriggerFormOpened = opened;
}
}
diff --git a/quartz-manager-frontend/src/polyfills.ts b/quartz-manager-frontend/src/polyfills.ts
index ecc7cec..95ab387 100644
--- a/quartz-manager-frontend/src/polyfills.ts
+++ b/quartz-manager-frontend/src/polyfills.ts
@@ -14,7 +14,7 @@
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
*/
-/***************************************************************************************************
+/** *************************************************************************************************
* BROWSER POLYFILLS
*/
@@ -50,7 +50,7 @@ import 'core-js/es6/reflect';
-/***************************************************************************************************
+/** *************************************************************************************************
* Zone JS is required by Angular itself.
*/
import 'zone.js/dist/zone'; // Included with Angular CLI.
@@ -59,7 +59,7 @@ import 'zone.js/dist/zone'; // Included with Angular CLI.
-/***************************************************************************************************
+/** *************************************************************************************************
* APPLICATION IMPORTS
*/
@@ -69,7 +69,7 @@ import 'zone.js/dist/zone'; // Included with Angular CLI.
*/
// import 'intl'; // Run `npm install --save intl`.
-/***************************************************************************************************
+/** *************************************************************************************************
* MATERIAL 2
*/
import 'hammerjs/hammer';
diff --git a/quartz-manager-frontend/src/typings.d.ts b/quartz-manager-frontend/src/typings.d.ts
index ef5c7bd..388fb92 100644
--- a/quartz-manager-frontend/src/typings.d.ts
+++ b/quartz-manager-frontend/src/typings.d.ts
@@ -1,5 +1,5 @@
/* SystemJS module definition */
-declare var module: NodeModule;
+declare let module: NodeModule;
interface NodeModule {
id: string;
}
diff --git a/quartz-manager-parent/.gitignore b/quartz-manager-parent/.gitignore
index 29e1e7f..a3232ff 100644
--- a/quartz-manager-parent/.gitignore
+++ b/quartz-manager-parent/.gitignore
@@ -4,4 +4,4 @@
.classpath
.project
.idea
-*.iml
+/**/*.iml
diff --git a/quartz-manager-parent/pom.xml b/quartz-manager-parent/pom.xml
index b23625b..15f0ba1 100644
--- a/quartz-manager-parent/pom.xml
+++ b/quartz-manager-parent/pom.xml
@@ -10,7 +10,7 @@
it.fabioformosa.quartz-manager
quartz-manager-parent
- 4.0.9
+ 4.0.11-SNAPSHOT
pom
@@ -43,6 +43,7 @@
9
UTF-8
+ 1.18.30
2.22.0
2.22.0
0.8.8
@@ -50,6 +51,7 @@
1.6.7
2.5.3
3.0.1
+ 3.11.0.3922
fabioformosa
https://sonarcloud.io
@@ -78,27 +80,32 @@
it.fabioformosa.quartz-manager
quartz-manager-common
- 4.0.9
+ 4.0.11-SNAPSHOT
it.fabioformosa.quartz-manager
quartz-manager-starter-api
- 4.0.9
+ 4.0.11-SNAPSHOT
it.fabioformosa.quartz-manager
quartz-manager-starter-security
- 4.0.9
+ 4.0.11-SNAPSHOT
it.fabioformosa.quartz-manager
quartz-manager-starter-persistence
- 4.0.9
+ 4.0.11-SNAPSHOT
it.fabioformosa.quartz-manager
quartz-manager-starter-ui
- 4.0.9
+ 4.0.11-SNAPSHOT
+
+
+ org.projectlombok
+ lombok
+ ${org.projectlombok.version}
@@ -133,6 +140,11 @@
maven-failsafe-plugin
${maven-failsafe-plugin.version}
+
+ org.sonarsource.scanner.maven
+ sonar-maven-plugin
+ ${sonar-maven-plugin.version}
+
org.jacoco
jacoco-maven-plugin
@@ -240,26 +252,25 @@
- ossrh
- https://oss.sonatype.org/content/repositories/snapshots
+ maven-central-release
+ https://central.sonatype.com/repository/maven-snapshots/
- ossrh
- https://oss.sonatype.org/service/local/staging/deploy/maven2/
-
+ maven-central-release
+ https://central.sonatype.com
- org.sonatype.plugins
- nexus-staging-maven-plugin
- ${nexus-staging-maven-plugin.version}
+ org.sonatype.central
+ central-publishing-maven-plugin
+ 0.7.0
true
- ossrh
- https://oss.sonatype.org/
- true
+ maven-central-release
+ true
+ published
diff --git a/quartz-manager-parent/quartz-manager-common/pom.xml b/quartz-manager-parent/quartz-manager-common/pom.xml
index 8e18ae9..2eec18c 100644
--- a/quartz-manager-parent/quartz-manager-common/pom.xml
+++ b/quartz-manager-parent/quartz-manager-common/pom.xml
@@ -3,7 +3,7 @@
it.fabioformosa.quartz-manager
quartz-manager-parent
- 4.0.9
+ 4.0.11-SNAPSHOT
quartz-manager-common
diff --git a/quartz-manager-parent/quartz-manager-starter-api/pom.xml b/quartz-manager-parent/quartz-manager-starter-api/pom.xml
index 053f50b..557bc03 100644
--- a/quartz-manager-parent/quartz-manager-starter-api/pom.xml
+++ b/quartz-manager-parent/quartz-manager-starter-api/pom.xml
@@ -5,7 +5,7 @@
it.fabioformosa.quartz-manager
quartz-manager-parent
- 4.0.9
+ 4.0.11-SNAPSHOT
quartz-manager-starter-api
diff --git a/quartz-manager-parent/quartz-manager-starter-api/src/main/java/it/fabioformosa/quartzmanager/api/jobs/AbstractQuartzManagerJob.java b/quartz-manager-parent/quartz-manager-starter-api/src/main/java/it/fabioformosa/quartzmanager/api/jobs/AbstractQuartzManagerJob.java
index 609ee8d..20d6c90 100644
--- a/quartz-manager-parent/quartz-manager-starter-api/src/main/java/it/fabioformosa/quartzmanager/api/jobs/AbstractQuartzManagerJob.java
+++ b/quartz-manager-parent/quartz-manager-starter-api/src/main/java/it/fabioformosa/quartzmanager/api/jobs/AbstractQuartzManagerJob.java
@@ -38,11 +38,13 @@ public abstract class AbstractQuartzManagerJob implements Job {
LogRecord logMsg = doIt(jobExecutionContext);
log.info(logMsg.getMessage());
+ String triggerName = jobExecutionContext.getTrigger().getKey().getName();
+
logMsg.setThreadName(Thread.currentThread().getName());
- webSocketLogsNotifier.send(logMsg);
+ webSocketLogsNotifier.send(triggerName, logMsg);
TriggerFiredBundleDTO triggerFiredBundleDTO = WebSocketProgressNotifier.buildTriggerFiredBundle(jobExecutionContext);
- webSocketProgressNotifier.send(triggerFiredBundleDTO);
+ webSocketProgressNotifier.send(triggerName, triggerFiredBundleDTO);
}
}
diff --git a/quartz-manager-parent/quartz-manager-starter-api/src/main/java/it/fabioformosa/quartzmanager/api/websockets/WebSocketLogsNotifier.java b/quartz-manager-parent/quartz-manager-starter-api/src/main/java/it/fabioformosa/quartzmanager/api/websockets/WebSocketLogsNotifier.java
index 9ced563..9cdbfb7 100644
--- a/quartz-manager-parent/quartz-manager-starter-api/src/main/java/it/fabioformosa/quartzmanager/api/websockets/WebSocketLogsNotifier.java
+++ b/quartz-manager-parent/quartz-manager-starter-api/src/main/java/it/fabioformosa/quartzmanager/api/websockets/WebSocketLogsNotifier.java
@@ -14,7 +14,7 @@ public class WebSocketLogsNotifier implements WebhookSender {
private SimpMessageSendingOperations messagingTemplate;
@Override
- public void send(LogRecord logRecord) {
- messagingTemplate.convertAndSend(TOPIC_LOGS, logRecord);
+ public void send(String triggerName, LogRecord logRecord) {
+ messagingTemplate.convertAndSend(TOPIC_LOGS + "/" + triggerName, logRecord);
}
}
diff --git a/quartz-manager-parent/quartz-manager-starter-api/src/main/java/it/fabioformosa/quartzmanager/api/websockets/WebSocketProgressNotifier.java b/quartz-manager-parent/quartz-manager-starter-api/src/main/java/it/fabioformosa/quartzmanager/api/websockets/WebSocketProgressNotifier.java
index 7eeba6d..d616bf9 100644
--- a/quartz-manager-parent/quartz-manager-starter-api/src/main/java/it/fabioformosa/quartzmanager/api/websockets/WebSocketProgressNotifier.java
+++ b/quartz-manager-parent/quartz-manager-starter-api/src/main/java/it/fabioformosa/quartzmanager/api/websockets/WebSocketProgressNotifier.java
@@ -20,8 +20,8 @@ public class WebSocketProgressNotifier implements WebhookSender {
- void send(T message);
+ void send(String triggerName, T message);
}
diff --git a/quartz-manager-parent/quartz-manager-starter-api/src/test/java/it/fabioformosa/quartzmanager/api/jobs/SampleJobTest.java b/quartz-manager-parent/quartz-manager-starter-api/src/test/java/it/fabioformosa/quartzmanager/api/jobs/SampleJobTest.java
index f56bd0d..2ffde76 100644
--- a/quartz-manager-parent/quartz-manager-starter-api/src/test/java/it/fabioformosa/quartzmanager/api/jobs/SampleJobTest.java
+++ b/quartz-manager-parent/quartz-manager-starter-api/src/test/java/it/fabioformosa/quartzmanager/api/jobs/SampleJobTest.java
@@ -4,16 +4,26 @@ import it.fabioformosa.quartzmanager.api.dto.TriggerFiredBundleDTO;
import it.fabioformosa.quartzmanager.api.jobs.entities.LogRecord;
import it.fabioformosa.quartzmanager.api.websockets.WebhookSender;
import org.assertj.core.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.quartz.*;
+import org.mockito.junit.jupiter.MockitoExtension;
+import org.quartz.JobBuilder;
+import org.quartz.JobDetail;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobKey;
+import org.quartz.ScheduleBuilder;
+import org.quartz.SimpleScheduleBuilder;
+import org.quartz.Trigger;
+import org.quartz.TriggerBuilder;
-import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+@ExtendWith(MockitoExtension.class)
class SampleJobTest {
@InjectMocks
@@ -24,14 +34,16 @@ class SampleJobTest {
@Mock
private WebhookSender webSocketLogsNotifier;
- @BeforeEach
- void setUp() {
- MockitoAnnotations.openMocks(this);
- }
+ @Captor
+ private ArgumentCaptor logRecordCaptor;
+
+ @Captor
+ private ArgumentCaptor triggerFiredBundleDTOCaptor;
@Test
void givenASampleJob_whenTheJobIsExecuted_thenTheWebhookSendersAreCalled() {
JobExecutionContext jobExecutionContext = Mockito.mock(JobExecutionContext.class);
+ String triggerName = "test-trigger";
ScheduleBuilder schedulerBuilder = SimpleScheduleBuilder.simpleSchedule()
.withRepeatCount(5)
@@ -40,6 +52,7 @@ class SampleJobTest {
.newJob(SampleJob.class).withIdentity(JobKey.jobKey("test-job"))
.build();
Trigger trigger = TriggerBuilder.newTrigger()
+ .withIdentity(triggerName)
.forJob(jobDetail)
.withSchedule(schedulerBuilder)
.build();
@@ -47,24 +60,23 @@ class SampleJobTest {
Mockito.when(jobExecutionContext.getJobDetail()).thenReturn(jobDetail);
sampleJob.execute(jobExecutionContext);
- Mockito.verify(webSocketLogsNotifier).send(argThat(actualLogRecord -> {
- Assertions.assertThat(actualLogRecord.getMessage()).isEqualTo("Hello!");
- Assertions.assertThat(actualLogRecord.getType()).isEqualTo(LogRecord.LogType.INFO);
- Assertions.assertThat(actualLogRecord.getDate()).isNotNull();
- Assertions.assertThat(actualLogRecord.getThreadName()).isNotNull();
- return true;
- }));
- Mockito.verify(webSocketProgressNotifier).send(argThat(triggerFiredBundleDTO -> {
- Assertions.assertThat(triggerFiredBundleDTO.getJobKey()).isEqualTo("test-job");
- Assertions.assertThat(triggerFiredBundleDTO.getRepeatCount()).isEqualTo(6);
- Assertions.assertThat(triggerFiredBundleDTO.getJobClass()).isEqualTo(SampleJob.class.getName());
- Assertions.assertThat(triggerFiredBundleDTO.getTimesTriggered()).isZero();
- Assertions.assertThat(triggerFiredBundleDTO.getNextFireTime()).isNull();
- Assertions.assertThat(triggerFiredBundleDTO.getPercentage()).isZero();
- Assertions.assertThat(triggerFiredBundleDTO.getFinalFireTime()).isNotNull();
- Assertions.assertThat(triggerFiredBundleDTO.getPreviousFireTime()).isNull();
- return true;
- }));
+ Mockito.verify(webSocketLogsNotifier).send(eq(triggerName), logRecordCaptor.capture());
+ LogRecord actualLogRecord = logRecordCaptor.getValue();
+ Assertions.assertThat(actualLogRecord.getMessage()).isEqualTo("Hello!");
+ Assertions.assertThat(actualLogRecord.getType()).isEqualTo(LogRecord.LogType.INFO);
+ Assertions.assertThat(actualLogRecord.getDate()).isNotNull();
+ Assertions.assertThat(actualLogRecord.getThreadName()).isNotNull();
+
+ Mockito.verify(webSocketProgressNotifier).send(eq(triggerName), triggerFiredBundleDTOCaptor.capture());
+ TriggerFiredBundleDTO triggerFiredBundleDTO = triggerFiredBundleDTOCaptor.getValue();
+ Assertions.assertThat(triggerFiredBundleDTO.getJobKey()).isEqualTo("test-job");
+ Assertions.assertThat(triggerFiredBundleDTO.getRepeatCount()).isEqualTo(6);
+ Assertions.assertThat(triggerFiredBundleDTO.getJobClass()).isEqualTo(SampleJob.class.getName());
+ Assertions.assertThat(triggerFiredBundleDTO.getTimesTriggered()).isZero();
+ Assertions.assertThat(triggerFiredBundleDTO.getNextFireTime()).isNull();
+ Assertions.assertThat(triggerFiredBundleDTO.getPercentage()).isZero();
+ Assertions.assertThat(triggerFiredBundleDTO.getFinalFireTime()).isNotNull();
+ Assertions.assertThat(triggerFiredBundleDTO.getPreviousFireTime()).isNull();
}
@Test
diff --git a/quartz-manager-parent/quartz-manager-starter-api/src/test/java/it/fabioformosa/quartzmanager/api/services/SimpleTriggerServiceIntegrationTest.java b/quartz-manager-parent/quartz-manager-starter-api/src/test/java/it/fabioformosa/quartzmanager/api/services/SimpleTriggerServiceIntegrationTest.java
index f26e829..74c633d 100644
--- a/quartz-manager-parent/quartz-manager-starter-api/src/test/java/it/fabioformosa/quartzmanager/api/services/SimpleTriggerServiceIntegrationTest.java
+++ b/quartz-manager-parent/quartz-manager-starter-api/src/test/java/it/fabioformosa/quartzmanager/api/services/SimpleTriggerServiceIntegrationTest.java
@@ -18,13 +18,17 @@ import java.util.Date;
@SpringBootTest
class SimpleTriggerServiceIntegrationTest {
+ private static final String SAMPLE_JOB_CLASS = "it.fabioformosa.quartzmanager.api.jobs.SampleJob";
+ private static final String SAMPLE_EXTRA_JOB_CLASS = "it.fabioformosa.samplepackage.SampleExtraJob";
+ private static final String FIRST_TRIGGER_SUFFIX = "A";
+ private static final String SECOND_TRIGGER_SUFFIX = "B";
+
@Autowired
private SimpleTriggerService simpleTriggerService;
@Test
void givenASimpleTriggerCommandDTOWithAllData_whenANewSimpleTriggerIsScheduled_thenShouldGetATriggertDTO() throws SchedulerException, ClassNotFoundException {
String simpleTriggerTestName = "simpleTriggerWithAllData";
- String jobClass = "it.fabioformosa.quartzmanager.api.jobs.SampleJob";
Date startDate = new Date();
Date endDate = DateUtils.addHoursToNow(5);
int repeatCount = 3;
@@ -41,7 +45,7 @@ class SimpleTriggerServiceIntegrationTest {
.repeatCount(repeatCount)
.repeatInterval(repeatInterval)
.misfireInstruction(misfireInstructionFireNow)
- .jobClass(jobClass)
+ .jobClass(SAMPLE_JOB_CLASS)
.build())
.build();
SimpleTriggerDTO simpleTriggerDTO = simpleTriggerService.scheduleSimpleTrigger(simpleTriggerCommand);
@@ -61,12 +65,11 @@ class SimpleTriggerServiceIntegrationTest {
@Test
void givenASimpleTriggerCommandDTOWithMissingOptionalField_whenANewSimpleTriggerIsScheduled_thenShouldGetATriggertDTO() throws SchedulerException, ClassNotFoundException {
String simpleTriggerTestName = "simpleTriggerWithoutOptionalData";
- String jobClass = "it.fabioformosa.quartzmanager.api.jobs.SampleJob";
SimpleTriggerCommandDTO simpleTriggerCommand = SimpleTriggerCommandDTO.builder()
.triggerName(simpleTriggerTestName)
.simpleTriggerInputDTO(SimpleTriggerInputDTO.builder()
- .jobClass(jobClass)
+ .jobClass(SAMPLE_JOB_CLASS)
.build())
.build();
SimpleTriggerDTO simpleTriggerDTO = simpleTriggerService.scheduleSimpleTrigger(simpleTriggerCommand);
@@ -81,4 +84,49 @@ class SimpleTriggerServiceIntegrationTest {
Assertions.assertThat(simpleTriggerDTO.getRepeatInterval()).isZero();
}
+ @Test
+ void givenTwoSimpleTriggerCommandDTOsForTheSameJob_whenScheduled_thenShouldCreateTwoTriggers() throws SchedulerException, ClassNotFoundException {
+ String triggerNamePrefix = "sameJobTrigger" + System.nanoTime();
+
+ SimpleTriggerDTO firstTrigger = simpleTriggerService.scheduleSimpleTrigger(
+ buildSimpleTriggerCommand(triggerNamePrefix + FIRST_TRIGGER_SUFFIX, SAMPLE_JOB_CLASS)
+ );
+ SimpleTriggerDTO secondTrigger = simpleTriggerService.scheduleSimpleTrigger(
+ buildSimpleTriggerCommand(triggerNamePrefix + SECOND_TRIGGER_SUFFIX, SAMPLE_JOB_CLASS)
+ );
+
+ Assertions.assertThat(firstTrigger.getTriggerKeyDTO().getName()).isEqualTo(triggerNamePrefix + FIRST_TRIGGER_SUFFIX);
+ Assertions.assertThat(secondTrigger.getTriggerKeyDTO().getName()).isEqualTo(triggerNamePrefix + SECOND_TRIGGER_SUFFIX);
+ Assertions.assertThat(firstTrigger.getJobDetailDTO().getJobClassName()).isEqualTo(SAMPLE_JOB_CLASS);
+ Assertions.assertThat(secondTrigger.getJobDetailDTO().getJobClassName()).isEqualTo(SAMPLE_JOB_CLASS);
+ Assertions.assertThat(firstTrigger.getJobKeyDTO().getName()).isNotEqualTo(secondTrigger.getJobKeyDTO().getName());
+ }
+
+ @Test
+ void givenTwoSimpleTriggerCommandDTOsForDifferentJobs_whenScheduled_thenShouldCreateTwoTriggers() throws SchedulerException, ClassNotFoundException {
+ String triggerNamePrefix = "differentJobTrigger" + System.nanoTime();
+
+ SimpleTriggerDTO firstTrigger = simpleTriggerService.scheduleSimpleTrigger(
+ buildSimpleTriggerCommand(triggerNamePrefix + FIRST_TRIGGER_SUFFIX, SAMPLE_JOB_CLASS)
+ );
+ SimpleTriggerDTO secondTrigger = simpleTriggerService.scheduleSimpleTrigger(
+ buildSimpleTriggerCommand(triggerNamePrefix + SECOND_TRIGGER_SUFFIX, SAMPLE_EXTRA_JOB_CLASS)
+ );
+
+ Assertions.assertThat(firstTrigger.getTriggerKeyDTO().getName()).isEqualTo(triggerNamePrefix + FIRST_TRIGGER_SUFFIX);
+ Assertions.assertThat(secondTrigger.getTriggerKeyDTO().getName()).isEqualTo(triggerNamePrefix + SECOND_TRIGGER_SUFFIX);
+ Assertions.assertThat(firstTrigger.getJobDetailDTO().getJobClassName()).isEqualTo(SAMPLE_JOB_CLASS);
+ Assertions.assertThat(secondTrigger.getJobDetailDTO().getJobClassName()).isEqualTo(SAMPLE_EXTRA_JOB_CLASS);
+ }
+
+ private static SimpleTriggerCommandDTO buildSimpleTriggerCommand(String triggerName, String jobClass) {
+ return SimpleTriggerCommandDTO.builder()
+ .triggerName(triggerName)
+ .simpleTriggerInputDTO(SimpleTriggerInputDTO.builder()
+ .jobClass(jobClass)
+ .startDate(DateUtils.addHoursToNow(1))
+ .build())
+ .build();
+ }
+
}
diff --git a/quartz-manager-parent/quartz-manager-starter-api/src/test/java/it/fabioformosa/quartzmanager/api/websockets/WebSocketNotifierTest.java b/quartz-manager-parent/quartz-manager-starter-api/src/test/java/it/fabioformosa/quartzmanager/api/websockets/WebSocketNotifierTest.java
new file mode 100644
index 0000000..94b38ad
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-starter-api/src/test/java/it/fabioformosa/quartzmanager/api/websockets/WebSocketNotifierTest.java
@@ -0,0 +1,48 @@
+package it.fabioformosa.quartzmanager.api.websockets;
+
+import it.fabioformosa.quartzmanager.api.dto.TriggerFiredBundleDTO;
+import it.fabioformosa.quartzmanager.api.jobs.entities.LogRecord;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.springframework.messaging.simp.SimpMessageSendingOperations;
+
+import static org.mockito.MockitoAnnotations.openMocks;
+
+class WebSocketNotifierTest {
+
+ @InjectMocks
+ private WebSocketLogsNotifier webSocketLogsNotifier;
+
+ @InjectMocks
+ private WebSocketProgressNotifier webSocketProgressNotifier;
+
+ @Mock
+ private SimpMessageSendingOperations messagingTemplate;
+
+ @BeforeEach
+ void setUp() {
+ openMocks(this);
+ }
+
+ @Test
+ void givenATriggerName_whenALogIsSent_thenShouldSendItToTheTriggerLogsTopic() {
+ LogRecord logRecord = new LogRecord(LogRecord.LogType.INFO, "Hello!");
+
+ webSocketLogsNotifier.send("trigger-1", logRecord);
+
+ Mockito.verify(messagingTemplate).convertAndSend("/topic/logs/trigger-1", logRecord);
+ }
+
+ @Test
+ void givenATriggerName_whenProgressIsSent_thenShouldSendItToTheTriggerProgressTopic() {
+ TriggerFiredBundleDTO triggerFiredBundleDTO = new TriggerFiredBundleDTO();
+
+ webSocketProgressNotifier.send("trigger-1", triggerFiredBundleDTO);
+
+ Mockito.verify(messagingTemplate).convertAndSend("/topic/progress/trigger-1", triggerFiredBundleDTO);
+ }
+
+}
diff --git a/quartz-manager-parent/quartz-manager-starter-persistence/pom.xml b/quartz-manager-parent/quartz-manager-starter-persistence/pom.xml
index 52f3e03..20811ef 100644
--- a/quartz-manager-parent/quartz-manager-starter-persistence/pom.xml
+++ b/quartz-manager-parent/quartz-manager-starter-persistence/pom.xml
@@ -3,7 +3,7 @@
it.fabioformosa.quartz-manager
quartz-manager-parent
- 4.0.9
+ 4.0.11-SNAPSHOT
quartz-manager-starter-persistence
diff --git a/quartz-manager-parent/quartz-manager-starter-security/pom.xml b/quartz-manager-parent/quartz-manager-starter-security/pom.xml
index 53d5f71..f69ee60 100644
--- a/quartz-manager-parent/quartz-manager-starter-security/pom.xml
+++ b/quartz-manager-parent/quartz-manager-starter-security/pom.xml
@@ -4,7 +4,7 @@
it.fabioformosa.quartz-manager
quartz-manager-parent
- 4.0.9
+ 4.0.11-SNAPSHOT
quartz-manager-starter-security
diff --git a/quartz-manager-parent/quartz-manager-starter-ui/pom.xml b/quartz-manager-parent/quartz-manager-starter-ui/pom.xml
index b4c0f64..f72cd7f 100644
--- a/quartz-manager-parent/quartz-manager-starter-ui/pom.xml
+++ b/quartz-manager-parent/quartz-manager-starter-ui/pom.xml
@@ -4,7 +4,7 @@
it.fabioformosa.quartz-manager
quartz-manager-parent
- 4.0.9
+ 4.0.11-SNAPSHOT
quartz-manager-starter-ui
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/deploy/dev.yaml b/quartz-manager-parent/quartz-manager-web-showcase/deploy/dev.yaml
new file mode 100644
index 0000000..1883818
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-web-showcase/deploy/dev.yaml
@@ -0,0 +1,9 @@
+apiVersion: deploy.cloud.google.com/v1
+kind: Target
+metadata:
+ name: dev
+ annotations: {}
+ labels: {}
+description: dev
+gke:
+ cluster: projects/quartz-manager-test/locations/europe-west8-a/clusters/gke-cluster
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/deploy/pipeline.yaml b/quartz-manager-parent/quartz-manager-web-showcase/deploy/pipeline.yaml
new file mode 100644
index 0000000..3d3c7fa
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-web-showcase/deploy/pipeline.yaml
@@ -0,0 +1,18 @@
+apiVersion: deploy.cloud.google.com/v1
+kind: DeliveryPipeline
+metadata:
+ name: quartz-manager-pipeline
+ labels:
+ app: quartz-manager-standalone
+description: quartz-manager-standalone delivery pipeline
+serialPipeline:
+ stages:
+ - targetId: dev
+ profiles:
+ - dev
+ - targetId: staging
+ profiles:
+ - staging
+ - targetId: prod
+ profiles:
+ - prod
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/deploy/prod.yaml b/quartz-manager-parent/quartz-manager-web-showcase/deploy/prod.yaml
new file mode 100644
index 0000000..ea621a6
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-web-showcase/deploy/prod.yaml
@@ -0,0 +1,10 @@
+apiVersion: deploy.cloud.google.com/v1
+kind: Target
+metadata:
+ name: prod
+ annotations: {}
+ labels: {}
+description: prod
+requireApproval: true
+gke:
+ cluster: projects/quartz-manager-test/locations/europe-west8-a/clusters/gke-cluster
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/deploy/staging.yaml b/quartz-manager-parent/quartz-manager-web-showcase/deploy/staging.yaml
new file mode 100644
index 0000000..ecaf3a7
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-web-showcase/deploy/staging.yaml
@@ -0,0 +1,10 @@
+apiVersion: deploy.cloud.google.com/v1
+kind: Target
+metadata:
+ name: staging
+ annotations: {}
+ labels: {}
+description: staging
+requireApproval: true
+gke:
+ cluster: projects/quartz-manager-test/locations/europe-west8-a/clusters/gke-cluster
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/helm/Chart.yaml b/quartz-manager-parent/quartz-manager-web-showcase/helm/Chart.yaml
new file mode 100644
index 0000000..5a63105
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-web-showcase/helm/Chart.yaml
@@ -0,0 +1,24 @@
+apiVersion: v2
+name: quartz-manager-standalone
+description: A Helm chart for Kubernetes
+
+
+# A chart can be either an 'application' or a 'library' chart.
+# Application charts are a collection of templates that can be packaged into versioned archives
+# to be deployed.
+#
+# Library charts provide useful utilities or functions for the chart developer. They're included as
+# a dependency of application charts to inject those utilities and functions into the rendering
+# pipeline. Library charts do not define any templates and therefore cannot be deployed.
+type: application
+
+# This is the chart version. This version number should be incremented each time you make changes
+# to the chart and its templates, including the app version.
+# Versions are expected to follow Semantic Versioning (https://semver.org/)
+version: 1.0.0
+
+# This is the version number of the application being deployed. This version number should be
+# incremented each time you make changes to the application. Versions are not expected to
+# follow Semantic Versioning. They should reflect the version the application is using.
+# It is recommended to use it with quotes.
+appVersion: "_HELM_APP_VERSION"
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/NOTES.txt b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/NOTES.txt
new file mode 100644
index 0000000..d432c5c
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/NOTES.txt
@@ -0,0 +1,22 @@
+1. Get the application URL by running these commands:
+{{- if .Values.ingress.enabled }}
+{{- range $host := .Values.ingress.hosts }}
+ {{- range .paths }}
+ http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
+ {{- end }}
+{{- end }}
+{{- else if contains "NodePort" .Values.service.type }}
+ export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "quartzmanager-standalone.fullname" . }})
+ export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
+ echo http://$NODE_IP:$NODE_PORT
+{{- else if contains "LoadBalancer" .Values.service.type }}
+ NOTE: It may take a few minutes for the LoadBalancer IP to be available.
+ You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "quartzmanager-standalone.fullname" . }}'
+ export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "quartzmanager-standalone.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
+ echo http://$SERVICE_IP:{{ .Values.service.port }}
+{{- else if contains "ClusterIP" .Values.service.type }}
+ export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "quartzmanager-standalone.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
+ export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
+ echo "Visit http://127.0.0.1:8080 to use your application"
+ kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT
+{{- end }}
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/_helpers.yaml b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/_helpers.yaml
new file mode 100644
index 0000000..59d7d95
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/_helpers.yaml
@@ -0,0 +1,62 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "quartzmanager-standalone.name" -}}
+{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Create a default fully qualified app name.
+We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
+If release name contains chart name it will be used as a full name.
+*/}}
+{{- define "quartzmanager-standalone.fullname" -}}
+{{- if .Values.fullnameOverride }}
+{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- $name := default .Chart.Name .Values.nameOverride }}
+{{- if contains $name .Release.Name }}
+{{- .Release.Name | trunc 63 | trimSuffix "-" }}
+{{- else }}
+{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
+{{- end }}
+{{- end }}
+{{- end }}
+
+{{/*
+Create chart name and version as used by the chart label.
+*/}}
+{{- define "quartzmanager-standalone.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "quartzmanager-standalone.labels" -}}
+helm.sh/chart: {{ include "quartzmanager-standalone.chart" . }}
+{{ include "quartzmanager-standalone.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "quartzmanager-standalone.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "quartzmanager-standalone.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+{{/*
+Create the name of the service account to use
+*/}}
+{{- define "quartzmanager-standalone.serviceAccountName" -}}
+{{- if .Values.serviceAccount.create }}
+{{- default (include "quartzmanager-standalone.fullname" .) .Values.serviceAccount.name }}
+{{- else }}
+{{- default "default" .Values.serviceAccount.name }}
+{{- end }}
+{{- end }}
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/configmap.yaml b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/configmap.yaml
new file mode 100644
index 0000000..aa87e0a
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/configmap.yaml
@@ -0,0 +1,9 @@
+apiVersion: "v1"
+kind: "ConfigMap"
+metadata:
+ name: {{ include "quartzmanager-standalone.fullname" . }}
+ namespace: {{ .Release.Namespace }}
+ labels:
+ app: {{ .Chart.Name }}
+data:
+ envName: {{ .Values.config.envName | quote }}
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/deployment.yaml b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/deployment.yaml
new file mode 100644
index 0000000..760aeea
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/deployment.yaml
@@ -0,0 +1,68 @@
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: {{ include "quartzmanager-standalone.fullname" . }}
+ labels:
+ {{- include "quartzmanager-standalone.labels" . | nindent 4 }}
+spec:
+ {{- if not .Values.autoscaling.enabled }}
+ replicas: {{ .Values.replicaCount }}
+ {{- end }}
+ selector:
+ matchLabels:
+ {{- include "quartzmanager-standalone.selectorLabels" . | nindent 6 }}
+ template:
+ metadata:
+ {{- with .Values.podAnnotations }}
+ annotations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ labels:
+ {{- include "quartzmanager-standalone.selectorLabels" . | nindent 8 }}
+ spec:
+ {{- with .Values.imagePullSecrets }}
+ imagePullSecrets:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ serviceAccountName: {{ include "quartzmanager-standalone.serviceAccountName" . }}
+ securityContext:
+ {{- toYaml .Values.podSecurityContext | nindent 8 }}
+ containers:
+ - name: {{ .Chart.Name }}
+ securityContext:
+ {{- toYaml .Values.securityContext | nindent 12 }}
+ image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+ imagePullPolicy: {{ .Values.image.pullPolicy }}
+ ports:
+ - name: http
+ containerPort: {{ .Values.service.port }}
+ protocol: TCP
+{{/* livenessProbe:*/}}
+{{/* initialDelaySeconds: 30*/}}
+{{/* timeoutSeconds: 10*/}}
+{{/* httpGet:*/}}
+{{/* path: /*/}}
+{{/* port: 8080*/}}
+{{/* readinessProbe:*/}}
+{{/* initialDelaySeconds: 30*/}}
+{{/* timeoutSeconds: 10*/}}
+{{/* httpGet:*/}}
+{{/* path: /*/}}
+{{/* port: 8080*/}}
+ resources:
+ {{- toYaml .Values.resources | nindent 12 }}
+ envFrom:
+ - configMapRef:
+ name: {{ include "quartzmanager-standalone.fullname" . }}
+ {{- with .Values.nodeSelector }}
+ nodeSelector:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.affinity }}
+ affinity:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
+ {{- with .Values.tolerations }}
+ tolerations:
+ {{- toYaml . | nindent 8 }}
+ {{- end }}
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/hpa.yaml b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/hpa.yaml
new file mode 100644
index 0000000..67973b7
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/hpa.yaml
@@ -0,0 +1,28 @@
+{{- if .Values.autoscaling.enabled }}
+apiVersion: autoscaling/v2beta1
+kind: HorizontalPodAutoscaler
+metadata:
+ name: {{ include "quartzmanager-standalone.fullname" . }}
+ labels:
+ {{- include "quartzmanager-standalone.labels" . | nindent 4 }}
+spec:
+ scaleTargetRef:
+ apiVersion: apps/v1
+ kind: Deployment
+ name: {{ include "quartzmanager-standalone.fullname" . }}
+ minReplicas: {{ .Values.autoscaling.minReplicas }}
+ maxReplicas: {{ .Values.autoscaling.maxReplicas }}
+ metrics:
+ {{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
+ - type: Resource
+ resource:
+ name: cpu
+ targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
+ {{- end }}
+ {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
+ - type: Resource
+ resource:
+ name: memory
+ targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
+ {{- end }}
+{{- end }}
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/ingress.yaml b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/ingress.yaml
new file mode 100644
index 0000000..46de18b
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/ingress.yaml
@@ -0,0 +1,61 @@
+{{- if .Values.ingress.enabled -}}
+{{- $fullName := include "quartzmanager-standalone.fullname" . -}}
+{{- $svcPort := .Values.service.port -}}
+{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
+ {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
+ {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
+ {{- end }}
+{{- end }}
+{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1
+{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
+apiVersion: networking.k8s.io/v1beta1
+{{- else -}}
+apiVersion: extensions/v1beta1
+{{- end }}
+kind: Ingress
+metadata:
+ name: {{ $fullName }}
+ labels:
+ {{- include "quartzmanager-standalone.labels" . | nindent 4 }}
+ {{- with .Values.ingress.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+spec:
+ {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
+ ingressClassName: {{ .Values.ingress.className }}
+ {{- end }}
+ {{- if .Values.ingress.tls }}
+ tls:
+ {{- range .Values.ingress.tls }}
+ - hosts:
+ {{- range .hosts }}
+ - {{ . | quote }}
+ {{- end }}
+ secretName: {{ .secretName }}
+ {{- end }}
+ {{- end }}
+ rules:
+ {{- range .Values.ingress.hosts }}
+ - host: {{ .host | quote }}
+ http:
+ paths:
+ {{- range .paths }}
+ - path: {{ .path }}
+ {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
+ pathType: {{ .pathType }}
+ {{- end }}
+ backend:
+ {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
+ service:
+ name: {{ $fullName }}
+ port:
+ number: {{ $svcPort }}
+ {{- else }}
+ serviceName: {{ $fullName }}
+ servicePort: {{ $svcPort }}
+ {{- end }}
+ {{- end }}
+ {{- end }}
+{{- end }}
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/service.yaml b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/service.yaml
new file mode 100644
index 0000000..96bcb76
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/service.yaml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Service
+metadata:
+ name: {{ include "quartzmanager-standalone.fullname" . }}
+ labels:
+ {{- include "quartzmanager-standalone.labels" . | nindent 4 }}
+spec:
+ type: {{ .Values.service.type }}
+ ports:
+ - port: {{ .Values.service.port }}
+ targetPort: http
+ protocol: TCP
+ name: http
+ selector:
+ {{- include "quartzmanager-standalone.selectorLabels" . | nindent 4 }}
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/serviceaccount.yaml b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/serviceaccount.yaml
new file mode 100644
index 0000000..6e11e89
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-web-showcase/helm/templates/serviceaccount.yaml
@@ -0,0 +1,12 @@
+{{- if .Values.serviceAccount.create -}}
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: {{ include "quartzmanager-standalone.serviceAccountName" . }}
+ labels:
+ {{- include "quartzmanager-standalone.labels" . | nindent 4 }}
+ {{- with .Values.serviceAccount.annotations }}
+ annotations:
+ {{- toYaml . | nindent 4 }}
+ {{- end }}
+{{- end }}
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/helm/values.yaml b/quartz-manager-parent/quartz-manager-web-showcase/helm/values.yaml
new file mode 100644
index 0000000..dab99e5
--- /dev/null
+++ b/quartz-manager-parent/quartz-manager-web-showcase/helm/values.yaml
@@ -0,0 +1,83 @@
+# Default values for hello-world.
+# This is a YAML-formatted file.
+# Declare variables to be passed into your templates.
+
+replicaCount: 1
+
+image:
+ repository: "europe-west8-docker.pkg.dev/quartz-manager-test/quartz-manager/quartz-manager-standalone/quartz-manager-standalone"
+ pullPolicy: IfNotPresent
+
+imagePullSecrets: []
+nameOverride: ""
+fullnameOverride: ""
+
+serviceAccount:
+ # Specifies whether a service account should be created
+ create: false
+ # Annotations to add to the service account
+ annotations: {}
+ # The name of the service account to use.
+ # If not set and create is true, a name is generated using the fullname template
+ name: ""
+
+podAnnotations: {}
+
+podSecurityContext: {}
+# fsGroup: 2000
+
+securityContext: {}
+ # capabilities:
+ # drop:
+ # - ALL
+ # readOnlyRootFilesystem: true
+# runAsNonRoot: true
+# runAsUser: 1000
+
+service:
+ type: ClusterIP
+ port: 8080
+
+ingress:
+ enabled: false
+ className: ""
+ annotations: {}
+ # kubernetes.io/ingress.class: nginx
+ # kubernetes.io/tls-acme: "true"
+ hosts:
+ - host: chart-example.local
+ paths:
+ - path: /
+ pathType: ImplementationSpecific
+ tls: []
+ # - secretName: chart-example-tls
+ # hosts:
+ # - chart-example.local
+
+resources: {}
+ # We usually recommend not to specify default resources and to leave this as a conscious
+ # choice for the user. This also increases chances charts run on environments with little
+ # resources, such as Minikube. If you do want to specify resources, uncomment the following
+ # lines, adjust them as necessary, and remove the curly braces after 'resources:'.
+ # limits:
+ # cpu: 100m
+ # memory: 128Mi
+ # requests:
+# cpu: 100m
+# memory: 128Mi
+
+autoscaling:
+ enabled: false
+ minReplicas: 1
+ maxReplicas: 100
+ targetCPUUtilizationPercentage: 80
+ # targetMemoryUtilizationPercentage: 80
+
+nodeSelector: {}
+
+tolerations: []
+
+affinity: {}
+
+config:
+ envName: NA
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/pom.xml b/quartz-manager-parent/quartz-manager-web-showcase/pom.xml
index 6e51702..0d80c5a 100644
--- a/quartz-manager-parent/quartz-manager-web-showcase/pom.xml
+++ b/quartz-manager-parent/quartz-manager-web-showcase/pom.xml
@@ -5,12 +5,12 @@
it.fabioformosa.quartz-manager
quartz-manager-parent
- 4.0.9
+ 4.0.11-SNAPSHOT
- quartz-manager-web-showcase
+ jar
- war
+ quartz-manager-web-showcase
Quartz Manager Web Showcase
A webapp that imports Quartz Manager API lib and the frontend webjar
@@ -49,15 +49,10 @@
org.springframework.boot
spring-boot-devtools
-
- org.springframework.boot
- spring-boot-configuration-processor
- true
-
-
+
org.springframework.boot
- spring-boot-starter-tomcat
- provided
+ spring-boot-configuration-processor
+ true
org.springframework.boot
@@ -123,30 +118,28 @@
-
-
-
- org.springframework.boot
- spring-boot-maven-plugin
-
-
-
- repackage
-
-
-
-
-
- org.apache.maven.plugins
- maven-compiler-plugin
- 3.8.0
-
- 9
- 9
-
-
-
-
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.0
+
+ 9
+ 9
+
+
+
diff --git a/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/ServletInitializer.java b/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/ServletInitializer.java
deleted file mode 100644
index dcc3414..0000000
--- a/quartz-manager-parent/quartz-manager-web-showcase/src/main/java/it/fabioformosa/ServletInitializer.java
+++ /dev/null
@@ -1,21 +0,0 @@
-package it.fabioformosa;
-
-import lombok.Generated;
-import org.springframework.boot.builder.SpringApplicationBuilder;
-import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
-
-/**
- * ServletInitializer needs to deploy quartz-manager into a servlet container as a war file
- *
- * @author Fabio Formosa
- *
- */
-@Generated
-public class ServletInitializer extends SpringBootServletInitializer {
-
- @Override
- protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
- return application.sources(QuartzManagerDemoApplication.class);
- }
-
-}
diff --git a/skaffold.yaml b/skaffold.yaml
new file mode 100644
index 0000000..035e751
--- /dev/null
+++ b/skaffold.yaml
@@ -0,0 +1,46 @@
+apiVersion: skaffold/v4beta7
+kind: Config
+build:
+ tagPolicy:
+ envTemplate:
+ template: "_IMAGE_TAG_POLICY"
+ artifacts:
+ - image: quartz-manager-standalone
+ context: ./
+profiles:
+ - name: dev
+ deploy:
+ helm:
+ releases:
+ - name: quartzmanager-standalone
+ createNamespace: true
+ namespace: quartzmanager-dev
+ chartPath: quartz-manager-parent/quartz-manager-web-showcase/helm
+# valuesFiles:
+# - helm/envs/dev/values.yaml
+ setValueTemplates:
+ image.tag: "_IMAGE_TAG_POLICY"
+ - name: staging
+ deploy:
+ helm:
+ releases:
+ - name: quartzmanager-standalone
+ createNamespace: true
+ namespace: quartzmanager-staging
+ chartPath: quartz-manager-parent/quartz-manager-web-showcase/helm
+ # valuesFiles:
+ # - helm/envs/dev/values.yaml
+ setValueTemplates:
+ image.tag: "_IMAGE_TAG_POLICY"
+ - name: prod
+ deploy:
+ helm:
+ releases:
+ - name: quartzmanager-standalone
+ createNamespace: true
+ namespace: quartzmanager-prod
+ chartPath: quartz-manager-parent/quartz-manager-web-showcase/helm
+ # valuesFiles:
+ # - helm/envs/dev/values.yaml
+ setValueTemplates:
+ image.tag: "_IMAGE_TAG_POLICY"