Skip to content

Commit

Permalink
Merge pull request #57 from jkingster/fix/ticket-filter-updates
Browse files Browse the repository at this point in the history
Fix bug (#55): When ti…
  • Loading branch information
jkingster authored May 23, 2024
2 parents d6ed1d5 + 820b92c commit ef1b53f
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 68 deletions.
10 changes: 10 additions & 0 deletions src/main/java/io/jacobking/quickticket/bridge/Bridge.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import io.jacobking.quickticket.core.database.repository.RepoType;
import io.jacobking.quickticket.gui.model.ViewModel;
import javafx.application.Platform;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.util.Callback;

import java.util.List;
import java.util.function.Predicate;
Expand All @@ -26,6 +28,14 @@ public Bridge(final Database database, final RepoType repoType) {
removalListener();
}

public Bridge(final Database database, final RepoType repoType, final Callback<V, Observable[]> callback) {
this.crud = database.call();
this.observableList = FXCollections.observableArrayList(callback);
this.repoType = repoType;
loadEntities();
removalListener();
}

protected void loadEntities() {
final List<E> entities = crud.getAll(repoType);
if (entities.isEmpty())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,53 +3,50 @@
import io.jacobking.quickticket.bridge.Bridge;
import io.jacobking.quickticket.core.database.Database;
import io.jacobking.quickticket.core.database.repository.RepoType;
import io.jacobking.quickticket.core.type.StatusType;
import io.jacobking.quickticket.gui.model.impl.TicketModel;
import io.jacobking.quickticket.tables.pojos.Ticket;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;

import java.util.Map;
import java.util.function.Predicate;

import static io.jacobking.quickticket.Tables.TICKET;

public class TicketBridge extends Bridge<Ticket, TicketModel> {

private ObservableList<TicketModel> baseUnfilteredList;
private final Map<StatusType, ObservableList<TicketModel>> ticketMap;

public TicketBridge(final Database database) {
super(database, RepoType.TICKET);
}
this.ticketMap = FXCollections.observableHashMap();

ticketMap.put(StatusType.OPEN, FXCollections.observableArrayList(
getObservableList().filtered(tm -> tm.statusProperty().get() == StatusType.OPEN)
));

ticketMap.put(StatusType.ACTIVE, FXCollections.observableArrayList(
getObservableList().filtered(tm -> tm.statusProperty().get() == StatusType.ACTIVE)
));

@Override protected void loadEntities() {
super.loadEntities();
this.baseUnfilteredList = FXCollections.observableArrayList(item -> new Observable[]{item.statusProperty()});
this.baseUnfilteredList.addAll(getObservableList());
ticketMap.put(StatusType.RESOLVED, FXCollections.observableArrayList(
getObservableList().filtered(tm -> tm.statusProperty().get() == StatusType.RESOLVED)
));

getObservableList().addListener((ListChangeListener<? super TicketModel>) change -> {
while (change.next()) {
if (change.wasAdded()) {
baseUnfilteredList.addAll(change.getAddedSubList());
}
ticketMap.put(StatusType.PAUSED, FXCollections.observableArrayList(
getObservableList().filtered(tm -> tm.statusProperty().get() == StatusType.PAUSED)
));

if (change.wasRemoved()) {
baseUnfilteredList.removeAll(change.getRemoved());
}
}
});
}


@Override
public TicketModel convertEntity(Ticket entity) {
return new TicketModel(entity);
}

public FilteredList<TicketModel> getFilteredList(final Predicate<TicketModel> predicate) {
return new FilteredList<>(baseUnfilteredList, predicate);
}

public TicketModel getLastViewed() {
final Ticket ticket = crud.getContext()
.selectFrom(TICKET)
Expand All @@ -58,4 +55,40 @@ public TicketModel getLastViewed() {
.fetchOneInto(Ticket.class);
return ticket == null ? null : new TicketModel(ticket);
}

@Override public TicketModel createModel(Ticket entity) {
final TicketModel model = super.createModel(entity);
final StatusType type = model.statusProperty().getValue();
final ObservableList<TicketModel> targetList = getListByStatus(type);
targetList.add(0, model);
return model;
}

@Override public void remove(int id) {
final TicketModel model = super.getModel(id);
if (model != null) {
super.remove(id);
final StatusType type = model.statusProperty().getValue();
getListByStatus(type).remove(model);
}
}

public boolean update(final TicketModel model, final StatusType originalStatus) {
if (super.update(model)) {
getListByStatus(originalStatus).remove(model);
final StatusType newStatus = model.statusProperty().get();
return getListByStatus(newStatus).add(model);
}
return false;
}

public ObservableList<TicketModel> getListByStatus(final StatusType statusType) {
return ticketMap.get(statusType);
}

public FilteredList<TicketModel> getFilteredList(final Predicate<TicketModel> predicate) {
return new FilteredList<>(getObservableList(), predicate);
}
}


Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.collections.ObservableMap;
import javafx.fxml.FXML;
import javafx.geometry.Pos;
import javafx.scene.control.Button;
Expand All @@ -38,20 +38,12 @@
import java.net.URISyntaxException;
import java.net.URL;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;

public class TicketController extends Controller {

private final FilteredList<TicketModel> open = ticket.getFilteredList(ticketModel -> ticketModel.statusProperty().getValue() == StatusType.OPEN);
private final FilteredList<TicketModel> active = ticket.getFilteredList(ticketModel -> ticketModel.statusProperty().getValue() == StatusType.ACTIVE);
private final FilteredList<TicketModel> paused = ticket.getFilteredList(ticketModel -> ticketModel.statusProperty().getValue() == StatusType.PAUSED);
private final FilteredList<TicketModel> resolved = ticket.getFilteredList(ticketModel -> ticketModel.statusProperty().getValue() == StatusType.RESOLVED);

private final ObjectProperty<TicketModel> lastViewed = new SimpleObjectProperty<>();

private final Map<Pane, FilteredList<TicketModel>> activePaneMap = new HashMap<>();
private final ObservableMap<Pane, ObservableList<TicketModel>> activePaneMap = FXCollections.observableHashMap();

@FXML private TableView<TicketModel> ticketTable;
@FXML private TableColumn<TicketModel, PriorityType> indicatorColumn;
Expand Down Expand Up @@ -187,28 +179,32 @@ private void handleIndicatorColumn() {
}

private void configureLabels() {
openLabel.setText(String.valueOf(open.size()));
activeLabel.setText(String.valueOf(active.size()));
pausedLabel.setText(String.valueOf(paused.size()));
resolvedLabel.setText(String.valueOf(resolved.size()));

addListener(openLabel, open);
addListener(activeLabel, active);
addListener(pausedLabel, paused);
addListener(resolvedLabel, resolved);
openLabel.setText(String.valueOf(getListByStatus(StatusType.OPEN).size()));
activeLabel.setText(String.valueOf(getListByStatus(StatusType.ACTIVE).size()));
pausedLabel.setText(String.valueOf(getListByStatus(StatusType.PAUSED).size()));
resolvedLabel.setText(String.valueOf(getListByStatus(StatusType.RESOLVED).size()));

addListener(openLabel, getListByStatus(StatusType.OPEN));
addListener(activeLabel, getListByStatus(StatusType.ACTIVE));
addListener(pausedLabel, getListByStatus(StatusType.PAUSED));
addListener(resolvedLabel, getListByStatus(StatusType.RESOLVED));
}

private void addListener(final Label label, final FilteredList<TicketModel> filteredList) {
filteredList.addListener((ListChangeListener<? super TicketModel>) change -> {
public TableView<TicketModel> getTicketTable() {
return ticketTable;
}

private void addListener(final Label label, final ObservableList<TicketModel> targetList) {
targetList.addListener((ListChangeListener<? super TicketModel>) change -> {
while (change.next()) {
final int size = filteredList.size();
final int size = targetList.size();
label.setText(String.valueOf(size));
}
});
}

@FXML private void onCreate() {
Display.show(Route.TICKET_CREATOR, DataRelay.of(ticketTable));
Display.show(Route.TICKET_CREATOR, DataRelay.of(this));
}

@FXML private void onResolve() {
Expand All @@ -217,9 +213,10 @@ private void addListener(final Label label, final FilteredList<TicketModel> filt
Alerts.showError("Failed to resolve ticket.", "No ticket was selected.", "Please try again after selecting a ticket.");
return;
}
final StatusType originalStatus = ticketModel.statusProperty().getValue();
ticketModel.statusProperty().setValue(StatusType.RESOLVED);

if (ticket.update(ticketModel)) {
if (ticket.update(ticketModel, originalStatus)) {
Alerts.showInput(
"Notify Employee",
"Would you like to notify the employee the ticket is resolved along with adding an ending comment?",
Expand Down Expand Up @@ -276,8 +273,9 @@ private void postCommentOnTicket(final TicketModel ticketModel, final String sys
return;
}

final StatusType originalStatus = ticketModel.statusProperty().getValue();
ticketModel.statusProperty().setValue(StatusType.OPEN);
if (ticket.update(ticketModel)) {
if (ticket.update(ticketModel, originalStatus)) {
Notifications.showInfo("Success", "Ticket re-opened successfully.");
ticketTable.refresh();
}
Expand Down Expand Up @@ -315,6 +313,7 @@ private void removeTicket(final TicketModel ticketModel) {
lastViewed.setValue(null);
}
}
setTicketTable();
}

private void onOpen(final TicketModel ticketModel) {
Expand Down Expand Up @@ -414,8 +413,8 @@ private void togglePane(final MouseEvent event) {

private void activatePane(final Pane pane) {
final StatusType statusType = (StatusType) pane.getUserData();
final FilteredList<TicketModel> filteredList = getFilteredListByStatus(statusType);
activePaneMap.put(pane, filteredList);
final ObservableList<TicketModel> targetList = getListByStatus(statusType);
activePaneMap.put(pane, targetList);
highlightPane(pane);
setTicketTable();
}
Expand All @@ -432,6 +431,10 @@ private void deactivatePane(final Pane pane) {
setTicketTable();
}

private ObservableList<TicketModel> getListByStatus(final StatusType type) {
return ticket.getListByStatus(type);
}

private void highlightPane(final Pane pane) {
pane.setStyle("-fx-background-color: #5DADD5;");
}
Expand All @@ -441,20 +444,11 @@ private void removePaneHighlight(final Pane pane) {
}


private FilteredList<TicketModel> getFilteredListByStatus(final StatusType statusType) {
return switch (statusType) {
case OPEN -> open;
case ACTIVE -> active;
case RESOLVED -> resolved;
case PAUSED -> paused;
};
}

private void setTicketTable() {
public void setTicketTable() {
final ObservableList<TicketModel> mergedList = FXCollections.observableArrayList();

for (final FilteredList<TicketModel> filteredList : activePaneMap.values()) {
mergedList.addAll(filteredList);
for (final ObservableList<TicketModel> targetList : activePaneMap.values()) {
mergedList.addAll(targetList);
}

ticketTable.setItems(mergedList);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import io.jacobking.quickticket.core.type.PriorityType;
import io.jacobking.quickticket.core.type.StatusType;
import io.jacobking.quickticket.core.utility.DateUtil;
import io.jacobking.quickticket.gui.alert.Alerts;
import io.jacobking.quickticket.gui.controller.Controller;
import io.jacobking.quickticket.gui.model.impl.EmployeeModel;
import io.jacobking.quickticket.gui.model.impl.TicketModel;
Expand All @@ -22,6 +21,7 @@

public class TicketCreatorController extends Controller {

private TicketController ticketController;
private TableView<TicketModel> ticketTable;

@FXML private ComboBox<StatusType> statusTypeComboBox;
Expand All @@ -47,15 +47,14 @@ public class TicketCreatorController extends Controller {
createButton.disableProperty().bind(titleField.textProperty().isEmpty());
}

@SuppressWarnings("unchecked") private void setDataRelay() {
private void setDataRelay() {
if (dataRelay == null) {
return;
}

dataRelay.mapFirst(TableView.class).ifPresentOrElse(tableView -> {
this.ticketTable = (TableView<TicketModel>) tableView;
}, () -> {
Alerts.showError("Data Relay Failure", "TicketTable<TicketModel> was not passed via data relay.", "Please report this.");
dataRelay.mapIndex(0, TicketController.class).ifPresent(controller -> {
this.ticketController = controller;
this.ticketTable = ticketController.getTicketTable();
});
}

Expand Down Expand Up @@ -119,6 +118,7 @@ private void configureEmployeeComboBox() {
sendInitialEmail(newTicket);
Display.close(Route.TICKET_CREATOR);

ticketController.setTicketTable();
ticketTable.scrollTo(0);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ private void updateTicketEmployee(final SearchableComboBox<EmployeeModel> employ
}

private void updateTicketStatus(final SearchableComboBox<StatusType> statusComboBox, final PopOver popOver) {
final StatusType originalStatus = ticketModel.statusProperty().getValue();
final StatusType type = statusComboBox.getSelectionModel().getSelectedItem();
if (type == null) {
Alerts.showError("Update failure.", "No update occurred.", "You must select a status.");
Expand All @@ -212,7 +213,7 @@ private void updateTicketStatus(final SearchableComboBox<StatusType> statusCombo

ticketModel.statusProperty().setValue(type);

if (ticket.update(ticketModel)) {
if (ticket.update(ticketModel, originalStatus)) {
postSystemComment("System", "Ticket status changed to: " + type.name());
reloadPostUpdate(statusComboBox, popOver);
Notifications.showInfo("Update", "Ticket status updated successfully!");
Expand Down
11 changes: 11 additions & 0 deletions src/main/resources/io/jacobking/quickticket/fxml/new_viwer.fxml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>

<?import java.net.URL?>
<?import javafx.scene.layout.AnchorPane?>

<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="500.0" prefWidth="750.0" styleClass="body" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1">
<stylesheets>
<URL value="@../css/core/base.css" />
<URL value="@../css/screen/viewer.css" />
</stylesheets>
</AnchorPane>

0 comments on commit ef1b53f

Please sign in to comment.