Skip to content

Commit 36ccff1

Browse files
rlamacraftrs-nicof
andauthored
RSDEV-272 UI changes for Digital Commons Data integration (#94)
This change makes the standard UI changes for supporting a new repository integration to which exports can be sent. This includes - a control for the sysadmin to allow the integration - a new card on the apps page for users to enable and connect to the appropriate server - a new section of the export dialog for providing the required metadata of a name and description --------- Co-authored-by: Nico Ferrante <nicola.ferrante@researchspace.com>
1 parent e88c1de commit 36ccff1

File tree

12 files changed

+397
-1
lines changed

12 files changed

+397
-1
lines changed

src/main/resources/bundles/system/system.properties

+2-1
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,8 @@ system.property.description.dmptool.available=Makes DMPTool integration availabl
345345
system.property.description.dmponline.available=Makes DMPonline integration available.
346346
system.property.description.digitalCommonsData.available=Makes DigitalCommonsData integration available.
347347
system.property.description.argos.available=Makes Argos integration available.
348-
system.property.description.zenodo.available=Makes Zenodo intergration available.
348+
system.property.description.zenodo.available=Makes Zenodo integration available.
349+
system.property.description.digital_commons_data.available=Makes Digital Commons Data integration available.
349350
system.property.description.github.available=Makes Github integration available. After enabling, user can add links \
350351
to files in Github repositories.
351352
system.property.description.api.available=Enables API access for users
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<%@ include file="/common/taglibs.jsp"%>
2+
<head>
3+
<title>You are connected to Digital Commons Data</title>
4+
<script src="<c:url value='/scripts/bower_components/bootstrap/dist/js/bootstrap.js'/>"></script>
5+
</head>
6+
7+
<div id="dcdAuthorizationSuccess" class="bootstrap-custom-flat">
8+
Success - RSpace was authorized to access Digital Commons Data
9+
<p class="font-weight-bold">You can close this window now or configure <a href="/apps"> more Apps</a>.</p>
10+
<p> If you want to revoke RSpace's access to your Digital Commons Data account, please click 'Disconnect':</p>
11+
<form action="<c:url value="/apps/dcd/connect" />" method="POST" style="width: 80%">
12+
<input type="hidden" name="_method" value="delete" />
13+
<button class="btn btn-primary" type="submit">Disconnect</button>
14+
</form>
15+
</div>
16+
17+
<%-- This script is an addition to make the new apps page backwards compatible. --%>
18+
<script>
19+
window.addEventListener("load", () => {
20+
if(window.opener.document.location.pathname === "/apps") {
21+
window.opener.dispatchEvent(new Event("DIGITALCOMMONSDATA_CONNECTED"));
22+
window.close();
23+
}
24+
});
25+
</script>
26+

src/main/webapp/WEB-INF/pages/system/settings_ajax.jsp

+1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
<div id="dmptool.available.description"><spring:message code="system.property.description.dmptool.available" /></div>
6969
<div id="argos.available.description"><spring:message code="system.property.description.argos.available" /></div>
7070
<div id="zenodo.available.description"><spring:message code="system.property.description.zenodo.available" /></div>
71+
<div id="digitalCommonsData.available.description"><spring:message code="system.property.description.digitalCommonsData.available" /></div>
7172
<div id="github.available.description"><spring:message code="system.property.description.github.available" /></div>
7273
<div id="api.available.description"><spring:message code="system.property.description.api.available" /></div>
7374
<div id="onboarding.available.description"><spring:message code="system.property.description.onboarding.available" /></div>

src/main/webapp/scripts/pages/system/settings_mod.js

+1
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ define(function() {
7373

7474
_printCategory('Repositories');
7575
_printSettings([ 'dataverse.available' ]);
76+
_printSettings([ 'digitalCommonsData.available' ]);
7677
_printSettings([ 'github.available' ]);
7778
_printSettings([ 'figshare.available' ]);
7879
_printSettings([ 'pyrat.available' ]);

src/main/webapp/ui/src/Export/ExportRepo.js

+14
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import DryadRepo from "./repositories/DryadRepo";
1414
import FigshareRepo from "./repositories/FigshareRepo";
1515
import DataverseRepo from "./repositories/DataverseRepo";
1616
import ZenodoRepo from "./repositories/ZenodoRepo";
17+
import DigitalCommonsDataRepo from "./repositories/DigitalCommonsDataRepo";
1718
import Alert from "@mui/material/Alert";
1819
import { type Validator } from "../util/Validator";
1920
import {
@@ -430,6 +431,19 @@ function ExportRepo({
430431
/>
431432
</>
432433
)}
434+
{repo.repoName === "app.digitalCommonsData" && (
435+
<DigitalCommonsDataRepo
436+
handleChange={handleChange}
437+
updatePeople={updatePeople}
438+
inputValidations={state.inputValidations}
439+
submitAttempt={state.submitAttempt}
440+
title={state.title}
441+
description={state.description}
442+
tags={state.tags}
443+
fetchingTags={fetchingTags}
444+
onTagsChange={({ target: { value } }) => {}}
445+
/>
446+
)}
433447
</Grid>
434448
</Grid>
435449
);

src/main/webapp/ui/src/Export/FormatChoice.js

+2
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ function FormatChoice({
9494
return { repoCfg: -1, ...repo };
9595
if (repo.displayName === "Dryad") return { repoCfg: -1, ...repo };
9696
if (repo.displayName === "Zenodo") return { repoCfg: -1, ...repo };
97+
if (repo.displayName === "Digital Commons Data")
98+
return { repoCfg: -1, ...repo };
9799

98100
const keys = Object.keys(repo.options);
99101
if (keys.length) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// @flow
2+
3+
import {
4+
default as React,
5+
type Node,
6+
type ComponentType,
7+
useEffect,
8+
} from "react";
9+
import Grid from "@mui/material/Grid";
10+
import TextField from "@mui/material/TextField";
11+
import { type Person, type StandardValidations } from "./common";
12+
import Tags, { type Tag } from "./Tags";
13+
14+
/*
15+
* This component collects the metadata required by Digital Commons Data to make a deposit.
16+
*/
17+
18+
type DigitalCommonsDataRepoArgs = {|
19+
// To modify the metadata relating to persons call updatePeople, for all
20+
// other metadata call handleChange. The form fields are uncontrolled so no
21+
// current value is passed in from the caller; modified values are simply
22+
// propagated up and the fields initialise to empty.
23+
updatePeople: (people: Array<Person>) => void,
24+
handleChange: (event: {
25+
target: { name: "subject" | "title" | "description", value: string },
26+
}) => void,
27+
28+
// Callers of this component should validate the modified values and use
29+
// this prop to signal as to whether the corresponding field should be in an
30+
// error state or not.
31+
inputValidations: StandardValidations,
32+
33+
// Error states will only be shown when this flag is true, which is to say
34+
// that the user has attempted to submit the form. This means we don't show
35+
// any error state whilst they are in the process of inputting the metadata.
36+
submitAttempt: boolean,
37+
38+
title: string,
39+
description: string,
40+
41+
tags: Array<Tag>,
42+
onTagsChange: ({
43+
target: {
44+
value: Array<Tag>,
45+
},
46+
}) => void,
47+
fetchingTags: boolean,
48+
|};
49+
50+
function DigitalCommonsDataRepo({
51+
handleChange,
52+
inputValidations,
53+
submitAttempt,
54+
updatePeople,
55+
title,
56+
description,
57+
tags,
58+
onTagsChange,
59+
fetchingTags,
60+
}: DigitalCommonsDataRepoArgs): Node {
61+
/*
62+
* DigitalCommonsData doesn't require all of the same information as all of the other
63+
* repositories, but the RSpace backend is set up to require author,
64+
* contact, and subject metadata. Rather than weaken the validations for
65+
* all repositories, for DigitalCommonsData we pass these dummy values which are then
66+
* ignored when the RSpace backend calls the DigitalCommonsData API.
67+
*/
68+
useEffect(() => {
69+
updatePeople([
70+
{
71+
uniqueName: "DUMMY_VALUE",
72+
email: "DUMMY_VALUE@example.com",
73+
type: "Author",
74+
},
75+
{
76+
uniqueName: "DUMMY_VALUE",
77+
email: "DUMMY_VALUE@example.com",
78+
type: "Contact",
79+
},
80+
]);
81+
handleChange({
82+
target: {
83+
name: "subject",
84+
value: "DUMMY_VALUE",
85+
},
86+
});
87+
}, []);
88+
89+
return (
90+
<Grid container style={{ width: "100%" }}>
91+
<Grid item xs={12}>
92+
<TextField
93+
name="title"
94+
error={submitAttempt && !inputValidations.title}
95+
label="Title *"
96+
onChange={({ target: { value } }) =>
97+
handleChange({ target: { name: "title", value } })
98+
}
99+
margin="normal"
100+
fullWidth
101+
value={title}
102+
/>
103+
</Grid>
104+
<Grid item xs={12}>
105+
<TextField
106+
error={submitAttempt && !inputValidations.description}
107+
label="Description *"
108+
name="description"
109+
multiline
110+
maxRows="4"
111+
onChange={({ target: { value } }) =>
112+
handleChange({ target: { name: "description", value } })
113+
}
114+
margin="normal"
115+
fullWidth
116+
value={description}
117+
/>
118+
</Grid>
119+
</Grid>
120+
);
121+
}
122+
123+
export default (DigitalCommonsDataRepo: ComponentType<DigitalCommonsDataRepoArgs>);

src/main/webapp/ui/src/eln/apps/CardListing.js

+20
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import Argos from "./integrations/Argos";
1111
import Box from "./integrations/Box";
1212
import Clustermarket from "./integrations/Clustermarket";
1313
import Dataverse from "./integrations/Dataverse";
14+
import DigitalCommonsData from "./integrations/DigitalCommonsData";
1415
import DMPonline from "./integrations/DMPonline";
1516
import DMPTool from "./integrations/DMPTool";
1617
import Dropbox from "./integrations/Dropbox";
@@ -102,6 +103,19 @@ function CardListing({ mode, integrationStates }: CardListingArgs): Node {
102103
[update]
103104
);
104105

106+
const digitalCommonsDataUpdate = React.useCallback(
107+
(newState: IntegrationStates["DIGITALCOMMONSDATA"]) => {
108+
void runInAction(async () => {
109+
integrationStates.DIGITALCOMMONSDATA = await update(
110+
"DIGITALCOMMONSDATA",
111+
newState
112+
);
113+
});
114+
},
115+
//eslint-disable-next-line react-hooks/exhaustive-deps
116+
[update]
117+
);
118+
105119
const dmponlineUpdate = React.useCallback(
106120
(newState: IntegrationStates["DMPONLINE"]) => {
107121
void runInAction(async () => {
@@ -338,6 +352,12 @@ function CardListing({ mode, integrationStates }: CardListingArgs): Node {
338352
update={dataverseUpdate}
339353
/>
340354
)}
355+
{integrationStates.DIGITALCOMMONSDATA.mode === mode && (
356+
<DigitalCommonsData
357+
integrationState={integrationStates.DIGITALCOMMONSDATA}
358+
update={digitalCommonsDataUpdate}
359+
/>
360+
)}
341361
{integrationStates.DMPONLINE.mode === mode && (
342362
<DMPonline
343363
integrationState={integrationStates.DMPONLINE}
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
//@flow strict
2+
3+
import Grid from "@mui/material/Grid";
4+
import React, { type Node, type AbstractComponent } from "react";
5+
import IntegrationCard from "../IntegrationCard";
6+
import { type IntegrationStates } from "../useIntegrationsEndpoint";
7+
import Button from "@mui/material/Button";
8+
import DcdIcon from "../icons/dcd.svg";
9+
import { useDigitalCommonsDataEndpoint } from "../useDigitalCommonsDataEndpoint";
10+
import AlertContext, { mkAlert } from "../../../stores/contexts/Alert";
11+
12+
type DigitalCommonsDataArgs = {|
13+
integrationState: IntegrationStates["DIGITALCOMMONSDATA"],
14+
update: (IntegrationStates["DIGITALCOMMONSDATA"]) => void,
15+
|};
16+
17+
export const COLOR = {
18+
hue: 26,
19+
saturation: 100,
20+
lightness: 50,
21+
};
22+
23+
/*
24+
* Digital Commons Data uses OAuth based authentication, as implemeted by the form below.
25+
*/
26+
function DigitalCommonsData({
27+
integrationState,
28+
update,
29+
}: DigitalCommonsDataArgs): Node {
30+
const { addAlert } = React.useContext(AlertContext);
31+
const { disconnect } = useDigitalCommonsDataEndpoint();
32+
const [connected, setConnected] = React.useState(
33+
integrationState.credentials.ACCESS_TOKEN.isPresent()
34+
);
35+
36+
React.useEffect(() => {
37+
const f = () => {
38+
setConnected(true);
39+
addAlert(
40+
mkAlert({
41+
variant: "success",
42+
message: "Successfully connected to Digital Commons Data.",
43+
})
44+
);
45+
};
46+
window.addEventListener("DIGITALCOMMONSDATA_CONNECTED", f);
47+
return () => {
48+
window.removeEventListener("DIGITALCOMMONSDATA_CONNECTED", f);
49+
};
50+
}, []);
51+
52+
return (
53+
<Grid item sm={6} xs={12} sx={{ display: "flex" }}>
54+
<IntegrationCard
55+
name="Digital Commons Data"
56+
integrationState={integrationState}
57+
explanatoryText="Export datasets to the data repository, with persistent unique identifiers to enable referencing and citation."
58+
image={DcdIcon}
59+
color={COLOR}
60+
update={(newMode) =>
61+
update({ mode: newMode, credentials: integrationState.credentials })
62+
}
63+
helpLinkText="Digital Commons Data integration docs"
64+
website="elsevier.digitalcommonsdata.com"
65+
docLink="dcd"
66+
usageText="You can export your files and data directly from RSpace to Digital Commons Data."
67+
setupSection={
68+
<>
69+
<ol>
70+
<li>
71+
Click on Connect to authorise RSpace to access your Digital
72+
Commons Data account.
73+
</li>
74+
<li>Enable the integration.</li>
75+
<li>
76+
Digital Commons Data will now be available as an option in the
77+
export dialog.
78+
</li>
79+
</ol>
80+
{connected ? (
81+
<form
82+
onSubmit={(e) => {
83+
e.preventDefault();
84+
void (async () => {
85+
await disconnect();
86+
setConnected(false);
87+
})();
88+
}}
89+
>
90+
<Button type="submit" sx={{ mt: 1 }}>
91+
Disconnect
92+
</Button>
93+
</form>
94+
) : (
95+
<form
96+
action="/apps/digitalcommonsdata/connect"
97+
method="POST"
98+
target="_blank"
99+
rel="opener"
100+
>
101+
<Button type="submit" sx={{ mt: 1 }} value="Connect">
102+
Connect
103+
</Button>
104+
</form>
105+
)}
106+
</>
107+
}
108+
/>
109+
</Grid>
110+
);
111+
}
112+
113+
export default (React.memo(
114+
DigitalCommonsData
115+
): AbstractComponent<DigitalCommonsDataArgs>);

0 commit comments

Comments
 (0)