Skip to content

Commit

Permalink
✨ References include resources referenced by the given ID
Browse files Browse the repository at this point in the history
Additional reference table to show the references in the payload of the given ID
  • Loading branch information
abgeorge7 committed Mar 13, 2020
1 parent d97ee30 commit ac8f7cc
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 67 deletions.
114 changes: 75 additions & 39 deletions src/components/tables/ReferenceTable.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import {Modal} from 'semantic-ui-react';
import {getReferencedBy} from '../../utils/api';
import {getReferencedBy, getReferences} from '../../utils/api';
import SortableTable from './SortableTable';
import './ReferenceTable.css';

Expand All @@ -10,59 +10,81 @@ class ReferenceTable extends React.Component {
super(props);
this.state = {
loadingReferences: false,
referenceData: [],
referencingData: [],
referencedByData: [],
showChildModal: null,
};
}

componentDidMount() {
this.fetchReferences();
this.fetchAllReferences();
}

componentDidUpdate(prevProps) {
if (this.props.resourceId !== prevProps.resourceId) {
this.fetchReferences();
if (this.props.resource.resourceId !== prevProps.resource.resourceId) {
this.fetchAllReferences();
}
}

fetchReferences = async () => {
fetchAllReferences = async () => {
this.setState({loadingReferences: true}, async () => {
this.props.setLoadingMessage(
`Fetching references for ${this.props.resourceId}...`,
`Fetching references for ${this.props.resource.id}...`,
);
const references = await getReferencedBy(
this.props.baseUrl,
this.props.resourceType,
this.props.resourceId,
);
let uniqueReferences = {};
references.forEach(reference => {
const mapValue = uniqueReferences[reference.profile];
if (!!mapValue) {
uniqueReferences[reference.profile] = {
...mapValue,
total: mapValue.total + 1,
children: mapValue.children.concat(reference),
};
} else {
uniqueReferences[reference.profile] = {
id: `${reference.resourceType}-${reference.name}`,
resourceType: reference.resourceType,
name: reference.name,
profile: reference.profile,
total: 1,
children: [reference],
};
}
});
const referenceData = Object.values(uniqueReferences);
const referencedByData = await this.fetchReferencedBy();
const referencingData = await this.fetchReferencing();
this.setState({
referenceData,
referencedByData,
referencingData,
loadingReferences: false,
});
});
};

fetchReferencedBy = async () => {
const references = await getReferencedBy(
this.props.baseUrl,
this.props.resource.resourceType,
this.props.resource.id,
);
return this.getReferenceMap(references);
};

fetchReferencing = async () => {
const referencingIds = Object.keys(this.props.resource)
.map(field => this.props.resource[field].reference)
.filter(field => field);
const allReferences = await getReferences(
this.props.baseUrl,
referencingIds,
);
return this.getReferenceMap(allReferences);
};

getReferenceMap = references => {
let uniqueReferences = {};
references.forEach(reference => {
const mapValue = uniqueReferences[reference.profile];
if (!!mapValue) {
uniqueReferences[reference.profile] = {
...mapValue,
total: mapValue.total + 1,
children: mapValue.children.concat(reference),
};
} else {
uniqueReferences[reference.profile] = {
id: `${reference.resourceType}-${reference.name}`,
resourceType: reference.resourceType,
name: reference.name,
profile: reference.profile,
total: 1,
children: [reference],
};
}
});
return Object.values(uniqueReferences);
};

onChildRowClick = child => {
this.setState({showChildModal: child});
};
Expand All @@ -81,12 +103,20 @@ class ReferenceTable extends React.Component {
>
<p>{this.props.loadingMessage}</p>
</div>
{this.state.referenceData && !this.state.loadingReferences ? (
{(this.state.referencedByData || this.state.referencingData) &&
!this.state.loadingReferences ? (
<div>
<h3>Resources that reference {this.props.resourceId}:</h3>
<h3>Resources that reference {this.props.resource.id}:</h3>
<SortableTable
headerCells={this.props.tableHeaders}
data={this.state.referencedByData}
rowChildren={true}
onChildRowClick={this.onChildRowClick}
/>
<h3>Resources referenced by {this.props.resource.id}:</h3>
<SortableTable
headerCells={this.props.tableHeaders}
data={this.state.referenceData}
data={this.state.referencingData}
rowChildren={true}
onChildRowClick={this.onChildRowClick}
/>
Expand Down Expand Up @@ -116,8 +146,10 @@ class ReferenceTable extends React.Component {
}

ReferenceTable.propTypes = {
resourceId: PropTypes.string.isRequired,
resourceType: PropTypes.string.isRequired,
resource: PropTypes.shape({
id: PropTypes.string.isRequired,
resourceType: PropTypes.string.isRequired,
}),
tableHeaders: PropTypes.arrayOf(
PropTypes.shape({
display: PropTypes.string.isRequired,
Expand All @@ -132,6 +164,10 @@ ReferenceTable.propTypes = {
};

ReferenceTable.defaultProps = {
resource: {
id: '',
resourceType: '',
},
onClick: () => {},
loadingMessage: '',
};
Expand Down
5 changes: 1 addition & 4 deletions src/components/tables/ResultsTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,7 @@ class ResultsTable extends React.Component {
<ReferenceTable
onClick={this.onReferenceRowClick}
tableHeaders={referencedByTableHeaders}
resourceId={this.state.rowData ? this.state.rowData.id : ''}
resourceType={
this.state.rowData ? this.state.rowData.resourceType : ''
}
resource={this.state.rowData ? this.state.rowData : null}
baseUrl={this.props.baseUrl}
loadingMessage={this.props.loadingMessage}
setLoadingMessage={this.props.setLoadingMessage}
Expand Down
66 changes: 42 additions & 24 deletions src/utils/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,31 +91,49 @@ export const getCapabilityStatementReferences = async (url, resourceType) =>
});

export const getReferencedBy = async (url, baseType, id) => {
let allReferences = await getCapabilityStatementReferences(
`${url}metadata`,
baseType,
);
let resourceReferences = await Promise.all(
allReferences.map(async ref => {
const data = await fetchAllResources(
`${url}${ref.type}?${baseType.toLowerCase()}=${baseType}/${id}`,
[],
);
return data.flat();
if (baseType) {
let allReferences = await getCapabilityStatementReferences(
`${url}metadata`,
baseType,
);
let resourceReferences = await Promise.all(
allReferences.map(async ref => {
const data = await fetchAllResources(
`${url}${ref.type}?${baseType.toLowerCase()}=${baseType}/${id}`,
[],
);
return data.flat();
}),
);
resourceReferences = [].concat
.apply([], resourceReferences)
.map(item => item.resource);
return await formatReferences(url, resourceReferences);
} else {
return [];
}
};

export const getReferences = async (url, referenceIds) => {
const resources = await Promise.all(
referenceIds.map(async reference => {
const resource = await fetchResource(`${url}${reference}`);
return resource;
}),
);
resourceReferences = [].concat
.apply([], resourceReferences)
.map(item => item.resource)
.map(item => ({
...item,
profile:
item.meta && item.meta.profile
? item.meta.profile
: [`${fhirUrl}${item.resourceType}`],
}));
resourceReferences = await Promise.all(
resourceReferences.map(async ref => {
return await formatReferences(url, resources);
};

export const formatReferences = async (url, references) => {
references = references.map(item => ({
...item,
profile:
item.meta && item.meta.profile
? item.meta.profile
: [`${fhirUrl}${item.resourceType}`],
}));
references = await Promise.all(
references.map(async ref => {
const data = await fetchResource(
`${url}StructureDefinition?url=${ref.profile[0]}`,
);
Expand All @@ -126,7 +144,7 @@ export const getReferencedBy = async (url, baseType, id) => {
return {...ref, name};
}),
);
return resourceReferences.filter(ref => ref.name);
return references.filter(ref => ref.name);
};

export const userIsAuthorized = (username, password, baseUrl) => {
Expand Down

0 comments on commit ac8f7cc

Please sign in to comment.