Skip to content

Commit

Permalink
CORE-1967 WIP auto-populate LocalContexts metadata in templates
Browse files Browse the repository at this point in the history
  • Loading branch information
psarando committed Feb 24, 2024
1 parent 3fac779 commit b09ab10
Show file tree
Hide file tree
Showing 6 changed files with 290 additions and 54 deletions.
2 changes: 2 additions & 0 deletions public/static/locales/en/localcontexts.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
{
"localContextsAttrDefaultValue": "The \"{{projectTitle}}\" project has Labels and/or Notices applied through the Local Contexts Hub. For more information, refer to the project page: {{projectPage}}",
"localContextsHubProjectURI": "Local Contexts Hub Project URI",
"projectMoreInfoWithLink": "For more information on the <ExternalLink href=\"https://localcontexts.org\">Local Contexts</ExternalLink> project for this data, please visit the project's page: <ProjectLink>{{projectTitle}}</ProjectLink>"
}
33 changes: 25 additions & 8 deletions src/components/data/listing/TableView.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* @author aramsey
* @author aramsey, psarando
*
* A component intended for showing a data listing in a table format.
*/
Expand Down Expand Up @@ -28,6 +28,10 @@ import EmptyTable from "components/table/EmptyTable";
import { formatDate } from "components/utils/DateFormatter";

import LocalContextsLabelDisplay from "components/metadata/LocalContextsLabelDisplay";
import {
LocalContextsAttrs,
parseProjectID,
} from "components/models/metadata/LocalContexts";
import ResourceTypes from "components/models/ResourceTypes";

import InstantLaunchButton from "components/instantlaunches";
Expand All @@ -36,6 +40,8 @@ import { defaultInstantLaunch } from "serviceFacades/instantlaunches";
import {
FILESYSTEM_METADATA_QUERY_KEY,
getFilesystemMetadata,
getLocalContextsProject,
LOCAL_CONTEXTS_QUERY_KEY,
} from "serviceFacades/metadata";

