2525import de .doubleslash .keeptime .model .settings .HeimatSettings ;
2626import de .doubleslash .keeptime .rest .integration .heimat .HeimatAPI ;
2727import de .doubleslash .keeptime .rest .integration .heimat .model .HeimatTask ;
28+ import javafx .application .Platform ;
2829import javafx .beans .property .SimpleObjectProperty ;
2930import javafx .beans .property .SimpleStringProperty ;
3031import javafx .collections .FXCollections ;
3132import javafx .collections .ObservableList ;
3233import javafx .collections .transformation .FilteredList ;
3334import javafx .fxml .FXML ;
3435import javafx .scene .control .*;
36+ import javafx .scene .layout .VBox ;
3537import javafx .scene .paint .Color ;
3638import javafx .stage .Stage ;
3739import org .slf4j .Logger ;
3840import org .slf4j .LoggerFactory ;
3941import org .springframework .stereotype .Component ;
4042
4143import java .time .LocalDate ;
44+ import java .util .ArrayList ;
4245import java .util .List ;
4346import java .util .Optional ;
47+ import java .util .stream .Collectors ;
4448
4549@ Component
4650public class MapExternalProjectsController {
@@ -92,11 +96,15 @@ private void initialize() {
9296 // but what happens with mapped projects not existing at that date? but actually not related to this feature alone
9397
9498 final HeimatAPI heimatAPI = new HeimatAPI (heimatSettings .getHeimatUrl (), heimatSettings .getHeimatPat ());
95- final List <HeimatTask > externalProjects = heimatAPI .getMyTasks (tasksForDateDatePicker .getValue ());
99+ final List <HeimatTask > allExternalProjects = heimatAPI .getMyTasks (tasksForDateDatePicker .getValue ());
100+ final List <HeimatTask > externalProjects = allExternalProjects .stream ()
101+ .filter (p -> !p .isStartAndEndTimeRequired ())
102+ .collect (Collectors .toCollection (ArrayList ::new ));
96103
97104 final List <ExternalProjectMapping > alreadyMappedProjects = externalProjectsMappingsRepository .findByExternalSystemId (
98105 ExternalSystem .Heimat );
99106
107+ final List <ExternalProjectMapping > invalidExternalMappings = new ArrayList <>();
100108 final List <ProjectMapping > projectMappings = model .getSortedAvailableProjects ().stream ().map (p -> {
101109 final Optional <ExternalProjectMapping > mapping = alreadyMappedProjects .stream ()
102110 .filter (mp -> mp .getProject ().getId ()
@@ -109,15 +117,16 @@ private void initialize() {
109117 .filter (ep -> ep .id () == mapping .get ().getExternalTaskId ())
110118 .findAny ();
111119 if (any .isEmpty ()) {
112- LOG .warn ("A mapping exists but task does not exist anymore in HEIMAT! {}." , mapping .get ());
113- // TODO show this to the user somehow
120+ LOG .warn ("A mapping exists but task does not exist anymore in HEIMAT! '{}'->'{}'." ,
121+ mapping .get ().getProject (), mapping .get ().getExternalTaskId ());
122+ invalidExternalMappings .add (mapping .get ());
114123 return new ProjectMapping (p , null );
115124 }
116125 return new ProjectMapping (p , any .get ());
117126 }).toList ();
118127
119128 final ObservableList <ProjectMapping > observableMappings = FXCollections .observableArrayList (projectMappings );
120- final FilteredList <ProjectMapping > value = new FilteredList <>(observableMappings , pm -> pm .getProject ().isWork ());
129+ final FilteredList <ProjectMapping > value = new FilteredList <>(observableMappings , pm -> pm .getProject ().isWork ());
121130 mappingTableView .setItems (value );
122131
123132 // KeepTime Project column
@@ -126,13 +135,13 @@ private void initialize() {
126135
127136 // External Project column with dropdown
128137 externalProjects .add (0 , null ); // option to clear selection
129- final ObservableList <HeimatTask > externalProjectsObservableList = FXCollections .observableArrayList (externalProjects );
138+ final ObservableList <HeimatTask > externalProjectsObservableList = FXCollections .observableArrayList (
139+ externalProjects );
130140 TableColumn <ProjectMapping , HeimatTask > externalColumn = new TableColumn <>("Heimat Project" );
131141 externalColumn .setCellValueFactory (data -> new SimpleObjectProperty <>(data .getValue ().heimatTask ));
132142 externalColumn .setCellFactory (col -> new TableCell <>() {
133143 // TODO search in box would be nice
134- private final ComboBox <HeimatTask > comboBox = new ComboBox <>(
135- externalProjectsObservableList );
144+ private final ComboBox <HeimatTask > comboBox = new ComboBox <>(externalProjectsObservableList );
136145
137146 @ Override
138147 protected void updateItem (HeimatTask item , boolean empty ) {
@@ -145,7 +154,7 @@ protected void updateItem(HeimatTask item, boolean empty) {
145154 if (empty || item == null ) {
146155 setText (null );
147156 } else {
148- setText (item .projectName () + " - " + item .name ());
157+ setText (item .taskHolderName () + " - " + item .name ());
149158 }
150159 }
151160 });
@@ -160,7 +169,7 @@ protected void updateItem(HeimatTask item, boolean empty) {
160169 setText (null );
161170 } else {
162171 // TODO maybe show if the project was already mapped
163- setText (item .projectName () + " - " + item .name ());
172+ setText (item .taskHolderName () + " - " + item .name ());
164173 }
165174 }
166175 });
@@ -195,7 +204,7 @@ protected void updateItem(HeimatTask item, boolean empty) {
195204 setText (null );
196205 } else {
197206 // TODO maybe show if the project was already mapped
198- setText (item .projectName () + " - " + item .name ());
207+ setText (item .taskHolderName () + " - " + item .name ());
199208 }
200209 }
201210 });
@@ -206,7 +215,7 @@ protected void updateItem(HeimatTask item, boolean empty) {
206215 if (empty || item == null ) {
207216 setText (null );
208217 } else {
209- setText (item .projectName () + " - " + item .name ());
218+ setText (item .taskHolderName () + " - " + item .name ());
210219 }
211220 }
212221 });
@@ -216,7 +225,8 @@ protected void updateItem(HeimatTask item, boolean empty) {
216225 final HeimatTask task = addNewProjectComboBox .getValue ();
217226 final int sortIndex = model .getAvailableProjects ().size ();
218227 final Project project = controller .addNewProject (
219- new Project (task .projectName () + " - " + task .name (), task .bookingHint (), Color .BLACK , true , sortIndex ));
228+ new Project (task .taskHolderName () + " - " + task .name (), task .bookingHint (), Color .BLACK , true ,
229+ sortIndex ));
220230 observableMappings .add (new ProjectMapping (project , task ));
221231 addNewProjectComboBox .getSelectionModel ().clearSelection ();
222232 });
@@ -240,7 +250,7 @@ protected void updateItem(HeimatTask item, boolean empty) {
240250 if (any .isPresent ()) {
241251 final ExternalProjectMapping projectMapping1 = any .get ();
242252 projectMapping1 .setExternalProjectName (
243- heimatTask .projectName ());
253+ heimatTask .taskHolderName ());
244254 projectMapping1 .setExternalTaskId (
245255 heimatTask .id ());
246256 projectMapping1 .setExternalTaskName (
@@ -251,7 +261,7 @@ protected void updateItem(HeimatTask item, boolean empty) {
251261 }
252262 return new ExternalProjectMapping (
253263 ExternalSystem .Heimat ,
254- heimatTask .projectName (),
264+ heimatTask .taskHolderName (),
255265 heimatTask .id (),
256266 heimatTask .name (),
257267 heimatTask .toString ()
@@ -270,7 +280,8 @@ protected void updateItem(HeimatTask item, boolean empty) {
270280 .anyMatch (
271281 wantedMapping ->
272282 wantedMapping .project .getId ()
273- == em .getProject ().getId ()
283+ == em .getProject ()
284+ .getId ()
274285 &&
275286 wantedMapping .heimatTask
276287 == null ))
@@ -283,6 +294,52 @@ protected void updateItem(HeimatTask item, boolean empty) {
283294 cancelButton .setOnAction (ae -> {
284295 thisStage .close ();
285296 });
297+
298+ final List <String > invalidMappingsAsString = invalidExternalMappings .stream ()
299+ .map (em -> "Task no longer exists: "
300+ + em .getExternalProjectName () + " - "
301+ + em .getExternalTaskName ()
302+ + "'. Was mapped to '" + em .getProject ()
303+ .getName ()
304+ + "'." )
305+ .toList ();
306+ List <String > notSupportedTasks = allExternalProjects .stream ()
307+ .filter (HeimatTask ::isStartAndEndTimeRequired )
308+ .map (p -> "Task " + p .taskHolderName () + " - " + p .name ()
309+ + " requires start+end time which is not supported." )
310+ .toList ();
311+ List <String > warnings = new ArrayList <>(notSupportedTasks );
312+ warnings .addAll (invalidMappingsAsString );
313+ if (!warnings .isEmpty ()) {
314+ Platform .runLater (() -> showInvalidMappingsDialog (warnings ));
315+ }
316+ }
317+
318+ private void showInvalidMappingsDialog (final List <String > warnings ) {
319+ Dialog <Void > dialog = new Dialog <>();
320+ dialog .initOwner (this .thisStage );
321+ dialog .setTitle ("Invalid mappings" );
322+ dialog .setHeaderText ("Please note to following issue:" );
323+
324+ VBox warningBox = new VBox (10 );
325+ for (String warning : warnings ) {
326+ Label label = new Label (warning );
327+ label .setWrapText (true );
328+ warningBox .getChildren ().add (label );
329+ }
330+
331+ ScrollPane scrollPane = new ScrollPane (warningBox );
332+ scrollPane .setFitToWidth (true );
333+ scrollPane .setPrefHeight (Math .min (300 , warnings .size () * 30 + 50 )); // Adjust height dynamically
334+
335+ dialog .getDialogPane ().setContent (scrollPane );
336+ dialog .getDialogPane ().setMinWidth (400 );
337+
338+ // Add OK button
339+ ButtonType okButton = new ButtonType ("OK" , ButtonBar .ButtonData .OK_DONE );
340+ dialog .getDialogPane ().getButtonTypes ().add (okButton );
341+
342+ dialog .showAndWait ();
286343 }
287344
288345 public static class ProjectMapping {
0 commit comments