-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Release draft #58
Release draft #58
Changes from all commits
fe70671
5e5f65f
63dd8ac
aa23d21
27e6ab7
d7c0013
4f67ed7
d0f1925
90a0511
52ca189
24cd8d4
8be7818
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import { trpc } from '@/util/trpc'; | ||
import { ArtifactResourceType } from '@/util/types/fhir'; | ||
import { Button, Center, Group, Modal, Stack, TextInput, Text, Tooltip } from '@mantine/core'; | ||
import { DateTime } from 'luxon'; | ||
import { useRouter } from 'next/router'; | ||
import { useState } from 'react'; | ||
import { AlertCircle, CircleCheck, InfoCircle } from 'tabler-icons-react'; | ||
import { notifications } from '@mantine/notifications'; | ||
|
||
export interface ReleaseModalProps { | ||
open: boolean; | ||
onClose: () => void; | ||
id: string; | ||
resourceType: ArtifactResourceType; | ||
} | ||
|
||
export default function ReleaseModal({ open = true, onClose, id, resourceType }: ReleaseModalProps) { | ||
const router = useRouter(); | ||
const [version, setVersion] = useState(''); | ||
|
||
const { data: resource } = trpc.draft.getDraftById.useQuery({ | ||
id: id, | ||
resourceType: resourceType | ||
}); | ||
const ctx = trpc.useContext(); | ||
const deleteMutation = trpc.draft.deleteDraft.useMutation({ | ||
onSuccess: () => { | ||
notifications.show({ | ||
title: `Draft ${resource?.resourceType} released!`, | ||
message: `Draft ${resource?.resourceType}/${resource?.id} successfully released to the Publishable Measure Repository!`, | ||
icon: <CircleCheck />, | ||
color: 'green' | ||
}); | ||
ctx.draft.getDraftCounts.invalidate(); | ||
ctx.draft.getDrafts.invalidate(); | ||
}, | ||
onError: e => { | ||
console.error(e); | ||
notifications.show({ | ||
title: `Release Failed!`, | ||
message: `Attempt to release ${resourceType} failed with message: ${e.message}`, | ||
icon: <AlertCircle />, | ||
color: 'red' | ||
}); | ||
} | ||
}); | ||
|
||
async function confirm() { | ||
// requirements: | ||
// https://build.fhir.org/ig/HL7/cqf-measures/measure-repository-service.html#release | ||
// TODO: release recursively all children (ignore for now). | ||
if (resource) { | ||
resource.version = version; | ||
resource.status = 'active'; | ||
resource.date = DateTime.now().toISO() || ''; | ||
} | ||
|
||
const res = await fetch(`${process.env.NEXT_PUBLIC_MRS_SERVER}/${resourceType}`, { | ||
method: 'POST', | ||
headers: { | ||
'Content-Type': 'application/json+fhir' | ||
}, | ||
body: JSON.stringify(resource) | ||
}); | ||
|
||
// Conditionally remove the base version if one is present | ||
let location = res.headers.get('Location'); | ||
if (location?.substring(0, 5) === '4_0_1') { | ||
location = location?.substring(5); // remove 4_0_1 (version) | ||
} | ||
|
||
if (res.status !== 201) { | ||
console.error(res.statusText); | ||
notifications.show({ | ||
title: `Release Failed!`, | ||
message: `Server unable to process request`, | ||
icon: <AlertCircle />, | ||
color: 'red' | ||
}); | ||
} else if (!location) { | ||
console.error('No resource location for released artifact'); | ||
notifications.show({ | ||
title: `Release Failed!`, | ||
message: `No resource location exists for draft artifact`, | ||
icon: <AlertCircle />, | ||
color: 'red' | ||
}); | ||
} else { | ||
// delete draft | ||
deleteMutation.mutate({ | ||
resourceType: resourceType, | ||
id: id | ||
}); | ||
|
||
// direct user to published artifact detail page | ||
router.push(location); | ||
} | ||
onClose(); | ||
} | ||
|
||
return ( | ||
<Modal opened={open} onClose={onClose} withCloseButton={false} size="lg"> | ||
<Stack> | ||
<Center> | ||
<Group spacing="xs"> | ||
Release {resourceType}/{id}? | ||
<Tooltip | ||
multiline | ||
label="Releasing a draft artifact changes the artifact's status from 'draft' to 'active', adds the user-specified version to the artifact, and sends the artifact to the Publishable Measure Repository. This action also deletes this draft artifact from the Authoring Measure Repository." | ||
> | ||
<div> | ||
<InfoCircle size="1rem" style={{ display: 'block', opacity: 0.5 }} /> | ||
</div> | ||
</Tooltip> | ||
</Group> | ||
</Center> | ||
<Text size="xs" fw={700}> | ||
NOTE: By releasing this artifact to the Publishable Measure Repository, this draft instance will be removed. | ||
</Text> | ||
<TextInput | ||
label="Add version" | ||
value={version} | ||
onChange={e => setVersion(e.target.value)} | ||
withAsterisk | ||
description="An artifact must have a version before it can be released to the Publishable Measure Repository" | ||
/> | ||
<Center> | ||
<Group pt={8} position="right"> | ||
<Button onClick={confirm} disabled={!version}> | ||
Release | ||
</Button> | ||
<Button variant="default" onClick={onClose}> | ||
Cancel | ||
</Button> | ||
</Group> | ||
</Center> | ||
</Stack> | ||
</Modal> | ||
); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,7 @@ import { notifications } from '@mantine/notifications'; | |
import { AlertCircle, CircleCheck, InfoCircle } from 'tabler-icons-react'; | ||
import { ArtifactResourceType } from '@/util/types/fhir'; | ||
import ArtifactFieldInput from '@/components/ArtifactFieldInput'; | ||
import ReleaseModal from '@/components/ReleaseModal'; | ||
|
||
interface DraftArtifactUpdates { | ||
url?: string; | ||
|
@@ -36,6 +37,8 @@ export default function ResourceAuthoringPage() { | |
resourceType: resourceType as ArtifactResourceType | ||
}); | ||
|
||
const [isModalOpen, setIsModalOpen] = useState(false); | ||
|
||
// checks if the field inputs have been changed by the user by checking | ||
// that they are different from the saved field values on the draft artifact | ||
// if the input is undefined on the draft artifact, then it is treated as | ||
|
@@ -226,29 +229,38 @@ export default function ResourceAuthoringPage() { | |
data={libOptions} | ||
/> | ||
)} | ||
<Button | ||
w={120} | ||
onClick={() => { | ||
const [additions, deletions] = parseUpdate( | ||
url, | ||
identifierValue, | ||
identifierSystem, | ||
name, | ||
title, | ||
description, | ||
library | ||
); | ||
resourceUpdate.mutate({ | ||
resourceType: resourceType as ArtifactResourceType, | ||
id: id as string, | ||
additions: additions, | ||
deletions: deletions | ||
}); | ||
}} | ||
disabled={!isChanged()} // only enable the submit button when a field has changed | ||
> | ||
Submit | ||
</Button> | ||
<Group> | ||
<Button | ||
w={120} | ||
onClick={() => { | ||
const [additions, deletions] = parseUpdate( | ||
url, | ||
identifierValue, | ||
identifierSystem, | ||
name, | ||
title, | ||
description, | ||
library | ||
); | ||
resourceUpdate.mutate({ | ||
resourceType: resourceType as ArtifactResourceType, | ||
id: id as string, | ||
additions: additions, | ||
deletions: deletions | ||
}); | ||
}} | ||
disabled={!isChanged()} // only enable the submit button when a field has changed | ||
> | ||
Update | ||
</Button> | ||
<Button | ||
w={120} | ||
onClick={() => setIsModalOpen(true)} | ||
//TODO/question: disabled={} any disable needed? any necessary fields? | ||
> | ||
Release | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This falls out of scope of "release" but interested in your thoughts on this - should we apply the updates to the draft measure automatically instead of having an "update" button? There's some pros/cons of both approaches, but it might be nice to automatically update the artifact content similar to how we automatically re-run calculation in fqm-testify whenever changes are made. As an example, I made an update to my draft artifact (removed the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah yes, I also noticed this! I think we should make a task for this. However, in the meantime, do you think it would be useful to at least have some sort of indication that changes have not been saved? So the user knows to update before releasing? Or should we just wait to do this task? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can hold off on this for now - I feel like this is a rare case and in general I feel like a user is not likely to make updates and then release directly afterward |
||
</Button> | ||
</Group> | ||
</Stack> | ||
</Grid.Col> | ||
<Grid.Col span={6}> | ||
|
@@ -262,6 +274,13 @@ export default function ResourceAuthoringPage() { | |
</Paper> | ||
</Grid.Col> | ||
</Grid> | ||
|
||
<ReleaseModal | ||
open={isModalOpen} | ||
onClose={() => setIsModalOpen(false)} | ||
id={id as string} | ||
resourceType={resourceType as ArtifactResourceType} | ||
/> | ||
</div> | ||
); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could address this in a follow-up task, but this app is getting pretty slow due to the redirects.
Screenshot below is the logs that I see on the backend. Looks like the data requirements are being calculated automatically, which we expect, but seems like dependent libraries are being found multiple times for the same libraries?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree this needs to be looked at. I think this should be done in a separate task since it looks like this is happening when the user just navigates to an artifact on the publishable measure repository, so it is a bit out of scope for this task.