diff --git a/waltz-data/src/main/java/org/finos/waltz/data/datatype_decorator/LogicalFlowDecoratorDao.java b/waltz-data/src/main/java/org/finos/waltz/data/datatype_decorator/LogicalFlowDecoratorDao.java index b145615f40..c91db2e4fa 100644 --- a/waltz-data/src/main/java/org/finos/waltz/data/datatype_decorator/LogicalFlowDecoratorDao.java +++ b/waltz-data/src/main/java/org/finos/waltz/data/datatype_decorator/LogicalFlowDecoratorDao.java @@ -95,6 +95,7 @@ public class LogicalFlowDecoratorDao extends DataTypeDecoratorDao { record.getDecoratorEntityId(), r.get(ENTITY_NAME_FIELD))) .rating(AuthoritativenessRatingValue.ofNullable(record.getRating())) + .targetInboundRating(AuthoritativenessRatingValue.of(record.getTargetInboundRating())) .provenance(record.getProvenance()) .lastUpdatedAt(record.getLastUpdatedAt().toLocalDateTime()) .lastUpdatedBy(record.getLastUpdatedBy()) diff --git a/waltz-data/src/main/java/org/finos/waltz/data/flow_classification_rule/FlowClassificationRuleDao.java b/waltz-data/src/main/java/org/finos/waltz/data/flow_classification_rule/FlowClassificationRuleDao.java index 080f538bba..15788e6839 100644 --- a/waltz-data/src/main/java/org/finos/waltz/data/flow_classification_rule/FlowClassificationRuleDao.java +++ b/waltz-data/src/main/java/org/finos/waltz/data/flow_classification_rule/FlowClassificationRuleDao.java @@ -53,7 +53,6 @@ import org.jooq.SelectConditionStep; import org.jooq.SelectOnConditionStep; import org.jooq.SelectSeekStep2; -import org.jooq.SelectSeekStep5; import org.jooq.SelectSeekStep6; import org.jooq.UpdateConditionStep; import org.jooq.UpdateSetMoreStep; @@ -103,16 +102,8 @@ public class FlowClassificationRuleDao { private final static EntityHierarchy ehOrgUnit = ENTITY_HIERARCHY.as("ehOrgUnit"); private final static EntityHierarchy ehDataType = ENTITY_HIERARCHY.as("ehDataType"); - private final static org.finos.waltz.schema.tables.DataType declaredDataType = org.finos.waltz.schema.tables.DataType.DATA_TYPE.as("declaredDataType"); - private final static org.finos.waltz.schema.tables.DataType impliedDataType = org.finos.waltz.schema.tables.DataType.DATA_TYPE.as("impliedDataType"); - - private final static Field declaredOrgUnitId = ehOrgUnit.ID.as("declaredOrgUnitId"); public static final Field vantagePointId = DSL.coalesce(ehOrgUnit.ID, FLOW_CLASSIFICATION_RULE.PARENT_ID); - private final static Field declaredOrgUnitLevel = ehOrgUnit.LEVEL.as("declaredOrgUnitLevel"); public static final Field vantagePointLevel = DSL.coalesce(ehOrgUnit.LEVEL, 0).as("parentLevel"); - private final static Field declaredDataTypeId = ehDataType.ID.as("declaredDataTypeId"); - private final static Field declaredDataTypeLevel = ehDataType.LEVEL.as("declaredDataTypeLevel"); - private static final Field PARENT_NAME_FIELD = InlineSelectFieldFactory.mkNameField( FLOW_CLASSIFICATION_RULE.PARENT_ID, FLOW_CLASSIFICATION_RULE.PARENT_KIND, @@ -180,7 +171,7 @@ public class FlowClassificationRuleDao { .subjectReference(mkRef(EntityKind.valueOf(r.get(FLOW_CLASSIFICATION_RULE.SUBJECT_ENTITY_KIND)), r.get(FLOW_CLASSIFICATION_RULE.SUBJECT_ENTITY_ID))) .classificationCode(r.get(FLOW_CLASSIFICATION.CODE)) .dataType(mkRef(EntityKind.DATA_TYPE, r.get(ehDataType.ID))) - .dataTypeRank(r.get(declaredDataTypeLevel)) + .dataTypeRank(r.get(ehDataType.LEVEL)) .ruleId(r.get(FLOW_CLASSIFICATION_RULE.ID)) .build(); @@ -368,37 +359,30 @@ public List findExpandedFlowClassificationRu .or(actorVantagePointCondition) .or(orgUnitVantagePointCondition); - SelectSeekStep5, String, Integer, Integer, Long, Long> select = dsl + SelectConditionStep> select = dsl .select(vantagePointId, FLOW_CLASSIFICATION_RULE.PARENT_KIND, vantagePointLevel, ehDataType.ID, - declaredDataTypeLevel, + ehDataType.LEVEL, FLOW_CLASSIFICATION_RULE.SUBJECT_ENTITY_ID, FLOW_CLASSIFICATION_RULE.SUBJECT_ENTITY_KIND, FLOW_CLASSIFICATION.CODE, FLOW_CLASSIFICATION_RULE.ID) .from(FLOW_CLASSIFICATION_RULE) - .leftJoin(ehOrgUnit) - .on(ehOrgUnit.ANCESTOR_ID.eq(FLOW_CLASSIFICATION_RULE.PARENT_ID) - .and(ehOrgUnit.KIND.eq(EntityKind.ORG_UNIT.name()) - .and(FLOW_CLASSIFICATION_RULE.PARENT_KIND.eq(EntityKind.ORG_UNIT.name())))) - .innerJoin(declaredDataType) - .on(declaredDataType.ID.eq(FLOW_CLASSIFICATION_RULE.DATA_TYPE_ID)) + .innerJoin(FLOW_CLASSIFICATION).on(FLOW_CLASSIFICATION.DIRECTION.eq(direction.name()) + .and(FLOW_CLASSIFICATION_RULE.FLOW_CLASSIFICATION_ID.eq(FLOW_CLASSIFICATION.ID))) .innerJoin(ehDataType) - .on(ehDataType.ANCESTOR_ID.eq(declaredDataType.ID).and(ehDataType.KIND.eq(EntityKind.DATA_TYPE.name()))) - .innerJoin(FLOW_CLASSIFICATION).on(FLOW_CLASSIFICATION_RULE.FLOW_CLASSIFICATION_ID.eq(FLOW_CLASSIFICATION.ID)) - .where(FLOW_CLASSIFICATION.DIRECTION.eq(direction.name()) - .and(vantagePointCondition)) - .orderBy( - FLOW_CLASSIFICATION_RULE.PARENT_KIND, - ehOrgUnit.LEVEL.desc(), - ehDataType.LEVEL.desc(), - ehOrgUnit.ID, - ehDataType.ID); + .on(ehDataType.KIND.eq(EntityKind.DATA_TYPE.name()) + .and(ehDataType.ANCESTOR_ID.eq(FLOW_CLASSIFICATION_RULE.DATA_TYPE_ID))) + .leftJoin(ehOrgUnit) + .on(FLOW_CLASSIFICATION_RULE.PARENT_KIND.eq(EntityKind.ORG_UNIT.name()) + .and(ehOrgUnit.KIND.eq(EntityKind.ORG_UNIT.name()) + .and(ehOrgUnit.ANCESTOR_ID.eq(FLOW_CLASSIFICATION_RULE.PARENT_ID) + .and(ehOrgUnit.ID.in(orgVantagePointIds))))) + .where(vantagePointCondition); - return select - .fetch(TO_VANTAGE_MAPPER); + return select.fetch(TO_VANTAGE_MAPPER); } @@ -413,7 +397,7 @@ private List findFlowClassificationRuleVanta FLOW_CLASSIFICATION_RULE.PARENT_KIND, vantagePointLevel, ehDataType.ID, - declaredDataTypeLevel, + ehDataType.LEVEL, FLOW_CLASSIFICATION_RULE.SUBJECT_ENTITY_ID, FLOW_CLASSIFICATION_RULE.SUBJECT_ENTITY_KIND, FLOW_CLASSIFICATION.CODE, @@ -647,9 +631,14 @@ public Set findCompanionDataTypeRules(long ruleId) { public Set findAppliedClassificationRulesForFlow(Long logicalFlowId) { - return baseSelect() + SelectConditionStep outboundRules = baseSelect() .innerJoin(LOGICAL_FLOW_DECORATOR).on(LOGICAL_FLOW_DECORATOR.FLOW_CLASSIFICATION_RULE_ID.eq(FLOW_CLASSIFICATION_RULE.ID)) - .where(LOGICAL_FLOW_DECORATOR.LOGICAL_FLOW_ID.eq(logicalFlowId)) + .where(LOGICAL_FLOW_DECORATOR.LOGICAL_FLOW_ID.eq(logicalFlowId)); + SelectConditionStep inboundRules = baseSelect() + .innerJoin(LOGICAL_FLOW_DECORATOR).on(LOGICAL_FLOW_DECORATOR.INBOUND_FLOW_CLASSIFICATION_RULE_ID.eq(FLOW_CLASSIFICATION_RULE.ID)) + .where(LOGICAL_FLOW_DECORATOR.LOGICAL_FLOW_ID.eq(logicalFlowId)); + return outboundRules + .union(inboundRules) .fetchSet(TO_DOMAIN_MAPPER); } diff --git a/waltz-jobs/src/main/java/org/finos/waltz/jobs/harness/FlowClassificationRuleHarness.java b/waltz-jobs/src/main/java/org/finos/waltz/jobs/harness/FlowClassificationRuleHarness.java index ab194e2ba7..74d869907d 100644 --- a/waltz-jobs/src/main/java/org/finos/waltz/jobs/harness/FlowClassificationRuleHarness.java +++ b/waltz-jobs/src/main/java/org/finos/waltz/jobs/harness/FlowClassificationRuleHarness.java @@ -52,7 +52,6 @@ public static void main(String[] args) { Set calculated = calc.calculate(waltz, apptio, Optional.empty()); System.out.printf("Calculated %d\n", calculated.size()); - System.out.println(calculated); // System.exit(-1); } diff --git a/waltz-ng/client/common/svelte/DataTypeNodeTooltipContent.svelte b/waltz-ng/client/common/svelte/DataTypeNodeTooltipContent.svelte index 6c4f6876c4..30f76b1a93 100644 --- a/waltz-ng/client/common/svelte/DataTypeNodeTooltipContent.svelte +++ b/waltz-ng/client/common/svelte/DataTypeNodeTooltipContent.svelte @@ -3,6 +3,7 @@ import Icon from "./Icon.svelte"; import RatingIndicatorCell from "../../ratings/components/rating-indicator-cell/RatingIndicatorCell.svelte"; import _ from "lodash"; + import DescriptionFade from "./DescriptionFade.svelte"; export let name; export let description; @@ -21,7 +22,7 @@
- {description} +
{#if !_.isEmpty(ratingCharacteristics)} @@ -29,25 +30,25 @@ {/if} {#if ratingCharacteristics}
-
Source Outbound Rating:
+
Producer Rating:
- This describes the rating of the data flow looking at outbound flow classification rules from the upstream entity. + This indicates the rating of the flow according whether this source entity is authorised to distribute this data type
-
Target Inbound Rating:
+
Consumer Rating:
- This describes the rating of the data flow looking at inbound flow classification rules for the downstream target entity. + This rating expresses whether the target entity has a preference for or against this type of data being sent to it
{/if} diff --git a/waltz-ng/client/common/svelte/DataTypeTreeNode.svelte b/waltz-ng/client/common/svelte/DataTypeTreeNode.svelte index 63410d164f..fd2b7a3fb9 100644 --- a/waltz-ng/client/common/svelte/DataTypeTreeNode.svelte +++ b/waltz-ng/client/common/svelte/DataTypeTreeNode.svelte @@ -90,7 +90,7 @@ {/if} {#if expanded || node.isExpanded} -
    +
      {#each sortedNodes as childNode}
    • {#if childNode.children.length > 0} @@ -179,5 +179,11 @@ border-left: 1px solid #eee; } + .root { + border-left: none; + padding-left: 0; + margin-left: 0; + } + \ No newline at end of file diff --git a/waltz-ng/client/common/svelte/DataTypeTreeSelector.svelte b/waltz-ng/client/common/svelte/DataTypeTreeSelector.svelte index fde96929b8..9d4f2a65c9 100644 --- a/waltz-ng/client/common/svelte/DataTypeTreeSelector.svelte +++ b/waltz-ng/client/common/svelte/DataTypeTreeSelector.svelte @@ -13,6 +13,7 @@ export let dataTypeIds = []; export let ratingCharacteristics = []; export let usageCharacteristics = []; + export let showSearch = true; const root = {name: "Root", isExpanded: true}; @@ -61,9 +62,11 @@ - +{#if showSearch} + +{/if} -
      +
      diff --git a/waltz-ng/client/common/svelte/FlowRatingCell.svelte b/waltz-ng/client/common/svelte/FlowRatingCell.svelte new file mode 100644 index 0000000000..85d1457fe4 --- /dev/null +++ b/waltz-ng/client/common/svelte/FlowRatingCell.svelte @@ -0,0 +1,39 @@ + + +
      + + {#if _.isEmpty(sourceOutboundClassification) || sourceOutboundClassification.code === "NO_OPINION"} + + {:else} + + {/if} + {#if _.isEmpty(targetInboundClassification) || targetInboundClassification.code === "NO_OPINION"} + + {:else} + + {/if} + +
      diff --git a/waltz-ng/client/common/svelte/RatingCharacteristicsDecorator.svelte b/waltz-ng/client/common/svelte/RatingCharacteristicsDecorator.svelte index 839cffed7d..b646c76f11 100644 --- a/waltz-ng/client/common/svelte/RatingCharacteristicsDecorator.svelte +++ b/waltz-ng/client/common/svelte/RatingCharacteristicsDecorator.svelte @@ -1,21 +1,16 @@ - - - - - - - - - \ No newline at end of file +
      +
      + +
      +
      diff --git a/waltz-ng/client/common/svelte/UsageCharacteristicsDecorator.svelte b/waltz-ng/client/common/svelte/UsageCharacteristicsDecorator.svelte index c927f31363..b4ff108c05 100644 --- a/waltz-ng/client/common/svelte/UsageCharacteristicsDecorator.svelte +++ b/waltz-ng/client/common/svelte/UsageCharacteristicsDecorator.svelte @@ -13,21 +13,18 @@ {#if !isConcrete && !_.isEmpty(usageCharacteristics)} + style="vertical-align: middle"/> {/if} {#if isEditMode && !_.isEmpty(usageCharacteristics.warningMessageForEditors)} + style="vertical-align: middle"/> {/if} {#if !isEditMode && !_.isEmpty(usageCharacteristics.warningMessageForViewers)} + style="vertical-align: middle"/> {/if} \ No newline at end of file diff --git a/waltz-ng/client/data-types/components/data-type-decorator-section/DataTypeDecoratorSection.svelte b/waltz-ng/client/data-types/components/data-type-decorator-section/DataTypeDecoratorSection.svelte index b1e3b862bd..73f822c5fd 100644 --- a/waltz-ng/client/data-types/components/data-type-decorator-section/DataTypeDecoratorSection.svelte +++ b/waltz-ng/client/data-types/components/data-type-decorator-section/DataTypeDecoratorSection.svelte @@ -5,13 +5,7 @@ import Toggle from "../../../common/svelte/Toggle.svelte"; import DataTypeDecoratorViewGrid from "./DataTypeDecoratorViewGrid.svelte"; import {dataTypeDecoratorStore} from "../../../svelte-stores/data-type-decorator-store"; - import { - selectedDecorator, - viewData, - enrichedDecorators, - selectedDataType - } from "./data-type-decorator-section-store"; - import {prepareData} from "./data-type-decorator-view-grid-utils"; + import {selectedDataType, selectedDecorator, viewData} from "./data-type-decorator-section-store"; import {onDestroy, onMount} from "svelte"; import localWritable from "../../../common/svelte/local-writable"; @@ -54,12 +48,6 @@ $: $viewData = $viewCall?.data; - $: { - if ($viewData) { - $enrichedDecorators = prepareData($viewData); - } - } -
      diff --git a/waltz-ng/client/data-types/components/data-type-decorator-section/DataTypeOverviewPanel.svelte b/waltz-ng/client/data-types/components/data-type-decorator-section/DataTypeOverviewPanel.svelte index bd63679010..7e5bc4ec61 100644 --- a/waltz-ng/client/data-types/components/data-type-decorator-section/DataTypeOverviewPanel.svelte +++ b/waltz-ng/client/data-types/components/data-type-decorator-section/DataTypeOverviewPanel.svelte @@ -4,12 +4,18 @@ import {dataTypeDecoratorStore} from "../../../svelte-stores/data-type-decorator-store"; import {mkSelectionOptions} from "../../../common/selector-utils"; import _ from "lodash"; - import DataTypeDecoratorTreeView from "../../../common/svelte/DataTypeDecoratorTreeView.svelte"; import Icon from "../../../common/svelte/Icon.svelte"; import {displayError} from "../../../common/error-utils"; import toasts from "../../../svelte-stores/toast-store"; import {logicalFlowStore} from "../../../svelte-stores/logical-flow-store"; - import {enrichedDecorators, selectedDataType, selectedDecorator} from "./data-type-decorator-section-store" + import { + enrichedDecorators, + selectedDataType, + selectedDecorator, + viewData + } from "./data-type-decorator-section-store" + import SavingPlaceholder from "../../../common/svelte/SavingPlaceholder.svelte"; + import SuggestedDataTypeTreeSelector from "./SuggestedDataTypeTreeSelector.svelte"; export let primaryEntityReference; @@ -23,11 +29,12 @@ let activeMode = Modes.VIEW; let selectionOptions; - let relatedDataTypesCall; let permissionsCall; let flowCall; + let viewCall; let ratingCharacteristicsCall; let usageCharacteristicsCall; + let saving = false; let workingDataTypes = []; let addedDataTypeIds = []; @@ -60,6 +67,8 @@ function save() { + saving = true; + const cmd = { entityReference: primaryEntityReference, addedDataTypeIds, @@ -68,9 +77,10 @@ dataTypeDecoratorStore.save(primaryEntityReference, cmd) .then(() => { + saving = false; toasts.success("Successfully saved data types"); - relatedDataTypesCall = dataTypeDecoratorStore.findBySelector(primaryEntityReference.kind, selectionOptions, true); activeMode = Modes.VIEW; + viewCall = dataTypeDecoratorStore.getViewForParentRef(primaryEntityReference, true); }) .catch(e => displayError("Could not save data type changes", e)); } @@ -78,12 +88,13 @@ $: { if (primaryEntityReference) { selectionOptions = mkSelectionOptions(primaryEntityReference); - relatedDataTypesCall = dataTypeDecoratorStore.findBySelector(primaryEntityReference.kind, selectionOptions); permissionsCall = logicalFlowStore.findPermissionsForFlow(primaryEntityReference?.id); flowCall = logicalFlowStore.getById(primaryEntityReference.id); + viewCall = dataTypeDecoratorStore.getViewForParentRef(primaryEntityReference); } } + $: { if (!_.isEmpty(logicalFlow)){ @@ -97,6 +108,7 @@ } } + $: $viewData = $viewCall?.data; $: logicalFlow = $flowCall?.data; $: dataTypeDecorators = $enrichedDecorators || []; $: dataTypes = _.map(dataTypeDecorators, d => d.dataTypeId); @@ -119,10 +131,14 @@
      {#if activeMode === Modes.VIEW}
      - +
      @@ -153,6 +167,11 @@ on:click={cancelEdit}> Cancel + {#if saving} + + + + {/if}
      {/if} diff --git a/waltz-ng/client/data-types/components/data-type-decorator-section/SuggestedDataTypeTreeSelector.svelte b/waltz-ng/client/data-types/components/data-type-decorator-section/SuggestedDataTypeTreeSelector.svelte new file mode 100644 index 0000000000..fe5f4a05ed --- /dev/null +++ b/waltz-ng/client/data-types/components/data-type-decorator-section/SuggestedDataTypeTreeSelector.svelte @@ -0,0 +1,63 @@ + + + +{#if showSuggested} + +
      + This is a filtered list of data types showing only those currently related to the upstream entity, alternatively you can + + + +
      +{:else } + +
      + Currently showing all data types, for a filtered view + + + +
      +{/if} diff --git a/waltz-ng/client/data-types/components/data-type-decorator-section/context-panel/DataTypeDecoratorViewTable.svelte b/waltz-ng/client/data-types/components/data-type-decorator-section/context-panel/DataTypeDecoratorViewTable.svelte index 7b22e4b710..304faecd70 100644 --- a/waltz-ng/client/data-types/components/data-type-decorator-section/context-panel/DataTypeDecoratorViewTable.svelte +++ b/waltz-ng/client/data-types/components/data-type-decorator-section/context-panel/DataTypeDecoratorViewTable.svelte @@ -22,9 +22,15 @@ - Classification + Source Outbound Classification - + + + + + Target Inbound Classification + + diff --git a/waltz-ng/client/data-types/components/data-type-decorator-section/context-panel/DataTypeDetailContextPanel.svelte b/waltz-ng/client/data-types/components/data-type-decorator-section/context-panel/DataTypeDetailContextPanel.svelte index fe5c77f3a3..f67b20fce7 100644 --- a/waltz-ng/client/data-types/components/data-type-decorator-section/context-panel/DataTypeDetailContextPanel.svelte +++ b/waltz-ng/client/data-types/components/data-type-decorator-section/context-panel/DataTypeDetailContextPanel.svelte @@ -46,10 +46,18 @@
      - {#if $selectedDecorator.flowClassificationRule && $selectedDecorator.rating !== 'DISCOURAGED'} - Flow Classification Rule - -
      This is the rule that has driven the classification of the flow
      + {#if $selectedDecorator.sourceOutboundRule && $selectedDecorator.rating !== 'DISCOURAGED'} + Source Outbound Classification Rule + +
      This is the rule where the source has driven the classification of the flow
      + {/if} +
      + +
      + {#if $selectedDecorator.targetInboundRule} + Target Inbound Classification Rule + +
      This is the rule where the target has driven the classification of the flow
      {/if}
      diff --git a/waltz-ng/client/data-types/components/data-type-decorator-section/data-type-decorator-section-store.js b/waltz-ng/client/data-types/components/data-type-decorator-section/data-type-decorator-section-store.js index 06bfe7811f..269286783a 100644 --- a/waltz-ng/client/data-types/components/data-type-decorator-section/data-type-decorator-section-store.js +++ b/waltz-ng/client/data-types/components/data-type-decorator-section/data-type-decorator-section-store.js @@ -1,10 +1,10 @@ -import {writable} from "svelte/store"; +import {derived, writable} from "svelte/store"; import _ from "lodash"; +import {prepareData} from "./data-type-decorator-view-grid-utils"; export const selectedDecorator = writable(null); export const selectedDataType = writable(null); export const viewData = writable(null); -export const enrichedDecorators = writable([]); export const filters = writable([]); @@ -13,4 +13,12 @@ export function updateFilters(filters, id, newFilter) { const withoutFilter = _.reject(filtersList, d => d.id === id); return _.concat(withoutFilter, newFilter); }) -} \ No newline at end of file +} + +export const enrichedDecorators = derived([viewData], ([$viewData]) => { + if ($viewData) { + return prepareData($viewData); + } else { + return []; + } +}); \ No newline at end of file diff --git a/waltz-ng/client/data-types/components/data-type-decorator-section/data-type-decorator-view-grid-utils.js b/waltz-ng/client/data-types/components/data-type-decorator-section/data-type-decorator-view-grid-utils.js index 40f758ee59..b7203f71ad 100644 --- a/waltz-ng/client/data-types/components/data-type-decorator-section/data-type-decorator-view-grid-utils.js +++ b/waltz-ng/client/data-types/components/data-type-decorator-section/data-type-decorator-view-grid-utils.js @@ -29,13 +29,22 @@ const baseColumns = [ sortFn: (a, b) => cmp(a?.decoratorEntity.name, b?.decoratorEntity.name) }, { - id: "flow_classification_rating", - name: "Flow Classification", - field: "flowClassification", + id: "source_outbound_classification", + name: "Source Outbound Classification", + field: "sourceOutboundClassification", sortable: true, width: 180, formatter: mkRatingSchemeItemFormatter(d => d.name, d => d), - sortFn: (a, b) => cmp(a?.flowClassification.name, b?.flowClassification.name) + sortFn: (a, b) => cmp(a?.sourceOutboundClassification.name, b?.sourceOutboundClassification.name) + }, + { + id: "target_inbound_classification", + name: "Target Inbound Classification", + field: "targetInboundClassification", + sortable: true, + width: 180, + formatter: mkRatingSchemeItemFormatter(d => d.name, d => d), + sortFn: (a, b) => cmp(a?.targetInboundClassification.name, b?.targetInboundClassification.name) } ]; @@ -83,7 +92,8 @@ export function prepareData($viewData) { .map(d => { const ratingsForDecorator = _.get(assessmentRatingsByDecoratorId, d.id, []); - const flowClassification = _.get(classificationsByCode, d.rating); + const sourceOutboundClassification = _.get(classificationsByCode, d.rating); + const targetInboundClassification = _.get(classificationsByCode, d.targetInboundRating); const ratingsByDefnId = _ .chain(ratingsForDecorator) @@ -97,15 +107,18 @@ export function prepareData($viewData) { {}) .value(); - const flowClassificationRule = _.get(flowClassificationRulesById, d.flowClassificationRuleId); + const sourceOutboundRule = _.get(flowClassificationRulesById, d.flowClassificationRuleId); + const targetInboundRule = _.get(flowClassificationRulesById, d.inboundFlowClassificationRuleId); return Object.assign( {}, d, { ...ratingsByDefnId, - flowClassification, - flowClassificationRule, + sourceOutboundClassification, + targetInboundClassification, + sourceOutboundRule, + targetInboundRule, assessmentRatings: ratingsForDecorator }); }) diff --git a/waltz-ng/client/data-types/components/related-data-types-section/RelatedDataTypesSection.svelte b/waltz-ng/client/data-types/components/related-data-types-section/RelatedDataTypesSection.svelte index 9553d11f17..ad8914e5e4 100644 --- a/waltz-ng/client/data-types/components/related-data-types-section/RelatedDataTypesSection.svelte +++ b/waltz-ng/client/data-types/components/related-data-types-section/RelatedDataTypesSection.svelte @@ -118,11 +118,11 @@ {:else}
      - +
      {#if focusedType} diff --git a/waltz-ng/client/logical-flow/components/aligned-data-types-list/AlignedDataTypesList.svelte b/waltz-ng/client/logical-flow/components/aligned-data-types-list/AlignedDataTypesList.svelte new file mode 100644 index 0000000000..fa0a7ed91b --- /dev/null +++ b/waltz-ng/client/logical-flow/components/aligned-data-types-list/AlignedDataTypesList.svelte @@ -0,0 +1,45 @@ + + +
        + {#each decorators as decorator} +
      • + + {decorator.decoratorEntity.name} +
      • + {/each} +
      diff --git a/waltz-ng/client/logical-flow/components/edit/logical-flow-counterpart-selector.html b/waltz-ng/client/logical-flow/components/edit/logical-flow-counterpart-selector.html index fd91679798..faaed31e59 100644 --- a/waltz-ng/client/logical-flow/components/edit/logical-flow-counterpart-selector.html +++ b/waltz-ng/client/logical-flow/components/edit/logical-flow-counterpart-selector.html @@ -18,45 +18,14 @@

      - -
      - - -
      -
      - - - Select an - - actor - - instead. -
      -
      + + - -
      - - - - -
      - - Select an - - application - - instead. -
      diff --git a/waltz-ng/client/logical-flow/components/edit/logical-flow-counterpart-selector.js b/waltz-ng/client/logical-flow/components/edit/logical-flow-counterpart-selector.js index e16d946315..20496d3de4 100644 --- a/waltz-ng/client/logical-flow/components/edit/logical-flow-counterpart-selector.js +++ b/waltz-ng/client/logical-flow/components/edit/logical-flow-counterpart-selector.js @@ -16,9 +16,10 @@ * */ -import {initialiseData} from '../../../common'; -import {entity} from '../../../common/services/enums/entity' -import template from './logical-flow-counterpart-selector.html'; +import {initialiseData} from "../../../common"; +import {entity} from "../../../common/services/enums/entity" +import template from "./logical-flow-counterpart-selector.html"; +import CounterpartPicker from "./svelte/CounterpartPicker.svelte" /** @@ -30,25 +31,19 @@ import template from './logical-flow-counterpart-selector.html'; const bindings = { - allActors: '<', - onAddApplication: '<', - onAddActor: '<', - onCancel: '<', + onSelect: "<", + onCancel: "<", }; const transclude = { - help: 'help', - heading: 'heading' + help: "help", + heading: "heading" }; const initialState = { - actorIcon: entity.ACTOR.icon, - applicationIcon: entity.APPLICATION.icon, - visibility: { - addingApplication: true, - } + CounterpartPicker }; @@ -60,11 +55,6 @@ function controller() { vm.$onChanges = (c) => { }; - - vm.showAddActor = (visible = true) => { - vm.visibility.addingApplication = !visible; - }; - } diff --git a/waltz-ng/client/logical-flow/components/edit/logical-flow-type-editor.html b/waltz-ng/client/logical-flow/components/edit/logical-flow-type-editor.html index 2e3af360d3..8081b9e8d4 100644 --- a/waltz-ng/client/logical-flow/components/edit/logical-flow-type-editor.html +++ b/waltz-ng/client/logical-flow/components/edit/logical-flow-type-editor.html @@ -27,29 +27,20 @@

      - - + +
      - - - Cancel -
      diff --git a/waltz-ng/client/logical-flow/components/edit/logical-flow-type-editor.js b/waltz-ng/client/logical-flow/components/edit/logical-flow-type-editor.js index af3eeb16d5..7c61a86509 100644 --- a/waltz-ng/client/logical-flow/components/edit/logical-flow-type-editor.js +++ b/waltz-ng/client/logical-flow/components/edit/logical-flow-type-editor.js @@ -20,6 +20,9 @@ import _ from "lodash"; import template from "./logical-flow-type-editor.html"; import {toEntityRefWithKind} from "../../../common/entity-utils"; import toasts from "../../../svelte-stores/toast-store"; +import {CORE_API} from "../../../common/services/core-api-utils"; +import {loadUsageData} from "../../../data-types/data-type-utils"; +import FlowDataTypeEditor from "./svelte/FlowDataTypeEditor.svelte"; const bindings = { @@ -37,7 +40,8 @@ const initialState = { onDelete: (x) => console.log("lfte: default onDelete()", x), onReload: (x) => console.log("lfte: default onReload()", x), onCancel: (x) => console.log("lfte: default onCancel()", x), - onSelect: (x) => console.log("lfte: default onSelect()", x) + onSelect: (x) => console.log("lfte: default onSelect()", x), + FlowDataTypeEditor }; @@ -57,29 +61,8 @@ function controller() { refresh(); }; - vm.onDirty = (dirtyFlag) => { - vm.isDirty = dirtyFlag; - }; - - vm.registerSaveFn = (saveFn) => { - vm.save = saveFn; - }; - vm.delete = () => vm.onDelete(vm.flow); vm.cancel = () => vm.onCancel(); - - vm.onSave = () => { - if (vm.save) { - vm.save() - .then(() => { - toasts.success("Data types updated successfully"); - vm.cancel(); //clear edit session - vm.onReload(); - }); - } else { - console.log("onSave - no impl"); - } - }; } diff --git a/waltz-ng/client/logical-flow/components/edit/svelte/CounterpartPicker.svelte b/waltz-ng/client/logical-flow/components/edit/svelte/CounterpartPicker.svelte new file mode 100644 index 0000000000..416dc8c336 --- /dev/null +++ b/waltz-ng/client/logical-flow/components/edit/svelte/CounterpartPicker.svelte @@ -0,0 +1,59 @@ + + +
        + {#each possibleSearchKinds as entityKind} +
      • + +
      • + {/each} +
      + +
      + +
      + +
      Search for the entity using the search box, you can filter limit the results to a particular entity kind using the filters above
      + + \ No newline at end of file diff --git a/waltz-ng/client/logical-flow/components/edit/svelte/FlowDataTypeEditor.svelte b/waltz-ng/client/logical-flow/components/edit/svelte/FlowDataTypeEditor.svelte new file mode 100644 index 0000000000..eea75eb4a1 --- /dev/null +++ b/waltz-ng/client/logical-flow/components/edit/svelte/FlowDataTypeEditor.svelte @@ -0,0 +1,125 @@ + + + +
      + + | + + {#if saving} + + + + {/if} +
      \ No newline at end of file diff --git a/waltz-ng/client/logical-flow/components/logical-flow-edit-panel/logical-flow-edit-panel.html b/waltz-ng/client/logical-flow/components/logical-flow-edit-panel/logical-flow-edit-panel.html index 52cb71824c..271ca7fa92 100644 --- a/waltz-ng/client/logical-flow/components/logical-flow-edit-panel/logical-flow-edit-panel.html +++ b/waltz-ng/client/logical-flow/components/logical-flow-edit-panel/logical-flow-edit-panel.html @@ -85,9 +85,7 @@
      - @@ -104,9 +102,7 @@
      - @@ -129,6 +125,7 @@
      + toasts.success("Data usage updated")); }; - const addSource = (kind, entity) => { - const counterpartRef = { id: entity.id, kind, name: entity.name }; + vm.addSource = (entity) => { + console.log({entity}); + const counterpartRef = { id: entity.id, kind: entity.kind, name: entity.name }; if (notifyIllegalFlow(toasts, vm.parentEntityRef, counterpartRef)) return; addFlow(mkNewFlow(counterpartRef, vm.parentEntityRef)) .then(() => selectSource(counterpartRef)); }; - const addTarget = (kind, entity) => { - const counterpartRef = { id: entity.id, kind, name: entity.name }; + vm.addTarget = (entity) => { + console.log({entity}); + const counterpartRef = { id: entity.id, kind: entity.kind, name: entity.name }; if (notifyIllegalFlow(toasts, vm.parentEntityRef, counterpartRef)) return; addFlow(mkNewFlow(vm.parentEntityRef, counterpartRef)) .then(() => selectTarget(counterpartRef)); }; - vm.addSourceApplication = (srcApp) => { - addSource("APPLICATION", srcApp); - }; - - vm.addSourceActor = (actor) => { - addSource("ACTOR", actor); - }; - - vm.addTargetApplication = (targetApp) => { - addTarget("APPLICATION", targetApp); - }; - - vm.addTargetActor = (actor) => { - addTarget("ACTOR", actor); - }; - vm.setDirtyChange = (dirty) => { vm.isDirty = dirty; }; @@ -412,6 +398,8 @@ function controller($element, vm.onSelectDataType = (dt) => { vm.dataTypeInfo = dt; } + + vm.selectionFilter = (d) => !_.includes(workingDataTypes, d.id); } diff --git a/waltz-ng/client/logical-flow/pages/view/logical-flow-view.html b/waltz-ng/client/logical-flow/pages/view/logical-flow-view.html index 2dea6cc726..1ddda6543b 100644 --- a/waltz-ng/client/logical-flow/pages/view/logical-flow-view.html +++ b/waltz-ng/client/logical-flow/pages/view/logical-flow-view.html @@ -72,10 +72,46 @@ }">
      - - +
      +
      + Provenance +
      +
      + + + + + +
      +
      +
      +
      + Read Only +
      +
      + + This flow is marked read only and cannot be edited +
      +
      +
      +
      + Data Types +
      +
      + + +
      +
      @@ -84,43 +120,16 @@
      -
      -
      - Provenance -
      -
      - - - - - -
      -
      -
      -
      - Read Only -
      -
      - - This flow is marked read only and cannot be edited +
      +
      + Last updated by + + () +
      -
      - Last updated by - - () -
      No information for this logical flow diff --git a/waltz-ng/client/logical-flow/pages/view/logical-flow-view.js b/waltz-ng/client/logical-flow/pages/view/logical-flow-view.js index c20b9393fc..4560fd5777 100644 --- a/waltz-ng/client/logical-flow/pages/view/logical-flow-view.js +++ b/waltz-ng/client/logical-flow/pages/view/logical-flow-view.js @@ -24,6 +24,7 @@ import {CORE_API} from "../../../common/services/core-api-utils"; import toasts from "../../../svelte-stores/toast-store"; import _ from "lodash"; import {displayError} from "../../../common/error-utils"; +import AlignedDataTypesList from "../../components/aligned-data-types-list/AlignedDataTypesList.svelte"; const initialState = { @@ -32,7 +33,8 @@ const initialState = { isRemoved: false, canEdit: false, canRestore: false, - canRemove: false + canRemove: false, + AlignedDataTypesList }; diff --git a/waltz-ng/client/playpen/1/playpen1.html b/waltz-ng/client/playpen/1/playpen1.html index 112636f421..6d2469ceb8 100644 --- a/waltz-ng/client/playpen/1/playpen1.html +++ b/waltz-ng/client/playpen/1/playpen1.html @@ -25,23 +25,14 @@
    • Playpen
    • - - -
      -
      - - -
      - - - - - + +
      +
      +
      -
      -
      + diff --git a/waltz-ng/client/playpen/1/playpen1.js b/waltz-ng/client/playpen/1/playpen1.js index 0c7669a5c8..9d97f938ad 100644 --- a/waltz-ng/client/playpen/1/playpen1.js +++ b/waltz-ng/client/playpen/1/playpen1.js @@ -19,17 +19,10 @@ import template from "./playpen1.html"; import {initialiseData} from "../../common"; -import Parent from "./Parent.svelte"; -import Unaware from "./Unaware.svelte"; +import CounterpartPicker from "../../logical-flow/components/edit/svelte/CounterpartPicker.svelte" const initData = { - Parent, - Unaware, - p: "ParentParam", - u: "UnawareParam", - visible: true, - counter: 1 - + CounterpartPicker }; @@ -43,7 +36,7 @@ function controller($q, } } -controller.$inject = ["$q", "ServiceBroker", "UserService"]; +controller.$inject = ["$q", "ServiceBroker"]; const view = { template, diff --git a/waltz-ng/client/ratings/components/rating-indicator-cell/RatingIndicatorCell.svelte b/waltz-ng/client/ratings/components/rating-indicator-cell/RatingIndicatorCell.svelte index c09b307eba..2b77058207 100644 --- a/waltz-ng/client/ratings/components/rating-indicator-cell/RatingIndicatorCell.svelte +++ b/waltz-ng/client/ratings/components/rating-indicator-cell/RatingIndicatorCell.svelte @@ -7,6 +7,7 @@ export let description; export let showName = true; export let showGroup = false; + export let size = "xl"; @@ -15,10 +16,10 @@
      - + - +
      diff --git a/waltz-ng/client/svelte-stores/data-type-store.js b/waltz-ng/client/svelte-stores/data-type-store.js index da1c315c24..f7d247633b 100644 --- a/waltz-ng/client/svelte-stores/data-type-store.js +++ b/waltz-ng/client/svelte-stores/data-type-store.js @@ -46,10 +46,19 @@ export function mkDataTypeStore() { {force}) }; + const findSuggestedByRef = (ref, force = false) => { + return remote.fetchViewList( + "GET", + `api/data-types/suggested/entity/${ref.kind}/${ref.id}`, + null, + {force}); + } + return { findAll, getById, - findByParentId + findByParentId, + findSuggestedByRef }; } diff --git a/waltz-ng/style/_waltz.scss b/waltz-ng/style/_waltz.scss index 1fce61f557..8d9c9176ab 100644 --- a/waltz-ng/style/_waltz.scss +++ b/waltz-ng/style/_waltz.scss @@ -467,3 +467,8 @@ details summary { cursor: pointer; display: list-item; } + + +.waltz-search-input { + width: 100%; +} \ No newline at end of file diff --git a/waltz-service/src/main/java/org/finos/waltz/service/data_flow_decorator/LogicalFlowDecoratorRatingsCalculator.java b/waltz-service/src/main/java/org/finos/waltz/service/data_flow_decorator/LogicalFlowDecoratorRatingsCalculator.java index 91c0d5221c..db1ce4d0cb 100644 --- a/waltz-service/src/main/java/org/finos/waltz/service/data_flow_decorator/LogicalFlowDecoratorRatingsCalculator.java +++ b/waltz-service/src/main/java/org/finos/waltz/service/data_flow_decorator/LogicalFlowDecoratorRatingsCalculator.java @@ -18,48 +18,52 @@ package org.finos.waltz.service.data_flow_decorator; -import org.finos.waltz.model.FlowDirection; -import org.finos.waltz.model.OrganisationalUnitIdProvider; -import org.finos.waltz.model.datatype.DataType; -import org.finos.waltz.model.datatype.DataTypeDecoratorRatingCharacteristics; -import org.finos.waltz.model.datatype.ImmutableDataTypeDecoratorRatingCharacteristics; -import org.finos.waltz.service.application.ApplicationService; -import org.finos.waltz.service.data_type.DataTypeService; -import org.finos.waltz.service.flow_classification_rule.FlowClassificationRuleResolver; +import org.finos.waltz.common.FunctionUtilities; import org.finos.waltz.data.flow_classification_rule.FlowClassificationRuleDao; import org.finos.waltz.data.logical_flow.LogicalFlowDao; import org.finos.waltz.model.EntityKind; import org.finos.waltz.model.EntityReference; +import org.finos.waltz.model.FlowDirection; +import org.finos.waltz.model.OrganisationalUnitIdProvider; import org.finos.waltz.model.application.Application; import org.finos.waltz.model.datatype.DataTypeDecorator; +import org.finos.waltz.model.datatype.DataTypeDecoratorRatingCharacteristics; import org.finos.waltz.model.datatype.ImmutableDataTypeDecorator; +import org.finos.waltz.model.datatype.ImmutableDataTypeDecoratorRatingCharacteristics; import org.finos.waltz.model.flow_classification_rule.FlowClassificationRuleVantagePoint; import org.finos.waltz.model.logical_flow.LogicalFlow; import org.finos.waltz.model.rating.AuthoritativenessRatingValue; +import org.finos.waltz.service.application.ApplicationService; +import org.finos.waltz.service.data_type.DataTypeService; +import org.finos.waltz.service.flow_classification_rule.FlowClassificationRuleResolver; import org.jooq.lambda.tuple.Tuple2; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.*; -import java.util.function.Predicate; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; import java.util.stream.Collectors; import static org.finos.waltz.common.Checks.checkNotNull; +import static org.finos.waltz.common.FunctionUtilities.time; import static org.finos.waltz.common.SetUtilities.asSet; import static org.finos.waltz.common.SetUtilities.map; import static org.finos.waltz.model.EntityReference.mkRef; import static org.finos.waltz.model.utils.IdUtilities.indexById; +import static org.finos.waltz.model.utils.IdUtilities.toIds; +import static org.springframework.util.ObjectUtils.isEmpty; @Service public class LogicalFlowDecoratorRatingsCalculator { private static final Logger LOG = LoggerFactory.getLogger(LogicalFlowDecoratorRatingsCalculator.class); - private static final Predicate IS_APP_TO_APP_FLOW = f -> - f.target().kind() == EntityKind.APPLICATION && - f.source().kind() == EntityKind.APPLICATION; - private final ApplicationService applicationService; private final FlowClassificationRuleDao flowClassificationRuleDao; private final LogicalFlowDao logicalFlowDao; @@ -147,27 +151,28 @@ public Set calculate(EntityReference sou EntityReference target, Optional> dataTypeIds) { - Application sourceApp = applicationService.getById(source.id()); - Application targetApp = applicationService.getById(target.id()); - Set targetOrgIds = asSet(targetApp.organisationalUnitId()); - Set sourceOrgIds = asSet(sourceApp.organisationalUnitId()); + boolean sourceIsApp = source.kind().equals(EntityKind.APPLICATION); + boolean targetIsApp = target.kind().equals(EntityKind.APPLICATION); + Application sourceApp = sourceIsApp ? applicationService.getById(source.id()) : null; + Application targetApp = targetIsApp ? applicationService.getById(target.id()) : null; + + Set targetOrgIds = !isEmpty(targetApp) ? asSet(targetApp.organisationalUnitId()) : Collections.emptySet(); + Set sourceOrgIds = !isEmpty(sourceApp) ? asSet(sourceApp.organisationalUnitId()) : Collections.emptySet(); - FlowClassificationRuleResolver outboundResolver = createResolver(FlowDirection.OUTBOUND, asSet(target), targetOrgIds); - FlowClassificationRuleResolver inboundResolver = createResolver(FlowDirection.INBOUND, asSet(source), sourceOrgIds); + Collection dtIds = dataTypeIds.orElseGet(() -> toIds(dataTypeService.findAll())); - Collection dtIds = dataTypeIds.orElseGet(() -> { - List allDataTypes = dataTypeService.findAll(); - return map(allDataTypes, dt -> dt.id().get()); - }); + FlowClassificationRuleResolver outboundResolver = time("out res", () -> createResolver(FlowDirection.OUTBOUND, asSet(target), targetOrgIds)); + FlowClassificationRuleResolver inboundResolver = time("in res", () -> createResolver(FlowDirection.INBOUND, asSet(source), sourceOrgIds)); - return dtIds + + return time("total dts", () -> dtIds .stream() .map(dtId -> { try { - EntityReference targetOu = mkRef(EntityKind.ORG_UNIT, targetApp.organisationalUnitId()); - EntityReference sourceOu = mkRef(EntityKind.ORG_UNIT, sourceApp.organisationalUnitId()); + EntityReference targetOu = targetIsApp ? mkRef(EntityKind.ORG_UNIT, targetApp.organisationalUnitId()) : null; + EntityReference sourceOu = sourceIsApp ? mkRef(EntityKind.ORG_UNIT, sourceApp.organisationalUnitId()) : null; Tuple2> outboundRatingAndRule = outboundResolver.resolve(targetOu, target, source, dtId); Tuple2> inboundRatingAndRule = inboundResolver.resolve(sourceOu, source, target, dtId); return ImmutableDataTypeDecoratorRatingCharacteristics @@ -185,7 +190,7 @@ public Set calculate(EntityReference sou }) .filter(Objects::nonNull) - .collect(Collectors.toSet()); + .collect(Collectors.toSet())); } @@ -228,9 +233,11 @@ private FlowClassificationRuleResolver createResolver(FlowDirection direction, // this brings back many expanded vantage points List flowClassificationRuleVantagePoints = - flowClassificationRuleDao.findExpandedFlowClassificationRuleVantagePoints(direction, vantagePointOrgUnitIdLookups, appVantagePoints, actorVantagePoints); + FunctionUtilities.time("do find expanded", + () -> flowClassificationRuleDao + .findExpandedFlowClassificationRuleVantagePoints(direction, vantagePointOrgUnitIdLookups, appVantagePoints, actorVantagePoints)); - return new FlowClassificationRuleResolver(direction, flowClassificationRuleVantagePoints); + return FunctionUtilities.time("mk resolver", () -> new FlowClassificationRuleResolver(direction, flowClassificationRuleVantagePoints)); } private Set getVantagePointIdsForKind(Set vantagePointEntityLookups, EntityKind entityKind) { diff --git a/waltz-service/src/main/java/org/finos/waltz/service/data_type/DataTypeDecoratorService.java b/waltz-service/src/main/java/org/finos/waltz/service/data_type/DataTypeDecoratorService.java index c2d3dad83d..ce5e7ed800 100644 --- a/waltz-service/src/main/java/org/finos/waltz/service/data_type/DataTypeDecoratorService.java +++ b/waltz-service/src/main/java/org/finos/waltz/service/data_type/DataTypeDecoratorService.java @@ -18,6 +18,7 @@ package org.finos.waltz.service.data_type; +import org.finos.waltz.common.FunctionUtilities; import org.finos.waltz.data.GenericSelector; import org.finos.waltz.data.GenericSelectorFactory; import org.finos.waltz.data.datatype_decorator.DataTypeDecoratorDao; @@ -65,9 +66,11 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Objects; import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; import static java.lang.String.format; import static org.finos.waltz.common.Checks.checkNotNull; @@ -156,13 +159,13 @@ public boolean updateDecorators(String userName, String currentDataTypeNames = getAssociatedDatatypeNamesAsCsv(entityReference); if (notEmpty(dataTypeIdsToAdd)) { - addDecorators(userName, entityReference, dataTypeIdsToAdd); + FunctionUtilities.time("add", () -> addDecorators(userName, entityReference, dataTypeIdsToAdd)); } if (notEmpty(dataTypeIdsToRemove)) { - removeDataTypeDecorator(userName, entityReference, dataTypeIdsToRemove); + FunctionUtilities.time("remove", () -> removeDataTypeDecorator(userName, entityReference, dataTypeIdsToRemove)); } - auditEntityDataTypeChanges(userName, entityReference, currentDataTypeNames); + FunctionUtilities.time("audit", ()-> auditEntityDataTypeChanges(userName, entityReference, currentDataTypeNames)); return true; } @@ -203,25 +206,25 @@ public int[] addDecorators(String userName, checkNotNull(userName, "userName cannot be null"); checkNotNull(dataTypeIds, "dataTypeIds cannot be null"); - Collection dataTypeDecorators = mkDecorators( + Collection dataTypeDecorators = FunctionUtilities.time("mkDecorators", ()-> mkDecorators( userName, entityReference, - dataTypeIds); + dataTypeIds)); DataTypeDecoratorDao dao = dataTypeDecoratorDaoSelectorFactory .getDao(entityReference.kind()); // This must execute first so that the decorators exist - int[] result = dao.addDecorators(dataTypeDecorators); + int[] result = FunctionUtilities.time("addDEcs", ()->dao.addDecorators(dataTypeDecorators)); audit(format("Added data types: %s", dataTypeIds.toString()), entityReference, userName); if (entityReference.kind().equals(LOGICAL_DATA_FLOW)) { - int rulesUpdated = flowClassificationRuleService.recalculateFlowRatingsForSelector(mkOpts(entityReference)); + int rulesUpdated = FunctionUtilities.time("recalc ratings", () -> flowClassificationRuleService.recalculateFlowRatingsForSelector(mkOpts(entityReference))); } - recalculateDataTypeUsageForApplications(entityReference); + FunctionUtilities.time("recalc usage", ()->recalculateDataTypeUsageForApplications(entityReference)); if (PHYSICAL_SPECIFICATION.equals(entityReference.kind())) { physicalSpecificationService.propagateDataTypesToLogicalFlows(userName, entityReference.id()); @@ -406,7 +409,13 @@ public DataTypeDecoratorView getDecoratorView(EntityReference parentEntityRef) { Set dataTypes = dataTypeService.findByIdSelector(selectionOptions); AssessmentsView assessmentsView = assessmentRatingService.getPrimaryAssessmentsViewForKindAndSelector(LOGICAL_DATA_FLOW_DATA_TYPE_DECORATOR, selectionOptions); FlowClassificationRulesView classificationRulesView = flowClassificationRuleService.getFlowClassificationsViewForFlow(parentEntityRef.id()); - Set ratings = map(decorators, d -> d.rating().orElse(null)); + + Set ratings = decorators + .stream() + .flatMap(d -> Stream.of(d.rating().orElse(null), d.targetInboundRating().orElse(null))) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + Set classifications = filter( flowClassificationService.findAll(), d -> ratings.contains(AuthoritativenessRatingValue.ofNullable(d.code()).orElse(null))); @@ -431,14 +440,14 @@ private EntityKind getDecoratorKind(EntityKind entityKind) { } } - public Set findDatatypeUsageCharacteristicsForSourceAndTarget(EntityReference source, - EntityReference target) { - return findDatatypeUsageCharacteristicsForSourceAndTarget(source, target, Optional.empty()); + public Set findDatatypeRatingCharacteristicsForSourceAndTarget(EntityReference source, + EntityReference target) { + return findDatatypeRatingCharacteristicsForSourceAndTarget(source, target, Optional.empty()); } - public Set findDatatypeUsageCharacteristicsForSourceAndTarget(EntityReference source, - EntityReference target, - Optional> dataTypeIds) { + public Set findDatatypeRatingCharacteristicsForSourceAndTarget(EntityReference source, + EntityReference target, + Optional> dataTypeIds) { return ratingsCalculator.calculate(source, target, dataTypeIds); } diff --git a/waltz-service/src/main/java/org/finos/waltz/service/flow_classification_rule/FlowClassificationRuleResolver.java b/waltz-service/src/main/java/org/finos/waltz/service/flow_classification_rule/FlowClassificationRuleResolver.java index 9d07b53f81..fcbf3be3f8 100644 --- a/waltz-service/src/main/java/org/finos/waltz/service/flow_classification_rule/FlowClassificationRuleResolver.java +++ b/waltz-service/src/main/java/org/finos/waltz/service/flow_classification_rule/FlowClassificationRuleResolver.java @@ -24,16 +24,20 @@ import org.finos.waltz.model.rating.AuthoritativenessRatingValue; import org.jooq.lambda.tuple.Tuple2; -import java.util.*; -import java.util.function.Function; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; import static java.util.Collections.emptyMap; import static org.finos.waltz.common.Checks.checkNotNull; import static org.finos.waltz.common.CollectionUtilities.head; -import static org.finos.waltz.common.CollectionUtilities.maybe; import static org.finos.waltz.common.CollectionUtilities.sort; import static org.finos.waltz.common.MapUtilities.groupAndThen; import static org.finos.waltz.common.MapUtilities.isEmpty; +import static org.finos.waltz.service.flow_classification_rule.FlowClassificationRuleUtilities.flowClassificationRuleVantagePointComparator; import static org.jooq.lambda.tuple.Tuple.tuple; @@ -42,20 +46,6 @@ public class FlowClassificationRuleResolver { private final Map>>> byVantagePointThenDataTypeThenSubject; private final FlowDirection direction; - private final Function kindComparator = d -> d.vantagePoint().kind().name(); - private final Function vantageComparator = FlowClassificationRuleVantagePoint::vantagePointRank; - private final Function dataTypeComparator = FlowClassificationRuleVantagePoint::dataTypeRank; - private final Function vantagePointIdComparator = d -> d.vantagePoint().id(); - private final Function dataTypeIdComparator = d -> d.dataType().id(); - private final Function subjectIdComparator = d -> d.subjectReference().id(); - private final Comparator flowClassificationRuleVantagePointComparator = Comparator - .comparing(kindComparator) - .thenComparing(vantageComparator).reversed() - .thenComparing(dataTypeComparator).reversed() - .thenComparing(vantagePointIdComparator) - .thenComparing(dataTypeIdComparator) - .thenComparing(subjectIdComparator); - /** * Construct the Resolver with an internal structure as follows: @@ -65,9 +55,14 @@ public class FlowClassificationRuleResolver { public FlowClassificationRuleResolver(FlowDirection direction, List flowClassificationVantagePoints) { checkNotNull(flowClassificationVantagePoints, "flowClassificationVantagePoints cannot be null"); + List orderedRvps = flowClassificationVantagePoints + .stream() + .sorted(flowClassificationRuleVantagePointComparator) + .collect(Collectors.toList()); + byVantagePointThenDataTypeThenSubject = groupAndThen( - flowClassificationVantagePoints, + orderedRvps, FlowClassificationRuleVantagePoint::vantagePoint, byVps -> groupAndThen( byVps, diff --git a/waltz-service/src/main/java/org/finos/waltz/service/flow_classification_rule/FlowClassificationRuleService.java b/waltz-service/src/main/java/org/finos/waltz/service/flow_classification_rule/FlowClassificationRuleService.java index 5cc08d1411..909b4c9946 100644 --- a/waltz-service/src/main/java/org/finos/waltz/service/flow_classification_rule/FlowClassificationRuleService.java +++ b/waltz-service/src/main/java/org/finos/waltz/service/flow_classification_rule/FlowClassificationRuleService.java @@ -18,6 +18,7 @@ package org.finos.waltz.service.flow_classification_rule; +import org.finos.waltz.common.FunctionUtilities; import org.finos.waltz.common.exception.NotFoundException; import org.finos.waltz.data.GenericSelector; import org.finos.waltz.data.GenericSelectorFactory; @@ -69,6 +70,7 @@ import org.springframework.stereotype.Service; import java.util.Collection; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Objects; @@ -226,8 +228,8 @@ public List findAll() { public int recalculateFlowRatingsForSelector(IdSelectionOptions options) { Select> flowSelector = logicalFlowIdSelectorFactory.apply(options); - Set population = logicalFlowDecoratorDao.fetchFlowDataTypePopulationForFlowSelector(flowSelector); - return recalculateRatingsForPopulation(population); + Set population = FunctionUtilities.time("find population", ()-> logicalFlowDecoratorDao.fetchFlowDataTypePopulationForFlowSelector(flowSelector)); + return FunctionUtilities.time("do recalculate", ()-> recalculateRatingsForPopulation(population)); } public int fastRecalculateAllFlowRatings() { @@ -258,8 +260,18 @@ private int recalculateRatingsForPopulation(Set population) { EntityHierarchy dtHierarchy = entityHierarchyService.fetchHierarchyForKind(EntityKind.DATA_TYPE); LOG.debug("Applying rules to population"); - Map> lfdIdToOutboundRuleIdMap = time("inbound vps", () -> applyVantagePoints(FlowDirection.OUTBOUND, outboundRuleVantagePoints, population, ouHierarchy, dtHierarchy)); - Map> lfdIdToInboundRuleIdMap = time("outbound vps", () -> applyVantagePoints(FlowDirection.INBOUND, inboundRuleVantagePoints, population, ouHierarchy, dtHierarchy)); + Map> lfdIdToOutboundRuleIdMap = time("inbound vps", () -> applyVantagePoints( + FlowDirection.OUTBOUND, + outboundRuleVantagePoints, + population, + ouHierarchy, + dtHierarchy)); + Map> lfdIdToInboundRuleIdMap = time("outbound vps", () -> applyVantagePoints( + FlowDirection.INBOUND, + inboundRuleVantagePoints, + population, + ouHierarchy, + dtHierarchy)); LOG.debug("Calculating diff"); Set> existingDecoratorRatingInfo = map( diff --git a/waltz-service/src/main/java/org/finos/waltz/service/flow_classification_rule/FlowClassificationRuleUtilities.java b/waltz-service/src/main/java/org/finos/waltz/service/flow_classification_rule/FlowClassificationRuleUtilities.java index cc20ade36d..8edb857b87 100644 --- a/waltz-service/src/main/java/org/finos/waltz/service/flow_classification_rule/FlowClassificationRuleUtilities.java +++ b/waltz-service/src/main/java/org/finos/waltz/service/flow_classification_rule/FlowClassificationRuleUtilities.java @@ -6,77 +6,34 @@ import org.finos.waltz.model.datatype.FlowDataType; import org.finos.waltz.model.entity_hierarchy.EntityHierarchy; import org.finos.waltz.model.flow_classification_rule.FlowClassificationRuleVantagePoint; -import org.finos.waltz.model.rating.AuthoritativenessRatingValue; -import org.finos.waltz.schema.tables.records.LogicalFlowDecoratorRecord; -import org.jooq.UpdateConditionStep; -import org.jooq.impl.DSL; import org.jooq.lambda.function.Function4; import org.jooq.lambda.tuple.Tuple2; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Objects; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; -import static org.finos.waltz.model.rating._AuthoritativenessRatingValue.DISCOURAGED; -import static org.finos.waltz.schema.tables.LogicalFlowDecorator.LOGICAL_FLOW_DECORATOR; import static org.jooq.lambda.tuple.Tuple.tuple; public class FlowClassificationRuleUtilities { - - protected static List> mkOutboundRuleUpdateStmts(Map outboundRatingCodeByRuleId, - Map> lfdIdToOutboundRuleIdMap) { - return lfdIdToOutboundRuleIdMap - .entrySet() - .stream() - .map(kv -> { - - Tuple2 ruleAndMatchOutcome = kv.getValue(); - - Long ruleId = ruleAndMatchOutcome.v1(); - String ratingCode = outboundRatingCodeByRuleId.get(ruleId); - - AuthoritativenessRatingValue ratingValue = MatchOutcome.POSITIVE_MATCH.equals(ruleAndMatchOutcome.v2) - ? AuthoritativenessRatingValue.of(ratingCode) - : DISCOURAGED; - - return DSL - .update(LOGICAL_FLOW_DECORATOR) - .set(LOGICAL_FLOW_DECORATOR.RATING, ratingValue.value()) - .set(LOGICAL_FLOW_DECORATOR.FLOW_CLASSIFICATION_RULE_ID, ruleId) - .where(LOGICAL_FLOW_DECORATOR.ID.eq(kv.getKey())); - }) - .collect(Collectors.toList()); - } - - protected static List> mkInboundRuleUpdateStmts(Map inboundRatingCodeByRuleId, - Map> lfdIdToInboundRuleIdMap) { - return lfdIdToInboundRuleIdMap - .entrySet() - .stream() - .map(kv -> { - - Tuple2 ruleAndMatchOutcome = kv.getValue(); - - Long ruleId = ruleAndMatchOutcome.v1(); - String ratingCode = inboundRatingCodeByRuleId.get(ruleId); - - if (MatchOutcome.POSITIVE_MATCH.equals(ruleAndMatchOutcome.v2)) { - return DSL - .update(LOGICAL_FLOW_DECORATOR) - .set(LOGICAL_FLOW_DECORATOR.TARGET_INBOUND_RATING, AuthoritativenessRatingValue.of(ratingCode).value()) - .set(LOGICAL_FLOW_DECORATOR.INBOUND_FLOW_CLASSIFICATION_RULE_ID, ruleId) - .where(LOGICAL_FLOW_DECORATOR.ID.eq(kv.getKey())); - } else { - return null; // For inbound rules we don't want to automatically discourage flows that are not covered - } - }) - .filter(Objects::nonNull) - .collect(Collectors.toList()); - } + private static final Function kindComparator = d -> d.vantagePoint().kind().name(); + private static final Function vantageComparator = FlowClassificationRuleVantagePoint::vantagePointRank; + private static final Function dataTypeComparator = FlowClassificationRuleVantagePoint::dataTypeRank; + private static final Function vantagePointIdComparator = d -> d.vantagePoint().id(); + private static final Function dataTypeIdComparator = d -> d.dataType().id(); + private static final Function subjectIdComparator = d -> d.subjectReference().id(); + public static final Comparator flowClassificationRuleVantagePointComparator = Comparator + .comparing(kindComparator) + .thenComparing(vantageComparator).reversed() + .thenComparing(dataTypeComparator).reversed() + .thenComparing(vantagePointIdComparator) + .thenComparing(dataTypeIdComparator) + .thenComparing(subjectIdComparator); protected static Map> applyVantagePoints(FlowDirection direction, @@ -88,8 +45,18 @@ protected static Map> applyVantagePoints(FlowDi Function4, Set, FlowDataType, MatchOutcome> matcher = determineMatcherFn(direction); Map> lfdIdToRuleAndOutcomeMap = new HashMap<>(); - ruleVantagePoints + + Set ruleDataTypes = population .stream() + .flatMap(d -> dtHierarchy.findAncestors(d.dtId()).stream()) + .collect(Collectors.toSet()); + + Set filteredRules = ruleVantagePoints + .stream() + .filter(rvp -> ruleDataTypes.contains(rvp.dataType().id())) + .collect(Collectors.toSet()); + + filteredRules .forEach(rvp -> { Set childOUs = ouHierarchy.findChildren(rvp.vantagePoint().id()); Set childDTs = dtHierarchy.findChildren(rvp.dataType().id()); @@ -126,16 +93,16 @@ private static Function4, Set, Set, FlowDataType, MatchOutcome> inboundMatcher = (rvp, childOUs, childDTs, p) -> { boolean subjectMatches = p.target().equals(rvp.subjectReference()); - boolean scopeMatches = checkScopeMatches(rvp, childOUs, p.source(), p.sourceOuId()); - boolean dtAndOuMatches = childDTs.contains(p.dtId()) && scopeMatches; + boolean dtMatches = childDTs.contains(p.dtId()); + boolean dtAndOuMatches = dtMatches && checkScopeMatches(rvp, childOUs, p.source(), p.sourceOuId()); return determineOutcome(subjectMatches, dtAndOuMatches); }; Function4, Set, FlowDataType, MatchOutcome> outboundMatcher = (rvp, childOUs, childDTs, p) -> { boolean subjectMatches = p.source().equals(rvp.subjectReference()); - boolean scopeMatches = checkScopeMatches(rvp, childOUs, p.target(), p.targetOuId()); - boolean dtAndOuMatches = childDTs.contains(p.dtId()) && scopeMatches; + boolean dtMatches = childDTs.contains(p.dtId()); + boolean dtAndOuMatches = dtMatches && checkScopeMatches(rvp, childOUs, p.target(), p.targetOuId()); return determineOutcome(subjectMatches, dtAndOuMatches); }; @@ -144,7 +111,9 @@ private static Function4, Set childOUs, EntityReference scopeEntity, Long scopeEntityOuId) { + private static boolean checkScopeMatches(FlowClassificationRuleVantagePoint rvp, + Set childOUs, + EntityReference scopeEntity, Long scopeEntityOuId) { if (rvp.vantagePoint().kind() == EntityKind.ORG_UNIT) { return scopeEntityOuId != null && childOUs.contains(scopeEntityOuId); } else { diff --git a/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/DataTypeDecoratorEndpoint.java b/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/DataTypeDecoratorEndpoint.java index 4064e1cd91..6a391371dc 100644 --- a/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/DataTypeDecoratorEndpoint.java +++ b/waltz-web/src/main/java/org/finos/waltz/web/endpoints/api/DataTypeDecoratorEndpoint.java @@ -115,7 +115,7 @@ public void register() { ListRoute findDatatypeRatingCharacteristicsForSourceAndTargetRoute = (req, res) -> { DataTypeDecoratorRatingCharacteristicsRequest request = readBody(req, DataTypeDecoratorRatingCharacteristicsRequest.class); - return dataTypeDecoratorService.findDatatypeUsageCharacteristicsForSourceAndTarget(request.source(), request.target()); + return dataTypeDecoratorService.findDatatypeRatingCharacteristicsForSourceAndTarget(request.source(), request.target()); }; getForList(findByEntityReference, findByEntityReferenceRoute); diff --git a/waltz-web/src/main/java/org/finos/waltz/web/endpoints/extracts/LogicalFlowExtractor.java b/waltz-web/src/main/java/org/finos/waltz/web/endpoints/extracts/LogicalFlowExtractor.java index f05e88430c..07c77967ea 100644 --- a/waltz-web/src/main/java/org/finos/waltz/web/endpoints/extracts/LogicalFlowExtractor.java +++ b/waltz-web/src/main/java/org/finos/waltz/web/endpoints/extracts/LogicalFlowExtractor.java @@ -23,6 +23,7 @@ import org.finos.waltz.data.data_type.DataTypeIdSelectorFactory; import org.finos.waltz.model.EntityKind; import org.finos.waltz.model.IdSelectionOptions; +import org.finos.waltz.schema.tables.FlowClassification; import org.finos.waltz.web.WebUtilities; import org.jooq.Condition; import org.jooq.DSLContext; @@ -86,7 +87,8 @@ public class LogicalFlowExtractor extends CustomDataExtractor { "Target Asset Code", "Target Org Unit", "Data Type", - "Authoritativeness"); + "Source Outbound Rating", + "Target Inbound Rating"); private final ApplicationIdSelectorFactory applicationIdSelectorFactory = new ApplicationIdSelectorFactory(); private final DataTypeIdSelectorFactory dataTypeIdSelectorFactory = new DataTypeIdSelectorFactory(); @@ -123,26 +125,6 @@ private SelectConditionStep prepareQuery(DSLContext dsl, IdSelectionOpti ? LOGICAL_FLOW_DECORATOR.DECORATOR_ENTITY_ID.in(dataTypeIdSelectorFactory.apply(options)) : DSL.trueCondition(); - Field sourceFlowId = LOGICAL_FLOW.ID.as("sourceFlowId"); - Field targetFlowId = LOGICAL_FLOW.ID.as("targetFlowId"); - - Select> sourceAppFlows = DSL - .select(sourceFlowId) - .from(LOGICAL_FLOW) - .innerJoin(APPLICATION) - .on(LOGICAL_FLOW.SOURCE_ENTITY_ID.eq(APPLICATION.ID)) - .where(LOGICAL_FLOW.SOURCE_ENTITY_KIND.eq(EntityKind.APPLICATION.name())) - .and(APPLICATION.ID.in(appIdSelector)); - - Select> targetAppFlows = DSL - .select(targetFlowId) - .from(LOGICAL_FLOW) - .innerJoin(APPLICATION) - .on(LOGICAL_FLOW.TARGET_ENTITY_ID.eq(APPLICATION.ID)) - .where(LOGICAL_FLOW.TARGET_ENTITY_KIND.eq(EntityKind.APPLICATION.name())) - .and(APPLICATION.ID.in(appIdSelector)); - - Field sourceOrgUnitNameField = DSL .when(LOGICAL_FLOW.SOURCE_ENTITY_KIND.eq(EntityKind.APPLICATION.name()), DSL.select(ORGANISATIONAL_UNIT.NAME) @@ -159,7 +141,13 @@ private SelectConditionStep prepareQuery(DSLContext dsl, IdSelectionOpti .on(ORGANISATIONAL_UNIT.ID.eq(APPLICATION.ORGANISATIONAL_UNIT_ID)) .where(APPLICATION.ID.eq(LOGICAL_FLOW.TARGET_ENTITY_ID))); - return dsl + Condition sourceIsApp = LOGICAL_FLOW.SOURCE_ENTITY_ID.in(appIdSelector).and(LOGICAL_FLOW.SOURCE_ENTITY_KIND.eq(EntityKind.APPLICATION.name())); + Condition targetIsApp = LOGICAL_FLOW.TARGET_ENTITY_ID.in(appIdSelector).and(LOGICAL_FLOW.TARGET_ENTITY_KIND.eq(EntityKind.APPLICATION.name())); + + FlowClassification sourceClassification = FLOW_CLASSIFICATION.as("sourceClassification"); + FlowClassification targetClassification = FLOW_CLASSIFICATION.as("targetClassification"); + + SelectConditionStep qry = dsl .select(SOURCE_NAME_FIELD.as("Source"), SOURCE_EXT_ID_FIELD.as("Source Asset Code"), sourceOrgUnitNameField.as("Source Org Unit")) @@ -167,26 +155,26 @@ private SelectConditionStep prepareQuery(DSLContext dsl, IdSelectionOpti TARGET_EXT_ID_FIELD.as("Target Asset Code"), targetOrgUnitNameField.as("Target Org Unit")) .select(DATA_TYPE.NAME.as("Data Type")) - .select(ENUM_VALUE.DISPLAY_NAME.as("Authoritativeness")) + .select(sourceClassification.NAME.as("Source Outbound Rating")) + .select(targetClassification.NAME.as("Target Inbound Rating")) .select(LOGICAL_FLOW.ID) .from(LOGICAL_FLOW) - .leftJoin(sourceAppFlows) - .on(sourceFlowId.eq(LOGICAL_FLOW.ID)) - .leftJoin(targetAppFlows) - .on(targetFlowId.eq(LOGICAL_FLOW.ID)) - .join(LOGICAL_FLOW_DECORATOR) - .on(LOGICAL_FLOW_DECORATOR.LOGICAL_FLOW_ID.eq(LOGICAL_FLOW.ID) + .innerJoin(LOGICAL_FLOW_DECORATOR) + .on(LOGICAL_FLOW_DECORATOR.LOGICAL_FLOW_ID.eq(LOGICAL_FLOW.ID) .and(LOGICAL_FLOW_DECORATOR.DECORATOR_ENTITY_KIND.eq(EntityKind.DATA_TYPE.name()))) - .join(DATA_TYPE) - .on(DATA_TYPE.ID.eq(LOGICAL_FLOW_DECORATOR.DECORATOR_ENTITY_ID) + .innerJoin(DATA_TYPE) + .on(DATA_TYPE.ID.eq(LOGICAL_FLOW_DECORATOR.DECORATOR_ENTITY_ID) .and(LOGICAL_FLOW_DECORATOR.DECORATOR_ENTITY_KIND.eq(EntityKind.DATA_TYPE.name()))) - .join(ENUM_VALUE) - .on(ENUM_VALUE.KEY.eq(LOGICAL_FLOW_DECORATOR.RATING) - .and(ENUM_VALUE.TYPE.eq("AuthoritativenessRating"))) - .where(LOGICAL_FLOW.ENTITY_LIFECYCLE_STATUS.ne(REMOVED.name())) + .innerJoin(sourceClassification) + .on(sourceClassification.CODE.eq(LOGICAL_FLOW_DECORATOR.RATING)) + .innerJoin(targetClassification) + .on(targetClassification.CODE.eq(LOGICAL_FLOW_DECORATOR.TARGET_INBOUND_RATING)) + .where(dsl.renderInlined(LOGICAL_FLOW.ENTITY_LIFECYCLE_STATUS.ne(REMOVED.name()) + .and(LOGICAL_FLOW.IS_REMOVED.isFalse()) .and(conditionForDataType) - .and(sourceFlowId.isNotNull() - .or(targetFlowId.isNotNull())); + .and(sourceIsApp.or(targetIsApp)))); + + return qry; } private Tuple3 prepareFlows(SelectConditionStep query,