refactor grid actions links
All checks were successful
Builder / Build-Project (push) Successful in 2m55s

This commit is contained in:
alex 2024-12-30 20:21:08 -05:00
parent 87418e03e5
commit fc77443317
7 changed files with 106 additions and 190 deletions

Binary file not shown.

View File

@ -33,6 +33,7 @@ import com.vaadin.flow.router.*;
import com.vaadin.flow.server.StreamResource;
import com.vaadin.flow.spring.annotation.SpringComponent;
import jakarta.annotation.security.PermitAll;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.vaadin.firitin.components.datepicker.VDatePicker;
import org.vaadin.firitin.form.BeanValidationForm;
@ -52,6 +53,7 @@ import java.util.UUID;
@Scope("prototype")
@PageTitle("Employee")
@Route(value = "/employees/:employeeId?/:action?", layout = MainLayout.class)
@Slf4j
public class EmployeeView extends BeanValidationForm<Employee> implements HasUrlParameter<String> {
private final EmployeeService employeeService;
private final ReportService reportService;
@ -340,10 +342,10 @@ public class EmployeeView extends BeanValidationForm<Employee> implements HasUrl
profileImagePreview.setMaxHeight("150px");
} catch (IOException e) {
Notification.show("Error al subir la imagen: " + e.getMessage());
e.printStackTrace();
log.error("Error uploading image", e);
} catch (Exception e) {
Notification.show("Error en el servidor al procesar la imagen.");
e.printStackTrace();
log.error("Error uploading image", e);
}
});
}

View File

