Skip to content

Commit

Permalink
Add Workspace Registration to Data-Portal (#1067)
Browse files Browse the repository at this point in the history
Co-authored-by: tianj7 <jtian1@uchicago.edu>
Co-authored-by: Mingfei Shao <2475897+mfshao@users.noreply.github.com>
  • Loading branch information
3 people authored and cmlsn committed Nov 29, 2022
1 parent aee4e10 commit 3c1ed43
Show file tree
Hide file tree
Showing 14 changed files with 521 additions and 77 deletions.
34 changes: 25 additions & 9 deletions docs/portal_config.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,7 @@ Below is an example, with inline comments describing what each JSON block config
"explorerHideEmptyFilterSection": false, // optional, when filtering data hide FilterSection when they are empty.
"explorerFilterValuesToHide": ["array of strings"], // optional, Values set in array will be hidden in guppy filters. Intended use is to hide missing data category from filters, for this it should be set to the same as `missing_data_alias` in Guppy server config
"studyRegistration": true, // optional, whether to enable the study registration feature
"workspaceRegistration": true, // optional, whether to enable the workspace registration feature
},
"dataExplorerConfig": { // required only if featureFlags.explorer is true; configuration for the Data Explorer (/explorer); can be replaced by explorerConfig, see Multi Tab Explorer doc
"charts": { // optional; indicates which charts to display in the Data Explorer
Expand Down Expand Up @@ -634,14 +635,6 @@ Below is an example, with inline comments describing what each JSON block config
"tagsDisplayName": "Tags" // optional, overrides the name of the mandatory tags column
"tableScrollHeight": 450 // optional, no scroll if omitted
},
"studyRegistrationConfig": { // optional, config for Study Registration and Study Registration Request Access page.
"studyRegistrationTrackingField": "registrant_username", // optional, one of the extra field that is being added to metadata when a study is registered, will be useful in the future. Defaults to "registrant_username"
"studyRegistrationValidationField": "is_registered", // optional, the other of the extra field that is being added to metadata when a study is registered, to check if a study has been registered, because after loading data from MDS/AggMDS into Discovery page, the metadata category information is lost. Defaults to "is_registered"
"studyRegistrationAccessCheckField": "registration_authz", // optional, the field that contains the value for Study Registration Request Access feature. Defaults to "registration_authz"
"studyRegistrationUIDField": "appl_id", // optional, the field which can be used to uniquely determine a metadata record for Study Registration. Defaults to "appl_id"
"studyRegistrationFormDisclaimerField": "This is a disclaimer", //optional, the disclaimer text that appears under the submit button on the study registration request access form. Defaults to undefined
"clinicalTrialFields": [] // optional, list of fields to fetch from ClinicalTrials.gov
},
"resourceBrowser": {), // see Resource Browser documentation
"workspacePageTitle": "", // title to display above workspacePageDescription
"workspacePageDescription": "", // html to display above the workspace options
Expand Down Expand Up @@ -676,6 +669,29 @@ Below is an example, with inline comments describing what each JSON block config
"connectSrcCSPWhitelist": [ // optional; Array of urls to add to the header CSP (Content-Security-Policy) connect-src 'self'
"https://example.s3.amazonaws.com" // full url to be added
],
"stridesPortalURL": "https://strides-admin-portal.org" // optional; If configured, will display a link on the workspace page which can direct user to the STRIDES admin portal
"stridesPortalURL": "https://strides-admin-portal.org" // optional; If configured, will display a link on the workspace page which can direct user to the STRIDES admin portal,
"registrationConfigs": { // optional; Required when using Kayako integration with Study/Workspace registration
"features":{ // Optional; Required when using study/Workspace registration
"studyRegistrationConfig": { // optional, config for Study Registration and Study Registration Request Access page.
"studyRegistrationTrackingField": "registrant_username", // optional, one of the extra field that is being added to metadata when a study is registered, will be useful in the future. Defaults to "registrant_username"
"studyRegistrationValidationField": "is_registered", // optional, the other of the extra field that is being added to metadata when a study is registered, to check if a study has been registered, because after loading data from MDS/AggMDS into Discovery page, the metadata category information is lost. Defaults to "is_registered"
"studyRegistrationAccessCheckField": "registration_authz", // optional, the field that contains the value for Study Registration Request Access feature. Defaults to "registration_authz"
"studyRegistrationUIDField": "appl_id", // optional, the field which can be used to uniquely determine a metadata record for Study Registration. Defaults to "appl_id"
"studyRegistrationFormDisclaimerField": "This is a disclaimer", //optional, the disclaimer text that appears under the submit button on the study registration request access form. Defaults to undefined
},
"workspaceRegistrationConfig" : { // optional, config for Workspace Registration Request Access page.
"workspacePolicyId": "workspace", // optional, name of the policy that is needed to provide workspace access; if missing, defaults to 'workspace'
"workspaceInfoMessage": "Please fill out this form to request and be approved for access to workspace.", //optional, any info message to give users more context before they fill the request access form
"successRedirect" : { // optional, upon succesful submission of the registration form, the user is presented with a button to go to a specific page. defaults to `{ link: '/', text: 'Go to Home Page' }`
"link": "/discovery",
"text": "Go to Discovery Page"
}
}
},
"kayakoConfig":{ //Required; if using either of the study/workspace registration feature
"kayakoDepartmentId": 21 // Required; the department ID in the kayako portal. Refer to Ops team to get more info
}
}
}
```
6 changes: 3 additions & 3 deletions src/StudyRegistration/StudyRegistrationRequestForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ import { Link, useLocation } from 'react-router-dom';
import './StudyRegistration.css';
import { userHasMethodForServiceOnResource } from '../authMappingUtils';
import {
hostname, requestorPath, useArboristUI, studyRegistrationConfig,
hostname, requestorPath, useArboristUI, studyRegistrationConfig, kayakoConfig,
} from '../localconf';
import { FormSubmissionState, StudyRegistrationProps } from './StudyRegistration';
import { createKayakoTicket } from './utils';
import { createKayakoTicket } from '../utils';
import { fetchWithCreds } from '../actions';

const { TextArea } = Input;
Expand Down Expand Up @@ -114,7 +114,7 @@ const StudyRegistrationRequestForm: React.FunctionComponent<StudyRegistrationPro
const [key, value] = entry;
contents = contents.concat(`\n${key}: ${value}`);
});
createKayakoTicket(subject, fullName, email, contents, 21).then(() => setFormSubmissionStatus({ status: 'success' }),
createKayakoTicket(subject, fullName, email, contents, kayakoConfig?.kayakoDepartmentId).then(() => setFormSubmissionStatus({ status: 'success' }),
(err) => setFormSubmissionStatus({ status: 'error', text: err.message }));
} else {
// eslint-disable-next-line no-console
Expand Down
23 changes: 1 addition & 22 deletions src/StudyRegistration/utils.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
studyRegistrationConfig, mdsURL, cedarWrapperURL, kayakoWrapperURL,
studyRegistrationConfig, mdsURL, cedarWrapperURL,
} from '../localconf';
import { fetchWithCreds } from '../actions';

Expand Down Expand Up @@ -69,24 +69,3 @@ export const registerStudyInMDS = async (metadataID, metadataToRegister = {}) =>
throw new Error(`Request for update study data failed: ${err}`);
}
};

export const createKayakoTicket = async (subject, fullName, email, contents, departmentID) => {
try {
const kayakoTicketCreationURL = `${kayakoWrapperURL}/ticket`;
await fetchWithCreds({
path: kayakoTicketCreationURL,
method: 'POST',
customHeaders: { 'Content-Type': 'application/json' },
body: JSON.stringify({
subject, fullname: fullName, email, contents, departmentid: departmentID,
}),
}).then((response) => {
if (response.status !== 201) {
throw new Error(`Request for create Kayako ticket failed with status ${response.status}`);
}
return response;
});
} catch (err) {
throw new Error(`Request for create Kayako ticket failed: ${err}`);
}
};
26 changes: 12 additions & 14 deletions src/Workspace/ErrorWorkspacePlaceholder.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,17 @@ import './Workspace.less';
import NotFoundSVG from '../img/not-found.svg';
import { components } from '../params';

class ErrorWorkspacePlaceholder extends React.Component {
render() {
const supportEmail = components.login?.email || 'support@datacommons.io';
return (
<div className='error-workspace-placeholder__error-msg'>
<h1>Error opening workspace...</h1>
<p>
Workspace access requires authorization. Please contact <a href={`mailto:${supportEmail}`}>{supportEmail}</a> for more information.
</p>
<NotFoundSVG />
</div>
);
}
}
const ErrorWorkspacePlaceholder = () => {
const supportEmail = components.login?.email || 'support@datacommons.io';
return (
<div className='error-workspace-placeholder__error-msg'>
<h1>Error opening workspace...</h1>
<p>
Workspace access requires authorization. Please contact <a href={`mailto:${supportEmail}`}>{supportEmail}</a> for more information.
</p>
<NotFoundSVG />
</div>
);
};

export default ErrorWorkspacePlaceholder;
10 changes: 4 additions & 6 deletions src/Workspace/Workspace.less
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,12 @@ div.workspace--fullpage {
}

.error-workspace-placeholder__error-msg {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: var(--g3-color__bg-cloud);
z-index: 1;
text-align: center;
width: 100%;
height: 100%;
padding-top: 40px;
min-height: calc(100vh - 242px);
}

.workspace__spinner-container {
Expand Down
31 changes: 13 additions & 18 deletions src/Workspace/index.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import React from 'react';
import { Redirect } from 'react-router-dom';
import parse from 'html-react-parser';
import Button from '@gen3/ui-component/dist/components/Button';
import {
Expand All @@ -11,6 +12,7 @@ import {
DownOutlined, UserOutlined, QuestionCircleOutlined, LoadingOutlined, ExclamationCircleOutlined,
} from '@ant-design/icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import isEnabled from '../helpers/featureFlags';
import {
workspaceUrl,
wtsPath,
Expand All @@ -25,6 +27,7 @@ import {
workspacePageDescription,
stridesPortalURL,
showExternalLoginsOnProfile,
workspaceErrorUrl,
} from '../localconf';
import './Workspace.less';
import { fetchWithCreds } from '../actions';
Expand Down Expand Up @@ -54,7 +57,7 @@ class Workspace extends React.Component {
interval: null,
payModelInterval: null,
workspaceID: null,
defaultWorkspace: false,
hasWorkspaceAccess: true,
workspaceIsFullpage: false,
externalLoginOptions: [],
payModel: {},
Expand Down Expand Up @@ -124,7 +127,7 @@ class Workspace extends React.Component {
});
this.setState({ options: sortedResults });
},
).catch(() => this.setState({ defaultWorkspace: true }));
).catch(() => this.setState({ hasWorkspaceAccess: false }));
}

getExternalLoginOptions = () => {
Expand Down Expand Up @@ -348,7 +351,7 @@ class Workspace extends React.Component {
payModel: data,
});
});
if (!this.state.defaultWorkspace) {
if (this.state.hasWorkspaceAccess) {
this.getWorkspaceStatus().then((data) => {
if (data.status === 'Launching' || data.status === 'Terminating' || data.status === 'Stopped') {
this.checkWorkspaceStatus();
Expand Down Expand Up @@ -502,7 +505,7 @@ class Workspace extends React.Component {
</Menu>
);

if (this.state.connectedStatus && this.state.workspaceStatus && !this.state.defaultWorkspace) {
if (this.state.connectedStatus && this.state.workspaceStatus && this.state.hasWorkspaceAccess) {
// NOTE both the containing element and the iframe have class '.workspace',
// although no styles should be shared between them. The reason for this
// is for backwards compatibility with Jenkins integration tests that select by classname.
Expand Down Expand Up @@ -733,20 +736,12 @@ class Workspace extends React.Component {
}
</div>
);
} if (this.state.defaultWorkspace && this.state.connectedStatus) {
// If this commons does not use Hatchery to spawn workspaces, then this
// default workspace is shown.
return (
<div className='workspace__default'>
<iframe
title='Workspace'
frameBorder='0'
className='workspace__iframe'
src={workspaceUrl}
onLoad={this.oniframeLoad}
/>
</div>
);
} if (this.state.connectedStatus && !this.state.hasWorkspaceAccess) {
if (isEnabled('workspaceRegistration')) {
console.log('This is navigated to workspace register page');
return <Redirect to='/workspace/register' />;
}
return <Redirect to={workspaceErrorUrl} />;
}
return <Spinner />;
}
Expand Down
51 changes: 51 additions & 0 deletions src/WorkspaceRegistration/WorkspaceRegistration.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
.workspace-reg-container {
padding: 30px 32px;
}

.workspace-reg-form-container {
border-radius: 8px;
background-color: #fff;
padding: 10px 16px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
font-family: inherit;
}

.workspace-reg-form {
width: 100%;
}

.workspace-reg-exp-text {
width: 100%;
display: flex;
justify-content: flex-end;
}

@media screen and (min-width: 1280px) {
.workspace-reg-form {
width: 60%;
min-width: 50%;
}
}

.workspace-reg-form-item {
display: flex;
align-items: baseline;
}

.workspace-reg-form-item__middle-icon {
padding-left: 8px;
}

.workspace-reg-form-item__last-item {
padding-left: 8px;
flex-grow: 1;
flex-shrink: 0;
}

.workspace-reg-disclaimer-text {
font-size: 0.8em;
text-align: center
}
Loading

0 comments on commit 3c1ed43

Please sign in to comment.