From ca8f11bcae1c38fc09da16c202f9845d782960f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Spada=20=E2=9A=94=EF=B8=8F?= <75368540+PierpaoloSpadafora@users.noreply.github.com> Date: Thu, 12 Dec 2024 02:17:41 +0100 Subject: [PATCH] fix --- .../demacs/rdm/controller/JsonController.java | 89 +++++++++-- .../implementation/JsonServiceImpl.java | 3 + .../app/components/home/home.component.css | 6 + .../app/components/home/home.component.html | 5 +- .../src/app/components/home/home.component.ts | 146 ++++++++++-------- .../schedule/schedule.component.html | 2 +- .../api/jsonController.service.ts | 30 ++-- ...UploadschedulesscheduledexternallyBody.ts} | 2 +- .../src/app/generated-api/model/models.ts | 2 +- 9 files changed, 186 insertions(+), 99 deletions(-) rename Frontend/src/app/generated-api/model/{jsonUploadschedulesBody.ts => jsonUploadschedulesscheduledexternallyBody.ts} (85%) diff --git a/Backend/src/main/java/unical/demacs/rdm/controller/JsonController.java b/Backend/src/main/java/unical/demacs/rdm/controller/JsonController.java index 1e775fb..1b65ee2 100644 --- a/Backend/src/main/java/unical/demacs/rdm/controller/JsonController.java +++ b/Backend/src/main/java/unical/demacs/rdm/controller/JsonController.java @@ -16,6 +16,12 @@ import java.util.List; import java.util.Map; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; @RestController @RequestMapping(value = "/api/v1/json", produces = "application/json") @@ -109,32 +115,72 @@ public ResponseEntity> exportMachine() { @Operation(summary = "Export Job data to JSON", description = "Export all Job data to JSON.", tags = {"json-controller"}) @GetMapping(value = "/export-job-scheduled-by-priority", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity> exportJobScheduledPriority() { - List schedules = jsonService.readScheduleFile("./data/job-scheduled-by-priority.json"); - return ResponseEntity.ok(schedules); + public ResponseEntity exportJobScheduledPriority() { + try { + List schedules = jsonService.readScheduleFile("./data/job-scheduled-by-priority.json"); + return ResponseEntity.ok(schedules); + } catch (RuntimeException e) { + String message = e.getMessage(); + if (message.startsWith("FILE_NOT_FOUND:")) { + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(Map.of("error", "Schedule file not found", "details", message)); + } + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(Map.of("error", "Error reading schedule file", "details", message)); + } } @Operation(summary = "Export Job data to JSON", description = "Export all Job data to JSON.", tags = {"json-controller"}) @GetMapping(value = "/export-job-scheduled-by-due-date", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity> exportJobScheduledDueDate() { - List schedules = jsonService.readScheduleFile("./data/job-scheduled-by-due-date.json"); - return ResponseEntity.ok(schedules); + public ResponseEntity exportJobScheduledDueDate() { + try { + List schedules = jsonService.readScheduleFile("./data/job-scheduled-by-due-date.json"); + return ResponseEntity.ok(schedules); + } catch (RuntimeException e) { + String message = e.getMessage(); + if (message.startsWith("FILE_NOT_FOUND:")) { + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(Map.of("error", "Schedule file not found", "details", message)); + } + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(Map.of("error", "Error reading schedule file", "details", message)); + } } @Operation(summary = "Export Job data to JSON", description = "Export all Job data to JSON.", tags = {"json-controller"}) @GetMapping(value = "/export-job-scheduled-by-duration", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity> exportJobScheduledDuration() { - List schedules = jsonService.readScheduleFile("./data/job-scheduled-by-duration.json"); - return ResponseEntity.ok(schedules); + public ResponseEntity exportJobScheduledDuration() { + try { + List schedules = jsonService.readScheduleFile("./data/job-scheduled-by-duration.json"); + return ResponseEntity.ok(schedules); + } catch (RuntimeException e) { + String message = e.getMessage(); + if (message.startsWith("FILE_NOT_FOUND:")) { + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(Map.of("error", "Schedule file not found", "details", message)); + } + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(Map.of("error", "Error reading schedule file", "details", message)); + } } @Operation(summary = "Export RO scheduled jobs", description = "Export all RO scheduled jobs to JSON.") - @GetMapping(value = "/export-job-scheduled-ro", produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity> exportJobScheduledRO() { - List schedules = jsonService.readScheduleFile("./data/job-scheduled-ro.json"); - return ResponseEntity.ok(schedules); + @GetMapping(value = "/export-job-scheduled-external", produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity exportJobScheduledExternal() { + try { + List schedules = jsonService.readScheduleFile("./data/job-scheduled-imported.json"); + return ResponseEntity.ok(schedules); + } catch (RuntimeException e) { + String message = e.getMessage(); + if (message.startsWith("FILE_NOT_FOUND:")) { + return ResponseEntity.status(HttpStatus.NOT_FOUND) + .body(Map.of("error", "Schedule file not found", "details", message)); + } + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(Map.of("error", "Error reading schedule file", "details", message)); + } } @Operation(summary = "Download all Schedules as JSON", description = "Download all Schedules as a JSON file.", @@ -147,18 +193,29 @@ public ResponseEntity> downloadSchedules() { @Operation(summary = "Import Schedules from JSON", description = "Upload and import Schedules from a JSON file.", tags = {"json-controller"}) - @PostMapping(value = "/upload-schedules", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @PostMapping(value = "/upload-schedules-scheduled-externally", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity> importSchedules(@RequestParam("file") MultipartFile file) { try { if (file.isEmpty()) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(Map.of("message", "File is empty.")); } - jsonService.importSchedules(file); + File directory = new File("./data"); + if (!directory.exists()) { + directory.mkdirs(); + } + Path filePath = Paths.get("./data/job-scheduled-imported.json"); + Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING); return ResponseEntity.ok(Map.of("message", "Schedules imported successfully.")); - } catch (RuntimeException e) { + } catch (IOException e) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) .body(Map.of("message", "Error importing schedules: " + e.getMessage())); } } + @GetMapping("/export-job-scheduled-ro") + public ResponseEntity> exportJobScheduledRO() { + List schedules = jsonService.readScheduleFile("./data/job-scheduled-ro.json"); + return ResponseEntity.ok(schedules); + } + } \ No newline at end of file diff --git a/Backend/src/main/java/unical/demacs/rdm/persistence/service/implementation/JsonServiceImpl.java b/Backend/src/main/java/unical/demacs/rdm/persistence/service/implementation/JsonServiceImpl.java index a4c9937..67ec67f 100644 --- a/Backend/src/main/java/unical/demacs/rdm/persistence/service/implementation/JsonServiceImpl.java +++ b/Backend/src/main/java/unical/demacs/rdm/persistence/service/implementation/JsonServiceImpl.java @@ -28,6 +28,9 @@ public class JsonServiceImpl implements IJsonService { public List readScheduleFile(String fileName) { File file = new File(fileName); + if (!file.exists()) { + throw new RuntimeException(new IOException("File not found: " + fileName)); + } try { return objectMapper.readValue(file, objectMapper.getTypeFactory().constructCollectionType(List.class, ScheduleWithMachineDTO.class)); diff --git a/Frontend/src/app/components/home/home.component.css b/Frontend/src/app/components/home/home.component.css index ac5aca3..4624074 100644 --- a/Frontend/src/app/components/home/home.component.css +++ b/Frontend/src/app/components/home/home.component.css @@ -173,6 +173,12 @@ border-left: 3px solid #3498db; } +.error-message { + color: red; + text-align: center; + margin-bottom: 1rem; +} + @media (max-width: 768px) { .page-container { padding: 1rem; diff --git a/Frontend/src/app/components/home/home.component.html b/Frontend/src/app/components/home/home.component.html index 647806a..74df893 100644 --- a/Frontend/src/app/components/home/home.component.html +++ b/Frontend/src/app/components/home/home.component.html @@ -3,7 +3,7 @@

Scheduled Jobs

-
@@ -98,5 +98,8 @@

{{ getMachineName(machineSchedules[0].machineId) }} +
+

{{ errorMessage }}

+
diff --git a/Frontend/src/app/components/home/home.component.ts b/Frontend/src/app/components/home/home.component.ts index b8283f7..6795618 100644 --- a/Frontend/src/app/components/home/home.component.ts +++ b/Frontend/src/app/components/home/home.component.ts @@ -3,7 +3,8 @@ import { ScheduleControllerService, JobDTO, JsonControllerService } from '../../generated-api'; import { Router } from '@angular/router'; import { Observable } from 'rxjs'; -import { ScheduleWithMachineDTO } from '../../generated-api/model/scheduleWithMachineDTO'; +import { ScheduleWithMachineDTO } from '../../generated-api'; +import Swal from 'sweetalert2'; @Component({ selector: 'app-home', @@ -14,16 +15,18 @@ export class HomeComponent implements OnInit { scheduleData: ScheduleWithMachineDTO[] = []; jobsMap: Map = new Map(); machinesMap: Map = new Map(); - machineNamesMap: Map = new Map(); // New map for machine names + machineNamesMap: Map = new Map(); scheduleTypes = [ { label: 'All Jobs', value: 'ALL' }, { label: 'Scheduled by Due Date', value: 'DUE_DATE' }, { label: 'Scheduled by Priority', value: 'PRIORITY' }, { label: 'Scheduled by Duration', value: 'DURATION' }, - { label: 'Scheduler di RICERCA OPERATIVA', value: 'RO' } + { label: 'External Scheduler ', value: 'EXTERNAL' } ]; selectedScheduleType = 'ALL'; + errorMessage: string = ''; + newSelectedScheduleType: string = this.selectedScheduleType; daysPerPageOptions = [1, 3, 5, 7]; selectedDaysPerPage = 3; @@ -42,18 +45,18 @@ export class HomeComponent implements OnInit { ) { } ngOnInit() { - this.fetchData(); + this.fetchData(this.selectedScheduleType); } onScheduleTypeChange() { - this.fetchData(); + this.fetchData(this.newSelectedScheduleType); } - fetchData() { + fetchData(scheduleType: string) { this.loading = true; let scheduleObservable: Observable; - switch (this.selectedScheduleType) { + switch (scheduleType) { case 'PRIORITY': scheduleObservable = this.jsonService.exportJobScheduledPriority(); break; @@ -63,8 +66,8 @@ export class HomeComponent implements OnInit { case 'DURATION': scheduleObservable = this.jsonService.exportJobScheduledDuration(); break; - case 'RO': - scheduleObservable = this.jsonService.exportJobScheduledRO(); + case 'EXTERNAL': + scheduleObservable = this.jsonService.exportJobScheduledExternal(); break; default: scheduleObservable = this.scheduleService.getAllSchedules(); @@ -72,60 +75,75 @@ export class HomeComponent implements OnInit { scheduleObservable.subscribe({ next: (scheduleData: ScheduleWithMachineDTO[]) => { - this.scheduleData = scheduleData; - - this.jsonService.exportJob().subscribe({ - next: (jobs: JobDTO[]) => { - this.jobsMap.clear(); - jobs.forEach(job => { - if (job.id !== undefined) { - this.jobsMap.set(job.id, job); - } - }); - - this.jsonService.exportMachineType().subscribe({ - next: (machineTypes) => { - this.machinesMap.clear(); - machineTypes.forEach(machineType => { - if (machineType.id !== undefined && machineType.name !== undefined) { - this.machinesMap.set(machineType.id, machineType.name); - } - }); - - // Fetch machine names - this.jsonService.exportMachine().subscribe({ - next: (machines) => { - this.machineNamesMap.clear(); - machines.forEach(machine => { - if (machine.id !== undefined && machine.name !== undefined) { - this.machineNamesMap.set(machine.id, machine.name); - } - }); - - this.processData(); - this.loading = false; - }, - error: (error: unknown) => { - console.error('Error fetching machines data', error); - this.loading = false; - } - }); - }, - error: (error: unknown) => { - console.error('Error fetching machine types data', error); - this.loading = false; - } - }); - }, - error: (error: unknown) => { - console.error('Error fetching jobs data', error); - this.loading = false; - } - }); + if (scheduleData.length === 0) { + this.errorMessage = 'Nessun job pianificato trovato per il tipo selezionato.'; + this.loading = false; + } else { + this.errorMessage = ''; + this.selectedScheduleType = scheduleType; + this.newSelectedScheduleType = scheduleType; + this.scheduleData = scheduleData; + + this.jsonService.exportJob().subscribe({ + next: (jobs: JobDTO[]) => { + this.jobsMap.clear(); + jobs.forEach(job => { + if (job.id !== undefined) { + this.jobsMap.set(job.id, job); + } + }); + + this.jsonService.exportMachineType().subscribe({ + next: (machineTypes) => { + this.machinesMap.clear(); + machineTypes.forEach(machineType => { + if (machineType.id !== undefined && machineType.name !== undefined) { + this.machinesMap.set(machineType.id, machineType.name); + } + }); + + // Fetch machine names + this.jsonService.exportMachine().subscribe({ + next: (machines) => { + this.machineNamesMap.clear(); + machines.forEach(machine => { + if (machine.id !== undefined && machine.name !== undefined) { + this.machineNamesMap.set(machine.id, machine.name); + } + }); + + this.processData(); + this.loading = false; + }, + error: (error: unknown) => { + console.error('Error fetching machines data', error); + this.loading = false; + } + }); + }, + error: (error: unknown) => { + console.error('Error fetching machine types data', error); + this.loading = false; + } + }); + }, + error: (error: unknown) => { + console.error('Error fetching jobs data', error); + this.loading = false; + } + }); + } }, error: (error: unknown) => { console.error('Error fetching schedule data', error); this.loading = false; + Swal.fire({ + icon: 'error', + title: 'Errore', + text: 'Impossibile caricare i dati. Il file potrebbe non essere presente.', + }); + // Ripristina il valore della select + this.newSelectedScheduleType = this.selectedScheduleType; } }); } @@ -179,26 +197,26 @@ export class HomeComponent implements OnInit { getUniqueMachineTypes(date: string): string[] { const machineTypeIds = Array.from(this.schedulesByDateAndMachine.get(date)?.keys() || []); const uniqueTypes = new Set(); - + machineTypeIds.forEach(id => { const machineName = this.machinesMap.get(id) || 'Unknown Machine Type'; uniqueTypes.add(machineName); }); - + return Array.from(uniqueTypes); } getSchedulesForMachineType(date: string, machineTypeName: string): ScheduleWithMachineDTO[][] { const machineTypeId = Array.from(this.machinesMap.entries()) .find(([_, name]) => name === machineTypeName)?.[0]; - + if (!machineTypeId) return []; const schedules = this.schedulesByDateAndMachine.get(date)?.get(machineTypeId) || []; - + // Group schedules by machineId const groupedSchedules = new Map(); - + schedules.forEach(schedule => { const machineId = schedule.machineId || 0; if (!groupedSchedules.has(machineId)) { diff --git a/Frontend/src/app/components/schedule/schedule.component.html b/Frontend/src/app/components/schedule/schedule.component.html index d01b296..484b4b8 100644 --- a/Frontend/src/app/components/schedule/schedule.component.html +++ b/Frontend/src/app/components/schedule/schedule.component.html @@ -55,7 +55,7 @@

Job partecipanti alla schedulazione

- +
diff --git a/Frontend/src/app/generated-api/api/jsonController.service.ts b/Frontend/src/app/generated-api/api/jsonController.service.ts index 1a81468..e61e429 100644 --- a/Frontend/src/app/generated-api/api/jsonController.service.ts +++ b/Frontend/src/app/generated-api/api/jsonController.service.ts @@ -204,15 +204,15 @@ export class JsonControllerService { } /** - * Export Job data to JSON - * Export all Job data to JSON. + * Export RO scheduled jobs + * Export all RO scheduled jobs to JSON. * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public exportJobScheduledPriority(observe?: 'body', reportProgress?: boolean): Observable>; - public exportJobScheduledPriority(observe?: 'response', reportProgress?: boolean): Observable>>; - public exportJobScheduledPriority(observe?: 'events', reportProgress?: boolean): Observable>>; - public exportJobScheduledPriority(observe: any = 'body', reportProgress: boolean = false ): Observable { + public exportJobScheduledExternal(observe?: 'body', reportProgress?: boolean): Observable>; + public exportJobScheduledExternal(observe?: 'response', reportProgress?: boolean): Observable>>; + public exportJobScheduledExternal(observe?: 'events', reportProgress?: boolean): Observable>>; + public exportJobScheduledExternal(observe: any = 'body', reportProgress: boolean = false ): Observable { let headers = this.defaultHeaders; @@ -229,7 +229,7 @@ export class JsonControllerService { const consumes: string[] = [ ]; - return this.httpClient.request>('get',`${this.basePath}/api/v1/json/export-job-scheduled-by-priority`, + return this.httpClient.request>('get',`${this.basePath}/api/v1/json/export-job-scheduled-external`, { withCredentials: this.configuration.withCredentials, headers: headers, @@ -240,15 +240,15 @@ export class JsonControllerService { } /** - * Export RO scheduled jobs - * Export all RO scheduled jobs to JSON. + * Export Job data to JSON + * Export all Job data to JSON. * @param observe set whether or not to return the data Observable as the body, response or events. defaults to returning the body. * @param reportProgress flag to report request and response progress. */ - public exportJobScheduledRO(observe?: 'body', reportProgress?: boolean): Observable>; - public exportJobScheduledRO(observe?: 'response', reportProgress?: boolean): Observable>>; - public exportJobScheduledRO(observe?: 'events', reportProgress?: boolean): Observable>>; - public exportJobScheduledRO(observe: any = 'body', reportProgress: boolean = false ): Observable { + public exportJobScheduledPriority(observe?: 'body', reportProgress?: boolean): Observable>; + public exportJobScheduledPriority(observe?: 'response', reportProgress?: boolean): Observable>>; + public exportJobScheduledPriority(observe?: 'events', reportProgress?: boolean): Observable>>; + public exportJobScheduledPriority(observe: any = 'body', reportProgress: boolean = false ): Observable { let headers = this.defaultHeaders; @@ -265,7 +265,7 @@ export class JsonControllerService { const consumes: string[] = [ ]; - return this.httpClient.request>('get',`${this.basePath}/api/v1/json/export-job-scheduled-ro`, + return this.httpClient.request>('get',`${this.basePath}/api/v1/json/export-job-scheduled-by-priority`, { withCredentials: this.configuration.withCredentials, headers: headers, @@ -546,7 +546,7 @@ export class JsonControllerService { formParams = formParams.append('file', file) as any || formParams; } - return this.httpClient.request<{ [key: string]: string; }>('post',`${this.basePath}/api/v1/json/upload-schedules`, + return this.httpClient.request<{ [key: string]: string; }>('post',`${this.basePath}/api/v1/json/upload-schedules-scheduled-externally`, { body: convertFormParamsToString ? formParams.toString() : formParams, withCredentials: this.configuration.withCredentials, diff --git a/Frontend/src/app/generated-api/model/jsonUploadschedulesBody.ts b/Frontend/src/app/generated-api/model/jsonUploadschedulesscheduledexternallyBody.ts similarity index 85% rename from Frontend/src/app/generated-api/model/jsonUploadschedulesBody.ts rename to Frontend/src/app/generated-api/model/jsonUploadschedulesscheduledexternallyBody.ts index 4ed505d..57800f5 100644 --- a/Frontend/src/app/generated-api/model/jsonUploadschedulesBody.ts +++ b/Frontend/src/app/generated-api/model/jsonUploadschedulesscheduledexternallyBody.ts @@ -10,6 +10,6 @@ * Do not edit the class manually. */ -export interface JsonUploadschedulesBody { +export interface JsonUploadschedulesscheduledexternallyBody { file: Blob; } \ No newline at end of file diff --git a/Frontend/src/app/generated-api/model/models.ts b/Frontend/src/app/generated-api/model/models.ts index 9903fb2..4863ca2 100644 --- a/Frontend/src/app/generated-api/model/models.ts +++ b/Frontend/src/app/generated-api/model/models.ts @@ -1,6 +1,6 @@ export * from './job'; export * from './jobDTO'; -export * from './jsonUploadschedulesBody'; +export * from './jsonUploadschedulesscheduledexternallyBody'; export * from './machine'; export * from './machineDTO'; export * from './machineType';