Skip to content

Commit

Permalink
🐛 Update archetype model, form and detail drawer to current hub spec (#…
Browse files Browse the repository at this point in the history
…1438)

### Summary

Resolves: #1436

With hub updates to tag handling and api field name changes related to
archetypes, adjustments needed to be made to the UI.

### Archetype model
- Update `models.ts` to the current state of `TagRef` and `Archetype` in
terms of field names and data types.

  - MSW stub data updated to use api model changes.

### Archetype Table 
- **Note**: The tags column on the archetype table is currently
displaying ALL tags returned with no source differentiation.

### Archetype Add/EditForm
- Update `ArchetypeForm` to use `criteria` instead of `criteriaTags` as
per the api model changes.

- With hub changes to combine the archetype and non-archetype tags into
a single field, the form processing now ignored non-archetype fields but
still sends them on an update.

- Note: This change mirrors the behavior of manual / non-manual tags on
applications and the application form.

- Stakeholder and stakeholder groups handling is updated to use the
`*ToRef()` helper function style introduced in the application form
change #1408.

### Archetype Detail Drawer

- Since all tags for an archetype are provided in the same field `tags`,
filter them into "archetype tags" (i.e. an empty source) and "assessment
tags" (i.e. have a non-empty source) to display them separately.

- Note: The "archetype tags" are the tags manually attached to the
archetype in the new/edit form.

---------

Signed-off-by: Scott J Dickerson <[email protected]>
  • Loading branch information
