diff --git a/.flow-node-tasks.lock b/.flow-node-tasks.lock deleted file mode 100644 index 3aef278..0000000 --- a/.flow-node-tasks.lock +++ /dev/null @@ -1,2 +0,0 @@ -19228 - diff --git a/pom.xml b/pom.xml index bcd7a9e..59b0699 100644 --- a/pom.xml +++ b/pom.xml @@ -90,6 +90,10 @@ slf4j-api 2.0.13 + + ch.qos.logback + logback-classic + @@ -179,7 +183,7 @@ org.apache.maven.plugins - + maven-failsafe-plugin diff --git a/src/main/bundles/prod.bundle b/src/main/bundles/prod.bundle new file mode 100644 index 0000000..f5ed287 Binary files /dev/null and b/src/main/bundles/prod.bundle differ diff --git a/src/main/java/com/example/application/Application.java b/src/main/java/com/example/application/Application.java index dafa6c7..4aa9fce 100644 --- a/src/main/java/com/example/application/Application.java +++ b/src/main/java/com/example/application/Application.java @@ -1,8 +1,11 @@ package com.example.application; import com.vaadin.flow.component.dependency.JsModule; +import com.vaadin.flow.component.html.Main; import com.vaadin.flow.component.page.AppShellConfigurator; import com.vaadin.flow.theme.Theme; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration; @@ -19,8 +22,27 @@ import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConf @JsModule("@vaadin/vaadin-lumo-styles/presets/compact.js") public class Application implements AppShellConfigurator { + private static final Logger logger = LoggerFactory.getLogger(Main.class); + public static void main(String[] args) { SpringApplication.run(Application.class, args); + + logger.info("Inicio de la aplicacion"); + + conectToService("localhost:8080"); + + logger.info("Aplicacion iniciada con exito"); + } + + private static void conectToService(String url) { + logger.debug("Intentando conectar la aplicacion a {} ", url); + + try { + Thread.sleep(2000); + logger.debug("Conexion exitosa a {}", url); + } catch (InterruptedException e) { + logger.error("Error en la conexion a {}", url, e); + } } } diff --git a/src/main/java/com/example/application/api/RedmineClient.java b/src/main/java/com/example/application/api/RedmineClient.java index 9a9b8a0..19a4e63 100644 --- a/src/main/java/com/example/application/api/RedmineClient.java +++ b/src/main/java/com/example/application/api/RedmineClient.java @@ -12,6 +12,7 @@ import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.util.ArrayList; import java.util.List; +import java.util.stream.Collectors; /*Esta clase se encarga de obtener los tickets desde redmine para poder mostrarlo en la vista de visualizacion de tickets*/ @@ -23,10 +24,13 @@ public class RedmineClient { private static final int PAGE_SIZE = 25; static String REDMINE_URL; static String API_KEY; + //private final RestTemplate restTemplate; + public RedmineClient(String redmineUrl, String apiKey) { REDMINE_URL = redmineUrl; API_KEY = apiKey; + //this.restTemplate = new RestTemplate(); } public List getTickets() { @@ -36,7 +40,7 @@ public class RedmineClient { while (true) { HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(REDMINE_URL + "/issues.json?limit=" + PAGE_SIZE + "&offset=" + offset)) + .uri(URI.create(REDMINE_URL + "/issues.json?key=" + PAGE_SIZE + "&offset=" + offset)) .header("Content-Type", "application/json") .header("X-Redmine-API-Key", API_KEY) .build(); @@ -60,6 +64,7 @@ public class RedmineClient { break; } } + System.out.println("Total tickets obtenidos: " + tickets.size()); return tickets; } @@ -73,8 +78,37 @@ public class RedmineClient { String subject = issue.get("subject").getAsString(); String description = issue.has("description") ? issue.get("description").getAsString() : ""; String status = issue.getAsJsonObject("status").get("name").getAsString(); - tickets.add(new Ticket(id, subject, description, status)); + + JsonObject authorJson = issue.getAsJsonObject("author"); + Ticket.User author = null; + if (authorJson != null) { + String username = authorJson.get("name").getAsString(); + author = new Ticket.User(username); + } + tickets.add(new Ticket(id, subject, description, status, author)); } return tickets; } + + public List getTicketsCreatedBy(String username) { + List allTickets = getTickets(); + List filteredTickets = allTickets.stream() + .filter(ticket -> ticket.getAuthor() != null && username.equals(ticket.getAuthor().getUsername())) + .collect(Collectors.toList()); + System.out.println("Total de tickets creados por " + username + ": " + filteredTickets.size()); + return filteredTickets; + } + + + private static class TicketResponse { + private List isues; + + public List getIssues() { + return isues; + } + + public void setIssues(List issues) { + this.isues = issues; + } + } } diff --git a/src/main/java/com/example/application/models/Ticket.java b/src/main/java/com/example/application/models/Ticket.java index 6b662a5..ac27b50 100644 --- a/src/main/java/com/example/application/models/Ticket.java +++ b/src/main/java/com/example/application/models/Ticket.java @@ -2,18 +2,22 @@ package com.example.application.models; /*Esta clase obtiene los detalles de los tickets*/ + public class Ticket { private int id; private String subject; private String description; private String status; + private User author; - public Ticket(int id, String subject, String description, String status) { + public Ticket(int id, String subject, String description, String status, User author) { this.id = id; this.subject = subject; this.description = description; this.status = status; + this.author = author; + } public int getId() { @@ -31,4 +35,28 @@ public class Ticket { public String getStatus() { return status; } + + public User getAuthor() { + return author; + } + + public void setAuthor(User author) { + this.author = author; + } + + public static class User { + private String username; + + public User(String username) { + this.username = username; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + } } diff --git a/src/main/java/com/example/application/views/MainLayout.java b/src/main/java/com/example/application/views/MainLayout.java index 0aee71b..cce994c 100644 --- a/src/main/java/com/example/application/views/MainLayout.java +++ b/src/main/java/com/example/application/views/MainLayout.java @@ -2,6 +2,7 @@ package com.example.application.views; import com.example.application.api.SecurityService; import com.example.application.views.crearnuevoticket.CrearnuevoTicketView; +import com.example.application.views.tickets.AllTicketsView; import com.example.application.views.tickets.MisTicketsView; import com.vaadin.flow.component.applayout.AppLayout; import com.vaadin.flow.component.applayout.DrawerToggle; @@ -84,6 +85,7 @@ public class MainLayout extends AppLayout { nav.addItem(new SideNavItem("Crear nuevo ticket", CrearnuevoTicketView.class, LineAwesomeIcon.EDIT.create())); nav.addItem(new SideNavItem("Mis tickets", MisTicketsView.class, LineAwesomeIcon.TICKET_ALT_SOLID.create())); + nav.addItem(new SideNavItem("Todos los tickets", AllTicketsView.class, LineAwesomeIcon.TICKET_ALT_SOLID.create())); return nav; diff --git a/src/main/java/com/example/application/views/crearnuevoticket/CrearnuevoTicketView.java b/src/main/java/com/example/application/views/crearnuevoticket/CrearnuevoTicketView.java index 418f0a9..bdf44f3 100644 --- a/src/main/java/com/example/application/views/crearnuevoticket/CrearnuevoTicketView.java +++ b/src/main/java/com/example/application/views/crearnuevoticket/CrearnuevoTicketView.java @@ -18,6 +18,7 @@ import com.vaadin.flow.component.textfield.TextArea; import com.vaadin.flow.component.textfield.TextField; import com.vaadin.flow.component.upload.Upload; import com.vaadin.flow.component.upload.receivers.MemoryBuffer; +import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import jakarta.annotation.security.PermitAll; @@ -28,6 +29,7 @@ import java.util.Map; @Route(value = "", layout = MainLayout.class) @PermitAll +@PageTitle("Nuevo ticket") public class CrearnuevoTicketView extends VerticalLayout { private MemoryBuffer buffer; diff --git a/src/main/java/com/example/application/views/tickets/AllTicketsView.java b/src/main/java/com/example/application/views/tickets/AllTicketsView.java new file mode 100644 index 0000000..6b5d463 --- /dev/null +++ b/src/main/java/com/example/application/views/tickets/AllTicketsView.java @@ -0,0 +1,79 @@ +package com.example.application.views.tickets; + +import com.example.application.api.RedmineClient; +import com.example.application.api.ServerPrpperties; +import com.example.application.models.Ticket; +import com.example.application.views.MainLayout; +import com.vaadin.flow.component.grid.Grid; +import com.vaadin.flow.component.html.Span; +import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.data.renderer.ComponentRenderer; +import com.vaadin.flow.router.PageTitle; +import com.vaadin.flow.router.Route; +import com.vaadin.flow.server.auth.AnonymousAllowed; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.List; + +@Route(value="tickets", layout = MainLayout.class) +@AnonymousAllowed +@PageTitle("Todos los tickets") +public class AllTicketsView extends VerticalLayout { + + private final RedmineClient redmineClient; + private final Grid grid; + + @Autowired + public AllTicketsView(ServerPrpperties prpperties) { + this.redmineClient = new RedmineClient(prpperties.REDMINE_URL, prpperties.API_KEY); + this.grid = new Grid<>(Ticket.class, false); + + grid.addColumn(Ticket::getId).setHeader("No.") + .setWidth("4em").setFlexGrow(0); + grid.addColumn(Ticket::getSubject).setHeader("Asunto") + .setAutoWidth(true).setFlexGrow(1); + grid.addColumn(createStatusRender()).setHeader("Estado") + .setWidth("7em").setFlexGrow(1); + grid.addColumn(Ticket::getDescription).setHeader("Descripción") + .setAutoWidth(true).setFlexGrow(1); + + + // Ajustar tamaño del Grid y Layout + grid.setSizeFull(); + setSizeFull(); + setPadding(false); + setMargin(false); + setSpacing(false); + + add(grid); + expand(grid); + + loadTickets(); + } + + private void loadTickets() { + List tickets = redmineClient.getTickets(); + grid.setItems(tickets); + } + + private ComponentRenderer createStatusRender() { + return new ComponentRenderer<>(ticket -> { + Span span = new Span(ticket.getStatus()); + switch (ticket.getStatus().toLowerCase()) { + case "en curso": + span.getElement().getStyle().set("color","purple"); + break; + case "comentarios": + span.getElement().getStyle().set("color","orange"); + break; + case "resuelta": + span.getElement().getStyle().set("color","green"); + break; + default: + span.getElement().getStyle().set("color","blue"); + break; + } + return span; + }); + } +} diff --git a/src/main/java/com/example/application/views/tickets/MisTicketsView.java b/src/main/java/com/example/application/views/tickets/MisTicketsView.java index d53254c..a770b8d 100644 --- a/src/main/java/com/example/application/views/tickets/MisTicketsView.java +++ b/src/main/java/com/example/application/views/tickets/MisTicketsView.java @@ -1,34 +1,44 @@ package com.example.application.views.tickets; import com.example.application.api.RedmineClient; +import com.example.application.api.SecurityService; import com.example.application.api.ServerPrpperties; import com.example.application.models.Ticket; import com.example.application.views.MainLayout; import com.vaadin.flow.component.grid.Grid; +import com.vaadin.flow.component.html.Span; import com.vaadin.flow.component.orderedlayout.VerticalLayout; +import com.vaadin.flow.data.renderer.ComponentRenderer; +import com.vaadin.flow.router.PageTitle; import com.vaadin.flow.router.Route; import com.vaadin.flow.server.auth.AnonymousAllowed; +import org.springframework.beans.factory.annotation.Autowired; import java.util.List; @Route(value="mytickets", layout = MainLayout.class) @AnonymousAllowed +@PageTitle("Mis tickets") public class MisTicketsView extends VerticalLayout { private final RedmineClient redmineClient; private final Grid grid; + private final SecurityService securityService; - public MisTicketsView(ServerPrpperties prpperties) { + + @Autowired + public MisTicketsView(ServerPrpperties prpperties, SecurityService securityService) { this.redmineClient = new RedmineClient(prpperties.REDMINE_URL, prpperties.API_KEY); this.grid = new Grid<>(Ticket.class, false); + this.securityService = securityService; // Definir columnas en el orden deseado - grid.addColumn(Ticket::getId).setHeader("NO") + grid.addColumn(Ticket::getId).setHeader("No.") .setWidth("4em").setFlexGrow(0); grid.addColumn(Ticket::getSubject).setHeader("Asunto") .setAutoWidth(true).setFlexGrow(1); - grid.addColumn(Ticket::getStatus).setHeader("Estado") + grid.addColumn(createStatusRender()).setHeader("Estado") .setWidth("7em").setFlexGrow(1); grid.addColumn(Ticket::getDescription).setHeader("Descripción") .setAutoWidth(true).setFlexGrow(1); @@ -44,11 +54,39 @@ public class MisTicketsView extends VerticalLayout { add(grid); expand(grid); - loadTickets(); + loadTickets(getAuthenticatedUsername()); } - private void loadTickets() { - List tickets = redmineClient.getTickets(); + private void loadTickets(String authenticatedUsername) { + List tickets = redmineClient.getTicketsCreatedBy(authenticatedUsername ); + System.out.println("Tickets para mostrar: " + tickets.size()); grid.setItems(tickets); } + + private String getAuthenticatedUsername() { + String username = securityService.getAuthenticatedUser().getUsername(); + System.out.println("Usuario autenticado: " + username); + return username; + } + + private ComponentRenderer createStatusRender() { + return new ComponentRenderer<>(ticket -> { + Span span = new Span(ticket.getStatus()); + switch (ticket.getStatus().toLowerCase()) { + case "open": + span.getElement().getStyle().set("color","green"); + break; + case "closed": + span.getElement().getStyle().set("color","red"); + break; + case "in progress": + span.getElement().getStyle().set("color","orange"); + break; + default: + span.getElement().getStyle().set("color","green"); + break; + } + return span; + }); + } } diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 2b907bd..16d91d8 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -13,12 +13,12 @@ spring.jpa.defer-datasource-initialization = true spring: ldap: urls: ldap://172.16.0.1:389 -base: DC=JUMAPACELAYA, DC=GOB, DC=MX +base: DC=JUMAPACELAYA, DC=GOB, DC=MX username: administrator password: Dr3na%134$4guA #################################################### -redmine.url=http://localhost:3000 -redmine.api_key=cf3be6168e66c99892c6212ea0bc64e8ab1c6848 \ No newline at end of file +redmine.url=http://localhost:3000/ +redmine.api_key=35164d2320404b66a71df90d514107790bc1aed6 \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml new file mode 100644 index 0000000..8e9c833 --- /dev/null +++ b/src/main/resources/logback.xml @@ -0,0 +1,12 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n + + + + + + +