From 3c5ef2007a0b5f1982897f46deea294276796342 Mon Sep 17 00:00:00 2001 From: woodjes Date: Tue, 7 Dec 2021 10:46:18 +0000 Subject: [PATCH] Report grid update columns, permissions, picker/edit views combined #CTCTOWALTZ-2376 #5682 --- .../main/ddl/liquibase/db.changelog-1.39.xml | 11 ++ .../waltz/data/report_grid/ReportGridDao.java | 107 +++++++---- .../data/report_grid/ReportGridMemberDao.java | 19 ++ .../report_grid/ReportGridCreateCommand.java | 5 + .../report_grid/ReportGridDefinition.java | 5 +- .../model/report_grid/ReportGridKind.java | 6 + .../report_grid/ReportGridUpdateCommand.java | 24 +++ .../report-grid-view-section.html | 7 +- .../report-grid-view-panel.js | 5 +- .../svelte/ReportGridControlPanel.svelte | 37 +++- .../components/svelte/ReportGridEditor.svelte | 42 ++++- .../svelte/ReportGridFilters.svelte | 2 - .../svelte/ReportGridOverview.svelte | 174 +++++++++++++++--- .../components/svelte/ReportGridPicker.svelte | 109 ++++------- .../ColumnDefinitionEditPanel.svelte | 18 +- .../ColumnDetailsEditor.svelte | 6 +- .../DropdownPicker.svelte | 2 +- .../ReportGridColumnSummary.svelte | 43 +++-- .../components/svelte/report-grid-store.js | 3 +- .../components/svelte/report-grid-utils.js | 11 ++ .../svelte-stores/report-grid-member-store.js | 31 ++++ .../client/svelte-stores/report-grid-store.js | 15 +- .../report_grid/ReportGridMemberService.java | 67 +++++++ .../report_grid/ReportGridService.java | 41 ++++- .../web/endpoints/api/ReportGridEndpoint.java | 30 ++- .../api/ReportGridMemberEndpoint.java | 62 +++++++ 26 files changed, 671 insertions(+), 211 deletions(-) create mode 100644 waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridKind.java create mode 100644 waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridUpdateCommand.java create mode 100644 waltz-ng/client/svelte-stores/report-grid-member-store.js create mode 100644 waltz-service/src/main/java/org/finos/waltz/service/report_grid/ReportGridMemberService.java create mode 100644 waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/ReportGridMemberEndpoint.java diff --git a/waltz-data/src/main/ddl/liquibase/db.changelog-1.39.xml b/waltz-data/src/main/ddl/liquibase/db.changelog-1.39.xml index 256fab4b00..427b42ea78 100644 --- a/waltz-data/src/main/ddl/liquibase/db.changelog-1.39.xml +++ b/waltz-data/src/main/ddl/liquibase/db.changelog-1.39.xml @@ -222,4 +222,15 @@ tableName="report_grid_member"/> + + + + + + + + diff --git a/waltz-data/src/main/java/org/finos/waltz/data/report_grid/ReportGridDao.java b/waltz-data/src/main/java/org/finos/waltz/data/report_grid/ReportGridDao.java index 930e640a91..dab96e9b9d 100644 --- a/waltz-data/src/main/java/org/finos/waltz/data/report_grid/ReportGridDao.java +++ b/waltz-data/src/main/java/org/finos/waltz/data/report_grid/ReportGridDao.java @@ -103,8 +103,9 @@ public Set findForUser(String username){ return dsl .select(rg.fields()) .from(rg) - .innerJoin(REPORT_GRID_MEMBER).on(rg.ID.eq(REPORT_GRID_MEMBER.GRID_ID)) - .where(REPORT_GRID_MEMBER.USER_ID.eq(username)) + .leftJoin(REPORT_GRID_MEMBER) + .on(rg.ID.eq(REPORT_GRID_MEMBER.GRID_ID)) + .where(rg.KIND.eq(ReportGridKind.PUBLIC.name()).or(REPORT_GRID_MEMBER.USER_ID.eq(username))) .fetchSet(r -> mkReportGridDefinition(rgcd.REPORT_GRID_ID.eq(r.get(rg.ID)), r.into(REPORT_GRID))); } @@ -165,12 +166,25 @@ public long create(ReportGridCreateCommand createCommand, String username) { record.setLastUpdatedAt(DateTimeUtilities.nowUtcTimestamp()); record.setLastUpdatedBy(username); record.setProvenance("waltz"); + record.setKind(createCommand.kind().name()); int insert = record.insert(); return record.getId(); } + public long update(long id, ReportGridUpdateCommand updateCommand, String username) { + return dsl + .update(rg) + .set(rg.NAME, updateCommand.name()) + .set(rg.DESCRIPTION, updateCommand.description()) + .set(rg.KIND, updateCommand.kind().name()) + .set(rg.LAST_UPDATED_AT, DateTimeUtilities.nowUtcTimestamp()) + .set(rg.LAST_UPDATED_BY, username) + .where(rg.ID.eq(id)) + .execute(); + } + // --- Helpers --- private ReportGridDefinition getGridDefinitionByCondition(Condition condition) { @@ -271,50 +285,56 @@ private Set findCellDataByGridCondition(Condition gridCondition, ReportGridDefinition gridDefn = getGridDefinitionByCondition(gridCondition); - Map> colsByKind = groupBy( - gridDefn.columnDefinitions(), - cd -> cd.columnEntityReference().kind()); + if(gridDefn == null ){ + return emptySet(); - Set requiredAssessmentDefinitions = map( - colsByKind.getOrDefault(EntityKind.ASSESSMENT_DEFINITION, emptySet()), - cd -> cd.columnEntityReference().id()); + } else { + + Map> colsByKind = groupBy( + gridDefn.columnDefinitions(), + cd -> cd.columnEntityReference().kind()); - Map> measurableColumnsByRollupKind = groupBy( - colsByKind.getOrDefault(EntityKind.MEASURABLE, emptySet()), - ReportGridColumnDefinition::ratingRollupRule); + Set requiredAssessmentDefinitions = map( + colsByKind.getOrDefault(EntityKind.ASSESSMENT_DEFINITION, emptySet()), + cd -> cd.columnEntityReference().id()); - Set exactMeasurableIds = map( - measurableColumnsByRollupKind.get(RatingRollupRule.NONE), - cd -> cd.columnEntityReference().id()); + Map> measurableColumnsByRollupKind = groupBy( + colsByKind.getOrDefault(EntityKind.MEASURABLE, emptySet()), + ReportGridColumnDefinition::ratingRollupRule); - Set summaryMeasurableIdsUsingHighest = map( - measurableColumnsByRollupKind.get(RatingRollupRule.PICK_HIGHEST), - cd -> cd.columnEntityReference().id()); + Set exactMeasurableIds = map( + measurableColumnsByRollupKind.get(RatingRollupRule.NONE), + cd -> cd.columnEntityReference().id()); - Set summaryMeasurableIdsUsingLowest = map( - measurableColumnsByRollupKind.get(RatingRollupRule.PICK_LOWEST), - cd -> cd.columnEntityReference().id()); + Set summaryMeasurableIdsUsingHighest = map( + measurableColumnsByRollupKind.get(RatingRollupRule.PICK_HIGHEST), + cd -> cd.columnEntityReference().id()); - Set requiredCostKinds = map( - colsByKind.getOrDefault(EntityKind.COST_KIND, emptySet()), - cd -> cd.columnEntityReference().id()); + Set summaryMeasurableIdsUsingLowest = map( + measurableColumnsByRollupKind.get(RatingRollupRule.PICK_LOWEST), + cd -> cd.columnEntityReference().id()); - Set requiredInvolvementKinds = map( - colsByKind.getOrDefault(EntityKind.INVOLVEMENT_KIND, emptySet()), - cd -> cd.columnEntityReference().id()); + Set requiredCostKinds = map( + colsByKind.getOrDefault(EntityKind.COST_KIND, emptySet()), + cd -> cd.columnEntityReference().id()); - Set requiredSurveyQuestionIds = map( - colsByKind.getOrDefault(EntityKind.SURVEY_QUESTION, emptySet()), - cd -> cd.columnEntityReference().id()); + Set requiredInvolvementKinds = map( + colsByKind.getOrDefault(EntityKind.INVOLVEMENT_KIND, emptySet()), + cd -> cd.columnEntityReference().id()); + Set requiredSurveyQuestionIds = map( + colsByKind.getOrDefault(EntityKind.SURVEY_QUESTION, emptySet()), + cd -> cd.columnEntityReference().id()); - return union( - fetchSummaryMeasurableData(appSelector, summaryMeasurableIdsUsingHighest, summaryMeasurableIdsUsingLowest), - fetchAssessmentData(appSelector, requiredAssessmentDefinitions), - fetchExactMeasurableData(appSelector, exactMeasurableIds), - fetchCostData(appSelector, requiredCostKinds), - fetchInvolvementData(appSelector, requiredInvolvementKinds), - fetchSurveyQuestionResponseData(appSelector, requiredSurveyQuestionIds)); + + return union( + fetchSummaryMeasurableData(appSelector, summaryMeasurableIdsUsingHighest, summaryMeasurableIdsUsingLowest), + fetchAssessmentData(appSelector, requiredAssessmentDefinitions), + fetchExactMeasurableData(appSelector, exactMeasurableIds), + fetchCostData(appSelector, requiredCostKinds), + fetchInvolvementData(appSelector, requiredInvolvementKinds), + fetchSurveyQuestionResponseData(appSelector, requiredSurveyQuestionIds)); + } } @@ -642,7 +662,22 @@ private ImmutableReportGridDefinition mkReportGridDefinition(Condition condition .lastUpdatedAt(toLocalDateTime(r.get(rg.LAST_UPDATED_AT))) .lastUpdatedBy(r.get(rg.LAST_UPDATED_BY)) .columnDefinitions(getColumnDefinitions(condition)) + .kind(ReportGridKind.valueOf(r.get(rg.KIND))) .build(); } + + + public Set findForOwner(String username) { + Condition isOwner = REPORT_GRID_MEMBER.USER_ID.eq(username) + .and(REPORT_GRID_MEMBER.ROLE.eq(ReportGridMemberRole.OWNER.name())); + + return dsl + .select(rg.fields()) + .from(rg) + .innerJoin(REPORT_GRID_MEMBER) + .on(rg.ID.eq(REPORT_GRID_MEMBER.GRID_ID)) + .where(isOwner) + .fetchSet(r -> mkReportGridDefinition(rgcd.REPORT_GRID_ID.eq(r.get(rg.ID)), r.into(REPORT_GRID))); + } } diff --git a/waltz-data/src/main/java/org/finos/waltz/data/report_grid/ReportGridMemberDao.java b/waltz-data/src/main/java/org/finos/waltz/data/report_grid/ReportGridMemberDao.java index 9e72b0fd11..f632056a43 100644 --- a/waltz-data/src/main/java/org/finos/waltz/data/report_grid/ReportGridMemberDao.java +++ b/waltz-data/src/main/java/org/finos/waltz/data/report_grid/ReportGridMemberDao.java @@ -26,6 +26,7 @@ import org.jooq.DSLContext; import org.jooq.Record; import org.jooq.RecordMapper; +import org.jooq.impl.DSL; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -61,5 +62,23 @@ public Set findByGridId(Long gridId){ .fetchSet(TO_DOMAIN_MAPPER); } + public int register(long gridId, String username, ReportGridMemberRole role) { + return dsl + .insertInto(REPORT_GRID_MEMBER) + .set(REPORT_GRID_MEMBER.GRID_ID, gridId) + .set(REPORT_GRID_MEMBER.USER_ID, username) + .set(REPORT_GRID_MEMBER.ROLE, role.name()) + .execute(); + } + + public boolean canUpdate(long gridId, String userId) { + return dsl + .fetchExists(DSL + .select(REPORT_GRID_MEMBER.GRID_ID) + .from(REPORT_GRID_MEMBER) + .where(REPORT_GRID_MEMBER.GRID_ID.eq(gridId) + .and(REPORT_GRID_MEMBER.USER_ID.eq(userId) + .and(REPORT_GRID_MEMBER.ROLE.eq(ReportGridMemberRole.OWNER.name()))))); + } } diff --git a/waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridCreateCommand.java b/waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridCreateCommand.java index 9ac2ccb511..e8cd718cc7 100644 --- a/waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridCreateCommand.java +++ b/waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridCreateCommand.java @@ -18,4 +18,9 @@ public abstract class ReportGridCreateCommand implements Command { @Nullable public abstract String description(); + + @Value.Default + public ReportGridKind kind(){ + return ReportGridKind.PUBLIC; + } } diff --git a/waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridDefinition.java b/waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridDefinition.java index c555e1b82c..3501dec72e 100644 --- a/waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridDefinition.java +++ b/waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridDefinition.java @@ -20,5 +20,8 @@ public abstract class ReportGridDefinition implements public abstract List columnDefinitions(); // columns - + @Value.Default + public ReportGridKind kind(){ + return ReportGridKind.PUBLIC; + } } diff --git a/waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridKind.java b/waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridKind.java new file mode 100644 index 0000000000..581a28cd8d --- /dev/null +++ b/waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridKind.java @@ -0,0 +1,6 @@ +package org.finos.waltz.model.report_grid; + +public enum ReportGridKind { + PUBLIC, + PRIVATE +} diff --git a/waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridUpdateCommand.java b/waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridUpdateCommand.java new file mode 100644 index 0000000000..858bd891c8 --- /dev/null +++ b/waltz-model/src/main/java/org/finos/waltz/model/report_grid/ReportGridUpdateCommand.java @@ -0,0 +1,24 @@ +package org.finos.waltz.model.report_grid; + +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import org.finos.waltz.model.IdProvider; +import org.finos.waltz.model.Nullable; +import org.finos.waltz.model.command.Command; +import org.immutables.value.Value; + +@Value.Immutable +@JsonSerialize(as = ImmutableReportGridUpdateCommand.class) +@JsonDeserialize(as = ImmutableReportGridUpdateCommand.class) +public abstract class ReportGridUpdateCommand implements Command { + + public abstract String name(); + + @Nullable + public abstract String description(); + + @Value.Default + public ReportGridKind kind(){ + return ReportGridKind.PUBLIC; + } +} diff --git a/waltz-ng/client/report-grid/components/grid-view-section/report-grid-view-section.html b/waltz-ng/client/report-grid/components/grid-view-section/report-grid-view-section.html index 56ff686da5..243267cc38 100644 --- a/waltz-ng/client/report-grid/components/grid-view-section/report-grid-view-section.html +++ b/waltz-ng/client/report-grid/components/grid-view-section/report-grid-view-section.html @@ -1,9 +1,6 @@
-
- - -
+ +
diff --git a/waltz-ng/client/report-grid/components/report-grid-view-panel/report-grid-view-panel.js b/waltz-ng/client/report-grid/components/report-grid-view-panel/report-grid-view-panel.js index 8de19cc555..c84c593a01 100644 --- a/waltz-ng/client/report-grid/components/report-grid-view-panel/report-grid-view-panel.js +++ b/waltz-ng/client/report-grid/components/report-grid-view-panel/report-grid-view-panel.js @@ -24,6 +24,7 @@ import _ from "lodash"; import ReportGridControlPanel from "../svelte/ReportGridControlPanel.svelte"; import {activeSummaryColRefs, filters, selectedGrid, columnDefs} from "../svelte/report-grid-store"; import {mkPropNameForRef, mkRowFilter, prepareColumnDefs, prepareTableData} from "../svelte/report-grid-utils"; +import {displayError} from "../../../common/error-utils"; const bindings = { parentEntityRef: "<", @@ -72,7 +73,6 @@ function controller($scope, serviceBroker, localStorageService) { CORE_API.ReportGridStore.getViewById, [vm.gridId, mkSelectionOptions(vm.parentEntityRef)], {force: true}) .then(r => { - // vm.filters = []; vm.loading = false; vm.rawGridData = r.data; @@ -82,6 +82,9 @@ function controller($scope, serviceBroker, localStorageService) { vm.allTableData = prepareTableData(vm.rawGridData); vm.allColumnDefs = prepareColumnDefs(vm.rawGridData); refresh(); + }) + .catch(e => { + displayError("Could not load grid data for id: " + vm.gridId, e) }); } diff --git a/waltz-ng/client/report-grid/components/svelte/ReportGridControlPanel.svelte b/waltz-ng/client/report-grid/components/svelte/ReportGridControlPanel.svelte index 7a56206247..f2393fb994 100644 --- a/waltz-ng/client/report-grid/components/svelte/ReportGridControlPanel.svelte +++ b/waltz-ng/client/report-grid/components/svelte/ReportGridControlPanel.svelte @@ -3,11 +3,21 @@ import ReportGridOverview from "./ReportGridOverview.svelte"; import ReportGridFilters from "./ReportGridFilters.svelte"; import ColumnDefinitionEditPanel from "./column-definition-edit-panel/ColumnDefinitionEditPanel.svelte"; - import {selectedGrid} from "./report-grid-store"; + import {selectedGrid, ownedReportIds} from "./report-grid-store"; + import {reportGridStore} from "../../../svelte-stores/report-grid-store"; + import _ from "lodash"; + import Icon from "../../../common/svelte/Icon.svelte"; export let onGridSelect = () => console.log("selecting grid"); export let onSave = () => console.log("Saved report grid"); - let selectedTab = "context" + let selectedTab = "overview" + + + $: isOwned = $selectedGrid && _.includes($ownedReportIds, $selectedGrid.definition?.id); + + $: ownedGridsCall = $selectedGrid.definition.id && reportGridStore.findForOwner(true); + $: $ownedReportIds = _.map($ownedGridsCall?.data, d => d.id); + @@ -15,11 +25,13 @@ + value="overview" + id="overview">
- {#if selectedTab === 'context'} + {#if selectedTab === 'overview'} {:else if selectedTab === 'filters'} diff --git a/waltz-ng/client/report-grid/components/svelte/ReportGridEditor.svelte b/waltz-ng/client/report-grid/components/svelte/ReportGridEditor.svelte index 33f7de5318..d574c144ee 100644 --- a/waltz-ng/client/report-grid/components/svelte/ReportGridEditor.svelte +++ b/waltz-ng/client/report-grid/components/svelte/ReportGridEditor.svelte @@ -1,5 +1,8 @@ @@ -30,15 +39,42 @@ bind:value={workingCopy.description}/>
+ + +
+
+ +
+ +
+
+ \ No newline at end of file diff --git a/waltz-ng/client/report-grid/components/svelte/ReportGridFilters.svelte b/waltz-ng/client/report-grid/components/svelte/ReportGridFilters.svelte index 184cedb38b..a6bac6e733 100644 --- a/waltz-ng/client/report-grid/components/svelte/ReportGridFilters.svelte +++ b/waltz-ng/client/report-grid/components/svelte/ReportGridFilters.svelte @@ -43,8 +43,6 @@ $filters = _.reject($filters, f => f.propName === refToRemove); } - $: console.log({chunkedSummaryData, fs: $filters, acS: $activeSummaryColRefs, ss: $summaries}) -
diff --git a/waltz-ng/client/report-grid/components/svelte/ReportGridOverview.svelte b/waltz-ng/client/report-grid/components/svelte/ReportGridOverview.svelte index 23811fae5a..dd6ff415b5 100644 --- a/waltz-ng/client/report-grid/components/svelte/ReportGridOverview.svelte +++ b/waltz-ng/client/report-grid/components/svelte/ReportGridOverview.svelte @@ -2,39 +2,159 @@ import ReportGridPicker from "./ReportGridPicker.svelte"; import NoData from "../../../common/svelte/NoData.svelte"; - import {selectedGrid} from "./report-grid-store"; + import {selectedGrid, ownedReportIds} from "./report-grid-store"; + import {reportGridKinds} from "./report-grid-utils"; + import ReportGridEditor from "./ReportGridEditor.svelte"; + import {toUpperSnakeCase} from "../../../common/string-utils"; + import {reportGridMemberStore} from "../../../svelte-stores/report-grid-member-store"; + import {reportGridStore} from "../../../svelte-stores/report-grid-store"; + import toasts from "../../../svelte-stores/toast-store"; import Icon from "../../../common/svelte/Icon.svelte"; + import _ from "lodash"; + + export let onGridSelect = () => console.log("selecting grid"); const Modes = { - VIEW: "VIEW", - PICKER: "PICKER", -} + VIEW: "VIEW", + EDIT: "EDIT" + } + + let activeMode = Modes.VIEW; + + + let grids = []; + $: reportGridCall = reportGridStore.findForUser(true); + $: grids = $reportGridCall.data; + + + $: gridOwnersCall = $selectedGrid?.definition?.id && reportGridMemberStore.findByGridId($selectedGrid?.definition.id); + $: gridOwners = $gridOwnersCall?.data || []; + + function selectGrid(grid) { + onGridSelect(grid); + } + + function create(grid){ + const createCmd = { + name: grid.name, + description: grid.description, + externalId: toUpperSnakeCase(grid.name), + kind: grid.kind + } + + let savePromise = reportGridStore.create(createCmd); + Promise.resolve(savePromise) + .then(r => { + toasts.success("Grid created successfully") + selectGrid(r.data); + activeMode = Modes.VIEW; + reportGridCall = reportGridStore.findForUser(true); + }) + .catch(e => toasts.error("Could not create grid")); + } + + function update(grid){ + const updateCmd = { + name: grid.name, + description: grid.description, + kind: grid.kind + } -export let onGridSelect = () => console.log("selecting grid"); -let activeMode = Modes.VIEW; + let savePromise = reportGridStore.update(grid.id, updateCmd); + Promise.resolve(savePromise) + .then(r => { + toasts.success("Grid updated successfully") + selectGrid(r.data); + activeMode = Modes.VIEW; + }) + .catch(e => toasts.error("Could not update grid")); + } -function selectGrid(grid) { - onGridSelect(grid); - activeMode = Modes.VIEW; -} + function saveReportGrid(grid) { + if(grid.id){ + update(grid); + } else { + create(grid); + } + } -function cancel() { - activeMode = Modes.VIEW -} + function createGrid() { + + const workingGrid = { + name: null, + description: null, + externalId: null + } + + $selectedGrid = { definition: workingGrid }; + activeMode = Modes.EDIT + } + + + function cancel(){ + activeMode = Modes.VIEW; + } + + $: gridOwnerNames = _.map(gridOwners, d => d.userId); -{#if activeMode === Modes.VIEW} - {#if $selectedGrid} -

{$selectedGrid.definition.name}

-

{$selectedGrid.definition.description}

- {:else} - No grid selected - {/if} - -{:else if activeMode === Modes.PICKER} - -{/if} +
+
+ +
+
+ {#if activeMode === Modes.EDIT} +

Editing report grid:

+ + {:else if activeMode === Modes.VIEW} + {#if $selectedGrid.definition.id} +

{$selectedGrid?.definition?.name}

+
+ {$selectedGrid.definition?.description || "No description provided"} +
+
+
+ Kind: {_.get(reportGridKinds[$selectedGrid?.definition?.kind], 'name', 'Unknown Kind')} +
+
+ Owners: + {#if !_.isEmpty(gridOwners)} + {_.join(gridOwnerNames, '; ')} + {:else} + None defined + {/if} +
+
+ {#if _.includes($ownedReportIds, $selectedGrid.definition?.id)} + +
+ To edit the columns for the grid use the 'Column Editor' tab above. +
+ {:else} +
+ You cannot edit this grid as you are not an owner. +
+ {/if} + {:else} + No grid selected + {/if} + {/if} +
+
+ + + \ No newline at end of file diff --git a/waltz-ng/client/report-grid/components/svelte/ReportGridPicker.svelte b/waltz-ng/client/report-grid/components/svelte/ReportGridPicker.svelte index 5acfb3e8e9..ace77d3474 100644 --- a/waltz-ng/client/report-grid/components/svelte/ReportGridPicker.svelte +++ b/waltz-ng/client/report-grid/components/svelte/ReportGridPicker.svelte @@ -1,14 +1,16 @@
-
- {#if activeMode === Modes.VIEW} +
+ {#if _.size(grids) > 10} + +
+ {/if} +
10}> {#if _.isEmpty(grids)} There are no report grids, would you like to @@ -83,38 +50,33 @@ - - - Grid Name - Description - - + + Grid Name + Description + - {#each grids as grid} - onSelect(grid)}> - {grid.description} - + {grid?.description || "No description"} {/each} - + @@ -122,15 +84,6 @@ {/if} - - {:else if activeMode === Modes.EDIT} -

Creating a new grid

- - {/if} +
-
\ No newline at end of file +
diff --git a/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/ColumnDefinitionEditPanel.svelte b/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/ColumnDefinitionEditPanel.svelte index 3a05f6bd96..6f700f0b40 100644 --- a/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/ColumnDefinitionEditPanel.svelte +++ b/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/ColumnDefinitionEditPanel.svelte @@ -10,7 +10,7 @@ import toasts from "../../../../svelte-stores/toast-store"; import ColumnDetailsEditor from "./ColumnDetailsEditor.svelte"; import NoData from "../../../../common/svelte/NoData.svelte"; - import {columnDefs, hasChanged, selectedColumn} from "../report-grid-store"; + import {columnDefs, hasChanged, selectedColumn, lastMovedColumn} from "../report-grid-store"; import ColumnRemovalConfirmation from "./ColumnRemovalConfirmation.svelte"; export let gridId; @@ -64,18 +64,21 @@ const columnDefs = _.map( columns, d => ({ - columnEntityReference: d.columnEntityReference,position: d.position, - usageKind: d.usageKind, - ratingRollupRule: d.ratingRollupRule, - displayName: d.displayName - })); + columnEntityReference: d.columnEntityReference, + position: d.position, + usageKind: d.usageKind, + ratingRollupRule: d.ratingRollupRule, + displayName: d.displayName + })); return reportGridStore .updateColumnDefinitions(gridId, {columnDefinitions: columnDefs}) .then(() => { onSave(); toasts.success("Report grid columns updated successfully"); - $selectedColumn = null + $selectedColumn = null; + $lastMovedColumn = null; + activeMode = Modes.VIEW; }) .catch(() => toasts.error("Unable to update report grid")); } @@ -122,7 +125,6 @@
Add a Column:
-
diff --git a/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/ColumnDetailsEditor.svelte b/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/ColumnDetailsEditor.svelte index 5ec1617097..f0b42151ec 100644 --- a/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/ColumnDetailsEditor.svelte +++ b/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/ColumnDetailsEditor.svelte @@ -49,9 +49,9 @@ -

{column.columnEntityReference.name}

+

{column?.columnEntityReference?.name}

- +
@@ -82,7 +82,7 @@ {#each _.orderBy($columnDefs, d => d.position) as column} - +
- {#if column.columnEntityReference.kind === 'MEASURABLE'} + {#if column?.columnEntityReference?.kind === 'MEASURABLE'} selectRollupKind(d, column)} defaultMessage="Select rollup kind" diff --git a/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/DropdownPicker.svelte b/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/DropdownPicker.svelte index bb73a7e954..924faf0e02 100644 --- a/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/DropdownPicker.svelte +++ b/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/DropdownPicker.svelte @@ -6,7 +6,7 @@ export let items = []; export let defaultMessage = "Select an option"; export let onSelect = () => console.log("Selecting"); - export let selectedItem = null; + export let selectedItem = null; let showDropdown = false; diff --git a/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/ReportGridColumnSummary.svelte b/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/ReportGridColumnSummary.svelte index fa6c481015..131b248320 100644 --- a/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/ReportGridColumnSummary.svelte +++ b/waltz-ng/client/report-grid/components/svelte/column-definition-edit-panel/ReportGridColumnSummary.svelte @@ -4,19 +4,22 @@ import Icon from "../../../../common/svelte/Icon.svelte"; import _ from "lodash" import {entity} from "../../../../common/services/enums/entity"; - import {columnDefs, selectedColumn, selectedGrid} from "../report-grid-store"; + import {columnDefs, selectedColumn, selectedGrid, lastMovedColumn} from "../report-grid-store"; import {move} from "../../../../common/list-utils"; import {sameRef} from "../../../../common/entity-utils"; export let onRemove = () => console.log("Removing entity") export let onEdit = () => console.log("Editing entity") + let lastMoved = null; + function getIcon(entityKind) { return _.get(entity[entityKind], 'icon', "fw"); } function moveColumn(positionCount, column) { const reorderedList = move($columnDefs, _.indexOf($columnDefs, column), positionCount); + $lastMovedColumn = column; $columnDefs = _.map(reorderedList, d => Object.assign( {}, @@ -51,36 +54,27 @@
{column?.columnEntityReference?.name || column?.columnEntityReference?.questionText} - {#if column.position === 0} - - - - {:else} - - {/if} + - {#if column.position === _.maxBy($columnDefs, d => d.position)?.position} - - - - {:else} - - {/if} + @@ -111,6 +105,11 @@ \ No newline at end of file diff --git a/waltz-ng/client/report-grid/components/svelte/report-grid-store.js b/waltz-ng/client/report-grid/components/svelte/report-grid-store.js index f0782c118f..c44fc1704b 100644 --- a/waltz-ng/client/report-grid/components/svelte/report-grid-store.js +++ b/waltz-ng/client/report-grid/components/svelte/report-grid-store.js @@ -8,6 +8,8 @@ export let filters = writable([]); export let activeSummaryColRefs = writable([]); export let columnDefs = writable([]); export let selectedColumn = writable(null); +export let lastMovedColumn = writable(null); +export let ownedReportIds = writable([]); export let columnsChanged = derived([columnDefs, selectedGrid], ([$columnDefs, $selectedGrid]) => { @@ -44,7 +46,6 @@ export let positionChanged = derived(columnDefs, ($columnDefs) => { export let hasChanged = derived( [columnsChanged, usageKindChanged, ratingRollupRuleChanged, positionChanged], ([$columnsChanged, $usageKindChanged, $ratingRollupRuleChanged, $positionChanged]) => { - console.log({$usageKindChanged}); return $columnsChanged || $usageKindChanged || $ratingRollupRuleChanged || $positionChanged; }) diff --git a/waltz-ng/client/report-grid/components/svelte/report-grid-utils.js b/waltz-ng/client/report-grid/components/svelte/report-grid-utils.js index b7848b7e8b..37c1be8e49 100644 --- a/waltz-ng/client/report-grid/components/svelte/report-grid-utils.js +++ b/waltz-ng/client/report-grid/components/svelte/report-grid-utils.js @@ -5,6 +5,17 @@ import {determineForegroundColor} from "../../../common/colors"; import {scaleLinear} from "d3-scale"; import extent from "d3-array/src/extent"; +export const reportGridKinds = { + PUBLIC: { + key: "PUBLIC", + name: "Public" + }, + PRIVATE: { + key: "PRIVATE", + name: "Private" + } +} + export const ratingRollupRule = { NONE: { key: "NONE", diff --git a/waltz-ng/client/svelte-stores/report-grid-member-store.js b/waltz-ng/client/svelte-stores/report-grid-member-store.js new file mode 100644 index 0000000000..37c8eab291 --- /dev/null +++ b/waltz-ng/client/svelte-stores/report-grid-member-store.js @@ -0,0 +1,31 @@ +/* + * Waltz - Enterprise Architecture + * Copyright (C) 2016, 2017, 2018, 2019 Waltz open source project + * See README.md for more information + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific + * + */ + +import {remote} from "./remote"; + +export function mkReportGridMemberStore() { + + const findByGridId = (id, force = false) => remote + .fetchViewList("GET", `api/report-grid-member/grid-id/${id}`, [], {force}); + + return { + findByGridId, + }; +} + +export const reportGridMemberStore = mkReportGridMemberStore(); diff --git a/waltz-ng/client/svelte-stores/report-grid-store.js b/waltz-ng/client/svelte-stores/report-grid-store.js index a4aac156c0..df530356c0 100644 --- a/waltz-ng/client/svelte-stores/report-grid-store.js +++ b/waltz-ng/client/svelte-stores/report-grid-store.js @@ -23,6 +23,12 @@ export function mkReportGridStore() { const findAll = (force = false) => remote .fetchAppList("GET", "api/report-grid/all", [], {force}); + const findForUser = (force = false) => remote + .fetchAppList("GET", "api/report-grid/user", [], {force}); + + const findForOwner = (force = false) => remote + .fetchAppList("GET", "api/report-grid/owner", [], {force}); + const updateColumnDefinitions = (id, updatecommand) => remote .execute( "POST", @@ -33,11 +39,18 @@ export function mkReportGridStore() { return remote.execute("POST", "api/report-grid/create", createCommand); } + const update = (id, updateCmd) => { + return remote.execute("POST", `api/report-grid/id/${id}/update`, updateCmd); + } + return { findAll, + findForUser, + findForOwner, updateColumnDefinitions, - create + create, + update }; } diff --git a/waltz-service/src/main/java/org/finos/waltz/service/report_grid/ReportGridMemberService.java b/waltz-service/src/main/java/org/finos/waltz/service/report_grid/ReportGridMemberService.java new file mode 100644 index 0000000000..1a4d7ebedd --- /dev/null +++ b/waltz-service/src/main/java/org/finos/waltz/service/report_grid/ReportGridMemberService.java @@ -0,0 +1,67 @@ +/* + * Waltz - Enterprise Architecture + * Copyright (C) 2016, 2017, 2018, 2019 Waltz open source project + * See README.md for more information + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific + * + */ + +package org.finos.waltz.service.report_grid; + +import org.finos.waltz.common.exception.InsufficientPrivelegeException; +import org.finos.waltz.data.application.ApplicationIdSelectorFactory; +import org.finos.waltz.data.report_grid.ReportGridMemberDao; +import org.finos.waltz.model.report_grid.*; +import org.finos.waltz.service.changelog.ChangeLogService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Set; + +import static org.finos.waltz.common.Checks.checkNotNull; + +@Service +public class ReportGridMemberService { + + private final ReportGridMemberDao reportGridMemberDao; + + + @Autowired + public ReportGridMemberService(ReportGridMemberDao reportGridMemberDao) { + checkNotNull(reportGridMemberDao, "reportGridMemberDao cannot be null"); + + this.reportGridMemberDao = reportGridMemberDao; + } + + + public Set findByGridId(Long gridId){ + return reportGridMemberDao.findByGridId(gridId); + } + + + public int register(long gridId, String username, ReportGridMemberRole role) { + return reportGridMemberDao.register(gridId, username, role); + } + + + public void checkIsOwner(long groupId, String userId) throws InsufficientPrivelegeException { + if (!reportGridMemberDao.canUpdate(groupId, userId)) { + throw new InsufficientPrivelegeException(userId + " cannot update group: " + groupId); + } + } + + + public boolean canUpdate(long groupId, String userId){ + return reportGridMemberDao.canUpdate(groupId, userId); + } +} diff --git a/waltz-service/src/main/java/org/finos/waltz/service/report_grid/ReportGridService.java b/waltz-service/src/main/java/org/finos/waltz/service/report_grid/ReportGridService.java index ddb1d29274..7aa779a741 100644 --- a/waltz-service/src/main/java/org/finos/waltz/service/report_grid/ReportGridService.java +++ b/waltz-service/src/main/java/org/finos/waltz/service/report_grid/ReportGridService.java @@ -18,8 +18,8 @@ package org.finos.waltz.service.report_grid; +import org.finos.waltz.common.exception.InsufficientPrivelegeException; import org.finos.waltz.model.*; -import org.finos.waltz.model.changelog.ImmutableChangeLog; import org.finos.waltz.service.changelog.ChangeLogService; import org.finos.waltz.service.rating_scheme.RatingSchemeService; import org.finos.waltz.data.application.ApplicationDao; @@ -34,7 +34,6 @@ import org.springframework.stereotype.Service; import java.util.List; -import java.util.Optional; import java.util.Set; import static java.lang.String.format; @@ -47,6 +46,7 @@ public class ReportGridService { private final RatingSchemeService ratingSchemeService; private final ApplicationDao applicationDao; private final ReportGridDao reportGridDao; + private final ReportGridMemberService reportGridMemberService; private final ChangeLogService changeLogService; private final ApplicationIdSelectorFactory applicationIdSelectorFactory = new ApplicationIdSelectorFactory(); @@ -56,13 +56,16 @@ public class ReportGridService { public ReportGridService(ReportGridDao reportGridDao, ApplicationDao applicationDao, RatingSchemeService ratingSchemeService, + ReportGridMemberService reportGridMemberService, ChangeLogService changeLogService) { checkNotNull(reportGridDao, "reportGridDao cannot be null"); + checkNotNull(reportGridMemberService, "reportGridMemberService cannot be null"); checkNotNull(applicationDao, "applicationDao cannot be null"); checkNotNull(ratingSchemeService, "ratingSchemeService cannot be null"); checkNotNull(changeLogService, "changeLogService cannot be null"); this.reportGridDao = reportGridDao; + this.reportGridMemberService = reportGridMemberService; this.applicationDao = applicationDao; this.ratingSchemeService = ratingSchemeService; this.changeLogService = changeLogService; @@ -74,6 +77,11 @@ public Set findAll(){ } + public Set findForUser(String username){ + return reportGridDao.findForUser(username); + } + + public ReportGrid getByIdAndSelectionOptions( long id, IdSelectionOptions idSelectionOptions) { @@ -88,9 +96,14 @@ public ReportGrid getByIdAndSelectionOptions( .withScope(HierarchyQueryScope.EXACT) : idSelectionOptions; - ReportGridInstance instance = mkInstance(id, opts); ReportGridDefinition definition = reportGridDao.getGridDefinitionById(id); + if(definition == null){ + return null; + } + + ReportGridInstance instance = mkInstance(id, opts); + return ImmutableReportGrid .builder() .definition(definition) @@ -119,8 +132,9 @@ private ReportGridInstance mkInstance(long id, IdSelectionOptions idSelectionOpt public ReportGridDefinition updateColumnDefinitions(long reportGridId, - ReportGridColumnDefinitionsUpdateCommand updateCommand) { - + ReportGridColumnDefinitionsUpdateCommand updateCommand, + String username) throws InsufficientPrivelegeException { + checkIsOwner(reportGridId, username); int newColumnCount = reportGridDao.updateColumnDefinitions(reportGridId, updateCommand.columnDefinitions()); return reportGridDao.getGridDefinitionById(reportGridId); } @@ -128,6 +142,23 @@ public ReportGridDefinition updateColumnDefinitions(long reportGridId, public ReportGridDefinition create(ReportGridCreateCommand createCommand, String username){ long gridId = reportGridDao.create(createCommand, username); + reportGridMemberService.register(gridId, username, ReportGridMemberRole.OWNER); return reportGridDao.getGridDefinitionById(gridId); } + + + public ReportGridDefinition update(long id, ReportGridUpdateCommand updateCommand, String username) throws InsufficientPrivelegeException { + checkIsOwner(id, username); + long gridId = reportGridDao.update(id, updateCommand, username); + return reportGridDao.getGridDefinitionById(id); + } + + + private void checkIsOwner(long reportGridId, String username) throws InsufficientPrivelegeException { + reportGridMemberService.checkIsOwner(reportGridId, username); + } + + public Set findForOwner(String username) { + return reportGridDao.findForOwner(username); + } } diff --git a/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/ReportGridEndpoint.java b/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/ReportGridEndpoint.java index b5b16d66f7..e028724eec 100644 --- a/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/ReportGridEndpoint.java +++ b/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/ReportGridEndpoint.java @@ -18,18 +18,17 @@ package org.finos.waltz.web.endpoints.api; -import org.finos.waltz.model.report_grid.ReportGridColumnDefinitionsUpdateCommand; -import org.finos.waltz.model.report_grid.ReportGridCreateCommand; -import org.finos.waltz.model.report_grid.ReportGridDefinition; +import org.finos.waltz.common.exception.InsufficientPrivelegeException; +import org.finos.waltz.model.report_grid.*; import org.finos.waltz.service.report_grid.ReportGridService; import org.finos.waltz.web.endpoints.Endpoint; -import org.finos.waltz.model.report_grid.ReportGrid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import spark.Request; import spark.Response; import java.io.IOException; +import java.util.Set; import static org.finos.waltz.web.WebUtilities.*; import static org.finos.waltz.web.endpoints.EndpointUtilities.*; @@ -51,15 +50,21 @@ public ReportGridEndpoint(ReportGridService reportGridService) { @Override public void register() { String findAllPath = mkPath(BASE_URL, "all"); + String findForUserPath = mkPath(BASE_URL, "user"); String createPath = mkPath(BASE_URL, "create"); + String updatePath = mkPath(BASE_URL, "id", ":id", "update"); + String findForOwnerPath = mkPath(BASE_URL, "owner"); String getViewByIdPath = mkPath(BASE_URL, "view", "id", ":id"); String updateColumnDefsPath = mkPath(BASE_URL, "id", ":id", "column-definitions", "update"); getForDatum(findAllPath, (req, resp) -> reportGridService.findAll()); + getForList(findForUserPath, (req, resp) -> reportGridService.findForUser(getUsername(req))); + getForList(findForOwnerPath, this::findForOwnerRoute); postForDatum(getViewByIdPath, this::getViewByIdRoute); postForDatum(updateColumnDefsPath, this::updateColumnDefsRoute); postForDatum(createPath, this::createRoute); + postForDatum(updatePath, this::updateRoute); } @@ -69,13 +74,24 @@ public ReportGrid getViewByIdRoute(Request req, Response resp) throws IOExceptio readIdSelectionOptionsFromBody(req)); } - public ReportGridDefinition updateColumnDefsRoute(Request req, Response resp) throws IOException { - return reportGridService.updateColumnDefinitions(getId(req), readBody(req, ReportGridColumnDefinitionsUpdateCommand.class)); + public ReportGridDefinition updateColumnDefsRoute(Request req, Response resp) throws IOException, InsufficientPrivelegeException { + return reportGridService.updateColumnDefinitions( + getId(req), + readBody(req, ReportGridColumnDefinitionsUpdateCommand.class), + getUsername(req)); } public ReportGridDefinition createRoute(Request req, Response resp) throws IOException { - return reportGridService.create(readBody(req, ReportGridCreateCommand.class), getUsername(req)); + return reportGridService. + create(readBody(req, ReportGridCreateCommand.class), getUsername(req)); } + public ReportGridDefinition updateRoute(Request req, Response resp) throws IOException, InsufficientPrivelegeException { + return reportGridService. + update(getId(req), readBody(req, ReportGridUpdateCommand.class), getUsername(req)); + } + public Set findForOwnerRoute(Request req, Response resp) { + return reportGridService.findForOwner(getUsername(req)); + } } diff --git a/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/ReportGridMemberEndpoint.java b/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/ReportGridMemberEndpoint.java new file mode 100644 index 0000000000..e837ac9ab3 --- /dev/null +++ b/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/ReportGridMemberEndpoint.java @@ -0,0 +1,62 @@ +/* + * Waltz - Enterprise Architecture + * Copyright (C) 2016, 2017, 2018, 2019 Waltz open source project + * See README.md for more information + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific + * + */ + +package org.finos.waltz.web.endpoints.api; + +import org.finos.waltz.model.report_grid.ReportGridMember; +import org.finos.waltz.service.report_grid.ReportGridMemberService; +import org.finos.waltz.web.endpoints.Endpoint; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import spark.Request; +import spark.Response; + +import java.io.IOException; +import java.util.Set; + +import static org.finos.waltz.web.WebUtilities.getId; +import static org.finos.waltz.web.WebUtilities.mkPath; +import static org.finos.waltz.web.endpoints.EndpointUtilities.getForList; + +@Service +public class ReportGridMemberEndpoint implements Endpoint { + + private static final String BASE_URL = mkPath("api", "report-grid-member"); + + private final ReportGridMemberService reportGridMemberService; + + + @Autowired + public ReportGridMemberEndpoint(ReportGridMemberService reportGridMemberService) { + + this.reportGridMemberService = reportGridMemberService; + } + + + @Override + public void register() { + String findForGridIdPath = mkPath(BASE_URL, "grid-id", ":id"); + + getForList(findForGridIdPath, this::findForGridIdRoute); + } + + + public Set findForGridIdRoute(Request req, Response resp) throws IOException { + return reportGridMemberService.findByGridId(getId(req)); + } +} \ No newline at end of file