-
Notifications
You must be signed in to change notification settings - Fork 1
Refactor of GetDigitalSpecimenComplete service and setup of data mapper to UI #244
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
Changes from all commits
c24cf87
67759ea
8f8442c
e9b242a
f9bebf3
a1bca54
1eb622b
c48b3c5
53f3ba8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import { useQuery } from '@tanstack/react-query'; | ||
| import { getDigitalSpecimenComplete } from 'services/digitalSpecimenService/getDigitalSpecimenComplete'; | ||
| import { mapDigitalSpecimen } from 'utils/DataMappers/digitalSpecimenDataMapper'; | ||
|
|
||
| /* Base constants */ | ||
| const staleTime = 1000 * 60 * 5; // How long until the time is stale | ||
| const gcTime = 1000 * 60 * 10; // Cache time: How long to store it in the cache | ||
|
|
||
| /* useQuery hook to retrieve the complete Digital Specimen data object by calling the getDigitalSpecimenComplete service */ | ||
| export const useDigitalSpecimenComplete = ({ doi, version }: | ||
| { doi: string, version?: number }) => { | ||
| return useQuery({ | ||
| queryKey: ['digitalSpecimen', doi, version], | ||
| queryFn: () => getDigitalSpecimenComplete({ doi, version }), | ||
| select: (data) => { | ||
| return { | ||
| ...data, | ||
| ...mapDigitalSpecimen(data), | ||
| } | ||
| }, | ||
| staleTime, | ||
| gcTime | ||
| }); | ||
| }; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| import apiClient from '../apiClient'; | ||
|
|
||
| /** | ||
| * Service that retrieves the complete digital specimen details through the apiClient | ||
| * Takes doi and version as a parameter object | ||
| * @returns An array with complete digital specimen data on specimen, media and annotations | ||
| */ | ||
| export const getDigitalSpecimenComplete = async ({ doi, version }: | ||
| { doi: string, version?: number }) => { | ||
| let endPoint: string; | ||
|
|
||
| if (version) { | ||
| endPoint = `digital-specimen/v1/${doi}/${version}/full`; | ||
| } else { | ||
| endPoint = `digital-specimen/v1/${doi}/full`; | ||
| } | ||
| try { | ||
| /* Call service and wait for response */ | ||
| const response = await apiClient.get(endPoint, { | ||
| params: { | ||
| doi, | ||
| version | ||
| } | ||
| }); | ||
|
|
||
| /* Throw error if response is not as expected */ | ||
| if(!response.data?.data) { | ||
|
southeo marked this conversation as resolved.
|
||
| throw new Error('Incorrect response format'); | ||
| } | ||
|
|
||
| /* Return response data */ | ||
| return response.data; | ||
| } catch (error) { | ||
| /* If error, throw error with generic error message */ | ||
| console.error('Error fetching the digital specimen:', error); | ||
|
|
||
| /* Rethrow error for useQuery */ | ||
| throw error; | ||
|
Contributor
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. why catch here just to log it? why not just add the logging on line 28?
Collaborator
Author
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. In the future, this will be caught by some form of error notification system I still have to implement. The error in the catch can be any kind of error, 500s, 404s. The error on line 28 is only thrown if the status is OK (200, 201), but the response that we get does not match what we expect at all. The catch takes care of my error codes. So separate error instances. |
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,62 @@ | ||
| /* Import schemas */ | ||
| import DIGITAL_SPECIMEN_SCHEMA_MAP from "./schemas/DigitalSpecimenSchema"; | ||
|
|
||
| /* Import types */ | ||
| import { DigitalSpecimenUIModel, SchemaMap, UIProperty } from "./types/dataMapperTypes"; | ||
|
|
||
| /** | ||
| * Function to get the accepted identification or the first one it can find | ||
| * @param ds The digital specimen object | ||
| * @returns Either the accepted identification, the first identification it can find or null in the edge case that there is none | ||
| */ | ||
| const getAcceptedIdentification = (ds: any) => { | ||
|
Collaborator
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 can return
Collaborator
Author
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. I adjusted the function to also return a null in case of no identifications whatsoever. Probably a bit of an edge case, but my mapper works also if no identifications are found. |
||
| const identifications = ds["ods:hasIdentifications"]; | ||
|
|
||
| /* Find verified identification or fallback to first identification */ | ||
| const primary = identifications?.find((item: any) => item["ods:isVerifiedIdentification"]) | ||
| ?? identifications?.[0]; | ||
|
|
||
| /* Return the taxon identification or null if for some reason there is no identification*/ | ||
| return primary?.["ods:hasTaxonIdentifications"]?.[0] ?? null; | ||
| } | ||
|
|
||
| /** | ||
| * Function to retrieve the primary event once | ||
| * @param ds The digital specimen object | ||
| * @returns Either the primary event if there is one or null | ||
| */ | ||
| const getPrimaryEvent = (ds: any) => { | ||
| return ds["ods:hasEvents"]?.[0] ?? null; | ||
| } | ||
|
|
||
| /** | ||
| * Transforms raw Digital Specimen data into a UI-ready model | ||
| * based on the DIGITAL_SPECIMEN_SCHEMA_MAP definitions. | ||
| * It is executed in the useDigitalSpecimen hook immediately when the call is being done. | ||
| */ | ||
| export const mapDigitalSpecimen = (rawData: any): DigitalSpecimenUIModel | null => { | ||
| const ds = rawData?.data?.attributes?.digitalSpecimen; | ||
| if (!ds) return null; | ||
|
|
||
| /* Find acceptedIdentification or second best option */ | ||
| const acceptedIdentification = getAcceptedIdentification(ds); | ||
| const primaryEvent = getPrimaryEvent(ds); | ||
|
|
||
| return Object.fromEntries( | ||
| Object.entries(DIGITAL_SPECIMEN_SCHEMA_MAP as SchemaMap).map(([groupKey, fields]) => { | ||
| const mappedFields: Record<string, UIProperty> = Object.fromEntries( | ||
| Object.entries(fields).map(([fieldKey, config]) => [ | ||
| fieldKey, | ||
| { | ||
| label: config.label, | ||
| value: config.resolve(ds, {acceptedIdentification, primaryEvent}), | ||
| isHtml: Boolean(config.isHtml), | ||
| type: config.type || 'base', | ||
| } | ||
| ]) | ||
| ); | ||
|
|
||
| return [groupKey, mappedFields]; | ||
| }) | ||
| ) as unknown as DigitalSpecimenUIModel; | ||
| }; | ||
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.
are you sure this cannot be changed with
overrides? Or are all the earlier packages vulnerable and new versions not compatible with formik ?https://docs.npmjs.com/cli/v8/configuring-npm/package-json#overrides
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 think I could. I have a follow up user story to address all these trivyignores, because the list is getting long and I'd like to clean them up.