From 34675b41c5ea872de65d18dd0b317ca8aed3a136 Mon Sep 17 00:00:00 2001 From: cristianpela Date: Sun, 10 Jan 2021 15:16:25 +0200 Subject: [PATCH] #262 "Tasks" card improvements. --- .../com/selfxdsd/selfweb/api/AllTasks.java | 258 ++++++++++++++++++ .../selfxdsd/selfweb/api/ContractsApi.java | 5 +- .../selfxdsd/selfweb/api/output/JsonTask.java | 2 + .../resources/public/js/getAndAddContracts.js | 32 ++- src/main/resources/templates/head.html | 2 + src/main/resources/templates/project.html | 8 +- 6 files changed, 299 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/selfxdsd/selfweb/api/AllTasks.java diff --git a/src/main/java/com/selfxdsd/selfweb/api/AllTasks.java b/src/main/java/com/selfxdsd/selfweb/api/AllTasks.java new file mode 100644 index 00000000..aa4a143c --- /dev/null +++ b/src/main/java/com/selfxdsd/selfweb/api/AllTasks.java @@ -0,0 +1,258 @@ +/** + * Copyright (c) 2020-2021, Self XDSD Contributors + * All rights reserved. + *

+ * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), + * to read the Software only. Permission is hereby NOT GRANTED to use, copy, + * modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software. + *