sjd78 authored Oct 6, 2023
1 parent c93d891 commit 73f375f
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 50 deletions.
7 changes: 4 additions & 3 deletions client/src/app/api/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ export interface IReadFile {

export interface TagRef extends Ref {
source?: string;
virtual?: boolean;
}

export interface MigrationWave {
Expand Down Expand Up @@ -744,12 +745,12 @@ export interface Archetype {
name: string;
description: string;
comments: string;
criteriaTags: Tag[];
tags: Tag[];
assessmentTags?: Tag[];
tags: TagRef[];
criteria: TagRef[];
stakeholders?: Ref[];
stakeholderGroups?: Ref[];
applications?: Ref[];
assessments?: Ref[];
assessed?: boolean;
review?: Ref;
}
1 change: 0 additions & 1 deletion client/src/app/components/Autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,6 @@ export const Autocomplete: React.FC<IAutocompleteProps> = ({
const matchingOption = options.find(
(o) => o.toLowerCase() === (hint || newSelectionText).toLowerCase()
);
console.log({ matchingOption, newSelectionText, options });
if (!matchingOption || selections.includes(matchingOption)) {
return;
}
Expand Down
4 changes: 2 additions & 2 deletions client/src/app/pages/archetypes/archetypes-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -375,8 +375,6 @@ const Archetypes: React.FC = () => {
/>
</Modal>

{/* TODO: Add duplicate confirm modal */}

{/* Delete confirm modal */}
<ConfirmDialog
title={t("dialog.title.deleteWithName", {
Expand All @@ -398,6 +396,8 @@ const Archetypes: React.FC = () => {
}
}}
/>

{/* Override existing assessment confirm modal */}
<ConfirmDialog
title={t("dialog.title.newAssessment")}
titleIconVariant={"warning"}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as React from "react";
import React, { useMemo } from "react";
import { useTranslation } from "react-i18next";

import {
Expand All @@ -19,6 +19,7 @@ import spacing from "@patternfly/react-styles/css/utilities/Spacing/spacing";
import { Archetype, Tag } from "@app/api/models";
import { EmptyTextMessage } from "@app/components/EmptyTextMessage";
import { PageDrawerContent } from "@app/components/PageDrawerContext";
import { useFetchTagCategories } from "@app/queries/tags";

import "./archetype-detail-drawer.css";

Expand All @@ -33,6 +34,24 @@ const ArchetypeDetailDrawer: React.FC<IArchetypeDetailDrawerProps> = ({
}) => {
const { t } = useTranslation();

const { tagCategories } = useFetchTagCategories();
const tags = useMemo(
() => tagCategories.flatMap((tc) => tc.tags).filter(Boolean),
[tagCategories]
);

const archetypeTags =
archetype?.tags
?.filter((t) => t?.source ?? "" === "")
.map((ref) => tags.find((tag) => ref.id === tag.id))
.filter(Boolean) ?? [];

const assessmentTags =
archetype?.tags
?.filter((t) => t?.source ?? "" !== "")
.map((ref) => tags.find((tag) => ref.id === tag.id))
.filter(Boolean) ?? [];

return (
<PageDrawerContent
isExpanded={!!archetype}
Expand Down Expand Up @@ -63,8 +82,8 @@ const ArchetypeDetailDrawer: React.FC<IArchetypeDetailDrawerProps> = ({
<DescriptionListGroup>
<DescriptionListTerm>{t("terms.tagsCriteria")}</DescriptionListTerm>
<DescriptionListDescription>
{archetype?.criteriaTags?.length ?? 0 > 0 ? (
<TagLabels tags={archetype?.criteriaTags} />
{archetype?.criteria?.length ?? 0 > 0 ? (
<TagLabels tags={archetype?.criteria} />
) : (
<EmptyTextMessage message={t("terms.none")} />
)}
Expand All @@ -74,8 +93,8 @@ const ArchetypeDetailDrawer: React.FC<IArchetypeDetailDrawerProps> = ({
<DescriptionListGroup>
<DescriptionListTerm>{t("terms.tagsArchetype")}</DescriptionListTerm>
<DescriptionListDescription>
{archetype?.tags?.length ?? 0 > 0 ? (
<TagLabels tags={archetype?.tags} />
{archetypeTags.length > 0 ? (
<TagLabels tags={archetypeTags} />
) : (
<EmptyTextMessage message={t("terms.none")} />
)}
Expand All @@ -85,8 +104,8 @@ const ArchetypeDetailDrawer: React.FC<IArchetypeDetailDrawerProps> = ({
<DescriptionListGroup>
<DescriptionListTerm>{t("terms.tagsAssessment")}</DescriptionListTerm>
<DescriptionListDescription>
{archetype?.assessmentTags?.length ?? 0 > 0 ? (
<TagLabels tags={archetype?.assessmentTags} />
{assessmentTags.length > 0 ? (
<TagLabels tags={assessmentTags} />
) : (
<EmptyTextMessage message={t("terms.none")} />
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
import type {
Archetype,
New,
Ref,
Stakeholder,
StakeholderGroup,
Tag,
Expand All @@ -37,14 +36,15 @@ import { useFetchTagCategories } from "@app/queries/tags";
import { useFetchStakeholderGroups } from "@app/queries/stakeholdergoups";
import { useFetchStakeholders } from "@app/queries/stakeholders";
import ItemsSelect from "@app/components/items-select/items-select";
import { matchItemsToRefs } from "@app/utils/model-utils";

export interface ArchetypeFormValues {
name: string;
description?: string;
comments?: string;

// TODO: a string[] only works here with `Autocomplete` if the entities have globally unique names
criteriaTags: string[];
criteria: string[];
tags: string[];
stakeholders?: string[];
stakeholderGroups?: string[];
Expand All @@ -66,15 +66,24 @@ export const ArchetypeForm: React.FC<ArchetypeFormProps> = ({
const {
existingArchetypes,
tags,
tagsToRefs,
stakeholders,
stakeholdersToRefs,
stakeholderGroups,
stakeholderGroupsToRefs,
createArchetype,
updateArchetype,
} = useArchetypeFormData({
id: archetype?.id,
onActionSuccess: onClose,
});

const archetypeTags =
archetype?.tags?.filter((t) => t?.source ?? "" === "") ?? [];

const assessmentTags =
archetype?.tags?.filter((t) => t?.source ?? "" !== "") ?? [];

const validationSchema = yup.object().shape({
name: yup
.string()
Expand Down Expand Up @@ -104,7 +113,7 @@ export const ArchetypeForm: React.FC<ArchetypeFormProps> = ({
.max(250, t("validation.maxLength", { length: 250 })),

// for complex data fields
criteriaTags: yup
criteria: yup
.array()
.of(yup.string())
.min(1)
Expand Down Expand Up @@ -144,9 +153,8 @@ export const ArchetypeForm: React.FC<ArchetypeFormProps> = ({
description: archetype?.description || "",
comments: archetype?.comments || "",

criteriaTags:
archetype?.criteriaTags?.map((tag) => tag.name).sort() ?? [],
tags: archetype?.tags?.map((tag) => tag.name).sort() ?? [],
criteria: archetype?.criteria?.map((tag) => tag.name).sort() ?? [],
tags: archetypeTags.map((tag) => tag.name).sort() ?? [],

stakeholders: archetype?.stakeholders?.map((sh) => sh.name).sort() ?? [],
stakeholderGroups:
Expand All @@ -157,38 +165,24 @@ export const ArchetypeForm: React.FC<ArchetypeFormProps> = ({
});

const onValidSubmit = (values: ArchetypeFormValues) => {
// Note: We need to manually retain the tags with source != "" in the payload
const tags = [...(tagsToRefs(values.tags) ?? []), ...assessmentTags];

const payload: New<Archetype> = {
name: values.name.trim(),
description: values.description?.trim() ?? "",
comments: values.comments?.trim() ?? "",

criteriaTags: values.criteriaTags
criteria: values.criteria
.map((tagName) => tags.find((tag) => tag.name === tagName))
.filter(Boolean) as Tag[],
.filter(Boolean),

tags: values.tags
.map((tagName) => tags.find((tag) => tag.name === tagName))
.filter(Boolean) as Tag[],

stakeholders:
values.stakeholders === undefined
? undefined
: (values.stakeholders
.map((name) => stakeholders.find((s) => s.name === name))
.map<Ref | undefined>((sh) =>
!sh ? undefined : { id: sh.id, name: sh.name }
)
.filter(Boolean) as Ref[]),
.filter(Boolean),

stakeholderGroups:
values.stakeholderGroups === undefined
? undefined
: (values.stakeholderGroups
.map((name) => stakeholderGroups.find((s) => s.name === name))
.map<Ref | undefined>((sg) =>
!sg ? undefined : { id: sg.id, name: sg.name }
)
.filter(Boolean) as Ref[]),
stakeholders: stakeholdersToRefs(values.stakeholders),
stakeholderGroups: stakeholderGroupsToRefs(values.stakeholderGroups),
};

if (archetype && !isDuplicating) {
Expand Down Expand Up @@ -218,9 +212,9 @@ export const ArchetypeForm: React.FC<ArchetypeFormProps> = ({
<ItemsSelect<Tag, ArchetypeFormValues>
items={tags}
control={control}
name="criteriaTags"
name="criteria"
label="Criteria Tags"
fieldId="criteriaTags"
fieldId="criteria"
isRequired
noResultsMessage={t("message.noResultsFoundTitle")}
placeholderText={t("composed.selectMany", {
Expand All @@ -234,7 +228,7 @@ export const ArchetypeForm: React.FC<ArchetypeFormProps> = ({
control={control}
name="tags"
label="Archetype Tags"
fieldId="archetypeTags"
fieldId="tags"
isRequired
noResultsMessage={t("message.noResultsFoundTitle")}
placeholderText={t("composed.selectMany", {
Expand Down Expand Up @@ -323,6 +317,7 @@ const useArchetypeFormData = ({
const { t } = useTranslation();
const { pushNotification } = React.useContext(NotificationsContext);

// Fetch data
const { archetypes: existingArchetypes } = useFetchArchetypes();
const { archetype } = useFetchArchetypeById(id);

Expand All @@ -335,6 +330,17 @@ const useArchetypeFormData = ({
const { stakeholderGroups } = useFetchStakeholderGroups();
const { stakeholders } = useFetchStakeholders();

// Helpers
const tagsToRefs = (names: string[] | undefined | null) =>
matchItemsToRefs(tags, (i) => i.name, names);

const stakeholdersToRefs = (names: string[] | undefined | null) =>
matchItemsToRefs(stakeholders, (i) => i.name, names);

const stakeholderGroupsToRefs = (names: string[] | undefined | null) =>
matchItemsToRefs(stakeholderGroups, (i) => i.name, names);

// Mutation notification handlers
const onCreateSuccess = (archetype: Archetype) => {
pushNotification({
title: t("toastr.success.createWhat", {
Expand Down Expand Up @@ -381,7 +387,10 @@ const useArchetypeFormData = ({
updateArchetype,
tagCategories,
tags,
tagsToRefs,
stakeholders,
stakeholdersToRefs,
stakeholderGroups,
stakeholderGroupsToRefs,
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const TagLabel: React.FC<{
// TODO: Refactor the application-tags-label.tsx so applications and archetypes can share `TagLabel`
// TODO: Sort tags?
// TODO: Group tags by categories?
// TODO: Display ONLY manual tags (source==="") or display tags from ALL sources?
const ArchetypeTagsColumn: React.FC<{ archetype: Archetype }> = ({
archetype,
}) => (
Expand Down
12 changes: 6 additions & 6 deletions client/src/mocks/stub-new-work/archetypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,37 +140,37 @@ const data: Record<number, Archetype> = {
name: "Wayne",
description: "Wayne does the bare minimum",
comments: "This one needs coffee",
criteriaTags: [tagData["1"]],
criteria: [tagData["1"]],
tags: [tagData["81"]],
assessmentTags: [],
stakeholders: [],
stakeholderGroups: [],
assessed: false,
},

2: {
id: 2,
name: "Garth",
description: "Garth has some extra tags",
comments: "This one needs tea",
criteriaTags: [tagData["2"]],
criteria: [tagData["2"]],
tags: [tagData["81"], tagData["82"]],
assessmentTags: [],
stakeholders: [],
stakeholderGroups: [],
assessed: false,
},

3: {
id: 3,
name: "Cassandra",
description: "Cassandra is the most complex",
comments: "This one needs cakes",
criteriaTags: [tagData["3"]],
criteria: [tagData["3"]],
tags: [tagData["81"], tagData["82"], tagData["83"]],
assessmentTags: [],
stakeholders: [],
stakeholderGroups: [],
// assessments: [{ id: 1, name: "test" }],
assessments: [],
assessed: false,
},
};

Expand Down

0 comments on commit 73f375f

Please sign in to comment.