@ -6,6 +6,7 @@ import com.primefactorsolutions.views.BaseView;
import com.primefactorsolutions.views.Constants;
import com.primefactorsolutions.views.EmployeeView;
import com.primefactorsolutions.views.MainLayout;
import com.primefactorsolutions.views.util.MenuBarUtils;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.html.Anchor;
@ -16,6 +17,8 @@ import com.vaadin.flow.server.StreamResource;
import com.vaadin.flow.spring.annotation.SpringComponent;
import com.vaadin.flow.spring.security.AuthenticationContext;
import jakarta.annotation.security.RolesAllowed;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.vaadin.firitin.components.grid.PagingGrid;
@ -33,6 +36,7 @@ import java.util.List;
@PageTitle("Employees")
@Route(value = "/employees", layout = MainLayout.class)
@RolesAllowed("ROLE_ADMIN")
@Slf4j
public class EmployeesListView extends BaseView {
private final EmployeeService employeeService;
@ -131,7 +135,7 @@ public class EmployeesListView extends BaseView {
workbook.write(out);
return new ByteArrayInputStream(out.toByteArray());
} catch (IOException e) {
e.printStackTrace();
log.error("Error generating excel", e);
return null;
}
}
@ -139,15 +143,12 @@ public class EmployeesListView extends BaseView {
private void configureTable() {
table.setColumns("firstName", "lastName", "status");
addEditButtonColumn("View", this::navigateToEmployeeView);
addEditButtonColumn("Edit", this::navigateToEditView);
table.addComponentColumn(employee -> MenuBarUtils.menuBar(
Pair.of("View", __ -> navigateToEmployeeView(employee)),
Pair.of("Edit", __ -> navigateToEditView(employee))));
setupPagingGrid();
}
private void addEditButtonColumn(final String label, final ButtonClickHandler handler) {
table.addComponentColumn(employee -> createButton(label, () -> handler.handle(employee), false));
}
private Button createButton(final String label, final Runnable onClickAction, final boolean isPrimary) {
Button button = new Button(label);

View File

@ -5,30 +5,24 @@ import com.primefactorsolutions.service.AssessmentService;
import com.primefactorsolutions.views.BaseView;
import com.primefactorsolutions.views.MainLayout;
import com.primefactorsolutions.views.SubmissionView;
import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEventListener;
import com.primefactorsolutions.views.util.MenuBarUtils;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.confirmdialog.ConfirmDialog;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.data.provider.DataProvider;
import com.vaadin.flow.data.provider.DataProviderListener;
import com.vaadin.flow.data.provider.Query;
import com.vaadin.flow.function.ValueProvider;
import com.vaadin.flow.data.provider.ListDataProvider;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.shared.Registration;
import com.vaadin.flow.spring.annotation.SpringComponent;
import com.vaadin.flow.spring.security.AuthenticationContext;
import jakarta.annotation.security.PermitAll;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.context.annotation.Scope;
import org.vaadin.addon.stefan.clipboard.ClientsideClipboard;
import org.vaadin.firitin.components.grid.VGrid;
import java.util.stream.Stream;
@SpringComponent
@Scope("prototype")
@PageTitle("Assessments")
@ -41,90 +35,48 @@ public class AssessmentsListView extends BaseView {
super(authenticationContext);
final HorizontalLayout hl = new HorizontalLayout();
final Button addAssessment = new Button("Add Assessment");
addAssessment.addClickListener((ComponentEventListener<ClickEvent<Button>>) buttonClickEvent -> {
this.getUI().flatMap(ui -> ui.navigate(AssessmentView.class, "new"));
});
addAssessment.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
addAssessment.addClickListener(buttonClickEvent ->
getUI().flatMap(ui -> ui.navigate(AssessmentView.class, "new")));
hl.add(addAssessment);
final VGrid<Assessment> grid = new VGrid<>(Assessment.class);
grid.setColumns("id", "candidate.email");
final Grid.Column<Assessment> statusColumn = grid.addColumn((ValueProvider<Assessment, Object>) assessment ->
final Grid.Column<Assessment> statusColumn = grid.addColumn(assessment ->
assessment.getAssessmentEvents().isEmpty()
? "N/A"
: assessment.getAssessmentEvents().getLast().getStatus().name());
statusColumn.setHeader("Status");
grid.addComponentColumn((ValueProvider<Assessment, Component>) assessment -> {
var result = new Button("Result", event ->
this.getUI().flatMap(ui -> ui.navigate(SubmissionView.class, assessment.getId().toString()))
);
result.setEnabled(assessment.isCompleted());
return result;
});
grid.addComponentColumn((ValueProvider<Assessment, Component>) assessment -> new Button("Copy Link", event ->
ClientsideClipboard.writeToClipboard(
String.format("email: %s link: https://careers.primefactorsolutions.com/evaluation/%s",
assessment.getCandidate().getEmail(),
assessment.getId()))
grid.addComponentColumn(assessment -> MenuBarUtils.menuBar(
Pair.of("View", __ ->
getUI().flatMap(ui -> ui.navigate(SubmissionView.class, assessment.getId().toString()))),
Pair.of("Copy", __ ->
ClientsideClipboard.writeToClipboard(
String.format("email: %s link: https://careers.primefactorsolutions.com/evaluation/%s",
assessment.getCandidate().getEmail(),
assessment.getId()))),
Pair.of("Email", __ -> {
ConfirmDialog dialog = new ConfirmDialog();
dialog.setHeader("Send Link Email");
dialog.setText(String.format("Enviar link por email al candidato %s?",
assessment.getCandidate().getEmail()));
dialog.setCancelable(true);
dialog.setConfirmText("Enviar");
dialog.setConfirmButtonTheme("primary");
dialog.addConfirmListener(confirmEvent -> {
try {
assessmentService.sendEmail(assessment);
} catch (Exception e) {
Notification.show("Error sending email: " + e.getMessage(), 10_000,
Notification.Position.TOP_CENTER);
}
});
dialog.open();
})
));
grid.addComponentColumn((ValueProvider<Assessment, Component>) assessment ->
new Button("Send Email", event -> {
ConfirmDialog dialog = new ConfirmDialog();
dialog.setHeader("Send Link Email");
dialog.setText(String.format("Enviar link por email al candidato %s?",
assessment.getCandidate().getEmail()));
dialog.setCancelable(true);
dialog.setConfirmText("Enviar");
dialog.setConfirmButtonTheme("primary");
dialog.addConfirmListener((ComponentEventListener<ConfirmDialog.ConfirmEvent>) confirmEvent -> {
try {
assessmentService.sendEmail(assessment);
} catch (Exception e) {
Notification.show("Error sending email: " + e.getMessage(), 10_000,
Notification.Position.TOP_CENTER);
}
});
dialog.open();
}));
grid.setDataProvider(new DataProvider<>() {
@Override
public boolean isInMemory() {
return false;
}
@Override
public int size(final Query<Assessment, Object> query) {
return assessmentService.getAssessments().size();
}
@SuppressWarnings("unused")
@Override
public Stream<Assessment> fetch(final Query<Assessment, Object> query) {
int limit = query.getLimit();
int pagerSize = query.getPageSize();
int page = query.getPage();
return assessmentService.getAssessments().stream();
}
@Override
public void refreshItem(final Assessment assessment) {
// no-op
}
@Override
public void refreshAll() {
}
@Override
public Registration addDataProviderListener(final DataProviderListener<Assessment> dataProviderListener) {
return null;
}
});
grid.setDataProvider(new ListDataProvider<>(assessmentService.getAssessments()));
grid.setAllRowsVisible(true);
getCurrentPageLayout().add(hl, grid);

View File

@ -4,25 +4,24 @@ import com.primefactorsolutions.model.Candidate;
import com.primefactorsolutions.service.CandidateService;
import com.primefactorsolutions.views.BaseView;
import com.primefactorsolutions.views.MainLayout;
import com.primefactorsolutions.views.util.MenuBarUtils;
import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.data.provider.DataProvider;
import com.vaadin.flow.data.provider.DataProviderListener;
import com.vaadin.flow.data.provider.Query;
import com.vaadin.flow.function.ValueProvider;
import com.vaadin.flow.data.provider.ListDataProvider;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.shared.Registration;
import com.vaadin.flow.spring.annotation.SpringComponent;
import com.vaadin.flow.spring.security.AuthenticationContext;
import jakarta.annotation.security.PermitAll;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.context.annotation.Scope;
import org.vaadin.firitin.components.grid.VGrid;
import java.util.stream.Stream;
import java.util.Map;
@SpringComponent
@Scope("prototype")
@ -36,6 +35,7 @@ public class CandidatesListView extends BaseView {
super(authenticationContext);
final HorizontalLayout hl = new HorizontalLayout();
final Button addCandidate = new Button("Add Candidate");
addCandidate.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
addCandidate.addClickListener((ComponentEventListener<ClickEvent<Button>>) buttonClickEvent -> {
this.getUI().flatMap(ui -> ui.navigate(CandidateView.class, "new"));
});
@ -44,48 +44,10 @@ public class CandidatesListView extends BaseView {
final VGrid<Candidate> grid = new VGrid<>(Candidate.class);
grid.setColumns("id", "email");
grid.setAllRowsVisible(true);
grid.addComponentColumn((ValueProvider<Candidate, Component>) candidate -> {
final Button edit = new Button("Edit");
edit.addClickListener((ComponentEventListener<ClickEvent<Button>>) buttonClickEvent ->
this.getUI().flatMap(ui -> ui.navigate(CandidateView.class, candidate.getId().toString())));
return edit;
});
grid.setDataProvider(new DataProvider<>() {
@Override
public boolean isInMemory() {
return false;
}
@Override
public int size(final Query<Candidate, Object> query) {
return candidateService.getCandidates().size();
}
@SuppressWarnings("unused")
@Override
public Stream<Candidate> fetch(final Query<Candidate, Object> query) {
int limit = query.getLimit();
int pagerSize = query.getPageSize();
int page = query.getPage();
return candidateService.getCandidates().stream();
}
@Override
public void refreshItem(final Candidate candidate) {
// no-op
}
@Override
public void refreshAll() {
// no-op
}
@Override
public Registration addDataProviderListener(final DataProviderListener<Candidate> dataProviderListener) {
return null;
}
});
grid.addComponentColumn(candidate ->
MenuBarUtils.menuBar(Map.of(Pair.of("Edit", VaadinIcon.PENCIL), menuItemClickEvent ->
getUI().flatMap(ui -> ui.navigate(CandidateView.class, candidate.getId().toString())))));
grid.setDataProvider(new ListDataProvider<>(candidateService.getCandidates()));
getCurrentPageLayout().add(hl, grid);
}

View File

@ -4,26 +4,22 @@ import com.primefactorsolutions.model.Question;
import com.primefactorsolutions.service.QuestionService;
import com.primefactorsolutions.views.BaseView;
import com.primefactorsolutions.views.MainLayout;
import com.primefactorsolutions.views.util.MenuBarUtils;
import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.data.provider.DataProvider;
import com.vaadin.flow.data.provider.DataProviderListener;
import com.vaadin.flow.data.provider.Query;
import com.vaadin.flow.function.ValueProvider;
import com.vaadin.flow.data.provider.ListDataProvider;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.shared.Registration;
import com.vaadin.flow.spring.annotation.SpringComponent;
import com.vaadin.flow.spring.security.AuthenticationContext;
import jakarta.annotation.security.PermitAll;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.context.annotation.Scope;
import org.vaadin.firitin.components.grid.VGrid;
import java.util.stream.Stream;
@SpringComponent
@Scope("prototype")
@PageTitle("Questions")
@ -36,53 +32,17 @@ public class QuestionsListView extends BaseView {
final HorizontalLayout hl = new HorizontalLayout();
final Button addQuestion = new Button("Add Question");
addQuestion.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
addQuestion.addClickListener((ComponentEventListener<ClickEvent<Button>>) buttonClickEvent ->
this.getUI().flatMap(ui -> ui.navigate(QuestionView.class, "new")));
hl.add(addQuestion);
final VGrid<Question> grid = new VGrid<>(Question.class);
grid.setColumns("id", "title");
grid.addComponentColumn((ValueProvider<Question, Component>) question -> {
final Button edit = new Button("Edit");
edit.addClickListener((ComponentEventListener<ClickEvent<Button>>) buttonClickEvent ->
this.getUI().flatMap(ui -> ui.navigate(QuestionView.class, question.getId().toString())));
return edit;
});
grid.setDataProvider(new DataProvider<>() {
@Override
public boolean isInMemory() {
return false;
}
@Override
public int size(final Query<Question, Object> query) {
return questionService.getQuestions().size();
}
@SuppressWarnings("unused")
@Override
public Stream<Question> fetch(final Query<Question, Object> query) {
int limit = query.getLimit();
int pagerSize = query.getPageSize();
int page = query.getPage();
return questionService.getQuestions().stream();
}
@Override
public void refreshItem(final Question question) {
// no-op
}
@Override
public void refreshAll() {
// no-op
}
@Override
public Registration addDataProviderListener(final DataProviderListener<Question> dataProviderListener) {
return null;
}
});
grid.addComponentColumn(question ->
MenuBarUtils.menuBar(Pair.of("Edit", __ ->
getUI().flatMap(ui -> ui.navigate(QuestionView.class, question.getId().toString())))));
grid.setDataProvider(new ListDataProvider<>(questionService.getQuestions()));
grid.setAllRowsVisible(true);
getCurrentPageLayout().add(hl, grid);

View File

@ -1,13 +1,25 @@
package com.primefactorsolutions.views.util;
import com.vaadin.flow.component.ClickEvent;
import com.vaadin.flow.component.ComponentEventListener;
import com.vaadin.flow.component.contextmenu.MenuItem;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.menubar.MenuBar;
import com.vaadin.flow.component.menubar.MenuBarVariant;
import lombok.experimental.UtilityClass;
import org.apache.commons.lang3.tuple.Pair;
import java.util.Map;
@UtilityClass
public class MenuBarUtils {
public static final Map<String, VaadinIcon> ICON_MAP = Map.of(
"View", VaadinIcon.EYE,
"Edit", VaadinIcon.PENCIL,
"Copy", VaadinIcon.COPY,
"Email", VaadinIcon.ENVELOPE
);
public static MenuItem createIconItem(final MenuBar menu, final VaadinIcon iconName, final String ariaLabel) {
final Icon icon = new Icon(iconName);
@ -16,4 +28,31 @@ public class MenuBarUtils {
return item;
}
public static MenuBar menuBar(final Map<Pair<String, VaadinIcon>,
ComponentEventListener<ClickEvent<MenuItem>>> entries) {
final MenuBar menuBar = new MenuBar();
menuBar.addThemeVariants(MenuBarVariant.LUMO_TERTIARY_INLINE);
entries.forEach((key, value) -> {
final MenuItem viewItem = MenuBarUtils.createIconItem(menuBar, key.getValue(), key.getKey());
viewItem.addClickListener(value);
});
return menuBar;
}
@SafeVarargs
public static MenuBar menuBar(final Pair<String, ComponentEventListener<ClickEvent<MenuItem>>>... entries) {
final MenuBar menuBar = new MenuBar();
menuBar.addThemeVariants(MenuBarVariant.LUMO_TERTIARY_INLINE);
for (Pair<String, ComponentEventListener<ClickEvent<MenuItem>>> entry: entries) {
final MenuItem viewItem = MenuBarUtils.createIconItem(menuBar,
ICON_MAP.get(entry.getKey()), entry.getKey());
viewItem.addClickListener(entry.getValue());
}
return menuBar;
}
}