+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package com.selfxdsd.selfweb.api; + +import com.selfxdsd.api.*; + +import java.math.BigDecimal; +import java.time.LocalDateTime; +import java.util.Comparator; +import java.util.Iterator; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +/** + * Lists all Contract tasks, active and invoiced, ordered by newest assignment + * date. + *
+ * Should be used only for listing via its iterator, otherwise will + * throw UnsupportedOperationException. + * @author criske + * @version $Id$ + * @since 0.0.1 + */ +class AllTasks implements Tasks { + + /** + * Contract. + */ + private final Contract ofContract; + + /** + * Ctor. + * + * @param ofContract Contract. + */ + AllTasks(final Contract ofContract) { + this.ofContract = ofContract; + } + + @Override + public Task getById(final String issueId, + final String repoFullName, + final String provider) { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public Task register(final Issue issue) { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public Task assign(final Task task, + final Contract contract, + final int days) { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public Task unassign(final Task task) { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public Tasks ofProject(final String repoFullName, + final String repoProvider) { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public Tasks ofContributor(final String username, final String provider) { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public Tasks ofContract(final Contract.Id id) { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public Tasks unassigned() { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public boolean remove(final Task task) { + throw new UnsupportedOperationException("Not supported"); + } + + @Override + public Iterator iterator() { + return Stream.concat( + StreamSupport.stream(this.ofContract + .tasks().spliterator(), false) + .map(StatusTask.Active::new), + StreamSupport.stream(this.ofContract + .invoices().spliterator(), false) + .flatMap(invoice -> StreamSupport + .stream(invoice.tasks().spliterator(), false) + .map(invoicedTask -> new StatusTask + .Closed(invoicedTask.task(), invoice.invoiceId())))) + .sorted(Comparator.comparing(Task::assignmentDate)) + .iterator(); + } + + /** + * Status task. This can be active or closed. + */ + abstract static class StatusTask implements Task { + + /** + * Delegate. + */ + private final Task delegate; + + /** + * Ctor. + * + * @param delegate Delegate. + */ + protected StatusTask(final Task delegate) { + this.delegate = delegate; + } + + @Override + public String issueId() { + return delegate.issueId(); + } + + @Override + public String role() { + return delegate.role(); + } + + @Override + public Issue issue() { + return delegate.issue(); + } + + @Override + public Project project() { + return delegate.project(); + } + + @Override + public Contributor assignee() { + return delegate.assignee(); + } + + @Override + public Contract contract() { + return delegate.contract(); + } + + @Override + public Task assign(final Contributor contributor) { + return delegate.assign(contributor); + } + + @Override + public Task unassign() { + return delegate.unassign(); + } + + @Override + public Resignations resignations() { + return delegate.resignations(); + } + + @Override + public LocalDateTime assignmentDate() { + return delegate.assignmentDate(); + } + + @Override + public LocalDateTime deadline() { + return delegate.deadline(); + } + + @Override + public BigDecimal value() { + return delegate.value(); + } + + @Override + public int estimation() { + return delegate.estimation(); + } + + /** + * Active task status. + */ + static class Active extends StatusTask { + + /** + * Ctor. + * + * @param delegate Delegate. + */ + protected Active(final Task delegate) { + super(delegate); + } + + @Override + public String toString() { + return "active:-"; + } + } + + /** + * Closed task status. + */ + static class Closed extends StatusTask { + + + /** + * Invoice id. + */ + private final int invoiceId; + + /** + * Ctor. + * + * @param delegate Delegate. + * @param invoiceId Invoice id. + */ + protected Closed(final Task delegate, final int invoiceId) { + super(delegate); + this.invoiceId = invoiceId; + } + + @Override + public String toString() { + return "closed:"+this.invoiceId; + } + } + } +} diff --git a/src/main/java/com/selfxdsd/selfweb/api/ContractsApi.java b/src/main/java/com/selfxdsd/selfweb/api/ContractsApi.java index d453322d..ca7b65d5 100644 --- a/src/main/java/com/selfxdsd/selfweb/api/ContractsApi.java +++ b/src/main/java/com/selfxdsd/selfweb/api/ContractsApi.java @@ -146,9 +146,9 @@ public ResponseEntity tasks( if(contract == null) { resp = ResponseEntity.noContent().build(); } else { - final Tasks tasks = contract.tasks(); + final Tasks all = new AllTasks(contract); resp = ResponseEntity.ok( - new JsonTasks(tasks).toString() + new JsonTasks(all).toString() ); } } @@ -304,7 +304,6 @@ public ResponseEntity invoicePdf( ) ); resp = ResponseEntity.ok() - .contentLength(pdf.length()) .contentType(MediaType.APPLICATION_PDF) .header( "Content-Disposition", diff --git a/src/main/java/com/selfxdsd/selfweb/api/output/JsonTask.java b/src/main/java/com/selfxdsd/selfweb/api/output/JsonTask.java index 22e7d167..248473f3 100644 --- a/src/main/java/com/selfxdsd/selfweb/api/output/JsonTask.java +++ b/src/main/java/com/selfxdsd/selfweb/api/output/JsonTask.java @@ -42,10 +42,12 @@ public JsonTask(final Task task) { super( Json.createObjectBuilder() .add("issueId", task.issueId()) + .add("invoiceNumber", task.toString().split(":")[1]) .add("assignmentDate", String.valueOf(task.assignmentDate())) .add("deadline", String.valueOf(task.deadline())) .add("estimation", task.estimation()) .add("value", task.value().divide(BigDecimal.valueOf(100))) + .add("status", task.toString().split(":")[0]) .build() ); } diff --git a/src/main/resources/public/js/getAndAddContracts.js b/src/main/resources/public/js/getAndAddContracts.js index 7c5e8b60..39837e65 100644 --- a/src/main/resources/public/js/getAndAddContracts.js +++ b/src/main/resources/public/js/getAndAddContracts.js @@ -23,8 +23,29 @@ var projectContractsCount = -1; ) $("#tasks").show(); $("#tasksTable").DataTable({ + dom: 'Qlrtip', + searchBuilder: { + columns: [6], + conditions: { + string: { + "!=": null, + "!null": null, + "contains" : null, + "ends" : null, + "null" : null, + "starts" : null, + } + } + }, language: { - loadingRecords: '' + loadingRecords: '', + searchBuilder:{ + add: "+", + title: { + 0: 'Filters', + _: 'Filters (%d)' + }, + }, }, ajax: { url: "/api/projects/" @@ -53,6 +74,9 @@ var projectContractsCount = -1; return "#" + data + "" } }, + { + data: "invoiceNumber", + }, { data: "assignmentDate", render: (data) => data.split('T')[0] @@ -68,8 +92,12 @@ var projectContractsCount = -1; { data: "value", render: (data) => formatEuro(data) + }, + { + data: "status", + orderable: false } - ] + ], }) } diff --git a/src/main/resources/templates/head.html b/src/main/resources/templates/head.html index 6457af7d..e2b39186 100644 --- a/src/main/resources/templates/head.html +++ b/src/main/resources/templates/head.html @@ -11,10 +11,12 @@ + + diff --git a/src/main/resources/templates/project.html b/src/main/resources/templates/project.html index 8404f57e..ec370b11 100644 --- a/src/main/resources/templates/project.html +++ b/src/main/resources/templates/project.html @@ -314,7 +314,7 @@

-