From 41018492839650dab8ffcd63537b054404113301 Mon Sep 17 00:00:00 2001 From: Eldrin Date: Fri, 2 Jun 2023 03:39:39 +0200 Subject: [PATCH] feat(ECC):Added pagination to ECC release list --- .../db/ComponentDatabaseHandler.java | 4 + .../datahandler/db/ReleaseRepository.java | 110 ++++++++++ .../sw360/components/ComponentHandler.java | 6 + .../sw360/portal/common/PortalConstants.java | 1 + .../sw360/portal/portlets/ecc/EccPortlet.java | 197 +++++++++++++++++- .../META-INF/resources/html/ecc/view.jsp | 55 ++--- .../src/main/thrift/components.thrift | 5 + 7 files changed, 337 insertions(+), 41 deletions(-) diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ComponentDatabaseHandler.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ComponentDatabaseHandler.java index 9ae1156c06..b5948ebc9a 100644 --- a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ComponentDatabaseHandler.java +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ComponentDatabaseHandler.java @@ -1972,6 +1972,10 @@ public List getAccessibleReleases(Set ids, User user) { return getAccessibleReleaseList(releaseRepository.makeSummary(SummaryType.SHORT, ids), user); } + public Map> getAccessibleReleasesWithPagination(User user, PaginationData pageData) throws TException { + return releaseRepository.getAccessibleReleasesWithPagination(user, pageData); + } + private List getAccessibleReleaseList(List releaseList, User user) { List resultList = new ArrayList(); for (Release release : releaseList) { diff --git a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ReleaseRepository.java b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ReleaseRepository.java index 2b837efec9..8b7064fbfc 100644 --- a/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ReleaseRepository.java +++ b/backend/src-common/src/main/java/org/eclipse/sw360/datahandler/db/ReleaseRepository.java @@ -16,6 +16,7 @@ import org.eclipse.sw360.datahandler.couchdb.SummaryAwareRepository; import org.eclipse.sw360.datahandler.thrift.components.Release; import org.eclipse.sw360.datahandler.thrift.users.User; +import org.eclipse.sw360.datahandler.thrift.PaginationData; import java.util.*; import com.cloudant.client.api.model.DesignDocument.MapReduce; @@ -27,6 +28,11 @@ import static com.google.common.base.Strings.isNullOrEmpty; +import com.google.common.collect.Maps; +import com.google.common.collect.Lists; +import com.cloudant.client.api.views.ViewRequest; +import com.cloudant.client.api.views.ViewResponse; + /** * CRUD access for the Release class * @@ -126,6 +132,40 @@ public class ReleaseRepository extends SummaryAwareRepository { " emit(doc.version.toLowerCase(), doc._id);" + " } " + "}"; + private static final String BY_STATUS_VIEW = + "function(doc) {" + + " if (doc.type == 'release') {" + + " emit(doc.eccInformation.eccStatus, doc._id);" + + " } " + + "}"; + + private static final String BY_ASSESSOR_CONTACT_PERSON_VIEW = + "function(doc) {" + + " if (doc.type == 'release') {" + + " emit(doc.eccInformation.assessorContactPerson, doc._id);" + + " } " + + "}"; + + private static final String BY_ASSESSOR_DEPARTMENT_VIEW = + "function(doc) {" + + " if (doc.type == 'release') {" + + " emit(doc.eccInformation.assessorDepartment, doc._id);" + + " } " + + "}"; + + private static final String BY_ASSESSMENT_DATE_VIEW = + "function(doc) {" + + " if (doc.type == 'release') {" + + " emit(doc.eccInformation.assessmentDate, doc._id);" + + " } " + + "}"; + + private static final String BY_CREATOR_DEPARTMENT_VIEW = + "function(doc) {" + + " if (doc.type == 'release') {" + + " emit(doc.creatorDepartment, doc._id);" + + " } " + + "}"; public ReleaseRepository(DatabaseConnectorCloudant db, VendorRepository vendorRepository) { super(Release.class, db, new ReleaseSummary(vendorRepository)); @@ -144,6 +184,11 @@ public ReleaseRepository(DatabaseConnectorCloudant db, VendorRepository vendorRe views.put("releaseByName", createMapReduce(BY_LOWERCASE_RELEASE_NAME_VIEW, null)); views.put("releaseByVersion", createMapReduce(BY_LOWERCASE_RELEASE_VERSION_VIEW, null)); views.put("releaseIdsByVendorId", createMapReduce(RELEASEIDSBYVENDORID, null)); + views.put("byStatus", createMapReduce(BY_STATUS_VIEW, null)); + views.put("byECCAssessorContactPerson", createMapReduce(BY_ASSESSOR_CONTACT_PERSON_VIEW, null)); + views.put("byECCAssessorGroup", createMapReduce(BY_ASSESSOR_DEPARTMENT_VIEW, null)); + views.put("byECCAssessmentDate", createMapReduce(BY_ASSESSMENT_DATE_VIEW, null)); + views.put("byCreatorGroup", createMapReduce(BY_CREATOR_DEPARTMENT_VIEW, null)); initStandardDesignDocument(views, db); } @@ -256,4 +301,69 @@ public Set searchByExternalIds(Map> externalIds) { public List getReferencingReleases(String releaseId) { return queryView("usedInReleaseRelation", releaseId); } + + public Map> getAccessibleReleasesWithPagination(User user, PaginationData pageData) { + final int rowsPerPage = pageData.getRowsPerPage(); + Map> result = Maps.newHashMap(); + List releases = Lists.newArrayList(); + final boolean ascending = pageData.isAscending(); + final int sortColumnNo = pageData.getSortColumnNumber(); + + ViewRequestBuilder query; + switch (sortColumnNo) { + case -1: + query = getConnector().createQuery(Release.class, "byCreatedOn"); + break; + case 0: + query = getConnector().createQuery(Release.class, "byStatus"); + break; + case 1: + query = getConnector().createQuery(Release.class, "byname"); + break; + case 2: + query = getConnector().createQuery(Release.class, "releaseByVersion"); + break; + case 3: + query = getConnector().createQuery(Release.class, "byCreatorGroup"); + break; + case 4: + query = getConnector().createQuery(Release.class, "byECCAssessorContactPerson"); + break; + case 5: + query = getConnector().createQuery(Release.class, "byECCAssessorGroup"); + break; + case 6: + query = getConnector().createQuery(Release.class, "byECCAssessmentDate"); + break; + default: + query = getConnector().createQuery(Release.class, "all"); + break; + } + + ViewRequest request = null; + if (rowsPerPage == -1) { + request = query.newRequest(Key.Type.STRING, Object.class).descending(!ascending).includeDocs(true).build(); + } else { + request = query.newPaginatedRequest(Key.Type.STRING, Object.class).rowsPerPage(rowsPerPage) + .descending(!ascending).includeDocs(true).build(); + } + + ViewResponse response = null; + try { + response = request.getResponse(); + int pageNo = pageData.getDisplayStart() / rowsPerPage; + int i = 1; + while (i <= pageNo) { + response = response.nextPage(); + i++; + } + releases = response.getDocsAs(Release.class); + } catch (Exception e) { + log.error("Error getting recent releases", e); + } + releases = makeSummaryWithPermissionsFromFullDocs(SummaryType.SUMMARY, releases, user); + pageData.setTotalRowCount(response.getTotalRowCount()); + result.put(pageData, releases); + return result; + } } diff --git a/backend/src/src-components/src/main/java/org/eclipse/sw360/components/ComponentHandler.java b/backend/src/src-components/src/main/java/org/eclipse/sw360/components/ComponentHandler.java index ee928e94d7..d311df8c59 100644 --- a/backend/src/src-components/src/main/java/org/eclipse/sw360/components/ComponentHandler.java +++ b/backend/src/src-components/src/main/java/org/eclipse/sw360/components/ComponentHandler.java @@ -120,6 +120,12 @@ public List getAccessibleReleaseSummary(User user) throws TException { return handler.getAccessibleReleaseSummary(user); } + @Override + public Map> getAccessibleReleasesWithPagination(User user, PaginationData pageData) throws TException { + assertUser(user); + return handler.getAccessibleReleasesWithPagination(user, pageData); + } + @Override public List refineSearch(String text, Map> subQueryRestrictions) throws TException { return componentSearchHandler.search(text, subQueryRestrictions); diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/PortalConstants.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/PortalConstants.java index 2a6fdb175f..f0065adce7 100644 --- a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/PortalConstants.java +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/common/PortalConstants.java @@ -590,6 +590,7 @@ public class PortalConstants { public static final String UNSUBSCRIBE = "unsubscribe"; public static final String UNSUBSCRIBE_RELEASE = "unsubscribe_release"; public static final String LOAD_COMPONENT_LIST = "load_component_list"; + public static final String LOAD_ECC_LIST = "load_ecc_list"; // fossology actions public static final String FOSSOLOGY_PREFIX = "fossology"; diff --git a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/ecc/EccPortlet.java b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/ecc/EccPortlet.java index c1fd8e2a6c..64357bbc98 100644 --- a/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/ecc/EccPortlet.java +++ b/frontend/sw360-portlet/src/main/java/org/eclipse/sw360/portal/portlets/ecc/EccPortlet.java @@ -24,8 +24,28 @@ import java.util.Collections; import java.util.List; +import com.liferay.portal.kernel.json.JSONArray; +import org.eclipse.sw360.portal.common.datatables.PaginationParser; +import org.eclipse.sw360.portal.common.datatables.data.PaginationParameters; +import javax.servlet.http.HttpServletRequest; +import com.liferay.portal.kernel.util.PortalUtil; +import com.liferay.portal.kernel.json.JSONFactoryUtil; +import com.liferay.portal.kernel.json.JSONObject; +import org.eclipse.sw360.portal.common.*; +import org.eclipse.sw360.datahandler.thrift.*; +import java.util.*; +import com.google.common.collect.*; +import org.eclipse.sw360.datahandler.common.SW360Utils; +import org.eclipse.sw360.datahandler.common.*; + import javax.portlet.*; +import static org.eclipse.sw360.datahandler.common.CommonUtils.*; +import static com.liferay.portal.kernel.json.JSONFactoryUtil.createJSONArray; +import static com.liferay.portal.kernel.json.JSONFactoryUtil.createJSONObject; +import static java.lang.Math.min; +import static com.google.common.base.Strings.nullToEmpty; +import static org.eclipse.sw360.portal.common.PortalConstants.*; import static org.eclipse.sw360.portal.common.PortalConstants.ECC_PORTLET_NAME; import static org.eclipse.sw360.portal.common.PortalConstants.RELEASE_LIST; @@ -50,6 +70,15 @@ public class EccPortlet extends Sw360Portlet { private static final Logger log = LogManager.getLogger(EccPortlet.class); + // ECC release view datatables, index of columns + private static final int RELEASE_NO_SORT = -1; + private static final int RELEASE_DT_ROW_ECC_STATUS = 0; + private static final int RELEASE_DT_ROW_NAME = 1; + private static final int RELEASE_DT_ROW_VERSION = 2; + private static final int RELEASE_DT_ROW_GROUP = 3; + private static final int RELEASE_DT_ROW_ASSESSOR_CONTACT_PERSON = 4; + private static final int RELEASE_DT_ROW_ASSESSOR_DEPARTMENT = 5; + private static final int RELEASE_DT_ROW_ASSESSMENT_DATE = 6; @Override public void doView(RenderRequest request, RenderResponse response) throws IOException, PortletException { @@ -59,19 +88,175 @@ public void doView(RenderRequest request, RenderResponse response) throws IOExce } private void prepareStandardView(RenderRequest request) { - final User user = UserCacheHolder.getUserFromRequest(request); - ComponentService.Iface client = thriftClients.makeComponentClient(); - try { - final List releaseSummary = client.getAccessibleReleaseSummary(user); + request.setAttribute(PortalConstants.EXACT_MATCH_CHECKBOX, nullToEmpty(request.getParameter(PortalConstants.EXACT_MATCH_CHECKBOX))); + } catch (Exception e) { + log.error("Could not fetch releases from backend", e); + } - request.setAttribute(RELEASE_LIST, releaseSummary); + } + + @Override + public void serveResource(ResourceRequest request, ResourceResponse response) throws IOException, PortletException { + try { + String action = request.getParameter(PortalConstants.ACTION); - } catch (TException e) { + if (PortalConstants.LOAD_ECC_LIST.equals(action)) { + serveECCReleaseList(request, response); + } + } catch (Exception e) { log.error("Could not fetch releases from backend", e); request.setAttribute(RELEASE_LIST, Collections.emptyList()); } + + + } + + private void serveECCReleaseList(ResourceRequest request, ResourceResponse response) throws IOException, PortletException { + HttpServletRequest originalServletRequest = PortalUtil.getOriginalServletRequest(PortalUtil.getHttpServletRequest(request)); + PaginationParameters paginationParameters = PaginationParser.parametersFrom(originalServletRequest); + //PortletUtils.handlePaginationSortOrder(request, paginationParameters, releaseFilteredFields, RELEASE_NO_SORT); + PaginationData pageData = new PaginationData(); + pageData.setRowsPerPage(paginationParameters.getDisplayLength()); + pageData.setDisplayStart(paginationParameters.getDisplayStart()); + pageData.setAscending(paginationParameters.isAscending().get()); + int sortParam = -1; + if (paginationParameters.getSortingColumn().isPresent()) { + sortParam = paginationParameters.getSortingColumn().get(); + if (sortParam == 1 && Integer.valueOf(paginationParameters.getEcho()) == 1) { + pageData.setSortColumnNumber(-1); + } else { + pageData.setSortColumnNumber(sortParam); + } + } + Map> releaseList = getReleaseList(request, pageData); + JSONArray jsonReleases = getReleaseData(releaseList.values().iterator().next(), paginationParameters, request); + JSONObject jsonResult = createJSONObject(); + int count = (int) (releaseList.keySet().iterator().next().getTotalRowCount()); + jsonResult.put(DATATABLE_RECORDS_TOTAL, count); + jsonResult.put(DATATABLE_RECORDS_FILTERED, count); + jsonResult.put(DATATABLE_DISPLAY_DATA, jsonReleases); + + try { + writeJSON(request, response, jsonResult); + } catch (IOException e) { + log.error("Problem rendering RequestStatus", e); + } + } + + private Map> getReleaseList(PortletRequest request, PaginationData pageData) throws IOException { + final User user = UserCacheHolder.getUserFromRequest(request); + ComponentService.Iface client = thriftClients.makeComponentClient(); + Map> releaseSummary = Maps.newHashMap(); + try { + releaseSummary = client.getAccessibleReleasesWithPagination(user, pageData); + request.setAttribute(RELEASE_LIST, releaseSummary); + } + catch (TException e) { + log.error("Could not search releases in backend ", e); + } + return releaseSummary; + } + + public JSONArray getReleaseData(List releaseList, PaginationParameters releaseParameters, ResourceRequest request) { + List sortedReleases = sortReleaseList(releaseList, releaseParameters); + int count = getReleaseDataCount(releaseParameters, releaseList.size()); + final int start = 0; + JSONArray releaseData = createJSONArray(); + for (int i = start; i < count; i++) { + JSONObject jsonObject = JSONFactoryUtil.createJSONObject(); + Release release = sortedReleases.get(i); + jsonObject.put("id", release.getId()); + jsonObject.put("DT_RowId", release.getId()); + jsonObject.put("status", nullToEmptyString(release.getEccInformation().getEccStatus())); + jsonObject.put("name", SW360Utils.printName(release)); + jsonObject.put("version", nullToEmpty(release.getVersion())); + jsonObject.put("group", nullToEmptyString(release.getCreatorDepartment())); + jsonObject.put("assessor_contact_person", nullToEmptyString(release.getEccInformation().getAssessorContactPerson())); + jsonObject.put("assessor_dept", nullToEmptyString(release.getEccInformation().getAssessorDepartment())); + jsonObject.put("assessment_date", nullToEmptyString(release.getEccInformation().getAssessmentDate())); + releaseData.put(jsonObject); + } + return releaseData; + } + + public static int getReleaseDataCount(PaginationParameters releaseParameters, int maxSize) { + if (releaseParameters.getDisplayLength() == -1) { + return maxSize; + } else { + return min(releaseParameters.getDisplayStart() + releaseParameters.getDisplayLength(), maxSize); + } + } + + private List sortReleaseList(List releaseList, PaginationParameters releaseParameters) { + boolean isAsc = releaseParameters.isAscending().orElse(true); + + switch (releaseParameters.getSortingColumn().orElse(RELEASE_DT_ROW_ECC_STATUS)) { + case RELEASE_DT_ROW_ECC_STATUS: + Collections.sort(releaseList, compareByECCStatus(isAsc)); + break; + case RELEASE_DT_ROW_NAME: + Collections.sort(releaseList, compareByName(isAsc)); + break; + case RELEASE_DT_ROW_VERSION: + Collections.sort(releaseList, compareByVersion(isAsc)); + break; + case RELEASE_DT_ROW_GROUP: + Collections.sort(releaseList, compareByCreatorGroup(isAsc)); + break; + case RELEASE_DT_ROW_ASSESSOR_CONTACT_PERSON: + Collections.sort(releaseList, compareByAssessorContactPerson(isAsc)); + break; + case RELEASE_DT_ROW_ASSESSOR_DEPARTMENT: + Collections.sort(releaseList, compareByAssessorDept(isAsc)); + break; + case RELEASE_DT_ROW_ASSESSMENT_DATE: + Collections.sort(releaseList, compareByAssessmentDate(isAsc)); + break; + default: + break; + } + return releaseList; } + + public static Comparator compareByECCStatus(boolean isAscending) { + Comparator comparator = Comparator.comparing(r -> CommonUtils.nullToEmptyString(r.getEccInformation().getEccStatus())); + return isAscending ? comparator : comparator.reversed(); + } + + public static Comparator compareByName(boolean isAscending) { + Comparator comparator = Comparator.comparing(r -> CommonUtils.nullToEmptyString(r.getName())); + return isAscending ? comparator : comparator.reversed(); + } + + public static Comparator compareByVersion(boolean isAscending) { + Comparator comparator = Comparator.comparing(r -> CommonUtils.nullToEmptyString(r.getVersion())); + return isAscending ? comparator : comparator.reversed(); + } + + public static Comparator compareByCreatorGroup(boolean isAscending) { + Comparator comparator = Comparator.comparing(r -> CommonUtils.nullToEmptyString(r.getCreatorDepartment())); + return isAscending ? comparator : comparator.reversed(); + } + + public static Comparator compareByAssessorContactPerson(boolean isAscending) { + Comparator comparator = Comparator.comparing(r -> CommonUtils.nullToEmptyString(r.getEccInformation().getAssessorContactPerson())); + return isAscending ? comparator : comparator.reversed(); + } + + public static Comparator compareByAssessorDept(boolean isAscending) { + Comparator comparator = Comparator.comparing(r -> CommonUtils.nullToEmptyString(r.getEccInformation().getAssessorDepartment())); + return isAscending ? comparator : comparator.reversed(); + } + + public static Comparator compareByAssessmentDate(boolean isAscending) { + Comparator comparator = Comparator.comparing(r -> CommonUtils.nullToEmptyString(r.getEccInformation().getAssessmentDate())); + return isAscending ? comparator : comparator.reversed(); + } + + + + } diff --git a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/ecc/view.jsp b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/ecc/view.jsp index c43358844c..b1481868d2 100644 --- a/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/ecc/view.jsp +++ b/frontend/sw360-portlet/src/main/resources/META-INF/resources/html/ecc/view.jsp @@ -16,7 +16,6 @@ - @@ -26,6 +25,10 @@ + + + +
@@ -44,39 +47,6 @@
- - - - - - - - - - - - - - - - - - - - - - - -
- - class="badge badge-empty badge-danger" <%--ECCStatus.OPEN || ECCStatus.REJECTED--%> - class="badge badge-empty badge-warning" <%--ECCStatus.IN_PROGRESS--%> - class="badge badge-empty badge-success" > <%--ECCStatus.APPROVED--%> - ! <%--ECCStatus.REJECTED--%> -   <%--ECCStatus.REJECTED--%> - -
@@ -90,7 +60,7 @@ AUI().use('liferay-portlet-url', function () { var PortletURL = Liferay.PortletURL; - require(['jquery', 'utils/includes/quickfilter', 'bridges/datatables'], function($, quickfilter, datatables) { + require(['jquery', 'utils/includes/quickfilter', 'bridges/datatables', 'bridges/jquery-ui'], function($, quickfilter, datatables) { var eccInfoTable; // initializing @@ -107,6 +77,18 @@ function configureEccInfoTable(){ return datatables.create('#eccInfoTable', { + bServerSide: true, + sAjaxSource: '<%=loadECCURL%>', + columns: [ + {"title": "", data: "status"}, + {"title": "", data: function(row){return row["name"];}, render: {display: renderReleaseNameLink}}, + {"title": "", data: "version", render: {display: renderReleaseNameLink}}, + {"title": "", data: "group"}, + {"title": "", data: "assessor_contact_person"}, + {"title": "", data: "assessor_dept"}, + {"title": "", data: "assessment_date"}, + ], + columnDefs: [], language: { url: "", loadingRecords: "" @@ -114,6 +96,9 @@ searching: true }, [0, 1, 2, 3, 4, 5, 6]); } + function renderReleaseNameLink(name, type, row) { + return $("").text(name)[0].outerHTML; + } }); }); diff --git a/libraries/datahandler/src/main/thrift/components.thrift b/libraries/datahandler/src/main/thrift/components.thrift index e411f5886b..ed264a1a0c 100644 --- a/libraries/datahandler/src/main/thrift/components.thrift +++ b/libraries/datahandler/src/main/thrift/components.thrift @@ -473,6 +473,11 @@ service ComponentService { */ list searchAccessibleReleases(1: string text, 2: User user); + /** + * list accessible releases with pagination for ECC page + */ + map> getAccessibleReleasesWithPagination(1: User user, 2: PaginationData pageData); + /** * get short summary of release by release name prefix **/