diff --git a/src/components/digitalSpecimen/DigitalSpecimen.tsx b/src/components/digitalSpecimen/DigitalSpecimen.tsx index a1331fd5..26afe70e 100644 --- a/src/components/digitalSpecimen/DigitalSpecimen.tsx +++ b/src/components/digitalSpecimen/DigitalSpecimen.tsx @@ -13,6 +13,7 @@ import { getDigitalSpecimen, setDigitalSpecimen } from 'redux-store/DigitalSpeci /* Import Types */ import { DigitalMedia } from 'app/types/DigitalMedia'; import { DigitalSpecimen as DigitalSpecimenType } from 'app/types/DigitalSpecimen'; +import { TourTopic } from 'app/Types'; /* Import Sources */ import DigitalSpecimenSchema from 'sources/dataModel/digitalSpecimen.json'; @@ -27,6 +28,7 @@ import GetDigitalSpecimenMasJobRecords from 'api/digitalSpecimen/GetDigitalSpeci import ScheduleDigitalSpecimenMas from "api/digitalSpecimen/ScheduleDigitalSpecimenMas"; /* Import Components */ +import DigitalSpecimenTourSteps from './tourSteps/DigitalSpecimenTourSteps'; import { ContentBlock, IdCard, TopBar } from './components/DigitalSpecimenComponents'; import { AnnotationSidePanel, BreadCrumbs, Header, Footer } from 'components/elements/Elements'; import { LoadingScreen } from 'components/elements/customUI/CustomUI'; @@ -46,6 +48,11 @@ const DigitalSpecimen = () => { const digitalSpecimen = useAppSelector(getDigitalSpecimen); const [digitalSpecimenDigitalMedia, setDigitalSpecimenDigitalMedia] = useState(); const [annotationMode, setAnnotationMode] = useState(false); + const [selectedTabIndex, setSelectedTabIndex] = useState(0); + const tourTopics: TourTopic[] = [{ + name: 'digitalSpecimen', + title: 'About this page' + }]; /* OnLoad, fetch digital specimen data */ fetch.FetchMultiple({ @@ -104,7 +111,7 @@ const DigitalSpecimen = () => {
{/* Render header*/} -
+
{/* Digital specimen page body */} @@ -121,7 +128,7 @@ const DigitalSpecimen = () => { {/* Top bar */} - + { {/* ID card */} { {/* Content block */} @@ -179,6 +189,8 @@ const DigitalSpecimen = () => { } + +
); }; diff --git a/src/components/digitalSpecimen/components/contentBlock/ContentBlock.tsx b/src/components/digitalSpecimen/components/contentBlock/ContentBlock.tsx index 4907bb89..d626b689 100644 --- a/src/components/digitalSpecimen/components/contentBlock/ContentBlock.tsx +++ b/src/components/digitalSpecimen/components/contentBlock/ContentBlock.tsx @@ -1,6 +1,5 @@ /* Import Dependencies */ import { isEmpty } from 'lodash'; -import { useState } from 'react'; /* Import Types */ import { DigitalMedia } from 'app/types/DigitalMedia'; @@ -14,7 +13,9 @@ import { Tabs } from 'components/elements/customUI/CustomUI'; /* Props Type */ type Props = { digitalSpecimen: DigitalSpecimen, - digitalSpecimenDigitalMedia: DigitalMedia[] | undefined + digitalSpecimenDigitalMedia: DigitalMedia[] | undefined, + selectedTabIndex: number, + SetSelectedTabIndex: Function }; @@ -22,13 +23,14 @@ type Props = { * Component that renders the content block on the digital specimen page * @param digitalSpecimen The selected digital specimen * @param digitalSpecimenDigitalMedia The digital media attached to the digital specimen + * @param selectedTabIndex The selected index for the digital specimen tabs + * @param SetSelectedTabIndex Function to set the selected tab index * @returns JSX Component */ const ContentBlock = (props: Props) => { - const { digitalSpecimen, digitalSpecimenDigitalMedia } = props; + const { digitalSpecimen, digitalSpecimenDigitalMedia, selectedTabIndex, SetSelectedTabIndex } = props; /* Base variables */ - const [selectedTabIndex, setSelectedTabIndex] = useState(0); const tabs = { 'digitalSpecimen': , ...(digitalSpecimenDigitalMedia && !isEmpty(digitalSpecimenDigitalMedia) && { @@ -51,7 +53,7 @@ const ContentBlock = (props: Props) => { }} tabClassName="fs-5 px-3" tabPanelClassName="h-100 overflow-y-scroll overflow-x-hidden" - SetSelectedIndex={(index: number) => setSelectedTabIndex(index)} + SetSelectedIndex={(index: number) => SetSelectedTabIndex(index)} /> ); diff --git a/src/components/digitalSpecimen/components/topBar/TopBar.tsx b/src/components/digitalSpecimen/components/topBar/TopBar.tsx index 4c306470..86ea976a 100644 --- a/src/components/digitalSpecimen/components/topBar/TopBar.tsx +++ b/src/components/digitalSpecimen/components/topBar/TopBar.tsx @@ -132,7 +132,9 @@ const TopBar = (props: Props) => { {versionDropdownItems && - + { } - + { + const { SetSelectedTabIndex } = props; + + /* Hooks */ + const dispatch = useAppDispatch(); + + /* Base variables */ + const tourTopic = useAppSelector(getTourTopic); + const digitalSpecimenSteps = DigitalSpecimenTourStepsText.digitalSpecimen; + const { options } = StepsConfig(); + let steps: { + intro: string, + element?: string + }[] = []; + + /* Construct Intro.js steps for digital specimen page */ + digitalSpecimenSteps.forEach((step, index) => { + steps.push({ + intro: step, + element: `.tourDigitalSpecimen${index + 1}` + }); + }); + + /** + * Function that checks what to do on a step change + * @param nextIndex The next (selected) index in the step chain + * @param resolve Function to resolve the step promise + */ + const OnStepChange = (nextIndex: number, resolve: Function) => { + const nextIndexToTabIndexMap = { + 6: 0, + 7: 1, + 8: 2, + 9: 3, + 10: 4, + 11: 5 + }; + + if (Object.keys(nextIndexToTabIndexMap).includes(`${nextIndex}`)) { + /* On step 7: set tab to digital specimen */ + SetSelectedTabIndex(0); + + resolve(); + } else { + resolve(); + } + }; + + return ( + { + return new Promise((resolve) => { + OnStepChange(nextIndex, resolve); + }); + }} + onStart={() => SetSelectedTabIndex(0)} + onExit={() => { + SetSelectedTabIndex(0); + dispatch(setTourTopic(undefined)); + }} + options={options} + /> + ); +}; + +export default DigitalSpecimenTourSteps; \ No newline at end of file diff --git a/src/components/search/tourSteps/CompareTourSteps.tsx b/src/components/search/tourSteps/CompareTourSteps.tsx index 8a2aea09..09fba5ed 100644 --- a/src/components/search/tourSteps/CompareTourSteps.tsx +++ b/src/components/search/tourSteps/CompareTourSteps.tsx @@ -26,7 +26,7 @@ type Props = { /** - * Component that renders the tour steps for the homepage + * Component that renders the tour steps for the compare functionality on the search page * @param pagination The pagination object used to index the digital specimen results * @returns JSX Component */ @@ -47,7 +47,7 @@ const CompareTourSteps = (props: Props) => { element?: string }[] = []; - /* Construct Intro.js steps for Homepage */ + /* Construct Intro.js steps for compare functionality on search page */ compareSteps.forEach((step, index) => { steps.push({ intro: step, diff --git a/src/components/search/tourSteps/SearchTourSteps.tsx b/src/components/search/tourSteps/SearchTourSteps.tsx index 5010eb37..294a3ddd 100644 --- a/src/components/search/tourSteps/SearchTourSteps.tsx +++ b/src/components/search/tourSteps/SearchTourSteps.tsx @@ -46,7 +46,7 @@ const SearchTourSteps = (props: Props) => { element?: string }[] = []; - /* Construct Intro.js steps for Homepage */ + /* Construct Intro.js steps for Search page */ searchSteps.forEach((step, index) => { steps.push({ intro: step, diff --git a/src/sources/tourText/digitalSpecimen.json b/src/sources/tourText/digitalSpecimen.json new file mode 100644 index 00000000..0671165a --- /dev/null +++ b/src/sources/tourText/digitalSpecimen.json @@ -0,0 +1,48 @@ +{ + "digitalSpecimen": [ + "This is the digital specimen page. This detailed page contains all the information about a digital specimen which is harmonised within the DiSSCo data model. Because of the bulk of information, it is broken up into different segments focusing on different topics.", + "At the top we already see quite some returning elements. The name of the specimen is displayed in big font, whilst the current level of MIDS (minimum information about a digital specimen) is displayed below it.", + "This dropdown element can be used to select a particular version of a specimen. By default, this will always be the latest version.", + "On the top right is the actions dropdown. This dropdown lists items with certain actions that can be executed upon the specimen. Follow the action specific tutorials for more on that.", + "On the left we see a familiar component: the ID card. Similar to the ID card on the search page, this component displays all core properties of the specimen, like for example: the physical identifier, type and specimen provider (organisation). The ID card is a static element which will always remain in place on this page.", + "Then, the biggest space on this page is appointed to the display of detailed specimen data. The different heritages of these data are divided by tabs, like: digital specimen, original data, digital media and provenance. By default, the digital specimen tab will be displayed.", + "In the digital specimen tab you can browse through the specimen data. This is also further divided into segmented blocks with assigned categories of data. For example: the location block only displays data about the location of the specimen, while the taxonomy block contains all taxonomic details.", + "If present, the digital media tab displays all the digital media attached to a specimen. Currently, the interface supports: images, videos and audio to be seen and heard. All other kinds of media will be displayed as attached files and tagged as ‘other media’.", + "The events tab shows all events present within the Digital Specimen", + "The identifications tab shows all identifications present within the Digital Specimen", + "The entity relationships tab shows all entity relationships present within the Digital Specimen", + "If present, the assertions tab shows all assertions present in the Digital Specimen" + ], + "annotate": [ + "DiSSCover’s main purpose is to give users the power to enrich existing specimen data. These enrichments are called: ‘annotations’. An annotation can be an addition or a correction; but other types like links, quality flags or a regular comment are also supported. Annotations exist to keep discussion about data quality alive. At the moment, annotations are read only and do not have any effect on the actual specimen data itself. This will be implemented in the future when a solid trust model has been established.", + "First off, where do these annotations hide? Well they are kept in a separate side panel which is disabled on default. There are multiple ways to trigger the annotation side panel. The most generic method is to select ‘view all annotations’ from the actions dropdown.", + "Select ‘view all annotation’ from the actions dropdown.", + "This is the annotations side panel. As you can see, annotations might pop up already depending on whether the specimen you are looking at has annotations or not. This side panel contains all functionality related to annotations and can show up in more places than just the specimen page.", + "You can filter on annotation type and also order displayed annotations, for example by creation date. Annotation types describe the purpose of annotations. Current motivations include: commenting, linking, adding, correcting and quality flagging.", + "To hide the side panel, click on this arrow pointing to the left at the top left corner.", + "As mentioned, there are multiple methods for triggering the annotations side panel. Another method for triggering the side panel, for a specific property of a specimen, is by selecting that property from the view. This is a useful method for when you only want to see annotations made for that property, or if you want to create an annotation on that property.", + "Let’s trigger the annotations side panel for the scientific name only. We can achieve this by clicking on the scientific name property in the ID card.", + "As you can see this triggered the annotations side panel. In this case, specifically for the scientific name property. This is indicated at the top of the side panel, noting the chosen property and its current value.", + "You can easily switch between specimen properties by clicking on another property in the view next to the side panel. For example, this simulates switching between the scientific name, specimen provider and licence properties. Everytime, the specific annotations are loaded for the chosen property only.", + "You can return to the overview of all annotations by clicking on the arrow to the left on the top that would normally close the side panel. If a specific property is chosen, it will first return to the overview of all annotations, before closing the entire side panel.", + "To add new annotations, you need to be logged into your DiSSCo account. A button will appear at the bottom of the side panel saying ‘add annotation’. Click on this button to display the annotation form.", + "Using this form, you can add annotations.", + "First you can choose a specimen class or property; or add an annotation on the whole specimen. The difference is that a property specific annotation will show up in the side panel when an user selects the property from the view, while annotations on the whole specimen only show up in the total overview.", + "Next, select one of the available annotation types. Selecting one will trigger the remaining fields of the form. These fields are directly influenced by the annotation type as not all are required with every type.", + "After filling in these fields with your values, save the annotation by clicking on the ‘save’ button. This will save your annotation and redirect you back to the overview, highlighting the new annotation.", + "To edit one of your existing annotations, click on the pencil icon.", + "To delete one of your existing annotations, click on the trash can icon." + ], + "MAS": [ + "Annotations are the key to enriching the data within the DiSSCo digital infrastructure. Aside from human annotation, machine learning is also being used to detect certain properties of specimen data and assert those as annotations to the digital object. These machine annotations are part of the services provided by DiSSCo and its partners to reach the goal of high data quality.", + "As a DiSSCo user, you are able to run Machine Annotation Services over digital objects like specimens or digital media. This tutorial will show you how to schedule Machine Annotation Services for a specimen.", + "First, make sure you are logged into your DiSSCo account. Then select ‘trigger automated annotations’ from the actions dropdown.", + "This will trigger a new window called ‘Automated Annotation Services’. It provides a description and the tools to schedule services. We explicitly say ‘schedule’, since services that are fired up by users will first get into a queue system. This means the Machine Annotation Service you chose to run might not run immediately (currently we do not provide any updates on the background progress).", + "First select the 'Schedule a new Service tab'", + "From the dropdown, select one of the available Machine Annotation Services. This will add it to a list below. Select as many as you want, as they will be run individually from each other. Note that not all Machine Annotation Services will show up for every specimen. That is because some have certain rulesets, like for example: the specimen must belong to the Palaeontology domain or the specimen must have 2D images attached to it. Depending on if the specimen complies to these rules, will make the options for the services pop up in the dropdown.", + "Finally, when you are done selecting, click on ‘schedule’ to schedule the chosen Machine Annotation Services. This also closes this window.", + "To see the annotations made by the Machine Annotation Service, open the annotations side panel from the actions dropdown.", + "Great chance the annotations do not show up yet. This is because the Machine Annotation Service is in a queue and we do not exactly know when to expect results.", + "To see if the Machine Annotation Service has completed running and generated annotations, click on the refresh button. This will refetch the annotations from the database. The time needed for annotations to pop up may depend on the type of Machine Annotation Service." + ] +} \ No newline at end of file