From 3d5143f059370f00e046cee9077954abb9bbaf31 Mon Sep 17 00:00:00 2001 From: Elsa Date: Tue, 30 Apr 2024 09:54:15 -0400 Subject: [PATCH 1/4] Add clone operation for draft artifacts --- ...rmationModal.tsx => ConfirmationModal.tsx} | 14 +- app/src/components/ResourceInfoCard.tsx | 139 +++++++++++++----- app/src/pages/authoring/index.tsx | 4 +- app/src/server/db/dbOperations.ts | 24 +++ app/src/server/trpc/routers/draft.ts | 40 ++--- app/src/server/trpc/routers/service.ts | 6 +- app/src/util/draftHelper.ts | 31 ++++ app/src/util/modifyResourceFields.ts | 7 +- 8 files changed, 195 insertions(+), 70 deletions(-) rename app/src/components/{DeletionConfirmationModal.tsx => ConfirmationModal.tsx} (66%) create mode 100644 app/src/util/draftHelper.ts diff --git a/app/src/components/DeletionConfirmationModal.tsx b/app/src/components/ConfirmationModal.tsx similarity index 66% rename from app/src/components/DeletionConfirmationModal.tsx rename to app/src/components/ConfirmationModal.tsx index 9b687018..4092b2f8 100644 --- a/app/src/components/DeletionConfirmationModal.tsx +++ b/app/src/components/ConfirmationModal.tsx @@ -1,23 +1,25 @@ import { Modal, Button, Center, Group, Text } from '@mantine/core'; import { AlertTriangle } from 'tabler-icons-react'; -export interface DeletionConfirmationModalProps { +export interface ConfirmationModalProps { open: boolean; onClose: () => void; onConfirm: () => void; + action: string; modalText?: string | null; } -export default function DeletionConfirmationModal({ +export default function ConfirmationModal({ open = true, onClose, onConfirm, + action, modalText -}: DeletionConfirmationModalProps) { +}: ConfirmationModalProps) { return (
- +
@@ -29,8 +31,8 @@ export default function DeletionConfirmationModal({ -
diff --git a/app/src/components/ResourceInfoCard.tsx b/app/src/components/ResourceInfoCard.tsx index 59c5dbd7..1be27c01 100644 --- a/app/src/components/ResourceInfoCard.tsx +++ b/app/src/components/ResourceInfoCard.tsx @@ -13,10 +13,10 @@ import { import Link from 'next/link'; import React, { useState } from 'react'; import { ResourceInfo } from '@/util/types/fhir'; -import { Edit, SquareArrowRight, Trash, AlertCircle, CircleCheck, Report } from 'tabler-icons-react'; +import { Edit, SquareArrowRight, Trash, AlertCircle, CircleCheck, Report, Copy } from 'tabler-icons-react'; import { trpc } from '@/util/trpc'; import { notifications } from '@mantine/notifications'; -import DeletionConfirmationModal from './DeletionConfirmationModal'; +import ConfirmationModal from './ConfirmationModal'; export interface ResourceInfoCardProps { resourceInfo: ResourceInfo; @@ -36,67 +36,106 @@ const useStyles = createStyles(theme => ({ export default function ResourceInfoCard({ resourceInfo, authoring }: ResourceInfoCardProps) { const { classes } = useStyles(); - const ctx = trpc.useContext(); - const [isConfirmationModalOpen, setIsConfirmationModalOpen] = useState(false); + const utils = trpc.useUtils(); + const [isDeleteConfirmationModalOpen, setIsDeleteConfirmationModalOpen] = useState(false); + const [isCloneConfirmationModalOpen, setIsCloneConfirmationModalOpen] = useState(false); - const successNotification = (resourceType: string, childArtifact: boolean, idOrUrl?: string) => { + const successNotification = (resourceType: string, childArtifact: boolean, action: string, idOrUrl?: string) => { let message; if (childArtifact) { - message = `Draft of child ${resourceType} artifact of url ${idOrUrl} successfully deleted`; + message = `Draft of child ${resourceType} artifact of url ${idOrUrl} successfully ${ + action === 'delete' ? 'deleted' : 'cloned' + }`; } else { - message = `Draft of ${resourceType}/${idOrUrl} successfully deleted`; + message = `Draft of ${resourceType}/${idOrUrl} successfully ${action === 'delete' ? 'deleted' : 'cloned'}`; } notifications.show({ - title: `${resourceType} Deleted!`, + title: `${resourceType} ${action === 'delete' ? 'Deleted' : 'Cloned'}!`, message: message, icon: , color: 'green' }); - ctx.draft.getDraftCounts.invalidate(); + utils.draft.getDraftCounts.invalidate(); }; - const errorNotification = (resourceType: string, errorMessage: string, childArtifact: boolean, idOrUrl?: string) => { + const errorNotification = ( + resourceType: string, + errorMessage: string, + childArtifact: boolean, + action: string, + idOrUrl?: string + ) => { let message; if (childArtifact) { - message = `Attempt to delete draft of child ${resourceType} artifact of url ${idOrUrl} failed with message: ${errorMessage}`; + message = `Attempt to ${action} draft of child ${resourceType} artifact of url ${idOrUrl} failed with message: ${errorMessage}`; } else { - message = `Attempt to delete draft of ${resourceType}/${idOrUrl} failed with message: ${errorMessage}`; + message = `Attempt to ${action} draft of ${resourceType}/${idOrUrl} failed with message: ${errorMessage}`; } notifications.show({ - title: `${resourceType} Deletion Failed!`, + title: `${resourceType} ${action === 'delete' ? 'Deletion' : 'Clone'} Failed!`, message: message, icon: , color: 'red' }); }; + const cloneMutation = trpc.draft.cloneParent.useMutation({ + onSuccess: (data, variables) => { + successNotification(variables.resourceType, false, 'clone', variables.id); + data.children.forEach(c => { + successNotification(c.resourceType, true, 'clone', c.url); + }); + utils.draft.getDrafts.invalidate(); + setIsCloneConfirmationModalOpen(false); + }, + onError: (e, variables) => { + errorNotification(variables.resourceType, e.message, false, 'clone', variables.id); + } + }); + const deleteMutation = trpc.draft.deleteParent.useMutation({ onSuccess: (data, variables) => { - successNotification(variables.resourceType, false, variables.id); + successNotification(variables.resourceType, false, 'delete', variables.id); data.children.forEach(c => { - successNotification(c.resourceType, true, c.url); + successNotification(c.resourceType, true, 'delete', c.url); }); - ctx.draft.getDrafts.invalidate(); + utils.draft.getDrafts.invalidate(); + setIsCloneConfirmationModalOpen(false); }, onError: (e, variables) => { - errorNotification(variables.resourceType, e.message, false, variables.id); + errorNotification(variables.resourceType, e.message, false, 'delete', variables.id); } }); return ( <> - setIsConfirmationModalOpen(false)} - modalText={`This will delete draft ${resourceInfo.resourceType} "${ + setIsCloneConfirmationModalOpen(false)} + onConfirm={() => { + cloneMutation.mutate({ + resourceType: resourceInfo.resourceType, + id: resourceInfo.id + }); + }} + action="clone" + modalText={`This will clone draft ${resourceInfo.resourceType} "${ resourceInfo.name ? resourceInfo.name : `${resourceInfo.resourceType}/${resourceInfo.id}` - }" and any child artifacts permanently.`} + }" and any child artifacts.`} + /> + setIsDeleteConfirmationModalOpen(false)} onConfirm={() => { deleteMutation.mutate({ resourceType: resourceInfo.resourceType, id: resourceInfo.id }); }} + action="delete" + modalText={`This will delete draft ${resourceInfo.resourceType} "${ + resourceInfo.name ? resourceInfo.name : `${resourceInfo.resourceType}/${resourceInfo.id}` + }" and any child artifacts permanently.`} /> @@ -155,25 +194,47 @@ export default function ResourceInfoCard({ resourceInfo, authoring }: ResourceIn {authoring && (resourceInfo.isChild ? ( - - - + + + + + + + + + + + + + + + + + ) : ( + + + setIsCloneConfirmationModalOpen(true)} + > + + + + + setIsDeleteConfirmationModalOpen(true)} + > - - - ) : ( - - setIsConfirmationModalOpen(true)} - > - - - + + ))} diff --git a/app/src/pages/authoring/index.tsx b/app/src/pages/authoring/index.tsx index 80256850..970cd593 100644 --- a/app/src/pages/authoring/index.tsx +++ b/app/src/pages/authoring/index.tsx @@ -35,7 +35,7 @@ export default function AuthoringPage() { error: artifactError } = trpc.service.getArtifactsByType.useQuery({ resourceType }); - const ctx = trpc.useContext(); + const utils = trpc.useUtils(); const { classes } = useStyles(); const router = useRouter(); @@ -59,7 +59,7 @@ export default function AuthoringPage() { icon: , color: 'green' }); - ctx.draft.getDraftCounts.invalidate(); + utils.draft.getDraftCounts.invalidate(); }; const errorNotification = ( diff --git a/app/src/server/db/dbOperations.ts b/app/src/server/db/dbOperations.ts index 41ad233d..6bebcb77 100644 --- a/app/src/server/db/dbOperations.ts +++ b/app/src/server/db/dbOperations.ts @@ -115,3 +115,27 @@ export async function batchDeleteDraft(drafts: FhirArtifact[]) { } if (error) throw error; } + +/** + * Clones a parent artifact and all of its children (if applicable) in a batch + */ +export async function batchCloneDraft(drafts: FhirArtifact[]) { + let error = null; + const client = await clientPromise; + const cloneSession = client.startSession(); + try { + await cloneSession.withTransaction(async () => { + for (const draft of drafts) { + const collection = await client.db().collection(draft.resourceType); + await collection.insertOne(draft as any, { session: cloneSession }); + } + }); + console.log('Batch clone transaction committed.'); + } catch (err) { + console.log('Batch clone transaction failed: ' + err); + error = err; + } finally { + await cloneSession.endSession(); + } + if (error) throw error; +} diff --git a/app/src/server/trpc/routers/draft.ts b/app/src/server/trpc/routers/draft.ts index a0bc75e7..6330bdef 100644 --- a/app/src/server/trpc/routers/draft.ts +++ b/app/src/server/trpc/routers/draft.ts @@ -8,10 +8,12 @@ import { updateDraft, deleteDraft, getDraftByUrl, - batchDeleteDraft + batchDeleteDraft, + batchCloneDraft } from '../../db/dbOperations'; import { publicProcedure, router } from '../trpc'; -import { getDraftChildren } from '@/util/serviceUtils'; +import { getParentDraftArtifactAndChildren } from '@/util/draftHelper'; +import { modifyResource } from '@/util/modifyResourceFields'; /** one big router with resource types passed in */ export const draftRouter = router({ @@ -74,27 +76,29 @@ export const draftRouter = router({ deleteParent: publicProcedure .input(z.object({ id: z.string(), resourceType: z.enum(['Measure', 'Library']) })) .mutation(async ({ input }) => { - // get the parent draft artifact by id - const draftRes = await getDraftById(input.id, input.resourceType); + const { draftArtifacts, draftRes, children } = await getParentDraftArtifactAndChildren( + input.id, + input.resourceType + ); - if (!draftRes) { - throw new Error(`No draft artifact found for resourceType ${input.resourceType}, id ${input.id}`); - } + await batchDeleteDraft(draftArtifacts); - // recursively get any child artifacts from the artifact if they exist - const children = draftRes?.relatedArtifact ? await getDraftChildren(draftRes.relatedArtifact) : []; + return { draftId: draftRes.id, children: children }; + }), - const childDrafts = children.map(async child => { - const draft = await getDraftByUrl(child.url, child.version, child.resourceType); - if (!draft) { - throw new Error('No artifacts found in search'); - } - return draft; - }); + cloneParent: publicProcedure + .input(z.object({ id: z.string(), resourceType: z.enum(['Measure', 'Library']) })) + .mutation(async ({ input }) => { + const { draftArtifacts, draftRes, children } = await getParentDraftArtifactAndChildren( + input.id, + input.resourceType + ); - const draftArtifacts = [draftRes].concat(await Promise.all(childDrafts)); + const clones = await draftArtifacts.map(async draftArtifact => { + return await modifyResource(draftArtifact, 'clone'); + }); - await batchDeleteDraft(draftArtifacts); + await batchCloneDraft(await Promise.all(clones)); return { draftId: draftRes.id, children: children }; }) diff --git a/app/src/server/trpc/routers/service.ts b/app/src/server/trpc/routers/service.ts index ff91df08..cebd9bb2 100644 --- a/app/src/server/trpc/routers/service.ts +++ b/app/src/server/trpc/routers/service.ts @@ -1,6 +1,6 @@ import { publicProcedure, router } from '../trpc'; import { batchCreateDraft, getDraftById, getDraftByUrl } from '@/server/db/dbOperations'; -import { modifyResourceToDraft } from '@/util/modifyResourceFields'; +import { modifyResource } from '@/util/modifyResourceFields'; import { FhirArtifact } from '@/util/types/fhir'; import { z } from 'zod'; import { TRPCError } from '@trpc/server'; @@ -94,9 +94,9 @@ export const serviceRouter = router({ const draftRes = artifactBundle.entry?.[0].resource; // increment the version in the url and update the relatedArtifact.resource to have the new version on the url - return await modifyResourceToDraft(draftRes as FhirArtifact); + return await modifyResource(draftRes as FhirArtifact, 'draft'); }); - const parentArtifact = await modifyResourceToDraft({ ...draftJson }); + const parentArtifact = await modifyResource({ ...draftJson }, 'draft'); const draftArtifacts = [parentArtifact].concat(await Promise.all(childDrafts)); // create a draft of the modified parent artifact and any children diff --git a/app/src/util/draftHelper.ts b/app/src/util/draftHelper.ts new file mode 100644 index 00000000..048f60c2 --- /dev/null +++ b/app/src/util/draftHelper.ts @@ -0,0 +1,31 @@ +import { getDraftById, getDraftByUrl } from '@/server/db/dbOperations'; +import { ArtifactResourceType } from './types/fhir'; +import { FhirArtifact } from '@/util/types/fhir'; +import { ChildArtifactInfo, getDraftChildren } from './serviceUtils'; + +export async function getParentDraftArtifactAndChildren( + id: string, + resourceType: ArtifactResourceType +): Promise<{ draftArtifacts: FhirArtifact[]; draftRes: FhirArtifact; children: ChildArtifactInfo[] }> { + // get the parent draft artifact by id + const draftRes = await getDraftById(id, resourceType); + + if (!draftRes) { + throw new Error(`No draft artifact found for resourceType ${resourceType}, id ${id}`); + } + + // recursively get any child artifacts from the artifact if they exist + const children = draftRes?.relatedArtifact ? await getDraftChildren(draftRes.relatedArtifact) : []; + + const childDrafts = children.map(async child => { + const draft = await getDraftByUrl(child.url, child.version, child.resourceType); + if (!draft) { + throw new Error('No artifacts found in search'); + } + return draft; + }); + + const draftArtifacts = [draftRes].concat(await Promise.all(childDrafts)); + + return { draftArtifacts, draftRes, children }; +} diff --git a/app/src/util/modifyResourceFields.ts b/app/src/util/modifyResourceFields.ts index 4828757d..a3708919 100644 --- a/app/src/util/modifyResourceFields.ts +++ b/app/src/util/modifyResourceFields.ts @@ -8,9 +8,12 @@ import { getDraftByUrl } from '@/server/db/dbOperations'; * draft status, and increments the version if it has one or sets it to * 0.0.1 if it does not */ -export async function modifyResourceToDraft(artifact: FhirArtifact) { +export async function modifyResource(artifact: FhirArtifact, action: string) { artifact.id = uuidv4(); - artifact.status = 'draft'; + if (action === 'draft') { + artifact.status = 'draft'; + } + let count = 0; // initial version coercion and increment From 2ffe831ef638411f010aed133ad0f2250f345607 Mon Sep 17 00:00:00 2001 From: Elsa Date: Tue, 30 Apr 2024 10:58:04 -0400 Subject: [PATCH 2/4] Fixed button formatting --- app/src/components/ResourceInfoCard.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/components/ResourceInfoCard.tsx b/app/src/components/ResourceInfoCard.tsx index 1be27c01..92874308 100644 --- a/app/src/components/ResourceInfoCard.tsx +++ b/app/src/components/ResourceInfoCard.tsx @@ -27,7 +27,7 @@ const useStyles = createStyles(theme => ({ card: { borderRadius: 6, border: `${rem(1)} solid ${theme.colors.gray[3]}`, - width: '800px', + width: '900px', [`@media (max-width: ${em(getBreakpointValue(theme.breakpoints.lg) - 1)})`]: { width: '100%' } @@ -139,7 +139,7 @@ export default function ResourceInfoCard({ resourceInfo, authoring }: ResourceIn /> - +
{resourceInfo.name ? resourceInfo.name : `${resourceInfo.resourceType}/${resourceInfo.id}`} From ac3925eb3189edfd38f5d856a84dc59c91f14d5f Mon Sep 17 00:00:00 2001 From: Elsa Date: Thu, 2 May 2024 11:03:13 -0400 Subject: [PATCH 3/4] Clone and other operation descriptions added to the README --- app/README.md | 86 +++++++++++++++++------- app/static/artifact-comment.png | Bin 0 -> 45259 bytes app/static/authoring-options.png | Bin 4805 -> 0 bytes app/static/clone.png | Bin 0 -> 3781 bytes app/static/draft-artifact-2.png | Bin 0 -> 7097 bytes app/static/draft-repository-options.png | Bin 0 -> 4937 bytes app/static/review.png | Bin 0 -> 3949 bytes app/static/update-release.png | Bin 0 -> 6335 bytes app/static/withdraw.png | Bin 0 -> 3777 bytes 9 files changed, 61 insertions(+), 25 deletions(-) create mode 100644 app/static/artifact-comment.png delete mode 100644 app/static/authoring-options.png create mode 100644 app/static/clone.png create mode 100644 app/static/draft-artifact-2.png create mode 100644 app/static/draft-repository-options.png create mode 100644 app/static/review.png create mode 100644 app/static/update-release.png create mode 100644 app/static/withdraw.png diff --git a/app/README.md b/app/README.md index 0e400c79..efa2b5a8 100644 --- a/app/README.md +++ b/app/README.md @@ -51,7 +51,7 @@ The application is divided into two main sets of functionality, _Repository_ and Screenshot of tabs -The Repository tab provides functionality for accessing and interacting with artifacts that are in the FHIR Measure Repository Service. The Authoring tab focuses on artifacts that are in the process of being drafted. Artifact content can be copied or moved between these two spaces through _draft_ and _release_ actions, described in the [Viewing](#viewing) and [Editing](#editing) sections. +The Repository tab provides functionality for accessing and interacting with artifacts that are in the FHIR Measure Repository Service. The Authoring tab focuses on artifacts that are in the process of being drafted. Artifact content can be copied or moved between these two spaces through _draft_ and _release_ actions, described in the [Draft](#draft) and [Release](#release) sections. Within these tabs, the left panel navigation allows for selecting artifact types or searching (Repository only) for artifacts so that they can be browsed for viewing or actions. @@ -61,46 +61,82 @@ Within these tabs, the left panel navigation allows for selecting artifact types The landing page can be accessed on first load or by clicking the Measure Repository home button in the top left corner. This page links to resources to learn more about the Measure Repository and shows existing FHIR service capabilities. -## Repository Tab +# Repository Tab The Repository tab displays sets of artifacts from the FHIR Measure Repository Service. Options allow for viewing resource details or reviewing the resource. Screenshot of repository options ### Viewing -- Measure: Resource details show the JSON as well as options to see the Narrative, Data Requirements, and Dependencies, if they exist. -- Library: Resource details show the JSON as well as options to see the ELM, CQL, Narrative, Data Requirements, and Dependencies, if they exist. -- Drafting: Both resource views allow the user to create a draft from the artifact. This action copies the existing artifact and any children it owns to the draft Authoring space with a draft status and an incremented version to logically differentiate it from the original artifact. See the [draft operation specification](http://hl7.org/fhir/us/cqfmeasures/measure-repository-service.html#draft). -### Reviewing +- Measure: Resource details show the JSON as well as options to see the Narrative, Data Requirements, and Dependencies, if they exist. +- Library: Resource details show the JSON as well as options to see the ELM, CQL, Narrative, Data Requirements, and Dependencies, if they exist. +- Drafting: Both resource views allow the user to create a draft from the artifact. This action copies the existing artifact and any children it owns to the draft Authoring space with a draft status and an incremented version to logically differentiate it from the original artifact. See the [draft operation specification](http://hl7.org/fhir/us/cqfmeasures/measure-repository-service.html#draft). -Reviewing a resource provides options for viewing existing comments on the resource or adding a new comment. (Note: this is currently partially implemented and requires updates for viewing comments.) +### Review -## Authoring Tab +While the Quality Measure IG is not yet entirely clear on the role of a review operation on active artifacts in a published measure repository, the frontend currently supports the temporary functionality of adding artifact comments on active artifacts due to the [review operation definition](https://build.fhir.org/ig/HL7/crmi-ig/OperationDefinition-crmi-review.html) including "regardless of status". However, this is not currently supported as an update to the artifact: artifact comments on active artifacts may be viewed in the frontend, but they may not yet be added to the artifact on the published measure repository through an update interaction. -The Authoring tab gives options for creating a new draft artifact from scratch or starting from a copy of an existing artifact from the FHIR Measure Repository. +# Authoring Tab + +The Authoring tab gives options for creating a new draft artifact from scratch or starting from a copy of an existing artifact from the FHIR Measure Repository. The Authoring tab also displays options for revising, reviewing, cloning, releasing, or withdrawing a draft artifact. + +Screenshot of draft repository options + +## Supported Authoring Measure Repository Capabilities + +The following capabilities are supported in the measure repository authoring frontend as currently defined by the [Quality Measure Implementation Guide](https://build.fhir.org/ig/HL7/cqf-measures/measure-repository-service.html#authoring-measure-repository). Note that these implementations are subject to change as the Measure Repository Service specification in the [QMIG](https://build.fhir.org/ig/HL7/cqf-measures/measure-repository-service.html#measure-repository-service) and the Artifact Repository Service in the [Canonical Resource Management Infrastructure Implementation Guide](https://hl7.org/fhir/uv/crmi/1.0.0-snapshot/CapabilityStatement-crmi-authoring-artifact-repository.html) are developed. + +### Submit + +The measure repository app supports the submit operation by allowing the creation of a new Measure or Library artifact in draft status. The user can achieve this action by navigating to the "Authoring" tab and clicking "Create New Draft [Measure or Library]" under "Start From Scratch": Screenshot of create draft artifact + +### Revise + +The measure repository app supports the revise operation by allowing draft artifacts to be updated through changes to the following basic resource fields: + +- url +- identifier value +- identifier system +- name +- title +- description +- library (Measure only) + +Screenshot of update/release draft artifact from authoring tab + +### Draft + +The measure repository app supports the draft operation by allowing the creating a new Measure or Library artifact from an existing Measure or Library in "active" status. The user can achieve this in two ways: either the dropdown menu on the "Authoring" tab under "Start From an Existing Library" or on the "Create Draft of [Measure or Library]" button in the top right corner of an existing active Measure or Library artifact in the "Repository" tab. As more formally specified in the [CRMI Draft Operation Definition](https://build.fhir.org/ig/HL7/crmi-ig/OperationDefinition-crmi-draft.html), the draft operation is applied to the resources that an artifact is composed of, recursively. This operation is done as a batch for an artifact and any child artifacts that it is composed of. + +Screenshot of create draft measure artifact from authoring tab + +Screenshot of create draft library artifact from repository tab + +### Release + +The measure repository app supports the release operation by allowing the update of an existing draft artifact to "active" status. This involves the newly active artifact to be POSTed to the published measure repository and thus removed from the draft repository. The user can achieve this by clicking the "Release" button on a draft artifact in the "Authoring" tab. As more formally specified in the [CRMI Release Operation Definition](https://build.fhir.org/ig/HL7/crmi-ig/OperationDefinition-crmi-release.html), the release operation is applied to the resources that an artifact is composed of, recursively. This operation is done as a batch for an artifact and any child artifacts that it is composed of. + +Screenshot of update/release draft artifact from authoring tab + +### Clone + +The measure repository app supports the clone operation by allowing the ability to clone an existing draft artifact to include the contents of the existing artifact with status "draft" and a new ID. The user can achieve this with the "clone" button on the draft artifact cards in the "Authoring" tab. As more formally specified in the [CRMI Clone Operation Definition](https://build.fhir.org/ig/HL7/crmi-ig/OperationDefinition-crmi-clone.html), the clone operation is applied to the resources that an artifact is composed of, recursively. This operation is done as a batch for an artifact and any child artifacts that it is composed of. + +Screenshot of clone button for artifact -The left navigation resource type selection displays sets of artifacts that are in progress and being drafted for potential addition to the FHIR Measure Repository. Options allow for editing, reviewing, or deleting a draft resource. +### Withdraw -Screenshot of authoring options +The measure repository app supports the withdraw operation by allowing the ability to delete an existing draft artifact from the draft repository. The user can achieve this with the "delete" button on the draft artifact cards in the "Authoring" tab. Although not formally specified in the QM or CRMI IGs yet, the withdraw operation is applied to the draft resources that an artifact is composed of, recursively. This operation is done as a batch for an artifact and any child artifacts that it is composed of. -### Editing -- Updating: A Measure or Library allows changes to basic resource fields: - - url - - identifier value - - identifier system - - name - - title - - description - - library (Measure only) -- Releasing: Both resource types may be released from the editing page. This action publishes the draft artifact and any children it owns to the Repository space, adding them to the FHIR Measure Repository and giving them an active status. The draft artifact(s) will be removed from the Authoring space. See the [release operation specification](http://hl7.org/fhir/us/cqfmeasures/measure-repository-service.html#release). +Screenshot of withdraw button for artifact -### Reviewing +### Review -Reviewing a resource provides options for viewing existing comments on the resource or adding a new comment. +The measure repository app supports the review operation by adding artifact comments to an existing draft artifact. The artifact comment is currently added to a draft artifact as a [CQFM Artifact Comment Extension]("http://hl7.org/fhir/us/cqfmeasures/StructureDefinition/cqfm-artifactComment"). This extension requires a type ("Documentation", "Review", "Guidance") which can be specified in the dropdown. Optionally, the extension can include an authoredOn date and the name of the user who endorsed the comment. The review operation is more formally defined in the [CRMI Review Operation Definition](https://build.fhir.org/ig/HL7/crmi-ig/OperationDefinition-crmi-review.html); however, creation of ArtifactAssessment resources in the repository is not yet supported. -### Deleting +Screenshot of review button for artifact -Deleting an artifact will permanently remove it from the draft database. +Screenshot of add draft artifact comment diff --git a/app/static/artifact-comment.png b/app/static/artifact-comment.png new file mode 100644 index 0000000000000000000000000000000000000000..d932e6d0731c8a2ee09a1740a3674457624d8a6a GIT binary patch literal 45259 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 literal 0 HcmV?d00001 diff --git a/app/static/authoring-options.png b/app/static/authoring-options.png deleted file mode 100644 index 25705b3878b14a8d2026a8da3624dead0bddf3ab..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4805 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 EKTu*N!TtzVDfH!l7C!WWM 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 literal 0 HcmV?d00001 diff --git a/app/static/review.png b/app/static/review.png new file mode 100644 index 0000000000000000000000000000000000000000..d813912778918492026cdd49af610fc3ba68858e GIT binary patch literal 3949 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 literal 0 HcmV?d00001 From a286dc2ff5ec023a5ccc744dd28bc0cb502b20b9 Mon Sep 17 00:00:00 2001 From: Elsa Date: Mon, 6 May 2024 12:13:06 -0400 Subject: [PATCH 4/4] Remove docker-compose content in README --- README.md | 61 +++++++++++++------------------------------------------ 1 file changed, 14 insertions(+), 47 deletions(-) diff --git a/README.md b/README.md index 8329b23f..0a8be883 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Measure Repository -A prototype implementation of a [FHIR Measure Repository Service](http://hl7.org/fhir/us/cqfmeasures/measure-repository-service.html) and associated frontend application. This repository is a monorepo that consists of: +A prototype implementation of a [FHIR Measure Repository Service](http://hl7.org/fhir/us/cqfmeasures/measure-repository-service.html) and associated frontend application. This repository is a monorepo that consists of: + - [Measure Repository Service](https://github.com/projecttacoma/measure-repository/blob/main/service/README.md) - Implements portions of the [FHIR Measure Repository Service](http://hl7.org/fhir/us/cqfmeasures/measure-repository-service.html) specification - Acts as a FHIR server and shared source of truth for measures and libraries @@ -33,9 +34,11 @@ npm install --workspace= ``` Make a copy of `.env` files: + ```bash cp app/.env.example app/.env.local ``` + ```bash cp service/.env.example service/.env ``` @@ -47,20 +50,25 @@ Make any changes to point to the measure repository service, Mongo database, and Use the mongodb configuration file to configure the single node replica set. For more information about the configuration file and system location, see the mongodb [configuration file documentation](https://www.mongodb.com/docs/manual/reference/configuration-options/). 1. First shutdown any currently running mongodb standalone instances: `brew services stop mongodb-community`. -2. Locate your [Mongo Configuration File](https://www.mongodb.com/docs/compass/current/settings/config-file/#:~:text=For%20macOS%20and%20Linux%2C%20the,%5Cmongodb%2Dcompass.). *System dependent but may be found at `/usr/local/etc/mongod.conf`*. +2. Locate your [Mongo Configuration File](https://www.mongodb.com/docs/compass/current/settings/config-file/#:~:text=For%20macOS%20and%20Linux%2C%20the,%5Cmongodb%2Dcompass.). _System dependent but may be found at `/usr/local/etc/mongod.conf`_. 3. Add this replication set configuration to the mongo configuration file: + ``` replication: replSetName: rs0 ``` + 4. Start mongodb again using homebrew: `brew services restart mongodb-community`. 5. Initialize the replica set using mongosh: + ```bash mongosh ``` + ```bash rs.initiate() ``` + 6. From here you can continue to use the replica set, and in the future, you can do a normal start of the server using homebrew: `brew services start mongodb-community` (without need to reinitialize the replica set). Further information on standalone to replica set conversion can be found in the mongodb [replica set conversion documentation](https://www.mongodb.com/docs/manual/tutorial/convert-standalone-to-replica-set/). @@ -94,11 +102,12 @@ To run `lint` and `prettier` in both the frontend and backend and unit tests in ```bash npm run check:all ``` -> Note: You may recieve a workspace error. This does not prevent the service from running, to remove the error for future builds, run `npx next telemetry disable` + +> Note: You may receive a workspace error. This does not prevent the service from running, to remove the error for future builds, run `npx next telemetry disable` ### Docker -To start the app and repository service in parallel, run +To start the app and repository service in parallel, run ```bash docker compose up --build @@ -106,49 +115,7 @@ docker compose up --build #### Deploying/Running with Docker Prebuilt Images -If you wish to run pre-built images from [Docker Hub](https://hub.docker.com/u/tacoma), create a `docker-compose.yml` in your environment with the content below. This file is also found at `docker-compose.example.yml`. - -``` -version: '3' - -services: - measure-service: - depends_on: - - mongo - image: tacoma/measure-repository-service - environment: - DATABASE_URL: 'mongodb://mongo:27017/measure-repository' - ports: - - "3000:3000" - stdin_open: true - tty: true - - measure-service-app: - depends_on: - - mongo - - measure-service - image: tacoma/measure-repository-app - environment: - # Change this for public location of measure-service this should be the FQDN and location of where the - # measure-service container is made public to users with `4_0_1` appended. ex. https://abacus.example.com/mrs/4_0_1 - PUBLIC_MRS_SERVER: http://localhost:3000/4_0_1 - MRS_SERVER: http://measure-service:3000/4_0_1 - MONGODB_URI: mongodb://mongo:27017/draft-repository - ports: - - '3001:3001' - stdin_open: true - tty: true - - mongo: - image: mongo:7.0 - expose: - - "27017:27017" - volumes: - - mongo_data:/data/db - -volumes: - mongo_data: -``` +If you wish to run pre-built images from [Docker Hub](https://hub.docker.com/u/tacoma), create a `docker-compose.yml` in your environment with the content in `docker-compose.example.yml`. Make sure to change the `PUBLIC_MRS_SERVER` environment variable in this file to match the location of where the FHIR server application will be accessible, this will be `http://localhost:3000/4_0_1` when connecting directly to the container running locally.