Skip to content

Commit

Permalink
Merge branch 'master' into collection_expansions
Browse files Browse the repository at this point in the history
  • Loading branch information
snyaggarwal committed Jan 20, 2022
2 parents 82a7aba + 967ad44 commit 4c69ec5
Show file tree
Hide file tree
Showing 10 changed files with 448 additions and 326 deletions.
362 changes: 181 additions & 181 deletions package-lock.json

Large diffs are not rendered by default.

14 changes: 7 additions & 7 deletions package.json
Expand Up @@ -8,13 +8,13 @@
"@airbrake/browser": "^2.1.7",
"@emotion/react": "^11.7.1",
"@emotion/styled": "^11.3.0",
"@mui/icons-material": "^5.2.5",
"@mui/lab": "^5.0.0-alpha.64",
"@mui/material": "^5.2.8",
"@mui/styles": "^5.2.3",
"@mui/icons-material": "^5.3.0",
"@mui/lab": "^5.0.0-alpha.65",
"@mui/material": "^5.3.0",
"@mui/styles": "^5.3.0",
"alertifyjs": "^1.13.1",
"axios": "^0.21.4",
"core-js": "^3.20.2",
"core-js": "^3.20.3",
"d3": "^7.3.0",
"d3-v6-tip": "^1.0.9",
"lodash": "^4.17.21",
Expand Down Expand Up @@ -45,11 +45,11 @@
"eslint": "./node_modules/.bin/eslint ./src"
},
"devDependencies": {
"@babel/core": "^7.16.7",
"@babel/core": "^7.16.10",
"@babel/plugin-proposal-class-properties": "^7.16.7",
"@babel/plugin-proposal-object-rest-spread": "^7.16.7",
"@babel/polyfill": "^7.12.1",
"@babel/preset-env": "^7.16.8",
"@babel/preset-env": "^7.16.10",
"@babel/preset-react": "^7.16.7",
"@babel/runtime": "7.0.0-beta.42",
"babel-eslint": "^10.1.0",
Expand Down
2 changes: 1 addition & 1 deletion src/components/collections/CollectionHomeTabs.jsx
Expand Up @@ -165,9 +165,9 @@ const CollectionHomeTabs = props => {
}
</div>
<CommonFormDrawer
size='large'
isOpen={referenceForm}
onClose={() => setReferenceForm(false)}
size='large'
formComponent={
<ReferenceForm onCancel={() => setReferenceForm(false)} reloadOnSuccess={tab < 3} parentURL={versionedObjectURL} collection={collection} />
}
Expand Down
124 changes: 90 additions & 34 deletions src/components/collections/ReferenceForm.jsx
@@ -1,13 +1,15 @@
import React from 'react';
import alertifyjs from 'alertifyjs';
import { Button, Switch, FormControlLabel } from '@mui/material';
import { Button, ButtonGroup } from '@mui/material';
import { set, get, isEmpty, isNumber, isNaN, cloneDeep, pullAt, find, map, compact } from 'lodash';
import APIService from '../../services/APIService';
import { SOURCE_CHILD_URI_REGEX } from '../../common/constants';
import { isConcept } from '../../common/utils';
import URLReferenceForm from './URLReferenceForm';
import ResourceReferenceForm from './ResourceReferenceForm';
import AddReferencesResult from './AddReferencesResult';
import AddReferencesResult from '../common/AddReferencesResult';
import ReferenceCascadeDialog from '../common/ReferenceCascadeDialog';
import Search from '../search/Search';

const EXPRESSION_MODEL = {uri: '', valid: false, count: undefined, error: ''}

Expand All @@ -16,8 +18,13 @@ class ReferenceForm extends React.Component {
super(props);
this.expressionRegex = new RegExp(SOURCE_CHILD_URI_REGEX);
this.state = {
isSubmitting: false,
cascadeDialog: false,
result: null,
byURL: false,
byResource: false,
cascadeMappings: true,
cascadeToConcepts: false,
fields: {
concepts: [],
mappings: [],
Expand Down Expand Up @@ -97,12 +104,28 @@ class ReferenceForm extends React.Component {
return
}

if(!this.anyInvalidExpression()) {
const { parentURL } = this.props
APIService.new().overrideURL(parentURL).appendToUrl('references/').put({data: {expressions: expressions}}).then(response => this.handleSubmitResponse(response))
if(!this.anyInvalidExpression()){
this.setState({cascadeDialog: true})
}
}

submitReferences = () => {
this.setState({isSubmitting: true}, () => {
const { cascadeMappings, cascadeToConcepts, fields } = this.state
const { parentURL } = this.props
let queryParams = {}
if(cascadeToConcepts)
queryParams = {cascade: 'sourceToConcepts'}
else if(cascadeMappings)
queryParams = {cascade: 'sourceMappings'}
APIService.new().overrideURL(parentURL).appendToUrl('references/').put(
{data: {expressions: compact(map(fields.expressions, 'uri'))}}, null, null, queryParams
).then(response => this.setState(
{cascadeDialog: false, isSubmitting: false}, () => this.handleSubmitResponse(response))
)
})
}

handleSubmitResponse(response) {
if(response.status === 200) { // success
this.setState({result: response.data})
Expand Down Expand Up @@ -132,50 +155,83 @@ class ReferenceForm extends React.Component {
}

render() {
const { byURL, fields, result } = this.state;
const { byURL, byResource, fields, result, cascadeDialog, isSubmitting } = this.state;
const { onCancel, collection } = this.props;
const byGlobal = !byResource && !byURL;
const header = `Add Reference(s)`;
return (
<div className='col-md-12' style={{marginBottom: '30px'}}>
<div className='col-md-12 no-side-padding'>
<h2>{header}</h2>
<h2 style={{margin: '10px 0'}}>{header}</h2>
</div>
<div className='col-md-12 no-side-padding'>
<div className='col-md-3'>
<FormControlLabel
control={<Switch checked={byURL} onChange={this.onSwitchChange} color='primary' name="byURL" />}
label="Add by URL"
style={{marginBottom: '20px'}}
/>
<div className='col-md-6 no-left-padding'>
<ButtonGroup>
<Button variant={byGlobal ? 'contained' : 'outlined'} onClick={() => this.setState({byURL: false, byResource: false})}>
By Global Search
</Button>
<Button variant={byURL ? 'contained' : 'outlined'} onClick={() => this.setState({byURL: true, byResource: false})}>
By URL
</Button>
<Button variant={byResource ? 'contained' : 'outlined'} onClick={() => this.setState({byURL: false, byResource: true})}>
By Resource Search
</Button>
</ButtonGroup>
</div>
<div className='col-md-9' style={{textAlign: 'right'}}>
<div className='col-md-6 no-right-padding' style={{textAlign: 'right'}}>
<Button style={{margin: '0 10px'}} color='primary' variant='outlined' type='submit' onClick={this.onSubmit}>
Add
</Button>
<Button style={{margin: '0 10px'}} variant='outlined' onClick={onCancel}>
<Button style={{margin: '0 10px'}} variant='outlined' color='secondary' onClick={onCancel}>
Cancel
</Button>
</div>
<form>
{
byURL ?
<URLReferenceForm
expressions={fields.expressions}
onAdd={this.onExpressionAdd}
onChange={this.onExpressionURIChange}
onBlur={this.onExpressionBlur}
onDelete={this.onExpressionDelete}
/> :
<ResourceReferenceForm onChange={this.onExpressionChange} />
}
</form>
<div className='col-md-12 no-side-padding'>
<form style={{margin: '15px 0'}}>
{
byGlobal &&
<Search {...this.props} resource='concepts' nested asReference onSelectChange={this.onExpressionChange} />
}
{
byURL &&
<URLReferenceForm
expressions={fields.expressions}
onAdd={this.onExpressionAdd}
onChange={this.onExpressionURIChange}
onBlur={this.onExpressionBlur}
onDelete={this.onExpressionDelete}
/>
}
{
byResource &&
<ResourceReferenceForm onChange={this.onExpressionChange} />
}
</form>
</div>
</div>
<AddReferencesResult
title={`Add to Collection: ${collection.id}`}
open={Boolean(result)}
onClose={this.onResultClose}
result={result}
/>
{
Boolean(result) &&
<AddReferencesResult
title={`Add to Collection: ${collection.id}`}
open={Boolean(result)}
onClose={this.onResultClose}
result={result}
/>
}
{
cascadeDialog &&
<ReferenceCascadeDialog
open={cascadeDialog}
references={fields.expressions}
onCascadeChange={states => this.setState({
cascadeToConcepts: states.cascadeToConcepts, cascadeMappings: states.cascadeMappings
})}
collectionName={`${collection.owner}/${collection.short_code}`}
onClose={() => this.setState({cascadeDialog: false})}
onAdd={this.submitReferences}
isAdding={isSubmitting}
/>
}
</div>
)
}
Expand Down
109 changes: 27 additions & 82 deletions src/components/common/AddToCollection.jsx
Expand Up @@ -2,21 +2,21 @@ import React from 'react';
import alertifyjs from 'alertifyjs';
import {
Button, Popper, MenuItem, MenuList, Grow, Paper, ClickAwayListener, Tooltip,
CircularProgress, Dialog, DialogActions, DialogContent, DialogContentText, DialogTitle,
FormControlLabel, Checkbox, Divider, TextField, InputAdornment
CircularProgress, Dialog, DialogActions, DialogContent, DialogTitle,
TextField, InputAdornment
} from '@mui/material'
import MuiAlert from '@mui/material/Alert';
import {
ArrowDropDown as ArrowDropDownIcon,
Loyalty as LoyaltyIcon,
Help as HelpIcon,
Search as SearchIcon,
} from '@mui/icons-material'
import { map, isEmpty, get, filter, cloneDeep } from 'lodash';
import APIService from '../../services/APIService';
import { getCurrentUserCollections, getCurrentUser } from '../../common/utils';
import CommonFormDrawer from '../common/CommonFormDrawer';
import CollectionForm from '../collections/CollectionForm';
import AddReferencesResult from './AddReferencesResult';
import ReferenceCascadeDialog from './ReferenceCascadeDialog';

const NEW_COLLECTION = {id: '__new__', name: 'Create New Collection'}

Expand All @@ -33,8 +33,7 @@ class AddToCollection extends React.Component {
collections: [],
cascadeMappings: true,
cascadeToConcepts: false,
notAdded: [],
added: [],
result: false,
collectionForm: false,
}
this.anchorRef = React.createRef(null);
Expand Down Expand Up @@ -66,7 +65,7 @@ class AddToCollection extends React.Component {

toggleOpen = () => this.setState({open: !this.state.open})

handleDialogClose = () => this.setState({selectedCollection: null, notAdded: []})
handleDialogClose = () => this.setState({selectedCollection: null})

onCheckboxChange = event => this.setState({[event.target.name]: event.target.checked})

Expand Down Expand Up @@ -94,13 +93,9 @@ class AddToCollection extends React.Component {
.then(response => {
this.setState({isAdding: false}, () => {
if(response.status === 200) {
const notAddedReferences = filter(response.data, {added: false})
const addedReferences = filter(response.data, {added: true})
this.setState({notAdded: notAddedReferences, added: addedReferences})
if(isEmpty(notAddedReferences)) {
alertifyjs.success('Successfully added reference(s)')
this.handleDialogClose()
}
this.setState({result: response.data})
alertifyjs.success('Successfully added reference(s)')
this.handleDialogClose()
} else {
alertifyjs.error('Something bad happened')
this.handleDialogClose()
Expand Down Expand Up @@ -148,12 +143,11 @@ class AddToCollection extends React.Component {

render() {
const {
open, allCollections, collections, selectedCollection, cascadeMappings, cascadeToConcepts, notAdded, added, isAdding, isLoading, searchedValue, collectionForm
open, allCollections, collections, selectedCollection, isAdding, isLoading, searchedValue, collectionForm, result
} = this.state;
const { references } = this.props
const openDialog = Boolean(selectedCollection)
const collectionName = openDialog ? `${selectedCollection.owner}/${selectedCollection.short_code}`: '';
const unableToAdd = !isEmpty(notAdded)
const _collections = [...collections, cloneDeep(NEW_COLLECTION)]
const noOverallCollections = !isLoading && allCollections.length === 0;
const noSearchResults = !isLoading && searchedValue && collections.length === 0;
Expand Down Expand Up @@ -241,77 +235,28 @@ class AddToCollection extends React.Component {
{
isAdding ?
<DialogContent style={{textAlign: 'center', margin: '50px'}}><CircularProgress /></DialogContent> :
(
unableToAdd ?
<DialogContent>
{
!isEmpty(added) &&
<MuiAlert variant="filled" severity="success" style={{margin: '5px 0'}}>
{`${added.length} Reference(s) successfully added.`}
</MuiAlert>
}
<MuiAlert variant="filled" severity="warning" style={{margin: '5px 0'}}>
{`${notAdded.length} Reference(s) listed below could not be added.`}
</MuiAlert>
{
map(notAdded, (reference, index) => (
<React.Fragment key={index}>
<div style={{padding: '10px', background: 'rgba(0, 0, 0, 0.05)'}}>
<span style={{marginRight: '5px'}}><b>{reference.expression}:</b></span>
<span>{get(reference, 'message.0', '')}</span>
</div>
<Divider />
</React.Fragment>

))
}
</DialogContent> :
<DialogContent>
<DialogContentText style={{color: 'black', marginBottom: '20px'}}>
{`${references.length} selected reference(s) will be added to collection ${collectionName}`}
</DialogContentText>
<FormControlLabel
control={<Checkbox checked={cascadeMappings} onChange={this.onCheckboxChange} name="cascadeMappings" size='small' style={{paddingRight: '4px'}}/>}
label={
<span className='flex-vertical-center'>
<span style={{marginRight: '5px', fontSize: '14px'}}>Automatically add associated mappings</span>
<Tooltip arrow title="A concept's associated mappings are mappings that originate from the specified concept (the 'from concept') and that are stored in the same source">
<HelpIcon fontSize='small' style={{fontSize: '14px'}}/>
</Tooltip>
</span>
}
/>
<FormControlLabel
control={<Checkbox checked={cascadeToConcepts} onChange={this.onCheckboxChange} name="cascadeToConcepts" size='small' style={{paddingRight: '4px'}}/>}
label={
<span className='flex-vertical-center'>
<span style={{marginRight: '5px', fontSize: '14px'}}>Automatically add associated mappings to concepts</span>
<Tooltip arrow title="A concept's associated mappings are mappings that originate from the specified concept (the 'from concept') and that are stored in the same source">
<HelpIcon fontSize='small' style={{fontSize: '14px'}}/>
</Tooltip>
</span>
}
/>
</DialogContent>
)
<ReferenceCascadeDialog references={references} onCascadeChange={states => this.setState({cascadeToConcepts: states.cascadeToConcepts, cascadeMappings: states.cascadeMappings})} collectionName={collectionName} />
}
<DialogActions>
{
unableToAdd ?
<React.Fragment>
<Button onClick={this.handleDialogClose} color="primary" disabled={isAdding}>
Close
</Button> :
<React.Fragment>
<Button onClick={this.handleDialogClose} color="primary" disabled={isAdding}>
Cancel
</Button>
<Button onClick={this.handleAdd} color="primary" disabled={isAdding}>
Add
</Button>
</React.Fragment>
}
Cancel
</Button>
<Button onClick={this.handleAdd} color="primary" disabled={isAdding}>
Add
</Button>
</React.Fragment>
</DialogActions>
</Dialog>
{
result &&
<AddReferencesResult
title={`Add Reference(s) Result`}
open={Boolean(result)}
onClose={() => this.setState({result: false})}
result={result}
/>
}
<CommonFormDrawer
isOpen={collectionForm}
onClose={this.toggleCollectionForm}
Expand Down

0 comments on commit 4c69ec5

Please sign in to comment.