diff --git a/waltz-data/src/main/ddl/liquibase/db.changelog-1.43.xml b/waltz-data/src/main/ddl/liquibase/db.changelog-1.43.xml index e073ff5a35..7c5e786348 100644 --- a/waltz-data/src/main/ddl/liquibase/db.changelog-1.43.xml +++ b/waltz-data/src/main/ddl/liquibase/db.changelog-1.43.xml @@ -157,4 +157,5 @@ + diff --git a/waltz-data/src/main/java/org/finos/waltz/data/assessment_definition/AssessmentDefinitionDao.java b/waltz-data/src/main/java/org/finos/waltz/data/assessment_definition/AssessmentDefinitionDao.java index e8fd87de90..2ffe9b6ea4 100644 --- a/waltz-data/src/main/java/org/finos/waltz/data/assessment_definition/AssessmentDefinitionDao.java +++ b/waltz-data/src/main/java/org/finos/waltz/data/assessment_definition/AssessmentDefinitionDao.java @@ -65,6 +65,7 @@ public class AssessmentDefinitionDao { .isReadOnly(record.getIsReadonly()) .provenance(record.getProvenance()) .visibility(AssessmentVisibility.valueOf(record.getVisibility())) + .definitionGroup(record.getDefinitionGroup()) .qualifierReference(maybeReadRef( record, ASSESSMENT_DEFINITION.QUALIFIER_KIND, @@ -114,6 +115,7 @@ public Collection findByEntityKindAndQualifier(EntityKind /** * Saves the given assessment definition. Either updating or inserting. * Returns the identifier for the record. + * * @param def the definition to save * @return the identifier for the record */ @@ -138,15 +140,16 @@ public Long save(AssessmentDefinition def) { r.setLastUpdatedAt(Timestamp.valueOf(def.lastUpdatedAt())); r.setLastUpdatedBy(def.lastUpdatedBy()); r.setProvenance(StringUtilities.ifEmpty(def.provenance(), "waltz")); + r.setDefinitionGroup(r.getDefinitionGroup()); def.qualifierReference() - .ifPresent(qualifier -> { - r.setQualifierId(qualifier.id()); - r.setQualifierKind(qualifier.kind().name()); - }); + .ifPresent(qualifier -> { + r.setQualifierId(qualifier.id()); + r.setQualifierKind(qualifier.kind().name()); + }); def.id() - .ifPresent(r::setId); + .ifPresent(r::setId); if (r.getId() == null) { r.insert(); diff --git a/waltz-model/src/main/java/org/finos/waltz/model/assessment_definition/AssessmentDefinition.java b/waltz-model/src/main/java/org/finos/waltz/model/assessment_definition/AssessmentDefinition.java index 00e0d2e217..11e8c70bfe 100644 --- a/waltz-model/src/main/java/org/finos/waltz/model/assessment_definition/AssessmentDefinition.java +++ b/waltz-model/src/main/java/org/finos/waltz/model/assessment_definition/AssessmentDefinition.java @@ -47,6 +47,11 @@ public abstract class AssessmentDefinition implements public abstract AssessmentVisibility visibility(); + @Value.Default + public String definitionGroup() { + return "Uncategorized"; + } + @Value.Default public EntityKind kind() { return EntityKind.ASSESSMENT_DEFINITION; diff --git a/waltz-ng/client/assessments/assessment-utils.js b/waltz-ng/client/assessments/assessment-utils.js index 16cefef7f3..b8167d65ce 100644 --- a/waltz-ng/client/assessments/assessment-utils.js +++ b/waltz-ng/client/assessments/assessment-utils.js @@ -230,4 +230,19 @@ function loadAssessments($q, serviceBroker, kind, ratingsPromise, primaryOnly = assessmentsByEntityId: enrichedByEntityId // assessmentsByEntityId: entity id -> assessment def external id -> assessment }; }); +} + + +export function isFavourite(favouriteDefinitionIds, id) { + return _.includes(favouriteDefinitionIds, id); +} + + +export function getIdsFromString(includedFavouritesString) { + return _.isNil(includedFavouritesString) + ? [] + : _.chain(includedFavouritesString.value) + .split(",") + .map(idString => _.toNumber(idString)) + .value(); } \ No newline at end of file diff --git a/waltz-ng/client/assessments/components/editor/AssessmentEditorView.svelte b/waltz-ng/client/assessments/components/editor/AssessmentEditorView.svelte index a211caba60..f9d7159138 100644 --- a/waltz-ng/client/assessments/components/editor/AssessmentEditorView.svelte +++ b/waltz-ng/client/assessments/components/editor/AssessmentEditorView.svelte @@ -4,7 +4,10 @@ import Markdown from "../../../common/svelte/Markdown.svelte"; import Icon from "../../../common/svelte/Icon.svelte"; import {fade} from 'svelte/transition'; + export let assessment; + + $: console.log({assessment}); diff --git a/waltz-ng/client/assessments/components/favourites-list/assessment-rating-favourites-list.js b/waltz-ng/client/assessments/components/favourites-list/assessment-rating-favourites-list.js index 798da648a9..dbe7951cad 100644 --- a/waltz-ng/client/assessments/components/favourites-list/assessment-rating-favourites-list.js +++ b/waltz-ng/client/assessments/components/favourites-list/assessment-rating-favourites-list.js @@ -19,7 +19,7 @@ import {initialiseData} from "../../../common"; import _ from "lodash"; import template from "./assessment-rating-favourites-list.html"; -import {mkAssessmentDefinitionsIdsKey} from "../../../user"; +import {mkAssessmentDefinitionsIdsBaseKey} from "../../../user"; import {CORE_API} from "../../../common/services/core-api-utils"; @@ -82,7 +82,7 @@ function controller(serviceBroker) { serviceBroker .loadAppData(CORE_API.UserPreferenceStore.findAllForUser, [], {force: true}) .then(r => vm.favouriteAssessmentDefnIds = getFavouriteAssessmentDefnIds( - mkAssessmentDefinitionsIdsKey(vm.parentEntityRef), + mkAssessmentDefinitionsIdsBaseKey(vm.parentEntityRef), r.data, vm.defaultPrimaryList)) .then(() => filterAssessments()); diff --git a/waltz-ng/client/assessments/components/list/AssessmentDefinitionTooltipContent.svelte b/waltz-ng/client/assessments/components/list/AssessmentDefinitionTooltipContent.svelte new file mode 100644 index 0000000000..b6468f57b0 --- /dev/null +++ b/waltz-ng/client/assessments/components/list/AssessmentDefinitionTooltipContent.svelte @@ -0,0 +1,22 @@ + + + +

+ {definition.name} + ({definition.externalId}) +

+ + +{#if definition.isReadOnly} +
+ + Assessments relating to this definition are read-only and cannot be edited. +
+{/if} \ No newline at end of file diff --git a/waltz-ng/client/assessments/components/list/AssessmentRatingList.svelte b/waltz-ng/client/assessments/components/list/AssessmentRatingList.svelte new file mode 100644 index 0000000000..3992297f5b --- /dev/null +++ b/waltz-ng/client/assessments/components/list/AssessmentRatingList.svelte @@ -0,0 +1,167 @@ + + + +
+ +
+ + + + + + + + {#each groupedAssessments as group} + + + + + + {#if _.includes(expansions, group.groupName)} + + {/if} + + {/each} +
+ + + + {group.groupName} + +
+
+ +
+ diff --git a/waltz-ng/client/assessments/components/list/AssessmentRatingListGroup.svelte b/waltz-ng/client/assessments/components/list/AssessmentRatingListGroup.svelte new file mode 100644 index 0000000000..419b9326d8 --- /dev/null +++ b/waltz-ng/client/assessments/components/list/AssessmentRatingListGroup.svelte @@ -0,0 +1,170 @@ + + +{#each group.provided as row} + selectAssessment(row)}> + + + + + + + + + {row.definition.name} + + + + + + + + + {#if row.rating.comment} + + {/if} + + + + +{/each} +{#if !_.isEmpty(group.notProvided)} + {#if notProvidedCollapsed} + + + + + + Not Rated + + + + + + {:else} + + + + + + Not Rated + + + {#each group.notProvided as row} + + + + + + + + + + {row.definition.name} + + + + + + Not Provided + + + {/each} + {/if} +{/if} + + + \ No newline at end of file diff --git a/waltz-ng/client/assessments/components/list/AssessmentRatingTooltipContent.svelte b/waltz-ng/client/assessments/components/list/AssessmentRatingTooltipContent.svelte new file mode 100644 index 0000000000..7ad3b9f2d2 --- /dev/null +++ b/waltz-ng/client/assessments/components/list/AssessmentRatingTooltipContent.svelte @@ -0,0 +1,28 @@ + + + +

{ratingItem.name}

+
+ {ratingItem.description} +
+{#if rating.comment} +
+ + + + +{/if} +
+ Last Modified: + +
\ No newline at end of file diff --git a/waltz-ng/client/assessments/components/list/assessment-rating-list.js b/waltz-ng/client/assessments/components/list/assessment-rating-list.js index 0fcbc36bf2..8de0e92d10 100644 --- a/waltz-ng/client/assessments/components/list/assessment-rating-list.js +++ b/waltz-ng/client/assessments/components/list/assessment-rating-list.js @@ -19,10 +19,11 @@ import {initialiseData} from "../../../common"; import _ from "lodash"; import template from "./assessment-rating-list.html"; -import {mkAssessmentDefinitionsIdsKey} from "../../../user"; +import {mkAssessmentDefinitionsIdsBaseKey} from "../../../user"; import {CORE_API} from "../../../common/services/core-api-utils"; import {displayError} from "../../../common/error-utils"; import toasts from "../../../svelte-stores/toast-store"; +import {isFavourite} from "../../assessment-utils"; const bindings = { assessments: "<", @@ -53,16 +54,13 @@ function getFavouriteAssessmentDefnIds(key, preferences, defaultList = []) { function controller(serviceBroker) { const vm = initialiseData(this, initialState); - function isFavourite(id) { - return _.includes(vm.favouriteAssessmentDefnIds, id); - } const partitionAssessments = () => { if (vm.assessments) { const [notProvided, provided] = _ .chain(vm.assessments) .sortBy(d => d.definition.name) - .map(a => Object.assign({}, a, { isFavourite: isFavourite(a.definition.id)})) + .map(a => Object.assign({}, a, {isFavourite: isFavourite(vm.favouriteAssessmentDefnIds, a.definition.id)})) .partition(assessment => _.isNil(assessment.rating)) .value(); @@ -72,7 +70,7 @@ function controller(serviceBroker) { }; vm.$onInit = () => { - vm.favouritesKey = mkAssessmentDefinitionsIdsKey(vm.parentEntityRef); + vm.favouritesKey = mkAssessmentDefinitionsIdsBaseKey(vm.parentEntityRef); }; vm.$onChanges = () => { @@ -90,7 +88,7 @@ function controller(serviceBroker) { vm.toggleFavourite = (assessmentRatingId) => { - const alreadyFavourite = isFavourite(assessmentRatingId); + const alreadyFavourite = isFavourite(vm.favouriteAssessmentDefnIds, assessmentRatingId); const newFavouritesList = (alreadyFavourite) ? _.without(vm.favouriteAssessmentDefnIds, assessmentRatingId) diff --git a/waltz-ng/client/assessments/components/list/assessment-rating-store.js b/waltz-ng/client/assessments/components/list/assessment-rating-store.js new file mode 100644 index 0000000000..998e15e24b --- /dev/null +++ b/waltz-ng/client/assessments/components/list/assessment-rating-store.js @@ -0,0 +1,60 @@ +import {derived, writable} from "svelte/store"; +import _ from "lodash"; +import {mkAssessmentDefinitionsIdsBaseKey} from "../../../user"; +import {userPreferenceStore} from "../../../svelte-stores/user-preference-store"; +import {getIdsFromString} from "../../assessment-utils"; + +function writePreference(favouriteIncludedKey, $favouriteIncludedIds) { + const userPreference = {key: favouriteIncludedKey, value: $favouriteIncludedIds.toString()}; + userPreferenceStore.saveForUser(userPreference); +} + +export function createStores(primaryEntityRef) { + + const baseKey = mkAssessmentDefinitionsIdsBaseKey(primaryEntityRef); + const favouriteIncludedKey = `${baseKey}.included`; + const favouriteExcludedKey = `${baseKey}.excluded`; + + const defaultPrimaryList = writable([]); + const favouriteExcludedIds = writable([]); + const favouriteIncludedIds = writable([]); + + const favouriteIds = derived( + [defaultPrimaryList, favouriteExcludedIds, favouriteIncludedIds], + + ([$defaultPrimaryList, $favouriteExcludedIds, $favouriteIncludedIds]) => { + return _.reject( + _.concat($defaultPrimaryList, $favouriteIncludedIds), + d => _.includes($favouriteExcludedIds, d)); + }) + + favouriteIds.subscribe(() => { + }) + + derived([favouriteIncludedIds], ($favouriteIncludedIds) => { + writePreference(favouriteIncludedKey, $favouriteIncludedIds); + }).subscribe(() => { + }); + + derived([favouriteExcludedIds], ($favouriteExcludedIds) => { + writePreference(favouriteExcludedKey, $favouriteExcludedIds); + }).subscribe(() => { + }); + + function setFromPreferences(userPreferences) { + + const includedFavouritesString = _.find(userPreferences, d => d.key === favouriteIncludedKey) + const excludedFavouritesString = _.find(userPreferences, d => d.key === favouriteExcludedKey) + + favouriteIncludedIds.set(getIdsFromString(includedFavouritesString)); + favouriteExcludedIds.set(getIdsFromString(excludedFavouritesString)); + } + + return { + defaultPrimaryList, + favouriteIncludedIds, + favouriteExcludedIds, + favouriteIds, + setFromPreferences + } +} diff --git a/waltz-ng/client/assessments/components/section/assessment-rating-section.html b/waltz-ng/client/assessments/components/section/assessment-rating-section.html index a542e12957..056f571779 100644 --- a/waltz-ng/client/assessments/components/section/assessment-rating-section.html +++ b/waltz-ng/client/assessments/components/section/assessment-rating-section.html @@ -18,39 +18,40 @@
-
-
- - -

- Assessments associated to this: - . - Click the stars in the first column to configure which assessments appear at the top of the screen for all - - pages. -

+
+ + +

+ Assessments associated to this: + . + Click the stars in the first column to configure which assessments appear at the top of the screen for all + + pages. + +

+
+
+
+ + Select a rating for more information or to edit
-
-
- - Select a rating for more information or to edit -
-
- - -
+
+ +
\ No newline at end of file diff --git a/waltz-ng/client/assessments/components/section/assessment-rating-section.js b/waltz-ng/client/assessments/components/section/assessment-rating-section.js index cb19fe4fab..641728abc4 100644 --- a/waltz-ng/client/assessments/components/section/assessment-rating-section.js +++ b/waltz-ng/client/assessments/components/section/assessment-rating-section.js @@ -26,6 +26,7 @@ import {resolveResponses} from "../../../common/promise-utils"; import _ from "lodash"; import toasts from "../../../svelte-stores/toast-store"; import AssessmentEditor from "../editor/AssessmentEditor.svelte"; +import AssessmentList from "../list/AssessmentRatingList.svelte"; const bindings = { parentEntityRef: "<", @@ -34,6 +35,7 @@ const bindings = { const initialState = { AssessmentEditor, + AssessmentList, permissions: [] }; diff --git a/waltz-ng/client/common/svelte/Tooltip.svelte b/waltz-ng/client/common/svelte/Tooltip.svelte new file mode 100644 index 0000000000..bd5c2e6f1a --- /dev/null +++ b/waltz-ng/client/common/svelte/Tooltip.svelte @@ -0,0 +1,44 @@ + + + + + + +
+
+ {#if open} + + {/if} +
+
diff --git a/waltz-ng/client/dynamic-section/dynamic-section-definitions.js b/waltz-ng/client/dynamic-section/dynamic-section-definitions.js index b32a9ce02d..5cce0f2c76 100644 --- a/waltz-ng/client/dynamic-section/dynamic-section-definitions.js +++ b/waltz-ng/client/dynamic-section/dynamic-section-definitions.js @@ -562,13 +562,13 @@ const orgUnitSections = [ const measurableSections = [ pack(appsSection, - [ - appCostsSummarySection, - appComplexitySummarySection, - entityStatisticSummarySection, - reportGridViewSection, - technologySummarySection - ]), + [ + appCostsSummarySection, + appComplexitySummarySection, + entityStatisticSummarySection, + reportGridViewSection, + technologySummarySection + ]), bookmarksSection, assessmentRatingSection, changeSetSection, diff --git a/waltz-ng/client/svelte-stores/user-preference-store.js b/waltz-ng/client/svelte-stores/user-preference-store.js new file mode 100644 index 0000000000..83edc5cb0a --- /dev/null +++ b/waltz-ng/client/svelte-stores/user-preference-store.js @@ -0,0 +1,46 @@ +/* + * 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 mkUserPreferenceStore() { + + const findAllForUser = (force) => { + return remote + .fetchViewList( + "GET", + "api/user-preference", + [], + {force}); + }; + + const saveForUser = (preference) => { + return remote + .execute( + "POST", + "api/user-preference/save", + preference); + }; + + return { + findAllForUser, + saveForUser + }; +} + +export const userPreferenceStore = mkUserPreferenceStore(); diff --git a/waltz-ng/client/system/svelte/assessment-definitions/AssessmentDefinitionEditor.svelte b/waltz-ng/client/system/svelte/assessment-definitions/AssessmentDefinitionEditor.svelte index f444ee7b41..46b732e521 100644 --- a/waltz-ng/client/system/svelte/assessment-definitions/AssessmentDefinitionEditor.svelte +++ b/waltz-ng/client/system/svelte/assessment-definitions/AssessmentDefinitionEditor.svelte @@ -5,7 +5,12 @@ import {ratingSchemeStore} from "../../../svelte-stores/rating-schemes"; import {assessmentRatingStore} from "../../../svelte-stores/assessment-rating"; - import {getRequiredFields, possibleVisibility, possibleEntityKinds, selectedDefinition} from "./assessment-definition-utils"; + import { + getRequiredFields, + possibleVisibility, + possibleEntityKinds, + selectedDefinition + } from "./assessment-definition-utils"; import MeasurableCategoryPicker from "./MeasurableCategoryPicker.svelte"; export let doCancel; @@ -101,7 +106,7 @@ disabled={hasRatings} bind:value={$selectedDefinition.entityKind}> - {#each possibleEntityKinds as k} + {#each possibleEntityKinds as k} @@ -132,7 +137,8 @@ {#if hasRatings}
- The associated category qualifier for this definition cannot be changed as ratings already exist. + The associated category qualifier for this definition cannot be changed as ratings + already exist. {/if} diff --git a/waltz-ng/client/system/svelte/assessment-definitions/AssessmentDefinitionsAdminView.svelte b/waltz-ng/client/system/svelte/assessment-definitions/AssessmentDefinitionsAdminView.svelte index 5eef0e57f8..839f99b04a 100644 --- a/waltz-ng/client/system/svelte/assessment-definitions/AssessmentDefinitionsAdminView.svelte +++ b/waltz-ng/client/system/svelte/assessment-definitions/AssessmentDefinitionsAdminView.svelte @@ -149,12 +149,12 @@ - - - - - - + + + + + + {#each definitionList as def} diff --git a/waltz-ng/client/user/index.js b/waltz-ng/client/user/index.js index b424b66278..9733f0fce6 100644 --- a/waltz-ng/client/user/index.js +++ b/waltz-ng/client/user/index.js @@ -39,9 +39,9 @@ export const groupLogicalFlowFilterExcludedTagIdsKey = "main.group-views.logical export const favouriteAssessmentDefinitionIdsKey = "main.app-view.assessment-rating.favouriteAssessmentDefnIds"; export const lastViewedFlowTabKey = "main.app-view.data-flows.lastTab"; -export function mkAssessmentDefinitionsIdsKey(entityReference) { +export function mkAssessmentDefinitionsIdsBaseKey(entityReference) { checkIsEntityRef(entityReference); - return favouriteAssessmentDefinitionIdsKey + _.camelCase(entityReference.kind); + return `${favouriteAssessmentDefinitionIdsKey}.${_.camelCase(entityReference.kind)}`; } export default () => { diff --git a/waltz-ng/package-lock.json b/waltz-ng/package-lock.json index 046b5a832a..0a8dff008c 100644 --- a/waltz-ng/package-lock.json +++ b/waltz-ng/package-lock.json @@ -1347,6 +1347,11 @@ "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", "dev": true }, + "@popperjs/core": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz", + "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==" + }, "@types/anymatch": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/@types/anymatch/-/anymatch-1.3.1.tgz", @@ -10739,6 +10744,14 @@ "setimmediate": "^1.0.4" } }, + "tippy.js": { + "version": "6.3.7", + "resolved": "https://registry.npmjs.org/tippy.js/-/tippy.js-6.3.7.tgz", + "integrity": "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==", + "requires": { + "@popperjs/core": "^2.9.0" + } + }, "tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", diff --git a/waltz-ng/package.json b/waltz-ng/package.json index f9fd9149c4..d3768fd089 100644 --- a/waltz-ng/package.json +++ b/waltz-ng/package.json @@ -42,29 +42,30 @@ "d3-ease": "1.0.7", "d3-force": "1.0.6", "d3-format": "1.0.2", - "d3-interpolate": "1.1.6", - "d3-path": "1.0.9", - "d3-sankey": "0.12.3", - "d3-scale": "1.0.7", - "d3-selection": "1.0.6", - "d3-selection-multi": "1.0.1", - "d3-shape": "1.0.6", - "d3-time-format": "2.0.5", - "d3-transition": "1.0.4", - "d3-zoom": "1.8.3", - "font-awesome": "4.7.0", - "html2canvas": "^1.4.1", - "json-stable-stringify": "1.0.1", - "lodash": "4.17.21", - "moment": "2.29.1", - "ng-showdown": "1.1.0", - "ng-tags-input": "3.2.0", - "patch-package": "6.4.7", - "satellizer": "0.15.5", - "svelte-flatpickr": "3.2.4", - "ui-select": "0.19.8", - "whatwg-fetch": "3.6.2", - "xlsx": "0.17.3" + "d3-interpolate": "1.1.6", + "d3-path": "1.0.9", + "d3-sankey": "0.12.3", + "d3-scale": "1.0.7", + "d3-selection": "1.0.6", + "d3-selection-multi": "1.0.1", + "d3-shape": "1.0.6", + "d3-time-format": "2.0.5", + "d3-transition": "1.0.4", + "d3-zoom": "1.8.3", + "font-awesome": "4.7.0", + "html2canvas": "^1.4.1", + "json-stable-stringify": "1.0.1", + "lodash": "4.17.21", + "moment": "2.29.1", + "ng-showdown": "1.1.0", + "ng-tags-input": "3.2.0", + "patch-package": "6.4.7", + "satellizer": "0.15.5", + "svelte-flatpickr": "3.2.4", + "tippy.js": "^6.3.7", + "ui-select": "0.19.8", + "whatwg-fetch": "3.6.2", + "xlsx": "0.17.3" }, "devDependencies": { "@babel/core": "7.16.0",
NameRating SchemeApplicable KindOperations
NameRating SchemeApplicable KindOperations