From 9a2268bddf700a68ed3d68e7288399390f22e117 Mon Sep 17 00:00:00 2001 From: Sarah Berenji Date: Thu, 23 Nov 2017 11:30:39 +0100 Subject: [PATCH 1/2] Adding UI for publication workflow (the user part) --- webui/src/components/editfiles.jsx | 58 ++++---- webui/src/components/editrecord.jsx | 215 +++++++++++++++++++++------- webui/src/components/search.jsx | 4 +- webui/src/components/selectbig.jsx | 6 +- webui/src/components/user.jsx | 4 + webui/src/data/server.js | 11 +- 6 files changed, 211 insertions(+), 87 deletions(-) diff --git a/webui/src/components/editfiles.jsx b/webui/src/components/editfiles.jsx index d0d30c1819..a326e1a60e 100644 --- a/webui/src/components/editfiles.jsx +++ b/webui/src/components/editfiles.jsx @@ -547,39 +547,43 @@ export const EditFiles = React.createClass({ this.updateNext(); const b2dropZone = this.props.setModal(false)} onFiles={fs => this.handleAdd(fs, 'b2drop')} />; + // FIXME: the following doesn't work, need to fix it and change the cursor to disabled icon + const disabledCursor = this.props.readOnly ? " , cursor: 'not-allowed'" : ""; return (
-
-

- Add files -

-
- this.handleAdd(fs, 'local')}/> -
-
- -
- - { !this.state.files.length ? false : -
- { this.renderUploadQueue() } -
- } -
- - { !this.props.files.length ? false : +
-
-

Uploaded files

+

+ Add files +

+
+ this.handleAdd(fs, 'local')}/>
-
- { this.renderRecordFiles() } +
+
+ + { !this.state.files.length ? false : +
+ { this.renderUploadQueue() } +
+ }
- } + + { !this.props.files.length ? false : +
+
+

Uploaded files

+
+
+ { this.renderRecordFiles() } +
+
+ } +
); }, diff --git a/webui/src/components/editrecord.jsx b/webui/src/components/editrecord.jsx index 1c12cb6487..cafff8ef18 100644 --- a/webui/src/components/editrecord.jsx +++ b/webui/src/components/editrecord.jsx @@ -99,6 +99,9 @@ const EditRecord = React.createClass({ errors: {}, dirty: false, waitingForServer: false, + readOnly: false, + reviewOrPublishConfirmed: null, + revokeSubmitted:false, }; }, @@ -122,7 +125,8 @@ const EditRecord = React.createClass({ this.setState({modal})} /> + setModal={modal => this.setState({modal})} + readOnly={this.state.readOnly} /> ); }, @@ -197,17 +201,17 @@ const EditRecord = React.createClass({ ); } else if (type === 'integer') { - return + return } else if (type === 'number') { - return + return } else if (type === 'string') { const value_str = ""+(value || ""); if (schema.get('enum')) { - return + return } else if (schema.get('format') === 'date-time') { const initial = (value_str && value_str !== "") ? moment(value_str).toDate() : null; return setter(moment(date).toISOString())} /> + onChange={date => setter(moment(date).toISOString())} disabled={this.state.readOnly} /> } else if (schema.get('format') === 'email') { return setter(event.target.value)} /> @@ -268,7 +272,7 @@ const EditRecord = React.createClass({ }; return ( + defaultValue={initial} onChange={onChange} disabled={this.state.readOnly} /> ); }, @@ -293,12 +297,12 @@ const EditRecord = React.createClass({ const languages = serverCache.getLanguages(); field = (languages instanceof Error) ? : this.setValue(schema, path, x)} value={this.getValue(path)} />; + onSelect={x=>this.setValue(schema, path, x)} value={this.getValue(path)} readOnly={this.state.readOnly} />; } else if (path.length === 2 && path[0] === 'disciplines') { const disciplines = serverCache.getDisciplines(); field = (disciplines instanceof Error) ? : this.setValue(schema, path, x)} value={this.getValue(path)} />; + onSelect={x=>this.setValue(schema, path, x)} value={this.getValue(path)} readOnly={this.state.readOnly} />; } else if (schema.get('type') === 'array') { const itemSchema = schema.get('items'); const raw_values = this.getValue(path); @@ -465,6 +469,7 @@ const EditRecord = React.createClass({ } record = addEmptyMetadataBlocks(record, props.blockSchemas) || record; this.setState({record}); + this.setState({reviewOrPublishConfirmed:record.get('publication_state')}); } else if (this.state.record && props.blockSchemas) { const record = addEmptyMetadataBlocks(this.state.record, props.blockSchemas); if (record) { @@ -472,6 +477,13 @@ const EditRecord = React.createClass({ } } + // Record is submitted for review: the publication_state is 'submitted' and readonly should be True + if(this.props.community && this.state.record){ + if(this.props.community.get("publication_workflow") == 'review_and_publish' && this.state.record.get('publication_state')=='submitted' && !this.state.revokeSubmitted){ + this.setState({readOnly: true}); + } + } + function addEmptyMetadataBlocks(record, blockSchemas) { if (!blockSchemas || !blockSchemas.length) { return false; @@ -550,6 +562,26 @@ const EditRecord = React.createClass({ return errors; }, + componentDidUpdate(prevProps, prevState) { + const original = this.props.record.get('metadata').toJS(); + let updated = this.state.record.toJS(); + // checkbox is enabled and record is going to be "submitted" for review by community admin + if (prevState.record.get('publication_state') !== this.state.record.get('publication_state') && !this.state.revokeSubmitted){ + const patch = compare(original, updated); + if (!patch || !patch.length) { + this.setState({dirty:false}); + return; + } + this.updateBrowserState(patch, 'submitted'); + } + // Revoking the submitted record for review. Going back to the draft mode. + if(prevState.revokeSubmitted !== this.state.revokeSubmitted && this.state.revokeSubmitted){ + updated['publication_state'] = 'draft'; + const patch = compare(original, updated); + this.updateBrowserState(patch, 'edit'); + } + }, + updateRecord(event) { event.preventDefault(); const errors = this.findValidationErrors(); @@ -557,25 +589,84 @@ const EditRecord = React.createClass({ this.setState({errors}); return; } - const original = this.props.record.get('metadata').toJS(); - const updated = this.state.record.toJS(); - const patch = compare(original, updated); - if (!patch || !patch.length) { - this.setState({dirty:false}); - return; - } - const afterPatch = (record) => { - if (this.props.isDraft && !this.isForPublication()) { - this.props.refreshCache(); - // TODO(edima): when a draft is publised, clean the state of - // records in versioned chain, to trigger a refetch of - // versioning data - this.setState({dirty:false, waitingForServer: false}); - notifications.clearAll(); - } else { - browser.gotoRecord(record.id); + + if(this.state.reviewOrPublishConfirmed == 'draft'){ + // Save draft + const original = this.props.record.get('metadata').toJS(); + const updated = this.state.record.toJS(); + const patch = compare(original, updated); + if (!patch || !patch.length) { + this.setState({dirty:false}); + return; } + this.updateBrowserState(patch, 'save_draft'); + } else if(this.state.reviewOrPublishConfirmed == 'published' && this.state.record.get('publication_state') == 'published'){ + // Editing metadata of a published record (workflow = direct_publish) + const original = this.props.record.get('metadata').toJS(); + const updated = this.state.record.toJS(); + const patch = compare(original, updated); + if (!patch || !patch.length) { + this.setState({dirty:false}); + return; + } + this.updateBrowserState(patch, 'edit_metadata'); + } else { + // (review workflow) submit a record for review or (direct publish workflow) Publishing a record + const record = this.state.record.set('publication_state', this.state.reviewOrPublishConfirmed); + this.setState({record}); + } + }, + + updateBrowserState(patch, caseValue) { + let afterPatch; + switch (caseValue) { + case 'submitted': + afterPatch = (record) => { + // Sending a record for review + if (this.props.community.get("publication_workflow") == 'review_and_publish'){ + this.setState({dirty:false, waitingForServer: false, readOnly: true}); + notifications.warning(`This record is submitted and waiting for review by your community administrator`); + browser.gotoEditRecord(record.id); + } else { + // direct publish workflow + browser.gotoRecord(record.id); + } + } + break; + + case 'edit': + afterPatch = (record) => { + this.setState({waitingForServer: false, revokeSubmitted: false}); + notifications.clearAll(); + browser.gotoEditRecord(record.id); + } + break; + + case 'save_draft': + afterPatch = (record) => { + // if (this.props.isDraft && !this.isForPublication()) { + this.props.refreshCache(); + // TODO(edima): when a draft is publised, clean the state of + // records in versioned chain, to trigger a refetch of + // versioning data + this.setState({dirty: false, waitingForServer: false, reviewOrPublishConfirmed: 'draft'}); + notifications.clearAll(); + // } + } + break; + + case 'edit_metadata': + afterPatch = (record) => { + // TODO(edima): when a draft is publised, clean the state of + // records in versioned chain, to trigger a refetch of + // versioning data + this.setState({dirty:false, waitingForServer: false}); + notifications.clearAll(); + browser.gotoRecord(record.id); + } + break; } + const onError = (xhr) => { this.setState({waitingForServer: false}); onAjaxError(xhr); @@ -587,19 +678,24 @@ const EditRecord = React.createClass({ } catch (_) { } } - this.setState({waitingForServer: true}); this.props.patchFn(patch, afterPatch, onError); }, + editSubmittedRecord(event){ + event.preventDefault(); + const record = this.state.record.set('publication_state', "draft"); + this.setState({record}); + this.setState({dirty:false, reviewOrPublishConfirmed:'draft', revokeSubmitted:true, readOnly:false}); + }, + isForPublication() { - return this.state.record.get('publication_state') == 'submitted'; + return this.state.reviewOrPublishConfirmed == 'submitted'; }, setPublishedState(e) { const state = e.target.checked ? 'submitted' : 'draft'; - const record = this.state.record.set('publication_state', state); - this.setState({record}); + this.setState({reviewOrPublishConfirmed:state}); }, renderUpdateRecordForm() { @@ -616,23 +712,29 @@ const EditRecord = React.createClass({ }, renderSubmitDraftForm() { - const klass = this.state.waitingForServer ? 'disabled' : - this.isForPublication() ? 'btn-primary btn-danger' : - this.state.dirty ? 'btn-primary' : 'disabled'; - const text = this.state.waitingForServer ? "Updating record, please wait..." : - this.isForPublication() ? 'Save and Publish' : - this.state.dirty ? 'Save Draft' : 'The draft is up to date'; - return ( -
- -

When the draft is published it will be assigned a PID, making it publicly citable. - But a published record's files can no longer be modified by its owner.

- -
- ); + if(this.props.community){ + const klass = this.state.waitingForServer ? 'disabled' : + this.isForPublication() ? 'btn-primary btn-danger' : + this.state.dirty ? 'btn-primary' : 'disabled'; + const text = this.state.waitingForServer ? "Updating record, please wait..." : + this.props.community.get("publication_workflow") == 'review_and_publish' ? (this.isForPublication() ? 'Save and submit for review' : + this.state.dirty ? 'Save Draft' : 'The draft is up to date') + : (this.isForPublication() ? 'Save and Publish' : + this.state.dirty ? 'Save Draft' : 'The draft is up to date'); + const label = this.props.community.get("publication_workflow") == 'review_and_publish' ? " Submit draft for review by your community administrator" : " Submit draft for publication"; + const publicationNote = this.props.community.get("publication_workflow") == 'review_and_publish' ? "" : "When the draft is published it will be assigned a PID, making it publicly citable. But a published record's files can no longer be modified by its owner." + + return ( +
+ +

{publicationNote}

+ +
+ ); + } }, render() { @@ -666,6 +768,7 @@ const EditRecord = React.createClass({ { this.props.isDraft ? this.renderFileBlock() : false }
+
{ this.renderFieldBlock(null, rootSchema) } @@ -673,14 +776,24 @@ const EditRecord = React.createClass({ blockSchemas.map(([id, blockSchema]) => this.renderFieldBlock(id, (blockSchema||Map()).get('json_schema'))) }
+
-
- {pairs(this.state.errors).map( ([id, msg]) => -
{msg}
) } - { this.props.isDraft ? this.renderSubmitDraftForm() : this.renderUpdateRecordForm() } -
+ {this.state.record.get('publication_state') == 'submitted' && this.state.readOnly ? +
+
+

Note that by editing the record, it will be revoked and won't being reviewd by your community admin anymore. You will need to submit it again.

+ +
+
+ : +
+ {pairs(this.state.errors).map( ([id, msg]) => +
{msg}
) } + { this.props.isDraft ? this.renderSubmitDraftForm() : this.renderUpdateRecordForm() } +
+ }
); diff --git a/webui/src/components/search.jsx b/webui/src/components/search.jsx index 6c3be8f3d0..6ab86d9a8a 100644 --- a/webui/src/components/search.jsx +++ b/webui/src/components/search.jsx @@ -13,11 +13,13 @@ export const SearchRecordRoute = React.createClass({ const communities = serverCache.getCommunities(); const location = this.props.location || {}; const drafts = (location.query.drafts == 1) ? 1 : ""; + const submitted = (location.query.submitted == 1) ? 1 : ""; const result = serverCache.searchRecords(location.query || {}); const numResults = (result && result.get('total')) || 0; + const title = submitted ? 'Submitted for review' : ( drafts ? 'Drafts' : 'Records'); return (
- {drafts ?

Drafts

:

Records

} +

{title}

(x && x.length !== undefined) ? x.length : 0; // fast check, not exact, but should work for our use case return nextProps.value !== this.props.value - || len(nextProps.data) !== len(this.props.data); + || len(nextProps.data) !== len(this.props.data) + || nextProps.readOnly !== this.props.readOnly; }, getInitialState: function(){ @@ -73,7 +74,8 @@ export const SelectBig = React.createClass({ filter={this.filter} caseSensitive={false} minLength={2} - busy={busy} /> + busy={busy} + disabled={this.props.readOnly} /> ); } }); diff --git a/webui/src/components/user.jsx b/webui/src/components/user.jsx index 5718cd454c..5fddf7711a 100644 --- a/webui/src/components/user.jsx +++ b/webui/src/components/user.jsx @@ -133,6 +133,10 @@ export const UserProfile = React.createClass({

Roles

{roles && roles.count() && typeof(communitiesList) !== "undefined" ? this.listRoles(roles, communitiesList) :

You have no assigned roles

}
+
+

Submitted Records for Review

+

List of submitted records waiting for review by your community administrator

+

Own records

diff --git a/webui/src/data/server.js b/webui/src/data/server.js index 429e437f16..907cf61c6f 100644 --- a/webui/src/data/server.js +++ b/webui/src/data/server.js @@ -574,14 +574,13 @@ class ServerCache { return this.store.getIn(['latestRecords']); } - searchRecords({q, community, sort, page, size, drafts}) { + searchRecords({q, community, sort, page, size, drafts, submitted}) { if (community) { q = (q ? '(' + q + ') && ' : '') + ' community:' + community; } if (drafts) { - // TODO: change this once the workflows are working. - // Add "submitted" drafts. - q = (q ? '(' + q + ') && ' : '') + 'publication_state:draft'; + const publication_state = submitted ? 'publication_state:submitted' : 'publication_state:draft'; + q = (q ? '(' + q + ') && ' : '') + publication_state; } (drafts == 1) ? this.getters.searchRecords.fetch({q, sort, page, size, drafts}) : this.getters.searchRecords.fetch({q, sort, page, size}); return this.store.getIn(['searchRecords']); @@ -996,8 +995,8 @@ export const browser = { return `${window.location.origin}/records/${recordId}`; }, - gotoSearch({q, community, sort, page, size, drafts}) { - const queryString = encode({q, community, sort, page, size, drafts}); + gotoSearch({q, community, sort, page, size, drafts, submitted}) { + const queryString = encode({q, community, sort, page, size, drafts, submitted}); // trigger a route reload which will do the new search, see SearchRecordRoute browserHistory.push(`/records/?${queryString}`); }, From 151ee419c5a8e08c3b5f155c1f9919bb74b893e9 Mon Sep 17 00:00:00 2001 From: Sarah Berenji Date: Thu, 1 Mar 2018 13:22:21 +0100 Subject: [PATCH 2/2] Adding UI for publication workflow (the admin part) --- webui/src/components/editrecord.jsx | 195 +++++++++++++++++++++++----- webui/src/components/user.jsx | 31 ++++- 2 files changed, 190 insertions(+), 36 deletions(-) diff --git a/webui/src/components/editrecord.jsx b/webui/src/components/editrecord.jsx index cafff8ef18..b8d9db77f9 100644 --- a/webui/src/components/editrecord.jsx +++ b/webui/src/components/editrecord.jsx @@ -61,6 +61,11 @@ export const EditRecordRoute = React.createClass({ } }, + currentUser(){ + const { id } = this.props.params; + return serverCache.getUser(); + }, + render() { const record = this.getRecordOrDraft(); if (!record) { @@ -74,15 +79,21 @@ export const EditRecordRoute = React.createClass({ return ; } const community = serverCache.getCommunity(record.getIn(['metadata', 'community'])); + if (community instanceof Error) { return ; } + + const user = this.currentUser(); + return ( ); @@ -102,6 +113,9 @@ const EditRecord = React.createClass({ readOnly: false, reviewOrPublishConfirmed: null, revokeSubmitted:false, + isResponsibleAdmin:false, + adminUserIsEditing:false, + checkPermission: false, }; }, @@ -461,7 +475,26 @@ const EditRecord = React.createClass({ this.componentWillReceiveProps(this.props); }, + + getCurrentUserRoles(currentUser, currentDraftCommunityID){ + var check = false; + currentUser.get('roles').forEach(role => { + if(currentDraftCommunityID == role.get('id')){ + check = true; + } + }); + return check; + }, + componentWillReceiveProps(props) { + // The current user should be abble to only see his/her own drafts and submitted records + if (props.record && this.props.currentUser){ + const ownerID = props.record.getIn(['metadata', 'owners']).first(); + if(ownerID == this.props.currentUser.get('id')){ + this.setState({checkPermission:true}); + } + } + if (props.record && !this.state.record) { let record = props.record.get('metadata'); if (!record.has('community_specific')) { @@ -477,10 +510,18 @@ const EditRecord = React.createClass({ } } - // Record is submitted for review: the publication_state is 'submitted' and readonly should be True - if(this.props.community && this.state.record){ - if(this.props.community.get("publication_workflow") == 'review_and_publish' && this.state.record.get('publication_state')=='submitted' && !this.state.revokeSubmitted){ + // Record is submitted for review: the publication_state is 'submitted' and readonly should be True. + // Also, check if the current user is the community administrator who should review the + // submitted draft and if so, set the isResponsibleAdmin state to true. + if(this.props.community){ + if(this.props.community.get("publication_workflow") == 'review_and_publish' && this.props.publicationState=='submitted' && !this.state.revokeSubmitted){ this.setState({readOnly: true}); + // Check if the current user is an admin of this draft's community who can review this draft + const isResponsibleAdmin = this.getCurrentUserRoles(this.props.currentUser, this.props.community.get('roles').get('admin').get('id')); + this.setState({isResponsibleAdmin}); + } + if(this.state.adminUserIsEditing){ + this.setState({readOnly: false}); } } @@ -565,15 +606,18 @@ const EditRecord = React.createClass({ componentDidUpdate(prevProps, prevState) { const original = this.props.record.get('metadata').toJS(); let updated = this.state.record.toJS(); - // checkbox is enabled and record is going to be "submitted" for review by community admin - if (prevState.record.get('publication_state') !== this.state.record.get('publication_state') && !this.state.revokeSubmitted){ - const patch = compare(original, updated); - if (!patch || !patch.length) { - this.setState({dirty:false}); - return; + // The checkbox at the end of the page is enabled and record is going to be "submitted" for review by community admin + if(prevState.record){ + if (prevState.record.get('publication_state') !== this.state.record.get('publication_state') && !this.state.revokeSubmitted){ + const patch = compare(original, updated); + if (!patch || !patch.length) { + this.setState({dirty:false}); + return; + } + this.updateBrowserState(patch, 'submitted'); } - this.updateBrowserState(patch, 'submitted'); } + // Revoking the submitted record for review. Going back to the draft mode. if(prevState.revokeSubmitted !== this.state.revokeSubmitted && this.state.revokeSubmitted){ updated['publication_state'] = 'draft'; @@ -634,7 +678,7 @@ const EditRecord = React.createClass({ } break; - case 'edit': + case 'edit_or_reject': afterPatch = (record) => { this.setState({waitingForServer: false, revokeSubmitted: false}); notifications.clearAll(); @@ -644,15 +688,13 @@ const EditRecord = React.createClass({ case 'save_draft': afterPatch = (record) => { - // if (this.props.isDraft && !this.isForPublication()) { this.props.refreshCache(); // TODO(edima): when a draft is publised, clean the state of // records in versioned chain, to trigger a refetch of // versioning data this.setState({dirty: false, waitingForServer: false, reviewOrPublishConfirmed: 'draft'}); notifications.clearAll(); - // } - } + } break; case 'edit_metadata': @@ -665,6 +707,20 @@ const EditRecord = React.createClass({ browser.gotoRecord(record.id); } break; + + case 'accept_and_publish': + afterPatch = (record) =>{ + browser.gotoRecord(record.id); + // TODO: Send an email to the record owner and notify her + } + break; + + case 'reject': + afterPatch = (record) =>{ + browser.gotoSearch({"community":this.props.community.get("id"),"submitted":1,"drafts":1}); + // TODO: Send an email to the record owner and notify her + } + break; } const onError = (xhr) => { @@ -682,13 +738,19 @@ const EditRecord = React.createClass({ this.props.patchFn(patch, afterPatch, onError); }, - editSubmittedRecord(event){ + editSubmittedDraft(event){ event.preventDefault(); const record = this.state.record.set('publication_state', "draft"); this.setState({record}); this.setState({dirty:false, reviewOrPublishConfirmed:'draft', revokeSubmitted:true, readOnly:false}); }, + adminEditSubmittedDraft(event){ + // When the admin user is editting the sumbitted draft, the 'publication_state' should still be 'submitted' + event.preventDefault(); + this.setState({dirty:false, readOnly:false, adminUserIsEditing:true}); + }, + isForPublication() { return this.state.reviewOrPublishConfirmed == 'submitted'; }, @@ -737,12 +799,100 @@ const EditRecord = React.createClass({ } }, + rejectSubmittedDraft(event){ + event.preventDefault(); + // Change the "record_state" from "submitted" to "draft" + const original = this.props.record.get('metadata').toJS(); + const updated = this.state.record.toJS(); + updated['publication_state'] = 'draft'; + const patch = compare(original, updated); + if (!patch || !patch.length) { + return; + } + this.updateBrowserState(patch, 'reject'); + }, + + acceptSubmittedDraft(event){ + event.preventDefault(); + // Changes the "record_state" from "submitted" to "published" + const original = this.props.record.get('metadata').toJS(); + const updated = this.state.record.toJS(); + updated['publication_state'] = 'published'; + const patch = compare(original, updated); + if (!patch || !patch.length) { + return; + } + this.updateBrowserState(patch, 'accept_and_publish'); + }, + + renderButtons(){ + if(this.state.record.get('publication_state') == 'submitted'){ + if(this.state.isResponsibleAdmin){ + // Current user is a responsible admin to approve or reject the submitted draft + // Then there will be two cases: either the admin is editing the submitted draft or not + if(this.state.readOnly){ + return( +

+
+
+ +
+
+

+
+
+ +
+
+ +
+
+
+ ) + } else { + // The admin is editing the submitted draft + return( +
+
+
+ +
+
+ +
+
+
+ ) + } + } else { + // A non admin user is submitting a draft for review + return( +
+
+

Note that by editing the record, it will be revoked and won't being reviewd by your community admin anymore. You will need to submit it again.

+ +
+
) + } + } else { + // The workflow is direct publish, only needs an 'Edit' button + return (
+ {pairs(this.state.errors).map( ([id, msg]) => +
{msg}
) } + { this.props.isDraft ? this.renderSubmitDraftForm() : this.renderUpdateRecordForm() } +
) + } + }, + render() { const rootSchema = this.props.rootSchema; const blockSchemas = this.props.blockSchemas; if (!this.state.record || !rootSchema) { return ; } + if (!this.state.checkPermission){ + return ; + } const editTitle = "Editing " + (this.props.isDraft ? "draft" : "record") + (this.props.isVersion ? " version": ""); return (
@@ -780,20 +930,7 @@ const EditRecord = React.createClass({
- {this.state.record.get('publication_state') == 'submitted' && this.state.readOnly ? -
-
-

Note that by editing the record, it will be revoked and won't being reviewd by your community admin anymore. You will need to submit it again.

- -
-
- : -
- {pairs(this.state.errors).map( ([id, msg]) => -
{msg}
) } - { this.props.isDraft ? this.renderSubmitDraftForm() : this.renderUpdateRecordForm() } -
- } + {this.renderButtons()}
); diff --git a/webui/src/components/user.jsx b/webui/src/components/user.jsx index 5fddf7711a..f2285ca6b0 100644 --- a/webui/src/components/user.jsx +++ b/webui/src/components/user.jsx @@ -98,7 +98,7 @@ export const UserProfile = React.createClass({ ); }, - createLink(communitiesList, name){ + createAdminPageLink(communitiesList, name){ return (admin page) }, @@ -106,7 +106,18 @@ export const UserProfile = React.createClass({ return roles.map(r =>
  • {r.get('description')} - {r.get('name').includes(':admin')? this.createLink(communitiesList, r.get('name')) : ""} + {r.get('name').includes(':admin')? this.createAdminPageLink(communitiesList, r.get('name')) : ""} +
  • ) + }, + + listRecordsForReview(roles, communitiesList){ + const adminRolesOnly = roles.filter( r => { + return r.get('name').includes('admin') + }); + + return adminRolesOnly.map(r => +
  • + {communitiesList[r.get('name').replace(new RegExp("(^com:|:[^:]*$)",'g'),"")]} community
  • ) }, @@ -117,10 +128,14 @@ export const UserProfile = React.createClass({ } const roles = user.get('roles'); const communitiesListTemp = serverCache.getCommunities(); - var communitiesList = communitiesListTemp.reduce(function(map, community){ - map[community.get('id').replace(new RegExp("-",'g'),"")] = community.get('name'); - return map; - }); + let communitiesList; + if(communitiesListTemp.size > 0){ + communitiesList = communitiesListTemp.reduce(function(map, community){ + map[community.get('id').replace(new RegExp("-",'g'),"")] = community.get('name'); + return map; + },{}); + } + return (

    User Profile

    @@ -135,7 +150,9 @@ export const UserProfile = React.createClass({

    Submitted Records for Review

    -

    List of submitted records waiting for review by your community administrator

    +

    List of your submitted records waiting for review by your community administrator

    + {roles && roles.count() && typeof(communitiesList) !== "undefined" ?

    List of submitted records waiting for your review:

    : "" } + {roles && roles.count() && typeof(communitiesList) !== "undefined" ? this.listRecordsForReview(roles, communitiesList) :

    There is no submitted draft for review

    }

    Own records