Skip to main content
Glama
HomePage.tsx10.2 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { Title, Group, Box, Textarea, Button, Alert, Grid } from '@mantine/core'; import type { ValueSet } from '@medplum/fhirtypes'; import { CodingInput, Document, ResourceInput, ResourceName, useMedplum } from '@medplum/react'; import { useState } from 'react'; import type { JSX } from 'react'; export function HomePage(): JSX.Element { const medplum = useMedplum(); const [searchTerm, setSearchTerm] = useState(''); const [customValueSet, setCustomValueSet] = useState(`{ "resourceType": "ValueSet", "id": "rxnorm-branded-drugs", "url": "http://example.org/fhir/ValueSet/rxnorm-branded-drugs", "version": "1.0.0", "name": "RxNormBrandedDrugs", "title": "RxNorm Branded Drug Components", "status": "active", "experimental": false, "date": "2025-01-28", "publisher": "National Library of Medicine", "description": "ValueSet of RxNorm branded drug components", "compose": { "include": [ { "system": "http://www.nlm.nih.gov/research/umls/rxnorm", "filter": [ { "property": "tty", "op": "in", "value": "BN,SBD,SBDG,BPCK" } ] } ] } }`); const [currentValueSet, setCurrentValueSet] = useState<ValueSet>(); const [selectedValueSet, setSelectedValueSet] = useState(''); const [selectedCode, setSelectedCode] = useState<any>(); const [error, setError] = useState<string>(); const [successMessage, setSuccessMessage] = useState<string>(); // Use a resource directly from the ValueSet search const handleValueSetChange = (valueSet: ValueSet | undefined): void => { setCurrentValueSet(valueSet); if (valueSet?.url) { setSearchTerm(valueSet.url); setSelectedValueSet(valueSet.url); } else { setSelectedValueSet(''); } setError(undefined); setSuccessMessage(undefined); }; const handleCreateOrUpdateValueSet = async (): Promise<void> => { try { setError(undefined); setSuccessMessage(undefined); // Parse the JSON to validate it const valueSetData = JSON.parse(customValueSet); // Check if a ValueSet with this URL already exists const existingValueSet = await medplum.search('ValueSet', { url: valueSetData.url, }); if (existingValueSet.entry?.[0]?.resource) { // Update the existing ValueSet valueSetData.id = existingValueSet.entry[0].resource.id; await medplum.updateResource(valueSetData as ValueSet); setSuccessMessage('ValueSet updated successfully'); } else { // Create the ValueSet resource await medplum.createResource(valueSetData as ValueSet); setSuccessMessage('ValueSet created successfully'); } // Update the search if the current search term matches the new ValueSet's URL if (searchTerm === valueSetData.url) { setCurrentValueSet(valueSetData); setSelectedValueSet(valueSetData.url); } } catch (err) { setError(err instanceof Error ? err.message : 'Failed to create or update ValueSet'); } }; const handleAddCode = (): void => { if (!selectedCode) { return; } try { const valueSet = JSON.parse(customValueSet); // Ensure compose.include exists if (!valueSet.compose) { valueSet.compose = { include: [] }; } if (!valueSet.compose.include) { valueSet.compose.include = []; } // Ensure expansion.exists and contains is an array if (!valueSet.expansion) { valueSet.expansion = { contains: [] }; } if (!valueSet.expansion.contains) { valueSet.expansion.contains = []; } // Set expansion.timestamp valueSet.expansion.timestamp = new Date().toISOString(); // Check if code already exists const exists = valueSet.expansion.contains.some( (item: any) => item.system === selectedCode.system && item.code === selectedCode.code ); if (!exists) { valueSet.expansion.contains.push({ system: selectedCode.system, code: selectedCode.code, display: selectedCode.display, }); // Remove compose if include is empty if (valueSet.compose && Array.isArray(valueSet.compose.include) && valueSet.compose.include.length === 0) { delete valueSet.compose; } setCustomValueSet(JSON.stringify(valueSet, null, 2)); setSuccessMessage('Code added to ValueSet'); } else { setError('Code already exists in ValueSet'); } } catch (_err) { setError('Failed to add code to ValueSet'); } }; const clearValueSet = (): void => { const cleared = { resourceType: 'ValueSet', url: 'http://example.org/fhir/ValueSet/custom', name: 'CustomValueSet', title: 'Custom Value Set', status: 'active', // no compose property }; setCustomValueSet(JSON.stringify(cleared, null, 2)); setSuccessMessage('ValueSet cleared'); }; return ( <Document> <Title>ValueSet Demo</Title> <Box mb="xl"> <p> This demo shows how to work with FHIR ValueSets. You can either search for existing ValueSets on the left, or create your own custom ValueSet on the right. Once a ValueSet is selected or created, you can use it for typeaheads. </p> </Box> <Grid mt="md"> <Grid.Col span={6}> <Title order={2}>Search Existing ValueSets</Title> <p style={{ marginBottom: '1rem' }}> Search for standard ValueSets that are already available in the system. Start typing to see suggestions. </p> <ul> <li>Try searching for "allergy", "condition", "clinical findings", or "snomed"</li> <li>Examples: allergyintolerance-code, clinical-findings, condition-code</li> <li>Or use a full URL like http://hl7.org/fhir/ValueSet/allergyintolerance-code</li> </ul> <Group> <Box style={{ width: '100%' }}> <ResourceInput<ValueSet> resourceType="ValueSet" name="valueSet" label="Search ValueSet" placeholder="Start typing to search for ValueSets..." onChange={handleValueSetChange} /> {error && ( <Alert color="red" mt="md"> {error} </Alert> )} {currentValueSet && ( <Box mt="md"> <p> Selected ValueSet: <ResourceName value={currentValueSet} link /> </p> {currentValueSet.url && ( <p> <strong>URL:</strong> {currentValueSet.url} </p> )} {currentValueSet.description && ( <p> <strong>Description:</strong> {currentValueSet.description} </p> )} </Box> )} </Box> </Group> {selectedValueSet && ( <Box mt="md"> <Title order={3} mb="md"> Select code from ValueSet </Title> <CodingInput name="code" path="code" binding={selectedValueSet} required onChange={(value) => setSelectedCode(value)} /> {selectedCode && ( <Box mt="md"> <p>Selected Code:</p> <pre style={{ fontSize: '0.875rem', backgroundColor: '#f8f9fa', padding: '1rem', borderRadius: '4px', margin: 0, whiteSpace: 'pre-wrap', wordBreak: 'break-word', maxWidth: '100%', }} > {JSON.stringify(selectedCode, null, 2)} </pre> <Button mt="md" onClick={handleAddCode}> Add to Custom ValueSet </Button> </Box> )} </Box> )} </Grid.Col> <Grid.Col span={6}> <Title order={2}>Create/Update ValueSet</Title> <p style={{ marginBottom: '1rem' }}> Define your own ValueSet by editing the JSON below. The example shows a ValueSet for RxNorm branded drugs. </p> <Box mb="md"> <ResourceInput<ValueSet> resourceType="ValueSet" name="valueset-name" label="ValueSet Name" placeholder="Type to search ValueSet names..." onChange={async (valueSet) => { if (valueSet) { setCustomValueSet(JSON.stringify(valueSet, null, 2)); } }} /> </Box> <Textarea label="Custom ValueSet (JSON)" placeholder="Enter custom ValueSet JSON..." value={customValueSet} onChange={(event) => setCustomValueSet(event.currentTarget.value)} error={error} autosize={false} minRows={30} styles={{ input: { height: '500px', overflowY: 'auto', }, }} /> <Box mt="md"> <Group> <Button onClick={handleCreateOrUpdateValueSet}>Create/Update ValueSet</Button> <Button variant="outline" onClick={clearValueSet}> Clear ValueSet </Button> </Group> </Box> {successMessage && ( <Alert color="green" mt="md"> {successMessage} </Alert> )} </Grid.Col> </Grid> </Document> ); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/medplum/medplum'

If you have feedback or need assistance with the MCP directory API, please join our Discord server