Skip to main content
Glama
ValueSetPreview.tsx7.03 kB
// SPDX-FileCopyrightText: Copyright Orangebot, Inc. and Medplum contributors // SPDX-License-Identifier: Apache-2.0 import { Alert, Group, Loader, Stack, Table, Text } from '@mantine/core'; import { normalizeErrorString } from '@medplum/core'; import type { Parameters, ParametersParameter, ValueSet, ValueSetExpansionContains } from '@medplum/fhirtypes'; import { DescriptionList, DescriptionListEntry, Document, ErrorBoundary, useMedplum, ValueSetAutocomplete, } from '@medplum/react'; import { IconAlertCircle } from '@tabler/icons-react'; import type { JSX } from 'react'; import { useCallback, useMemo, useState } from 'react'; import classes from './ValueSetPreview.module.css'; export interface ValueSetPreviewProps { readonly valueSet: ValueSet; } interface CodeSystemPropertyListProps { readonly properties: ParametersParameter[]; } /** * Formats a property value from a ParametersParameter part. * Handles various value types: code, string, boolean, integer, decimal, date, and dateTime. * * @param part - The ParametersParameter part containing the value * @returns The formatted string value or 'N/A' if no value is present */ function formatPropertyValue(part: ParametersParameter): string { return ( part.valueCode || part.valueString || (part.valueBoolean === undefined ? undefined : String(part.valueBoolean)) || (part.valueInteger === undefined ? undefined : String(part.valueInteger)) || (part.valueDecimal === undefined ? undefined : String(part.valueDecimal)) || part.valueDate || part.valueDateTime || 'N/A' ); } /** * Renders a list of CodeSystem properties from a CodeSystem/$lookup operation result. * Each property displays its code, description, and value in a tabular format. * * @param props - Component props * @param props.properties - Array of filtered ParametersParameter objects representing CodeSystem properties * @returns JSX element displaying the properties */ function CodeSystemPropertyList(props: CodeSystemPropertyListProps): JSX.Element { const { properties } = props; // Extract values from each property const propertyData = properties.map((param) => { let code = ''; let description = ''; let value = ''; param.part?.forEach((part) => { if (part.name === 'code') { code = part.valueCode || ''; } else if (part.name === 'description') { description = part.valueString || ''; } else if (part.name === 'value') { value = formatPropertyValue(part); } }); return { code, description, value }; }); return ( <Table className={classes.propertyTable}> <Table.Thead> <Table.Tr> <Table.Th>Code</Table.Th> <Table.Th>Description</Table.Th> <Table.Th>Value</Table.Th> </Table.Tr> </Table.Thead> <Table.Tbody> {propertyData.map((property, index) => ( <Table.Tr key={`property-${index}`}> <Table.Td>{property.code}</Table.Td> <Table.Td>{property.description}</Table.Td> <Table.Td>{property.value}</Table.Td> </Table.Tr> ))} </Table.Tbody> </Table> ); } /** * ValueSetPreview component displays a ValueSet and allows users to select values from it. * When a value is selected, it performs a CodeSystem/$lookup operation to retrieve * additional property information about the selected code. * * @param props - Component props * @param props.valueSet - The ValueSet resource to preview * @returns JSX element displaying the ValueSet preview interface */ export function ValueSetPreview(props: ValueSetPreviewProps): JSX.Element { const { valueSet } = props; const medplum = useMedplum(); const valueSetUrl = valueSet.url; const [selectedValue, setSelectedValue] = useState<ValueSetExpansionContains | undefined>(); const [lookupResult, setLookupResult] = useState<Parameters | undefined>(); const [isLoadingLookup, setIsLoadingLookup] = useState(false); const [lookupError, setLookupError] = useState<Error | undefined>(); const handleValueChange = useCallback( async (newValue: ValueSetExpansionContains | undefined): Promise<void> => { setSelectedValue(newValue); setLookupResult(undefined); setLookupError(undefined); if (!newValue?.code || !newValue?.system) { setIsLoadingLookup(false); return; } setIsLoadingLookup(true); try { // Call CodeSystem/$lookup operation const params = new URLSearchParams({ system: newValue.system, code: newValue.code }); const url = medplum.fhirUrl('CodeSystem', '$lookup') + '?' + params.toString(); const result = await medplum.get(url); setLookupResult(result as Parameters); } catch (error) { setLookupError(error instanceof Error ? error : new Error(String(error))); } finally { setIsLoadingLookup(false); } }, [medplum] ); const properties = useMemo(() => { return lookupResult?.parameter?.filter((param) => param.name === 'property' && param.part) ?? []; }, [lookupResult]); const hasProperties = properties.length > 0; return ( <Document> <Stack gap="xl"> <ValueSetAutocomplete binding={valueSetUrl} placeholder="Select a value from the ValueSet" onChange={(values) => handleValueChange(values[0])} defaultValue={selectedValue} maxValues={1} /> {selectedValue ? ( <Stack gap="md"> <DescriptionList> <DescriptionListEntry term="Code">{selectedValue.code}</DescriptionListEntry> {selectedValue.system && ( <DescriptionListEntry term="System">{selectedValue.system}</DescriptionListEntry> )} {selectedValue.display && ( <DescriptionListEntry term="Display">{selectedValue.display}</DescriptionListEntry> )} </DescriptionList> {isLoadingLookup && ( <Group gap="xs"> <Loader size="sm" /> <Text size="sm" c="dimmed"> Loading properties... </Text> </Group> )} {!isLoadingLookup && lookupError && ( <Alert icon={<IconAlertCircle size={16} />} title="Lookup Failed" color="red"> Failed to retrieve code information: {normalizeErrorString(lookupError)} </Alert> )} {!isLoadingLookup && !lookupError && hasProperties && ( <ErrorBoundary> <Stack gap="xs" mt="lg"> <Text fw={500} size="sm" c="dimmed" className={classes.propertiesTitle}> Properties </Text> <CodeSystemPropertyList properties={properties} /> </Stack> </ErrorBoundary> )} </Stack> ) : null} </Stack> </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