vintasend 0.4.0 → 0.4.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/examples/vintasend-medplum-example/.env.example +11 -0
- package/dist/examples/vintasend-medplum-example/IMPLEMENTATION_PLAN_FILE_ATTACHMENTS.md +597 -0
- package/dist/examples/vintasend-medplum-example/README.md +190 -0
- package/dist/examples/vintasend-medplum-example/TUTORIAL_EMAIL_NOTIFICATIONS.md +2596 -0
- package/dist/examples/vintasend-medplum-example/bots/handlers/send-pending-notifications-bot.ts +39 -0
- package/dist/examples/vintasend-medplum-example/bots/handlers/send-task-assignment-email.ts +41 -0
- package/dist/examples/vintasend-medplum-example/bots/handlers/task-due-soon-notification-bot.ts +86 -0
- package/dist/examples/vintasend-medplum-example/bots/index.ts +53 -0
- package/dist/examples/vintasend-medplum-example/bots/services/emails/schedule-task-due-soon-email.ts +84 -0
- package/dist/examples/vintasend-medplum-example/bots/services/emails/send-task-assignment-email.test.ts +388 -0
- package/dist/examples/vintasend-medplum-example/bots/services/emails/send-task-assignment-email.ts +113 -0
- package/dist/examples/vintasend-medplum-example/bots/shared/task-due-soon-helpers.ts +115 -0
- package/dist/examples/vintasend-medplum-example/bots/task-assignment-bot.ts +41 -0
- package/dist/examples/vintasend-medplum-example/compiled-notification-templates.json +6 -0
- package/dist/examples/vintasend-medplum-example/esbuild-script.mjs +71 -0
- package/dist/examples/vintasend-medplum-example/index.html +14 -0
- package/dist/examples/vintasend-medplum-example/lib/constants.ts +32 -0
- package/dist/examples/vintasend-medplum-example/lib/extensions.ts +1 -0
- package/dist/examples/vintasend-medplum-example/lib/file-upload.test.ts +389 -0
- package/dist/examples/vintasend-medplum-example/lib/file-upload.ts +222 -0
- package/dist/examples/vintasend-medplum-example/lib/medplum-singleton.ts +18 -0
- package/dist/examples/vintasend-medplum-example/lib/notification-service.test.ts +293 -0
- package/dist/examples/vintasend-medplum-example/lib/notification-service.ts +284 -0
- package/dist/examples/vintasend-medplum-example/lib/patients.ts +20 -0
- package/dist/examples/vintasend-medplum-example/notification-templates/emails/task-assignment/body.html.pug +37 -0
- package/dist/examples/vintasend-medplum-example/notification-templates/emails/task-assignment/subject.txt.pug +4 -0
- package/dist/examples/vintasend-medplum-example/notification-templates/emails/task-due-soon/body.html.pug +34 -0
- package/dist/examples/vintasend-medplum-example/notification-templates/emails/task-due-soon/subject.txt.pug +4 -0
- package/dist/examples/vintasend-medplum-example/package.json +75 -0
- package/dist/examples/vintasend-medplum-example/plugins/gql-plugin.mjs +31 -0
- package/dist/examples/vintasend-medplum-example/postcss.config.mjs +21 -0
- package/dist/examples/vintasend-medplum-example/public/favicon.ico +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/acuity.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/auth0.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/azure.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/calcom.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/candid.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/claude.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/datadog.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/deepseek.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/entra.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/epic.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/google.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/healthgorilla.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/healthie.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/labcorp.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/okta.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/openai.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/particle.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/quest.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/recaptcha.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/snowflake.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/stedi.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/stripe.png +0 -0
- package/dist/examples/vintasend-medplum-example/public/img/integrations/sumo.png +0 -0
- package/dist/examples/vintasend-medplum-example/scripts/README.md +162 -0
- package/dist/examples/vintasend-medplum-example/scripts/client.ts +18 -0
- package/dist/examples/vintasend-medplum-example/scripts/deploy-bots.ts +171 -0
- package/dist/examples/vintasend-medplum-example/src/App.tsx +185 -0
- package/dist/examples/vintasend-medplum-example/src/components/ChargeItem/ChargeItemList.test.tsx +350 -0
- package/dist/examples/vintasend-medplum-example/src/components/ChargeItem/ChargeItemList.tsx +241 -0
- package/dist/examples/vintasend-medplum-example/src/components/ChargeItem/ChargeItemPanel.test.tsx +616 -0
- package/dist/examples/vintasend-medplum-example/src/components/ChargeItem/ChargeItemPanel.tsx +138 -0
- package/dist/examples/vintasend-medplum-example/src/components/Conditions/ConditionItem.test.tsx +92 -0
- package/dist/examples/vintasend-medplum-example/src/components/Conditions/ConditionItem.tsx +47 -0
- package/dist/examples/vintasend-medplum-example/src/components/Conditions/ConditionList.test.tsx +464 -0
- package/dist/examples/vintasend-medplum-example/src/components/Conditions/ConditionList.tsx +186 -0
- package/dist/examples/vintasend-medplum-example/src/components/Conditions/ConditionModal.test.tsx +80 -0
- package/dist/examples/vintasend-medplum-example/src/components/Conditions/ConditionModal.tsx +82 -0
- package/dist/examples/vintasend-medplum-example/src/components/DoseSpotIcon.test.tsx +100 -0
- package/dist/examples/vintasend-medplum-example/src/components/DoseSpotIcon.tsx +20 -0
- package/dist/examples/vintasend-medplum-example/src/components/IntegrationCard.module.css +3 -0
- package/dist/examples/vintasend-medplum-example/src/components/IntegrationCard.tsx +62 -0
- package/dist/examples/vintasend-medplum-example/src/components/MessageWithLinks.tsx +47 -0
- package/dist/examples/vintasend-medplum-example/src/components/PerformingLabInput.test.tsx +299 -0
- package/dist/examples/vintasend-medplum-example/src/components/PerformingLabInput.tsx +52 -0
- package/dist/examples/vintasend-medplum-example/src/components/ResourceFormWithRequiredProfile.tsx +82 -0
- package/dist/examples/vintasend-medplum-example/src/components/encounter/BillingTab.test.tsx +1016 -0
- package/dist/examples/vintasend-medplum-example/src/components/encounter/BillingTab.tsx +298 -0
- package/dist/examples/vintasend-medplum-example/src/components/encounter/EncounterChart.test.tsx +732 -0
- package/dist/examples/vintasend-medplum-example/src/components/encounter/EncounterChart.tsx +282 -0
- package/dist/examples/vintasend-medplum-example/src/components/encounter/EncounterHeader.test.tsx +268 -0
- package/dist/examples/vintasend-medplum-example/src/components/encounter/EncounterHeader.tsx +224 -0
- package/dist/examples/vintasend-medplum-example/src/components/encounter/SignAddendum.test.tsx +255 -0
- package/dist/examples/vintasend-medplum-example/src/components/encounter/SignAddendum.tsx +212 -0
- package/dist/examples/vintasend-medplum-example/src/components/encounter/SignLockDialog.test.tsx +120 -0
- package/dist/examples/vintasend-medplum-example/src/components/encounter/SignLockDialog.tsx +57 -0
- package/dist/examples/vintasend-medplum-example/src/components/encounter/VisitDetailsPanel.test.tsx +224 -0
- package/dist/examples/vintasend-medplum-example/src/components/encounter/VisitDetailsPanel.tsx +100 -0
- package/dist/examples/vintasend-medplum-example/src/components/labs/CoverageInput.test.tsx +431 -0
- package/dist/examples/vintasend-medplum-example/src/components/labs/CoverageInput.tsx +130 -0
- package/dist/examples/vintasend-medplum-example/src/components/labs/LabListItem.module.css +31 -0
- package/dist/examples/vintasend-medplum-example/src/components/labs/LabListItem.test.tsx +234 -0
- package/dist/examples/vintasend-medplum-example/src/components/labs/LabListItem.tsx +143 -0
- package/dist/examples/vintasend-medplum-example/src/components/labs/LabOrderDetails.module.css +11 -0
- package/dist/examples/vintasend-medplum-example/src/components/labs/LabOrderDetails.test.tsx +875 -0
- package/dist/examples/vintasend-medplum-example/src/components/labs/LabOrderDetails.tsx +943 -0
- package/dist/examples/vintasend-medplum-example/src/components/labs/LabResultDetails.test.tsx +413 -0
- package/dist/examples/vintasend-medplum-example/src/components/labs/LabResultDetails.tsx +203 -0
- package/dist/examples/vintasend-medplum-example/src/components/labs/LabSelectEmpty.tsx +22 -0
- package/dist/examples/vintasend-medplum-example/src/components/labs/README.md +104 -0
- package/dist/examples/vintasend-medplum-example/src/components/labs/TestMetadataCardInput.test.tsx +318 -0
- package/dist/examples/vintasend-medplum-example/src/components/labs/TestMetadataCardInput.tsx +87 -0
- package/dist/examples/vintasend-medplum-example/src/components/messages/ChatList.test.tsx +126 -0
- package/dist/examples/vintasend-medplum-example/src/components/messages/ChatList.tsx +38 -0
- package/dist/examples/vintasend-medplum-example/src/components/messages/ChatListItem.module.css +23 -0
- package/dist/examples/vintasend-medplum-example/src/components/messages/ChatListItem.test.tsx +167 -0
- package/dist/examples/vintasend-medplum-example/src/components/messages/ChatListItem.tsx +53 -0
- package/dist/examples/vintasend-medplum-example/src/components/messages/NewTopicDialog.test.tsx +94 -0
- package/dist/examples/vintasend-medplum-example/src/components/messages/NewTopicDialog.tsx +165 -0
- package/dist/examples/vintasend-medplum-example/src/components/messages/ParticipantFilter.module.css +8 -0
- package/dist/examples/vintasend-medplum-example/src/components/messages/ParticipantFilter.test.tsx +523 -0
- package/dist/examples/vintasend-medplum-example/src/components/messages/ParticipantFilter.tsx +230 -0
- package/dist/examples/vintasend-medplum-example/src/components/messages/ThreadInbox.module.css +23 -0
- package/dist/examples/vintasend-medplum-example/src/components/messages/ThreadInbox.test.tsx +567 -0
- package/dist/examples/vintasend-medplum-example/src/components/messages/ThreadInbox.tsx +358 -0
- package/dist/examples/vintasend-medplum-example/src/components/plandefinition/AddPlanDefinition.module.css +40 -0
- package/dist/examples/vintasend-medplum-example/src/components/plandefinition/AddPlanDefinition.tsx +257 -0
- package/dist/examples/vintasend-medplum-example/src/components/schedule/CreateVisit.module.css +7 -0
- package/dist/examples/vintasend-medplum-example/src/components/schedule/CreateVisit.test.tsx +279 -0
- package/dist/examples/vintasend-medplum-example/src/components/schedule/CreateVisit.tsx +156 -0
- package/dist/examples/vintasend-medplum-example/src/components/spaces/HistoryList.module.css +45 -0
- package/dist/examples/vintasend-medplum-example/src/components/spaces/HistoryList.test.tsx +90 -0
- package/dist/examples/vintasend-medplum-example/src/components/spaces/HistoryList.tsx +84 -0
- package/dist/examples/vintasend-medplum-example/src/components/spaces/ResourceBox.module.css +26 -0
- package/dist/examples/vintasend-medplum-example/src/components/spaces/ResourceBox.tsx +90 -0
- package/dist/examples/vintasend-medplum-example/src/components/spaces/ResourcePanel.test.tsx +305 -0
- package/dist/examples/vintasend-medplum-example/src/components/spaces/ResourcePanel.tsx +46 -0
- package/dist/examples/vintasend-medplum-example/src/components/spaces/SpacesInbox.module.css +262 -0
- package/dist/examples/vintasend-medplum-example/src/components/spaces/SpacesInbox.test.tsx +622 -0
- package/dist/examples/vintasend-medplum-example/src/components/spaces/SpacesInbox.tsx +286 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/NewTaskModal.tsx +275 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskAttachmentList.tsx +132 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskBoard.module.css +45 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskBoard.test.tsx +749 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskBoard.tsx +416 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskDetailPanel.test.tsx +278 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskDetailPanel.tsx +133 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskDetailsModal.module.css +16 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskDetailsModal.test.tsx +255 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskDetailsModal.tsx +203 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskFileUpload.tsx +129 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskFilterMenu.test.tsx +156 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskFilterMenu.tsx +142 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskFilterMenu.utils.ts +28 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskInputNote.test.tsx +134 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskInputNote.tsx +250 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskListItem.module.css +23 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskListItem.test.tsx +149 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskListItem.tsx +53 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskNoteItem.test.tsx +68 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskNoteItem.tsx +46 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskProperties.test.tsx +555 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskProperties.tsx +170 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskSelectEmpty.test.tsx +32 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/TaskSelectEmpty.tsx +34 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/SimpleTask.test.tsx +47 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/SimpleTask.tsx +29 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskPanel.test.tsx +285 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskPanel.tsx +129 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskQuestionnaireForm.test.tsx +455 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskQuestionnaireForm.tsx +167 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskServiceRequest.test.tsx +435 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskServiceRequest.tsx +116 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskStatusPanel.module.css +38 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskStatusPanel.test.tsx +200 -0
- package/dist/examples/vintasend-medplum-example/src/components/tasks/encounter/TaskStatusPanel.tsx +84 -0
- package/dist/examples/vintasend-medplum-example/src/components/utils.test.ts +176 -0
- package/dist/examples/vintasend-medplum-example/src/components/utils.ts +17 -0
- package/dist/examples/vintasend-medplum-example/src/config/constants.ts +3 -0
- package/dist/examples/vintasend-medplum-example/src/hooks/useDebouncedUpdateResource.test.tsx +166 -0
- package/dist/examples/vintasend-medplum-example/src/hooks/useDebouncedUpdateResource.ts +28 -0
- package/dist/examples/vintasend-medplum-example/src/hooks/useEncounter.test.tsx +94 -0
- package/dist/examples/vintasend-medplum-example/src/hooks/useEncounter.ts +11 -0
- package/dist/examples/vintasend-medplum-example/src/hooks/useEncounterChart.test.tsx +477 -0
- package/dist/examples/vintasend-medplum-example/src/hooks/useEncounterChart.ts +191 -0
- package/dist/examples/vintasend-medplum-example/src/hooks/usePatient.test.tsx +100 -0
- package/dist/examples/vintasend-medplum-example/src/hooks/usePatient.ts +18 -0
- package/dist/examples/vintasend-medplum-example/src/hooks/useThreadInbox.test.tsx +379 -0
- package/dist/examples/vintasend-medplum-example/src/hooks/useThreadInbox.ts +194 -0
- package/dist/examples/vintasend-medplum-example/src/index.css +8 -0
- package/dist/examples/vintasend-medplum-example/src/main.tsx +57 -0
- package/dist/examples/vintasend-medplum-example/src/pages/SearchPage.module.css +6 -0
- package/dist/examples/vintasend-medplum-example/src/pages/SearchPage.test.tsx +295 -0
- package/dist/examples/vintasend-medplum-example/src/pages/SearchPage.tsx +124 -0
- package/dist/examples/vintasend-medplum-example/src/pages/SignInPage.test.tsx +77 -0
- package/dist/examples/vintasend-medplum-example/src/pages/SignInPage.tsx +22 -0
- package/dist/examples/vintasend-medplum-example/src/pages/encounter/EncounterChartPage.test.tsx +87 -0
- package/dist/examples/vintasend-medplum-example/src/pages/encounter/EncounterChartPage.tsx +27 -0
- package/dist/examples/vintasend-medplum-example/src/pages/encounter/EncounterModal.module.css +16 -0
- package/dist/examples/vintasend-medplum-example/src/pages/encounter/EncounterModal.test.tsx +287 -0
- package/dist/examples/vintasend-medplum-example/src/pages/encounter/EncounterModal.tsx +151 -0
- package/dist/examples/vintasend-medplum-example/src/pages/integrations/DoseSpotFavoritesPage.test.tsx +519 -0
- package/dist/examples/vintasend-medplum-example/src/pages/integrations/DoseSpotFavoritesPage.tsx +179 -0
- package/dist/examples/vintasend-medplum-example/src/pages/integrations/FavoriteMedicationsTable.tsx +76 -0
- package/dist/examples/vintasend-medplum-example/src/pages/integrations/IntegrationsPage.test.tsx +234 -0
- package/dist/examples/vintasend-medplum-example/src/pages/integrations/IntegrationsPage.tsx +222 -0
- package/dist/examples/vintasend-medplum-example/src/pages/labs/OrderLabsPage.test.tsx +356 -0
- package/dist/examples/vintasend-medplum-example/src/pages/labs/OrderLabsPage.tsx +275 -0
- package/dist/examples/vintasend-medplum-example/src/pages/messages/MessagesPage.module.css +8 -0
- package/dist/examples/vintasend-medplum-example/src/pages/messages/MessagesPage.test.tsx +103 -0
- package/dist/examples/vintasend-medplum-example/src/pages/messages/MessagesPage.tsx +78 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/CommunicationTab.test.tsx +84 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/CommunicationTab.tsx +82 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/DoseSpotAdvancedOptions.test.tsx +364 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/DoseSpotAdvancedOptions.tsx +149 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/DoseSpotTab.test.tsx +159 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/DoseSpotTab.tsx +37 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/EditTab.test.tsx +140 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/EditTab.tsx +72 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/ExportTab.test.tsx +57 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/ExportTab.tsx +14 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/IntakeFormPage.test.tsx +241 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/IntakeFormPage.tsx +710 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/LabsPage.module.css +37 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/LabsPage.test.tsx +428 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/LabsPage.tsx +334 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientPage.module.css +24 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientPage.test.tsx +154 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientPage.tsx +115 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientPage.utils.test.ts +223 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientPage.utils.ts +89 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientSearchPage.test.tsx +147 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientSearchPage.tsx +79 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/PatientTabsNavigation.tsx +35 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/TasksTab.test.tsx +185 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/TasksTab.tsx +115 -0
- package/dist/examples/vintasend-medplum-example/src/pages/patient/TimelineTab.tsx +14 -0
- package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourceCreatePage.test.tsx +170 -0
- package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourceCreatePage.tsx +117 -0
- package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourceDetailPage.tsx +28 -0
- package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourceEditPage.test.tsx +131 -0
- package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourceEditPage.tsx +65 -0
- package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourceHistoryPage.test.tsx +108 -0
- package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourceHistoryPage.tsx +16 -0
- package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourcePage.module.css +7 -0
- package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourcePage.test.tsx +37 -0
- package/dist/examples/vintasend-medplum-example/src/pages/resource/ResourcePage.tsx +44 -0
- package/dist/examples/vintasend-medplum-example/src/pages/resource/useResourceType.ts +44 -0
- package/dist/examples/vintasend-medplum-example/src/pages/resource/utils.ts +9 -0
- package/dist/examples/vintasend-medplum-example/src/pages/schedule/SchedulePage.test.tsx +302 -0
- package/dist/examples/vintasend-medplum-example/src/pages/schedule/SchedulePage.tsx +416 -0
- package/dist/examples/vintasend-medplum-example/src/pages/spaces/ChatInput.tsx +91 -0
- package/dist/examples/vintasend-medplum-example/src/pages/spaces/SpacesPage.module.css +6 -0
- package/dist/examples/vintasend-medplum-example/src/pages/spaces/SpacesPage.test.tsx +102 -0
- package/dist/examples/vintasend-medplum-example/src/pages/spaces/SpacesPage.tsx +44 -0
- package/dist/examples/vintasend-medplum-example/src/pages/tasks/TasksPage.module.css +7 -0
- package/dist/examples/vintasend-medplum-example/src/pages/tasks/TasksPage.test.tsx +133 -0
- package/dist/examples/vintasend-medplum-example/src/pages/tasks/TasksPage.tsx +91 -0
- package/dist/examples/vintasend-medplum-example/src/test-utils/render.tsx +20 -0
- package/dist/examples/vintasend-medplum-example/src/test.setup.ts +49 -0
- package/dist/examples/vintasend-medplum-example/src/types/encounter.ts +8 -0
- package/dist/examples/vintasend-medplum-example/src/types/spaces.ts +10 -0
- package/dist/examples/vintasend-medplum-example/src/utils/chargeitems.test.ts +141 -0
- package/dist/examples/vintasend-medplum-example/src/utils/chargeitems.ts +59 -0
- package/dist/examples/vintasend-medplum-example/src/utils/claims.test.ts +153 -0
- package/dist/examples/vintasend-medplum-example/src/utils/claims.ts +65 -0
- package/dist/examples/vintasend-medplum-example/src/utils/communication-search.ts +47 -0
- package/dist/examples/vintasend-medplum-example/src/utils/coverage.test.ts +48 -0
- package/dist/examples/vintasend-medplum-example/src/utils/coverage.ts +33 -0
- package/dist/examples/vintasend-medplum-example/src/utils/documentReference.test.ts +102 -0
- package/dist/examples/vintasend-medplum-example/src/utils/documentReference.ts +55 -0
- package/dist/examples/vintasend-medplum-example/src/utils/encounter.test.ts +169 -0
- package/dist/examples/vintasend-medplum-example/src/utils/encounter.ts +261 -0
- package/dist/examples/vintasend-medplum-example/src/utils/intake-form.test.ts +154 -0
- package/dist/examples/vintasend-medplum-example/src/utils/intake-form.ts +272 -0
- package/dist/examples/vintasend-medplum-example/src/utils/intake-utils.test.ts +1137 -0
- package/dist/examples/vintasend-medplum-example/src/utils/intake-utils.ts +827 -0
- package/dist/examples/vintasend-medplum-example/src/utils/notifications.test.ts +27 -0
- package/dist/examples/vintasend-medplum-example/src/utils/notifications.ts +15 -0
- package/dist/examples/vintasend-medplum-example/src/utils/spaceMessaging.ts +249 -0
- package/dist/examples/vintasend-medplum-example/src/utils/spacePersistence.test.ts +450 -0
- package/dist/examples/vintasend-medplum-example/src/utils/spacePersistence.ts +147 -0
- package/dist/examples/vintasend-medplum-example/src/utils/task-search.ts +63 -0
- package/dist/examples/vintasend-medplum-example/src/vite-env.d.ts +3 -0
- package/dist/examples/vintasend-medplum-example/tsconfig.bots.json +4 -0
- package/dist/examples/vintasend-medplum-example/tsconfig.json +19 -0
- package/dist/examples/vintasend-medplum-example/vercel.json +3 -0
- package/dist/examples/vintasend-medplum-example/vite.config.ts +44 -0
- package/dist/services/notification-backends/base-notification-backend.d.ts +5 -0
- package/dist/services/notification-service.js +11 -1
- package/dist/services/notification-template-renderers/base-email-template-renderer.d.ts +5 -0
- package/package.json +1 -1
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "medplum-provider",
|
|
3
|
+
"version": "5.0.10",
|
|
4
|
+
"private": true,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "tsc && vite build",
|
|
8
|
+
"dev": "vite",
|
|
9
|
+
"lint": "eslint .",
|
|
10
|
+
"lint:fix": "eslint . --fix",
|
|
11
|
+
"preview": "vite preview",
|
|
12
|
+
"test": "vitest run",
|
|
13
|
+
"test:coverage": "vitest run --coverage",
|
|
14
|
+
"clean": "rm -rf dist && rm -f compiled-notification-templates.json",
|
|
15
|
+
"compile-templates": "compile-pug-templates ./notification-templates ./compiled-notification-templates.json",
|
|
16
|
+
"bots:build": "npm run clean && npm run compile-templates && tsc --project tsconfig.bots.json && node --no-warnings esbuild-script.mjs",
|
|
17
|
+
"bots:deploy": "tsx scripts/deploy-bots.ts",
|
|
18
|
+
"bots:build:dev": "npm run clean && npm run compile-templates && node --no-warnings esbuild-script.mjs"
|
|
19
|
+
},
|
|
20
|
+
"prettier": {
|
|
21
|
+
"printWidth": 120,
|
|
22
|
+
"singleQuote": true,
|
|
23
|
+
"trailingComma": "es5"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@mantine/core": "8.3.11",
|
|
27
|
+
"@mantine/hooks": "8.3.11",
|
|
28
|
+
"@mantine/notifications": "8.3.11",
|
|
29
|
+
"@mantine/spotlight": "8.3.11",
|
|
30
|
+
"@medplum/bot-layer": "^5.0.12",
|
|
31
|
+
"@medplum/core": "5.0.10",
|
|
32
|
+
"@medplum/dosespot-react": "5.0.10",
|
|
33
|
+
"@medplum/eslint-config": "5.0.10",
|
|
34
|
+
"@medplum/fhirtypes": "5.0.10",
|
|
35
|
+
"@medplum/health-gorilla-core": "5.0.10",
|
|
36
|
+
"@medplum/health-gorilla-react": "5.0.10",
|
|
37
|
+
"@medplum/mock": "^5.0.12",
|
|
38
|
+
"@medplum/react": "5.0.10",
|
|
39
|
+
"@sentry/esbuild-plugin": "^4.7.0",
|
|
40
|
+
"@tabler/icons-react": "3.36.1",
|
|
41
|
+
"@testing-library/dom": "10.4.1",
|
|
42
|
+
"@testing-library/jest-dom": "6.9.1",
|
|
43
|
+
"@testing-library/react": "16.3.1",
|
|
44
|
+
"@testing-library/user-event": "14.6.1",
|
|
45
|
+
"@types/node": "22.19.3",
|
|
46
|
+
"@types/react": "19.2.7",
|
|
47
|
+
"@types/react-big-calendar": "1.16.3",
|
|
48
|
+
"@types/react-dom": "19.2.3",
|
|
49
|
+
"@vitejs/plugin-react": "5.1.2",
|
|
50
|
+
"dayjs": "1.11.19",
|
|
51
|
+
"dotenv": "^17.2.3",
|
|
52
|
+
"fast-glob": "^3.3.3",
|
|
53
|
+
"jsdom": "27.4.0",
|
|
54
|
+
"postcss": "8.5.6",
|
|
55
|
+
"postcss-preset-mantine": "1.18.0",
|
|
56
|
+
"react": "19.2.3",
|
|
57
|
+
"react-big-calendar": "1.19.4",
|
|
58
|
+
"react-dom": "19.2.3",
|
|
59
|
+
"react-router": "7.12.0",
|
|
60
|
+
"tsx": "^4.21.0",
|
|
61
|
+
"typescript": "5.9.3",
|
|
62
|
+
"uuid": "11.1.0",
|
|
63
|
+
"vite": "7.3.1",
|
|
64
|
+
"vitest": "4.0.16"
|
|
65
|
+
},
|
|
66
|
+
"packageManager": "npm@10.9.4",
|
|
67
|
+
"engines": {
|
|
68
|
+
"node": "^22.18.0 || >=24.2.0"
|
|
69
|
+
},
|
|
70
|
+
"dependencies": {
|
|
71
|
+
"vintasend": "^0.4.3",
|
|
72
|
+
"vintasend-medplum": "^0.4.5",
|
|
73
|
+
"vintasend-sendgrid": "^0.4.3"
|
|
74
|
+
}
|
|
75
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import fs from 'fs/promises';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* esbuild plugin for handling GraphQL files.
|
|
5
|
+
* Automatically exports all named operations (queries, mutations) and fragments.
|
|
6
|
+
*/
|
|
7
|
+
export const gqlPlugin = {
|
|
8
|
+
name: 'gql',
|
|
9
|
+
setup(build) {
|
|
10
|
+
build.onLoad({ filter: /\.gql$/ }, async (args) => {
|
|
11
|
+
const contents = await fs.readFile(args.path, 'utf8');
|
|
12
|
+
|
|
13
|
+
// Simple regex to find all named operations and fragments
|
|
14
|
+
const operationRegex = /(query|mutation|fragment)\s+([a-zA-Z][a-zA-Z0-9_]*)/g;
|
|
15
|
+
const matches = [...contents.matchAll(operationRegex)];
|
|
16
|
+
|
|
17
|
+
const exports = matches
|
|
18
|
+
.map(([, , name]) => `export const ${name} = doc;`)
|
|
19
|
+
.join('\n');
|
|
20
|
+
|
|
21
|
+
return {
|
|
22
|
+
contents: `
|
|
23
|
+
const doc = \`${contents}\`;
|
|
24
|
+
${exports}
|
|
25
|
+
export default doc;
|
|
26
|
+
`,
|
|
27
|
+
loader: 'js',
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors
|
|
2
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
3
|
+
import mantinePreset from 'postcss-preset-mantine';
|
|
4
|
+
import simpleVars from 'postcss-simple-vars';
|
|
5
|
+
|
|
6
|
+
const config = {
|
|
7
|
+
plugins: [
|
|
8
|
+
mantinePreset(),
|
|
9
|
+
simpleVars({
|
|
10
|
+
variables: {
|
|
11
|
+
'mantine-breakpoint-xs': '36em',
|
|
12
|
+
'mantine-breakpoint-sm': '48em',
|
|
13
|
+
'mantine-breakpoint-md': '62em',
|
|
14
|
+
'mantine-breakpoint-lg': '75em',
|
|
15
|
+
'mantine-breakpoint-xl': '88em',
|
|
16
|
+
},
|
|
17
|
+
}),
|
|
18
|
+
],
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
export default config;
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
# Scripts
|
|
2
|
+
|
|
3
|
+
This directory contains automation scripts for setting up and managing your Medplum environment.
|
|
4
|
+
|
|
5
|
+
## setup-task-assignment-subscription.ts
|
|
6
|
+
|
|
7
|
+
Creates or updates the FHIR Subscription that triggers the task assignment email bot.
|
|
8
|
+
|
|
9
|
+
### What it does:
|
|
10
|
+
|
|
11
|
+
1. **Authenticates** with Medplum using client credentials
|
|
12
|
+
2. **Creates/finds** the Task Assignment Email Bot resource
|
|
13
|
+
3. **Creates/updates** a Subscription with criteria: `Task?owner:exists=true`
|
|
14
|
+
4. **Configures** the subscription to trigger on Task create and update events
|
|
15
|
+
|
|
16
|
+
### Prerequisites:
|
|
17
|
+
|
|
18
|
+
Create a `.env` file with your Medplum credentials:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
MEDPLUM_BASE_URL=https://api.medplum.com
|
|
22
|
+
MEDPLUM_CLIENT_ID=your-client-id
|
|
23
|
+
MEDPLUM_CLIENT_SECRET=your-client-secret
|
|
24
|
+
APP_BASE_URL=https://your-app-url.com
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### Usage:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npm run setup:subscription
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Expected Output:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
✅ Successfully authenticated with Medplum
|
|
37
|
+
✅ Found existing bot: abc-123
|
|
38
|
+
✅ Updated subscription: def-456
|
|
39
|
+
|
|
40
|
+
📋 Subscription Details:
|
|
41
|
+
ID: def-456
|
|
42
|
+
Status: active
|
|
43
|
+
Criteria: Task?owner:exists=true
|
|
44
|
+
Bot: abc-123 (Task Assignment Email Bot)
|
|
45
|
+
Triggers: Task create, update (when owner exists)
|
|
46
|
+
|
|
47
|
+
✅ Setup complete!
|
|
48
|
+
|
|
49
|
+
📝 Next steps:
|
|
50
|
+
1. Deploy your bot code: npm run bots:deploy
|
|
51
|
+
2. Test by creating/updating a Task with an owner
|
|
52
|
+
3. Check bot logs in Medplum console for execution details
|
|
53
|
+
|
|
54
|
+
✨ Script completed successfully
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### When to run:
|
|
58
|
+
|
|
59
|
+
- **Initial setup**: When first deploying your application
|
|
60
|
+
- **After bot changes**: If you modify the bot or subscription criteria
|
|
61
|
+
- **Environment changes**: When setting up a new environment (dev, staging, prod)
|
|
62
|
+
- **CI/CD**: Include in your deployment pipeline
|
|
63
|
+
|
|
64
|
+
### Idempotent Design:
|
|
65
|
+
|
|
66
|
+
This script is safe to run multiple times. It will:
|
|
67
|
+
- Use existing Bot if found (by identifier)
|
|
68
|
+
- Update existing Subscription if found (by identifier)
|
|
69
|
+
- Create new resources only if they don't exist
|
|
70
|
+
|
|
71
|
+
### Troubleshooting:
|
|
72
|
+
|
|
73
|
+
**Authentication Error:**
|
|
74
|
+
```
|
|
75
|
+
❌ Error setting up subscription: Authentication failed
|
|
76
|
+
```
|
|
77
|
+
- Verify your `MEDPLUM_CLIENT_ID` and `MEDPLUM_CLIENT_SECRET` in `.env`
|
|
78
|
+
- Ensure the client has permission to create Bot and Subscription resources
|
|
79
|
+
|
|
80
|
+
**Resource Creation Failed:**
|
|
81
|
+
```
|
|
82
|
+
❌ Error creating Bot: Forbidden
|
|
83
|
+
```
|
|
84
|
+
- Check that your client has the necessary permissions in Medplum
|
|
85
|
+
- You may need to grant `Bot` and `Subscription` resource creation permissions
|
|
86
|
+
|
|
87
|
+
**Subscription Not Triggering:**
|
|
88
|
+
- Verify the bot code is deployed: `npm run bots:deploy`
|
|
89
|
+
- Check subscription status in Medplum console (should be "active")
|
|
90
|
+
- Review bot logs for execution errors
|
|
91
|
+
- Ensure Task resources have the `owner` field populated
|
|
92
|
+
|
|
93
|
+
### FHIR Resources Created:
|
|
94
|
+
|
|
95
|
+
#### Bot Resource:
|
|
96
|
+
```json
|
|
97
|
+
{
|
|
98
|
+
"resourceType": "Bot",
|
|
99
|
+
"identifier": [
|
|
100
|
+
{
|
|
101
|
+
"system": "https://your-domain.com/bot-identifier",
|
|
102
|
+
"value": "task-assignment-email-bot"
|
|
103
|
+
}
|
|
104
|
+
],
|
|
105
|
+
"name": "Task Assignment Email Bot",
|
|
106
|
+
"description": "Sends email notifications when tasks are assigned to practitioners"
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
#### Subscription Resource:
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"resourceType": "Subscription",
|
|
114
|
+
"identifier": [
|
|
115
|
+
{
|
|
116
|
+
"system": "https://your-domain.com/subscription-identifier",
|
|
117
|
+
"value": "task-assignment-email-subscription"
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
"status": "active",
|
|
121
|
+
"reason": "Trigger email notification when a task is assigned",
|
|
122
|
+
"criteria": "Task?owner:exists=true",
|
|
123
|
+
"channel": {
|
|
124
|
+
"type": "rest-hook",
|
|
125
|
+
"endpoint": "Bot/bot-id-here"
|
|
126
|
+
},
|
|
127
|
+
"extension": [
|
|
128
|
+
{
|
|
129
|
+
"url": "https://medplum.com/fhir/StructureDefinition/subscription-supported-interaction",
|
|
130
|
+
"valueCode": "create"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"url": "https://medplum.com/fhir/StructureDefinition/subscription-supported-interaction",
|
|
134
|
+
"valueCode": "update"
|
|
135
|
+
}
|
|
136
|
+
]
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### Understanding the Subscription:
|
|
141
|
+
|
|
142
|
+
- **criteria**: `Task?owner:exists=true` matches any Task with an owner
|
|
143
|
+
- **channel.type**: `rest-hook` invokes a bot endpoint
|
|
144
|
+
- **channel.endpoint**: Points to the Bot resource
|
|
145
|
+
- **extension**: Specifies to trigger on both create and update operations
|
|
146
|
+
|
|
147
|
+
### Testing the Subscription:
|
|
148
|
+
|
|
149
|
+
After running the setup, test it by creating a Task:
|
|
150
|
+
|
|
151
|
+
```typescript
|
|
152
|
+
const task = await medplum.createResource({
|
|
153
|
+
resourceType: 'Task',
|
|
154
|
+
status: 'requested',
|
|
155
|
+
intent: 'order',
|
|
156
|
+
code: { text: 'Test task' },
|
|
157
|
+
owner: { reference: 'Practitioner/123' }, // This triggers the subscription
|
|
158
|
+
requester: { reference: 'Practitioner/456' },
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Check the bot logs in Medplum console to verify execution.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { MedplumClient } from '@medplum/core';
|
|
2
|
+
import { config } from 'dotenv';
|
|
3
|
+
|
|
4
|
+
// Load environment variables from .env file
|
|
5
|
+
config();
|
|
6
|
+
|
|
7
|
+
export async function getMedplumClient() {
|
|
8
|
+
const medplum = new MedplumClient({
|
|
9
|
+
clientId: process.env.MEDPLUM_CLIENT_ID,
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
await medplum.startClientLogin(
|
|
13
|
+
process.env.MEDPLUM_CLIENT_ID as string,
|
|
14
|
+
process.env.MEDPLUM_CLIENT_SECRET as string
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
return medplum;
|
|
18
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { ContentType, getReferenceString, MedplumClient, WithId } from '@medplum/core';
|
|
2
|
+
import { Bot, Bundle, BundleEntry, Questionnaire } from '@medplum/fhirtypes';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import { BotDescription, BOTS } from '../bots/index.js';
|
|
5
|
+
import { BOTS_SYSTEM } from '../lib/constants.js';
|
|
6
|
+
import { getMedplumClient } from './client.js';
|
|
7
|
+
|
|
8
|
+
async function readBotFiles(description: BotDescription, medplum: MedplumClient) {
|
|
9
|
+
const distFile = fs.readFileSync(`dist/bots/handlers/${description.name}.js`, 'utf-8');
|
|
10
|
+
|
|
11
|
+
const [sourceCodeAttachment, executableCodeAttachment] = await Promise.all([
|
|
12
|
+
medplum.createAttachment({
|
|
13
|
+
data: distFile,
|
|
14
|
+
contentType: 'application/javascript',
|
|
15
|
+
}),
|
|
16
|
+
medplum.createAttachment({
|
|
17
|
+
data: distFile,
|
|
18
|
+
contentType: 'application/javascript',
|
|
19
|
+
}),
|
|
20
|
+
]);
|
|
21
|
+
|
|
22
|
+
return { sourceCodeAttachment, executableCodeAttachment };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function generateBundle(medplum: MedplumClient): Promise<Bundle> {
|
|
26
|
+
const bundle: Bundle = {
|
|
27
|
+
resourceType: 'Bundle',
|
|
28
|
+
type: 'transaction',
|
|
29
|
+
entry: (
|
|
30
|
+
await Promise.all(
|
|
31
|
+
BOTS.map(async (botDescription): Promise<BundleEntry[]> => {
|
|
32
|
+
const botName = botDescription.name;
|
|
33
|
+
const botReferencePlaceholder = `$bot-${botName}-reference`;
|
|
34
|
+
const botIdPlaceholder = `$bot-${botName}-id`;
|
|
35
|
+
const results: BundleEntry[] = [];
|
|
36
|
+
const { cronString, timeout, runAsUser, criteria, extension } = botDescription;
|
|
37
|
+
|
|
38
|
+
const { executableCodeAttachment, sourceCodeAttachment } = await readBotFiles(botDescription, medplum);
|
|
39
|
+
|
|
40
|
+
results.push({
|
|
41
|
+
request: { method: 'PUT', url: botReferencePlaceholder },
|
|
42
|
+
resource: {
|
|
43
|
+
resourceType: 'Bot',
|
|
44
|
+
id: botIdPlaceholder,
|
|
45
|
+
identifier: [{ system: BOTS_SYSTEM, value: botName }],
|
|
46
|
+
name: botName,
|
|
47
|
+
runtimeVersion: 'awslambda',
|
|
48
|
+
sourceCode: sourceCodeAttachment,
|
|
49
|
+
executableCode: executableCodeAttachment,
|
|
50
|
+
runAsUser: runAsUser ?? false,
|
|
51
|
+
...(cronString && { cronString }),
|
|
52
|
+
...(timeout && { timeout }),
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
if (criteria) {
|
|
57
|
+
results.push({
|
|
58
|
+
request: {
|
|
59
|
+
method: 'PUT',
|
|
60
|
+
url: `Subscription?url=${botReferencePlaceholder}`,
|
|
61
|
+
},
|
|
62
|
+
resource: {
|
|
63
|
+
resourceType: 'Subscription',
|
|
64
|
+
status: 'active',
|
|
65
|
+
reason: `${botName}-subscription`,
|
|
66
|
+
criteria,
|
|
67
|
+
extension: extension ?? [],
|
|
68
|
+
channel: {
|
|
69
|
+
endpoint: botReferencePlaceholder,
|
|
70
|
+
type: 'rest-hook',
|
|
71
|
+
payload: 'application/fhir+json',
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return results;
|
|
78
|
+
})
|
|
79
|
+
)
|
|
80
|
+
).flat(),
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return bundle;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function deployBots(): Promise<void> {
|
|
87
|
+
// eslint-disable-next-line no-console
|
|
88
|
+
console.log('\nUploading bots...\n');
|
|
89
|
+
|
|
90
|
+
const medplum = await getMedplumClient();
|
|
91
|
+
|
|
92
|
+
const profile = await medplum.getProfile();
|
|
93
|
+
const projectId = profile?.meta?.project;
|
|
94
|
+
|
|
95
|
+
const questionnaires: Questionnaire[] = [];
|
|
96
|
+
|
|
97
|
+
const bundleData = await generateBundle(medplum);
|
|
98
|
+
|
|
99
|
+
let transactionString = JSON.stringify(bundleData);
|
|
100
|
+
const botEntries: BundleEntry[] =
|
|
101
|
+
(bundleData as Bundle).entry?.filter((e) => e.resource?.resourceType === 'Bot') || [];
|
|
102
|
+
const botIds: Record<string, string> = {};
|
|
103
|
+
|
|
104
|
+
for (const botDescription of BOTS) {
|
|
105
|
+
const botName = botDescription.name;
|
|
106
|
+
|
|
107
|
+
let existingBot = await medplum.searchOne('Bot', { name: botName });
|
|
108
|
+
if (!existingBot) {
|
|
109
|
+
const createBotUrl = new URL(`admin/projects/${projectId as string}/bot`, medplum.getBaseUrl());
|
|
110
|
+
existingBot = (await medplum.post(createBotUrl, {
|
|
111
|
+
name: botName,
|
|
112
|
+
})) as WithId<Bot>;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (!existingBot) {
|
|
116
|
+
throw new Error(`Bot ${botName} not found`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
const botMembership = await medplum.searchOne('ProjectMembership', { user: getReferenceString(existingBot) });
|
|
120
|
+
if (botMembership && botMembership.admin !== botDescription.needsAdminMembership) {
|
|
121
|
+
await medplum.post(`admin/projects/${projectId as string}/members/${botMembership.id}`, {
|
|
122
|
+
...botMembership,
|
|
123
|
+
admin: botDescription.needsAdminMembership,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
botIds[botName] = existingBot.id as string;
|
|
128
|
+
|
|
129
|
+
// Replace the Bot id placeholder in the bundle
|
|
130
|
+
transactionString = transactionString
|
|
131
|
+
.replaceAll(`$bot-${botName}-reference`, getReferenceString(existingBot))
|
|
132
|
+
.replaceAll(`$bot-${botName}-id`, existingBot.id as string);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
for (const questionnaire of questionnaires) {
|
|
136
|
+
transactionString = transactionString.replaceAll(
|
|
137
|
+
`$${questionnaire.name}`,
|
|
138
|
+
getReferenceString(questionnaire) as string
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// eslint-disable-next-line no-console
|
|
143
|
+
console.log('\nUploading bots bundle...\n');
|
|
144
|
+
|
|
145
|
+
// Execute the transaction to upload / update the bot
|
|
146
|
+
const transaction = JSON.parse(transactionString);
|
|
147
|
+
|
|
148
|
+
const batchResponse = await medplum.executeBatch(transaction);
|
|
149
|
+
// await medplum.executeBatch(transaction);
|
|
150
|
+
|
|
151
|
+
const errors = batchResponse.entry?.filter((e) => !['200', '201'].includes(e.response?.status ?? ''));
|
|
152
|
+
if (errors && errors.length > 0) {
|
|
153
|
+
throw new Error(`${JSON.stringify(errors, null, 2)}`);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Deploy the bots
|
|
157
|
+
for (const entry of botEntries) {
|
|
158
|
+
const botName = (entry?.resource as Bot)?.name as string;
|
|
159
|
+
|
|
160
|
+
// eslint-disable-next-line no-console
|
|
161
|
+
console.log(`Deploying ${botName}...`);
|
|
162
|
+
|
|
163
|
+
await medplum.post(medplum.fhirUrl('Bot', botIds[botName], '$deploy'));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// eslint-disable-next-line no-console
|
|
167
|
+
console.log('\nAll bots deployed!\n');
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// eslint-disable-next-line no-console
|
|
171
|
+
deployBots().catch(console.error);
|