import {
Expand Down Expand Up @@ -74,9 +80,10 @@ function ResourceNameCell({
const { avus } = metadata;

const rightsURI = avus
?.find((avu) => avu.attr === "LocalContexts")
?.find((avu) => avu.attr === LocalContextsAttrs.RIGHTS_ALIAS)
?.avus?.find(
(childAVU) => childAVU.attr === "rightsURI"
(childAVU) =>
childAVU.attr === LocalContextsAttrs.RIGHTS_URI
)?.value;

if (rightsURI) {
Expand All @@ -90,6 +97,19 @@ function ResourceNameCell({
), // fail silently.
});

const projectID = parseProjectID(localContextsProjectURI);

const { data: project } = useQuery({
queryKey: [LOCAL_CONTEXTS_QUERY_KEY, projectID],
queryFn: () => getLocalContextsProject({ projectID }),
enabled: URL.canParse(localContextsProjectURI),
onError: (error) =>
console.log("Error fetching Local Contexts project.", {
localContextsProjectURI,
error,
}), // fail silently.
});

return (
<TableCell>
<Stack
Expand All @@ -112,11 +132,8 @@ function ResourceNameCell({
>
{resource.label}
</SpanLink>
{localContextsProjectURI && (
<LocalContextsLabelDisplay
size="small"
rightsURI={localContextsProjectURI}
/>
{localContextsProjectURI && project && (
<LocalContextsLabelDisplay size="small" project={project} />
)}

{instantLaunch && (
Expand Down
32 changes: 1 addition & 31 deletions src/components/metadata/LocalContextsLabelDisplay.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React from "react";

import { useQuery } from "react-query";
import {
Card,
CardContent,
Expand All @@ -17,11 +16,6 @@ import { Trans, useTranslation } from "i18n";
import DEDialog from "components/utils/DEDialog";
import ExternalLink from "components/utils/ExternalLink";

import {
LOCAL_CONTEXTS_QUERY_KEY,
getLocalContextsProject,
} from "serviceFacades/metadata";

const sizeToSpacing = (size, theme) =>
size === "large"
? theme.spacing(8)
Expand Down Expand Up @@ -100,31 +94,7 @@ const LocalContextsLabel = ({ baseId, label, project, size = "medium" }) => {
);
};

const LocalContextsLabelDisplay = ({ rightsURI, size = "medium" }) => {
// Remove any trailing slash from the rightsURI
// and take the final part of the path as the project ID.
const projectID = rightsURI?.replace(/\/$/, "").split("/").at(-1);

const { data: project } = useQuery({
queryKey: [
LOCAL_CONTEXTS_QUERY_KEY,
projectID && {
projectID,
},
],
queryFn: () =>
getLocalContextsProject({
projectID,
}),
enabled: !!projectID,
onError: (error) => {
console.log("Error fetching Local Contexts project.", {
rightsURI,
error,
});
},
});

const LocalContextsLabelDisplay = ({ project, size = "medium" }) => {
const labels = [
...(project?.notice || []),
...(project?.bc_labels || []),
Expand Down
217 changes: 217 additions & 0 deletions src/components/metadata/templates/LocalContextsField.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/**
* @author psarando
*/
import React from "react";

import { useQuery } from "react-query";

import { useTranslation } from "i18n";

import LocalContextsLabelDisplay from "../LocalContextsLabelDisplay";

import FormTextField from "components/forms/FormTextField";
import {
LocalContextsAttrs,
parseProjectID,
} from "components/models/metadata/LocalContexts";

import {
LOCAL_CONTEXTS_QUERY_KEY,
getLocalContextsProject,
} from "serviceFacades/metadata";

import { Skeleton } from "@mui/material";

const findAVU = (avus, attr) => avus?.find((avu) => avu.attr === attr);

const LocalContextsField = ({
avu,
onUpdate,
form: { setFieldValue, ...form },
field: { value, onChange, ...field },
...props
}) => {
const { t } = useTranslation("localcontexts");

const [rightsURIAVU, setRightsURIAVU] = React.useState(
() =>
findAVU(avu.avus, LocalContextsAttrs.RIGHTS_URI) || {
attr: LocalContextsAttrs.RIGHTS_URI,
value: "",
unit: "",
}
);

const [projectHubURI, setProjectHubURI] = React.useState(
rightsURIAVU.value
);

const [rightsIDSchemeURIAVU] = React.useState(() => {
let rightsIDScheme = findAVU(
avu.avus,
LocalContextsAttrs.RIGHTS_ID_SCHEME
);

if (
rightsIDScheme?.value !== LocalContextsAttrs.RIGHTS_ID_SCHEME_VALUE
) {
rightsIDScheme = {
attr: LocalContextsAttrs.RIGHTS_ID_SCHEME,
value: LocalContextsAttrs.RIGHTS_ID_SCHEME_VALUE,
unit: "",
};
}

return rightsIDScheme;
});

const [schemeURIAVU] = React.useState(() => {
let schemeURI = findAVU(avu.avus, LocalContextsAttrs.SCHEME_URI);

if (schemeURI?.value !== LocalContextsAttrs.SCHEME_URI_VALUE) {
schemeURI = {
attr: LocalContextsAttrs.SCHEME_URI,
value: LocalContextsAttrs.SCHEME_URI_VALUE,
unit: "",
};
}

return schemeURI;
});

const projectID = parseProjectID(projectHubURI);

const { data: project, isFetching } = useQuery({
queryKey: [LOCAL_CONTEXTS_QUERY_KEY, projectID],
queryFn: () =>
getLocalContextsProject({
projectID,
}),
enabled: URL.canParse(projectHubURI),
onSuccess: (project) => {
let newValue = avu.value || "";

const notices =
project?.notice?.filter((label) => label?.name) || [];
const bc_labels =
project?.bc_labels?.filter((label) => label?.name) || [];
const tk_labels =
project?.tk_labels?.filter((label) => label?.name) || [];

const labels = [...bc_labels, ...tk_labels];

const newLabels = [...notices, ...labels];

if (newLabels.length === 1) {
newValue = newLabels[0].label_text || newLabels[0].default_text;
} else {
newValue = t("localContextsAttrDefaultValue", {
projectTitle: project?.title,
projectPage: project?.project_page,
});
}

let newAVUs = avu.avus || [];

const currentLabels = newAVUs
.filter(
(childAVU) => childAVU.attr === LocalContextsAttrs.RIGHTS_ID
)
?.map((childAVU) => childAVU.value);

const missingLabels = newLabels.filter(
(label) => !currentLabels.includes(label.name)
);

if (missingLabels.length > 0) {
newAVUs = newAVUs.filter(
(childAVU) =>
childAVU.attr !== LocalContextsAttrs.RIGHTS_URI &&
childAVU.attr !== LocalContextsAttrs.RIGHTS_ID_SCHEME &&
childAVU.attr !== LocalContextsAttrs.SCHEME_URI &&
(childAVU.attr !== LocalContextsAttrs.RIGHTS_ID ||
newLabels.find(
(label) => label.name === childAVU.value
))
);

newAVUs = [
...newAVUs,
rightsURIAVU,
schemeURIAVU,
rightsIDSchemeURIAVU,
...missingLabels.map((label) => ({
attr: LocalContextsAttrs.RIGHTS_ID,
value: label.name,
unit: "",
})),
];
}

if (avu.value !== newValue || avu.avus !== newAVUs) {
onUpdate({ ...avu, value: newValue, avus: newAVUs });
}
},
onError: (error) => {
console.log("Error fetching Local Contexts project.", {
projectHubURI,
error,
});
},
});

const updateProjectHubURI = (uri) => {
setProjectHubURI(uri);

let newAVUs = avu.avus || [];

if (rightsURIAVU.value !== uri) {
const newRightsURIAVU = {
attr: LocalContextsAttrs.RIGHTS_URI,
value: uri,
unit: "",
};
setRightsURIAVU(newRightsURIAVU);

newAVUs = newAVUs.filter(
(childAVU) =>
childAVU.attr !== LocalContextsAttrs.RIGHTS_URI &&
childAVU.attr !== LocalContextsAttrs.RIGHTS_ID_SCHEME &&
childAVU.attr !== LocalContextsAttrs.SCHEME_URI
);

newAVUs = [
...newAVUs,
newRightsURIAVU,
schemeURIAVU,
rightsIDSchemeURIAVU,
];

onUpdate({ ...avu, avus: newAVUs });
}
};

return (
<>
<FormTextField
multiline
form={form}
field={field}
value={projectHubURI}
onChange={(event) => updateProjectHubURI(event?.target?.value)}
{...props}
label={t("localContextsHubProjectURI")}
required
/>
{isFetching ? (
<Skeleton variant="rectangular">
<LocalContextsLabelDisplay project={project} />
</Skeleton>
) : (
<LocalContextsLabelDisplay project={project} />
)}
</>
);
};

export default LocalContextsField;
Loading

0 comments on commit b09ab10

Please sign in to comment.