From d60f5ae2e3048262ee5b76090ecdb048f7d05573 Mon Sep 17 00:00:00 2001 From: TomDijkema Date: Tue, 10 Dec 2024 16:38:54 +0100 Subject: [PATCH 01/10] Implement basic for prefilling annotation classes Implement basic for prefilling annotation classes --- src/app/Boot.ts | 2 +- src/app/utilities/AnnotateUtilities.ts | 14 ++-- src/app/utilities/ClassAnnotationUtilities.ts | 81 +++++++++++++++++++ 3 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 src/app/utilities/ClassAnnotationUtilities.ts diff --git a/src/app/Boot.ts b/src/app/Boot.ts index bde58abe..daf6b41a 100644 --- a/src/app/Boot.ts +++ b/src/app/Boot.ts @@ -18,7 +18,7 @@ type Callback = (bootState: { /** * Function that runs the application's necessary processes before it can be booted - * @returns True or false depening on if is has booted + * @returns True or false depening on if it has booted */ const Boot = (callback: Callback) => { /* Initiate keycloak which will render the root after finishing setting up */ diff --git a/src/app/utilities/AnnotateUtilities.ts b/src/app/utilities/AnnotateUtilities.ts index 2f63697a..f90491ae 100644 --- a/src/app/utilities/AnnotateUtilities.ts +++ b/src/app/utilities/AnnotateUtilities.ts @@ -5,6 +5,7 @@ import jp from 'jsonpath'; import { cloneDeep, isEmpty, toLower } from 'lodash'; /* Import Utilities */ +import { CheckForClassDefaultValues } from './ClassAnnotationUtilities'; import { ExtractLowestLevelSchema, ExtractClassesAndTermsFromSchema, MakeJsonPathReadableString } from 'app/utilities/SchemaUtilities'; /* Import Types */ @@ -208,7 +209,7 @@ const GenerateAnnotationFormFieldProperties = async (jsonPath: string, superClas /** * Function to check for a default value for a term - * + * @param key The term key to check */ const CheckForTermDefaultValue = (key: string) => { if (toLower(key).includes('date')) { @@ -242,7 +243,7 @@ const GenerateAnnotationFormFieldProperties = async (jsonPath: string, superClas formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = classFormValues ?? {}; } else if (classProperty.value.includes('has') && classProperty.value.at(-3) === 's') { - const localClassValues: Dict[] | undefined = classValues ?? []; + const localClassValues: Dict[] = classValues ?? []; if (!classValues) { const parentFieldName: string = classProperty.value.replace(`$`, jsonPath).split('[').slice(0, -1).join('['); @@ -252,9 +253,12 @@ const GenerateAnnotationFormFieldProperties = async (jsonPath: string, superClas PushToLocalClassValues(parentValues, childFieldName, (value: Dict) => localClassValues.push(value)); } - formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = classValues ?? localClassValues ?? []; + CheckForClassDefaultValues(classProperty.value.replace(`$`, jsonPath)); + + formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = classValues ?? + (!isEmpty(localClassValues) ? localClassValues : undefined) ?? CheckForClassDefaultValues(classProperty.value.replace(`$`, jsonPath)) ?? []; } else { - formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = {}; + formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = CheckForClassDefaultValues(jsonPath) ?? {}; } /* For each term of class, add it to the properties array of the corresponding class in the annotation form fields dictionary */ @@ -271,7 +275,7 @@ const GenerateAnnotationFormFieldProperties = async (jsonPath: string, superClas }); /* Check if the term field needs to be filled with a default value */ - if (CheckForTermDefaultValue(termOption.key)) { + if (CheckForTermDefaultValue(termOption.key) && !(termOption.key in classFormValues)) { classFormValues[termOption.key] = CheckForTermDefaultValue(termOption.key); } }); diff --git a/src/app/utilities/ClassAnnotationUtilities.ts b/src/app/utilities/ClassAnnotationUtilities.ts new file mode 100644 index 00000000..3cb057ca --- /dev/null +++ b/src/app/utilities/ClassAnnotationUtilities.ts @@ -0,0 +1,81 @@ +/* Import Dependencies */ +import KeycloakService from "app/Keycloak"; + +/* Import Utilities */ +import { FormatFieldNameFromJsonPath } from "./AnnotateUtilities"; + + +/* Utilities associated with a class annotation */ + + +/** + * Function to check for class default values and if present, return them + * @param jsonPath The JSON path of the class to check + */ +const CheckForClassDefaultValues = (jsonPath: string) => { + const className: string = FormatFieldNameFromJsonPath(jsonPath.replaceAll(/\[(\d+)\]/g, '')).split('_').slice(-1)[0].replace('$', '').replaceAll("'", ''); + + switch (className) { + case 'ods:hasAgents': { + return ClassAgents(jsonPath); + } + case 'ods:hasIdentifiers': { + return ClassIdentifiers(); + } + case 'ods:hasRoles': { + return ClassRoles(); + } + }; +}; + +/** + * Function to create a prefilled agent values object + * @param jsonPath The full provided JSON path + * @returns + */ +const ClassAgents = (jsonPath: string) => { + /* Extract parent class name from JSON path */ + // const parentClassName: string = FormatFieldNameFromJsonPath(jsonPath.replaceAll(/\[(\d+)\]/g, '')).split('_').slice(-2)[0].replace('$', '').replaceAll("'", ''); + + /* Construct agent values object */ + const classValues = { + "@type": 'schema:Person', + "schema:name": `${KeycloakService.GetParsedToken()?.given_name ?? ''} ${KeycloakService.GetParsedToken()?.family_name ?? ''}` + }; + + return classValues; +}; + +/** + * Function to create a prefilled role values object + * @returns + */ +const ClassIdentifiers = () => { + /* Construct identifier values object */ + const classValues = { + "@type": '', + "dcterms:title": '', + "dcterms:identifier": '' + }; + + return [classValues]; +}; + +/** + * Function to create a prefilled role values object + * @param roleForClassName The class name which to create a role for + * @returns + */ +const ClassRoles = () => { + /* Construct role values object */ + const classValues = { + "@type": '', + "schema:roleName": '' + }; + + return [classValues]; +}; + +export { + CheckForClassDefaultValues +}; \ No newline at end of file From 4a2879ceeec7e7ecc7b4cffa0ba8ced7a6b51c90 Mon Sep 17 00:00:00 2001 From: TomDijkema Date: Wed, 11 Dec 2024 09:17:06 +0100 Subject: [PATCH 02/10] Finnish setup for default class values in annotation wizard form Finnish setup for default class values in annotation wizard form --- src/app/utilities/AnnotateUtilities.ts | 29 ++++++++---- src/app/utilities/ClassAnnotationUtilities.ts | 45 +++++++++++++------ .../steps/AnnotationFormStep.tsx | 2 +- .../steps/formFields/SelectField.tsx | 2 +- 4 files changed, 55 insertions(+), 23 deletions(-) diff --git a/src/app/utilities/AnnotateUtilities.ts b/src/app/utilities/AnnotateUtilities.ts index f90491ae..52d9c961 100644 --- a/src/app/utilities/AnnotateUtilities.ts +++ b/src/app/utilities/AnnotateUtilities.ts @@ -183,7 +183,7 @@ const FormatJsonPathFromFieldName = (fieldName: string): string => { * @param schemaName The name of the base schema * @returns The annotation form field properties and their associated form values */ -const GenerateAnnotationFormFieldProperties = async (jsonPath: string, superClass: SuperClass, schemaName: string) => { +const GenerateAnnotationFormFieldProperties = async (jsonPath: string, superClass: SuperClass, schemaName: string, motivation: string) => { const annotationFormFieldProperties: { [propertyName: string]: AnnotationFormProperty } = {}; @@ -241,24 +241,37 @@ const GenerateAnnotationFormFieldProperties = async (jsonPath: string, superClas } }); - formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = classFormValues ?? {}; + formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = {}; + + /* Check if (default) values are present, if so, set form values property with them */ + if (!isEmpty(classFormValues)) { + formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = classFormValues; + } else if (motivation !== 'oa:editing') { + formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = CheckForClassDefaultValues(classProperty.value.replace(`$`, jsonPath)) ?? {}; + } } else if (classProperty.value.includes('has') && classProperty.value.at(-3) === 's') { - const localClassValues: Dict[] = classValues ?? []; + let localClassValues: Dict[] = classValues ?? []; if (!classValues) { const parentFieldName: string = classProperty.value.replace(`$`, jsonPath).split('[').slice(0, -1).join('['); const parentValues: Dict | undefined = jp.value(superClass, parentFieldName); const childFieldName: string = classProperty.value.split('[').pop()?.replace(']', '').replaceAll("'", '') ?? ''; - PushToLocalClassValues(parentValues, childFieldName, (value: Dict) => localClassValues.push(value)); + PushToLocalClassValues(parentValues, childFieldName, (value: Dict) => localClassValues?.push(value)); } - CheckForClassDefaultValues(classProperty.value.replace(`$`, jsonPath)); + formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = []; - formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = classValues ?? - (!isEmpty(localClassValues) ? localClassValues : undefined) ?? CheckForClassDefaultValues(classProperty.value.replace(`$`, jsonPath)) ?? []; + /* Check if (default) values are present, if so, set form values property with them */ + if (classValues) { + formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = classValues; + } else if (!isEmpty(localClassValues)) { + formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = localClassValues; + } else if (motivation !== 'oa:editing') { + formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = CheckForClassDefaultValues(classProperty.value.replace(`$`, jsonPath)) ?? []; + } } else { - formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = CheckForClassDefaultValues(jsonPath) ?? {}; + formValues[FormatFieldNameFromJsonPath(classProperty.value.replace(`$`, jsonPath))] = CheckForClassDefaultValues(classProperty.value.replace(`$`, jsonPath)) ?? {}; } /* For each term of class, add it to the properties array of the corresponding class in the annotation form fields dictionary */ diff --git a/src/app/utilities/ClassAnnotationUtilities.ts b/src/app/utilities/ClassAnnotationUtilities.ts index 3cb057ca..03d8c017 100644 --- a/src/app/utilities/ClassAnnotationUtilities.ts +++ b/src/app/utilities/ClassAnnotationUtilities.ts @@ -11,16 +11,20 @@ import { FormatFieldNameFromJsonPath } from "./AnnotateUtilities"; /** * Function to check for class default values and if present, return them * @param jsonPath The JSON path of the class to check + * @returns Prefilled data array or object depending on provided class */ const CheckForClassDefaultValues = (jsonPath: string) => { const className: string = FormatFieldNameFromJsonPath(jsonPath.replaceAll(/\[(\d+)\]/g, '')).split('_').slice(-1)[0].replace('$', '').replaceAll("'", ''); switch (className) { case 'ods:hasAgents': { - return ClassAgents(jsonPath); + return ClassAgents(); + } + case 'ods:hasGeoreference': { + return ClassGeoreference(); } case 'ods:hasIdentifiers': { - return ClassIdentifiers(); + return ClassIdentifiers(jsonPath); } case 'ods:hasRoles': { return ClassRoles(); @@ -30,32 +34,48 @@ const CheckForClassDefaultValues = (jsonPath: string) => { /** * Function to create a prefilled agent values object - * @param jsonPath The full provided JSON path - * @returns + * @returns Prefilled agents values array */ -const ClassAgents = (jsonPath: string) => { - /* Extract parent class name from JSON path */ - // const parentClassName: string = FormatFieldNameFromJsonPath(jsonPath.replaceAll(/\[(\d+)\]/g, '')).split('_').slice(-2)[0].replace('$', '').replaceAll("'", ''); - +const ClassAgents = () => { /* Construct agent values object */ const classValues = { "@type": 'schema:Person', + "schema:identifier": KeycloakService.GetParsedToken()?.orcid, "schema:name": `${KeycloakService.GetParsedToken()?.given_name ?? ''} ${KeycloakService.GetParsedToken()?.family_name ?? ''}` }; + return [classValues]; +}; + +/** + * Function to create a prefilled role values object + * @returns Prefilled georeferene values object + */ +const ClassGeoreference = () => { + /* Construct role values object */ + const classValues = { + "@type": 'ods:Georeference' + }; + return classValues; }; /** * Function to create a prefilled role values object - * @returns + * @returns Prefilled identifiers values array */ -const ClassIdentifiers = () => { +const ClassIdentifiers = (jsonPath: string) => { + /* Extract parent class name from JSON path */ + const parentClassName: string = FormatFieldNameFromJsonPath(jsonPath.replaceAll(/\[(\d+)\]/g, '')).split('_').slice(-2)[0].replace('$', '').replaceAll("'", ''); + + /* Set parent specific values */ + const dctermsIdentifier: string = parentClassName === 'ods:hasAgents' ? KeycloakService.GetParsedToken()?.orcid : ''; + /* Construct identifier values object */ const classValues = { "@type": '', "dcterms:title": '', - "dcterms:identifier": '' + "dcterms:identifier": dctermsIdentifier }; return [classValues]; @@ -63,8 +83,7 @@ const ClassIdentifiers = () => { /** * Function to create a prefilled role values object - * @param roleForClassName The class name which to create a role for - * @returns + * @returns Prefilled roles values array */ const ClassRoles = () => { /* Construct role values object */ diff --git a/src/components/elements/annotationSidePanel/components/annotationWizard/steps/AnnotationFormStep.tsx b/src/components/elements/annotationSidePanel/components/annotationWizard/steps/AnnotationFormStep.tsx index e3f8fd97..9df716d9 100644 --- a/src/components/elements/annotationSidePanel/components/annotationWizard/steps/AnnotationFormStep.tsx +++ b/src/components/elements/annotationSidePanel/components/annotationWizard/steps/AnnotationFormStep.tsx @@ -94,7 +94,7 @@ const AnnotationFormStep = (props: Props) => { } /* For selected class, get annotation form field properties and their values */ - GenerateAnnotationFormFieldProperties(jsonPath, localSuperClass, schemaName).then(({ annotationFormFieldProperties, newFormValues }) => { + GenerateAnnotationFormFieldProperties(jsonPath, localSuperClass, schemaName, formValues?.motivation).then(({ annotationFormFieldProperties, newFormValues }) => { let parentJsonPath: string = '$'; if (annotationTarget?.jsonPath && FormatFieldNameFromJsonPath(annotationTarget.jsonPath).split('_').length > 1) { diff --git a/src/components/elements/annotationSidePanel/components/annotationWizard/steps/formFields/SelectField.tsx b/src/components/elements/annotationSidePanel/components/annotationWizard/steps/formFields/SelectField.tsx index 77e63913..21611aaf 100644 --- a/src/components/elements/annotationSidePanel/components/annotationWizard/steps/formFields/SelectField.tsx +++ b/src/components/elements/annotationSidePanel/components/annotationWizard/steps/formFields/SelectField.tsx @@ -31,7 +31,7 @@ const SelectField = (props: Props) => {