DatasetDisplay.tsx 18.8 KB
Newer Older
1
2

import * as React from 'react';
Matija Obreza's avatar
Matija Obreza committed
3
import { translate } from 'react-i18next';
Matija Obreza's avatar
Matija Obreza committed
4
import { withStyles } from '@material-ui/core/styles';
5

Valeriy Panov's avatar
Valeriy Panov committed
6
import {log} from 'utilities/debug';
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
7
import {fixDate} from 'utilities';
Valeriy Panov's avatar
Valeriy Panov committed
8

9
10
11
12
13
import Dataset from 'model/catalog/Dataset';
import Descriptor from 'model/catalog/Descriptor';
import RepositoryFile from 'model/repository/RepositoryFile';
import DatasetCreator from 'model/catalog/DatasetCreator';
import { AVAILABLE_LICENSES } from 'model/License';
14
import { PublishState } from 'model/common.model';
15
16
17
18

import confirm from 'utilities/confirmAlert';
import Authorize from 'ui/common/authorized/Authorize';
import Section from 'ui/common/layout/Section';
19
import Markdown from 'ui/catalog/markdown';
20
import PrettyDate from 'ui/common/time/PrettyDate';
21
import { DescriptorLink, ExternalLink, PartnerLink } from 'ui/catalog/Links';
22
23

import LocationMap from './LocationMap';
Matija Obreza's avatar
Matija Obreza committed
24
import Button from '@material-ui/core/Button';
Maxim Babichev's avatar
Maxim Babichev committed
25
import { Properties, PropertiesItem } from 'ui/catalog/Properties';
Matija Obreza's avatar
Matija Obreza committed
26
27
28
29
30
import Grid from '@material-ui/core/Grid';
import Divider from '@material-ui/core/Divider';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import ListItemText from '@material-ui/core/ListItemText';
31

32
import AccessionRefsTable from 'ui/catalog/accession/AccessionRefsTable';
33
import Permissions from 'ui/common/permission/Permissions';
Matija Obreza's avatar
Matija Obreza committed
34
import CropChips from 'crops/ui/c/CropChips';
35

36
import Card, {CardHeader, CardContent, CardActions } from 'ui/common/Card';
Viacheslav Pavlov's avatar
Viacheslav Pavlov committed
37
import McpdDate from 'ui/common/time/McpdDate';
38
39
40
41
42
43
44
45
46
47
48

const styles = (theme) => ({
    root: {
        flexGrow: 1,
    },
    gray: {
        backgroundColor: '#f3f2ee',
    },
    title: {
        fontSize: '30px',
        fontWeight: 'bold',
49
        [theme.breakpoints.down('sm')]: {
50
51
52
53
54
55
56
57
58
59
60
61
62
63
            fontSize: '24px',
        },
    },
    grayRowsEven: theme.table.grayRowsEven,
    grayRowsOdd: theme.table.grayRowsOdd,
    green: {
        color: '#88ba42',
    },
    grayTitleBig: {
        fontSize: '14px',
        fontWeight: 'bold',
        lineHeight: '22px',
        padding: '15px 14px',
        margin: '0 1px',
64
        [theme.breakpoints.down('sm')]: {
65
66
67
68
69
70
71
72
73
74
            marginLeft: '0',
            marginRight: '0',
        },
    },
    grayTitleSmall: {
        fontSize: '14px',
        lineHeight: '22px',
        padding: '10px 14px',
        margin: '0 1px',
        minHeight: '100%',
75
        [theme.breakpoints.down('sm')]: {
76
77
78
79
80
81
82
83
84
            marginLeft: '0',
            marginRight: '0',
        },
    },
    rightTextWrapper: {
        display: 'flex',
        justifyContent: 'space-between',
        margin: '0 1px',
        padding: '10px 20px',
85
        [theme.breakpoints.down('sm')]: {
86
87
88
89
90
91
92
93
94
95
            marginLeft: '0',
            marginRight: '0',
            padding: '10px 14px',
        },
    },
    buttonGreen: theme.buttons.green,
    dataContainer: {
        flexWrap: 'nowrap',
        marginBottom: '2px',
        wordWrap: 'break-word',
96
        [theme.breakpoints.down('sm')]: {
97
98
99
100
            flexWrap: 'wrap',
        },
    },
    dataName: {
101
        [theme.breakpoints.down('md')]: {
102
103
104
105
106
            display: 'none',
        },
    },
    margin1: {
        margin: '0 1px',
107
        [theme.breakpoints.down('sm')]: {
108
109
110
111
112
113
114
115
            margin: '0',
        },
    },
    grayTitleA: {
        display: 'block',
        padding: '10px 14px',
    },
    centerAlign : {
116
         [theme.breakpoints.down('md')]: {
117
118
119
120
            justifyContent: 'center',
         },
     },
    pdTop0: {
121
        [theme.breakpoints.down('sm')]: {
122
123
124
125
126
127
128
129
            paddingTop: '0',
            marginLeft: '0',
            marginRight: '0',
        },
    },
});

interface IDetailInfoProps extends React.ClassAttributes<any> {
Matija Obreza's avatar
Matija Obreza committed
130
    t: any;
131
132
    classes: any;
    dataset: Dataset;
133
134
135
    publishDataset?: (dataset: Dataset, needToRedirect?: boolean) => void;
    approveDataset?: (dataset: Dataset) => void;
    rejectDataset?: (dataset: Dataset, needToRedirect?: boolean) => void;
136
137
138
139
140
141
142
143
144
145
146
147
    deleteDataset?: (dataset: Dataset) => any;
}

class DetailInfo extends React.Component<IDetailInfoProps, any> {
    private onPublish = (e) => {
      const {dataset, publishDataset} = this.props;

      if (! publishDataset) {
        return;
      }

      confirm(<span>Publish <b>{ dataset.title }</b>?</span>, {
148
        description: `The dataset will be reviewing by administrator before publishing.`,
149
150
151
        confirmLabel: 'Publish',
        abortLabel: 'Cancel',
      }).then(() => {
Valeriy Panov's avatar
Valeriy Panov committed
152
        log('Publishing dataset', dataset);
153
154
155
156
157
158
159
        publishDataset(dataset);
      }).catch(() => {
          // don't
      });
    }

    private onUnpublish = (e) => {
160
      const {dataset, rejectDataset} = this.props;
161

162
      if (! rejectDataset) {
163
164
165
166
167
168
169
170
        return;
      }

      confirm(<span>Unpublish <b>{ dataset.title }</b>?</span>, {
          // description: `Deleting the descriptor is only possible when there is no associated data.`,
          confirmLabel: 'Unpublish',
          abortLabel: 'Cancel',
      }).then(() => {
171
172
        log('Unpublishing dataset', dataset);
        rejectDataset(dataset, false);
173
174
175
176
177
      }).catch(() => {
          // don't
      });
    }

178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
    private onApprove = (e) => {
      const {dataset, approveDataset} = this.props;

      if (! approveDataset) {
        return;
      }

      confirm(<span>Approve <b>{ dataset.title }</b>?</span>, {
          description: `After approving the dataset no changes are permitted, a new version must be created.`,
          confirmLabel: 'Approve',
          abortLabel: 'Cancel',
      }).then(() => {
        log('Approving dataset', dataset);
        approveDataset(dataset);
      }).catch(() => {
        // don't
      });
    }

    private onReject = (e) => {
      const {dataset, rejectDataset} = this.props;

      if (! rejectDataset) {
        return;
      }

      log('Rejecting dataset', dataset);
      rejectDataset(dataset, true);
    }

208
209
210
211
212
213
214
215
    private onDelete = (e) => {
      const {dataset, deleteDataset} = this.props;

      if (! deleteDataset) {
        return;
      }

      confirm(<span>Delete <b>{ dataset.title }</b>?</span>, {
Maxym Borodenko's avatar
Maxym Borodenko committed
216
          description: `Deleting the dataset will remove all related data.`,
217
218
219
220
221
222
223
224
225
226
          confirmLabel: 'Delete',
          abortLabel: 'Cancel',
      }).then(() => {
          deleteDataset(dataset);
      }).catch(() => {
          // don't
      });
    }

    public render() {
Matija Obreza's avatar
Matija Obreza committed
227
        const { classes, dataset, publishDataset, deleteDataset, t } = this.props;
228
229

        if (! dataset) {
Valeriy Panov's avatar
Valeriy Panov committed
230
          log('Waiting for dataset.');
231
232
233
          return null;
        }

Valeriy Panov's avatar
Valeriy Panov committed
234
        const license = dataset.rights && AVAILABLE_LICENSES.find((e) => e.code === dataset.rights);
Maxym Borodenko's avatar
Maxym Borodenko committed
235
        const oneDay = 24 * 60 * 60 * 1000;
236
        const oneDayPassed = dataset && (fixDate(dataset.lastModifiedDate).getTime() <= (new Date()).getTime() - oneDay);
Valeriy Panov's avatar
Valeriy Panov committed
237

238
239
240
        return (
            <div className={ classes.root }>
              <Grid container spacing={ 0 }>
Maxym Borodenko's avatar
Maxym Borodenko committed
241
                <Grid item xs={ 12 } className="p-10" id="dataset-top">
242
                    <Card className={ classes.card } square>
Maxym Borodenko's avatar
Maxym Borodenko committed
243
244
245
246
                        <CardHeader className={ classes.cardHeader }
                                    title={ <Markdown basic source={ dataset.title } /> }
                                    subheader={ <small>{ dataset.versionTag }</small> } />
                        <CardContent className={ classes.cardContent }>
Matija Obreza's avatar
Matija Obreza committed
247
                          { dataset.description && <Markdown className="mb-20" source={ dataset.description } /> }
248
249

                          <Properties>
Matija Obreza's avatar
Matija Obreza committed
250
251
252
253
254
255
                            <PropertiesItem title="Data provider:"><PartnerLink to={ dataset.owner } /></PropertiesItem>
                            { dataset.crops && dataset.crops.length > 0 &&
                              <PropertiesItem title="Crop:"><CropChips crops={ dataset.crops } /></PropertiesItem>
                            }
                            <PropertiesItem title="Number of accessions:">{ dataset.accessionCount }</PropertiesItem>
                            <PropertiesItem title="Number of traits:">{ dataset.descriptorCount }</PropertiesItem>
256
257
                            <PropertiesItem title="Start of evaluation:"><McpdDate value={ dataset.startDate }/></PropertiesItem>
                            <PropertiesItem title="End of evaluation:"><McpdDate value={ dataset.endDate }/></PropertiesItem>
258
                          </Properties>
259
260
261
                      </CardContent>
                      { publishDataset && (dataset._permissions.write || dataset._permissions.delete) && (
                        <CardActions>
262
263
                          { dataset.state === PublishState.PUBLISHED ?
                              (dataset._permissions.manage && !oneDayPassed) ?
Maxym Borodenko's avatar
Maxym Borodenko committed
264
265
266
267
268
                                  <Button onClick={ this.onUnpublish } type="button">Un-publish</Button>
                                  :
                                  <Authorize role="ROLE_ADMINISTRATOR">
                                      <Button onClick={ this.onUnpublish } type="button">Un-publish</Button>
                                  </Authorize>
269
270
271
272
273
274
275
276
                              : null
                          }
                          { dataset.state === PublishState.DRAFT && dataset._permissions.write && <Button onClick={ this.onPublish } type="button">Publish</Button> }
                          { dataset.state !== PublishState.PUBLISHED && dataset._permissions.write && <Button onClick={ this.onReject } type="button">Edit</Button> }
                          { dataset.state === PublishState.REVIEWING &&
                            <Authorize role="ROLE_ADMINISTRATOR">
                              <Button onClick={ this.onApprove } type="button">Approve</Button>
                            </Authorize>
277
                          }
278
                          { dataset.state !== PublishState.PUBLISHED && deleteDataset && dataset._permissions.delete && <Button onClick={ this.onDelete } type="button">Delete</Button> }
279
                          { dataset._permissions.manage && <Permissions clazz={ Dataset.clazz } id={ dataset.id } /> }
280
281
282
283
284
285
286
                        </CardActions>
                      ) }
                  </Card>
                </Grid>
              </Grid>

              <Grid container spacing={ 0 }>
Matija Obreza's avatar
Matija Obreza committed
287
                <Grid item xs={ 12 } md={ 12 } lg={ 12 } className="p-10" id="dataset-metadata">
288
                  <Section title="Dataset metadata">
Matija Obreza's avatar
Matija Obreza committed
289
290
291
                    { dataset.creators && dataset.creators.length > 0 &&
                      <div>
                        <div className="pt-15 pb-15 pl-20 pr-20">
Matija Obreza's avatar
Matija Obreza committed
292
                            <h4 className="font-bold m-0">Dataset creators</h4>
Matija Obreza's avatar
Matija Obreza committed
293
294
295
296
297
                        </div>
                        <Divider/>
                        <Grid container spacing={ 0 } className="p-20">
                            <Grid item xs={ 12 }>
                              <Properties>
298
                                { dataset.creators && dataset.creators.map((e: DatasetCreator, i) => (
Matija Obreza's avatar
Matija Obreza committed
299
300
301
302
303
304
                                  <PropertiesItem title={ t(`dataset.creator.role.${e.role}`) } key={ e.id }>
                                      <span>
                                        <b>{ e.fullName }</b>
                                        { e.institutionalAffiliation && <span> { e.institutionalAffiliation }</span> }
                                      </span>
                                      { /* { e.email && <div><a href={ `mailto:${e.email}` }>{ e.email }</a></div> } */ }
Matija Obreza's avatar
Matija Obreza committed
305
306
307
308
309
310
                                  </PropertiesItem>
                                )) }
                              </Properties>
                            </Grid>
                        </Grid>
                        <Divider/>
311
                      </div>
Matija Obreza's avatar
Matija Obreza committed
312
313
                    }

Matija Obreza's avatar
Matija Obreza committed
314
315
316
317
318
319
320
321
322
323
                      <div className="pt-15 pb-15 pl-20 pr-20">
                          <h4 className="font-bold m-0">Dataset use and licensing</h4>
                      </div>
                      <Divider/>
                      { license &&
                        <Grid container spacing={ 0 } className="p-20">
                            <Properties>
                                <PropertiesItem title="Licensed under:"><b>{ license.code }</b> { license.title }</PropertiesItem>
                                { license.url &&
                                  <PropertiesItem title="More information:">
Matija Obreza's avatar
Matija Obreza committed
324
                                    <ExternalLink link={ license.url }>{ license.url }</ExternalLink>
Matija Obreza's avatar
Matija Obreza committed
325
326
327
328
329
                                  </PropertiesItem>
                                }
                            </Properties>
                        </Grid>
                      }
Matija Obreza's avatar
Matija Obreza committed
330

Matija Obreza's avatar
Matija Obreza committed
331
                      <Divider/>
Maxim Babichev's avatar
Maxim Babichev committed
332
333
                      <div className="pt-15 pb-15 pl-20 pr-20">
                          <h4 className="font-bold m-0">
Matija Obreza's avatar
Matija Obreza committed
334
                              Data and resources
Maxim Babichev's avatar
Maxim Babichev committed
335
                          </h4>
336
337
338
339
                      </div>
                      <Divider/>
                      <Grid container spacing={ 0 } className="p-20">
                          <Grid item xs={ 12 }>
Matija Obreza's avatar
Matija Obreza committed
340
                            <Properties>
341
                              {
Matija Obreza's avatar
Matija Obreza committed
342
343
344
                                  dataset.repositoryFiles && dataset.repositoryFiles.map((e: RepositoryFile) => (
                                      <PropertiesItem key={ e.uuid } title={
                                        <a href={ `/proxy/api/v0/repository/download/${e.uuid}` }>
Matija Obreza's avatar
Matija Obreza committed
345
                                          <Button variant="raised" component="span" className={ `${classes.buttonGreen} ${classes.button}` }>
Matija Obreza's avatar
Matija Obreza committed
346
347
348
349
350
351
352
                                            Download
                                          </Button>
                                        </a>
                                       }>
                                          <p>{ e.title || 'Dataset file' }</p>
                                          <p>{ e.originalFilename }</p>
                                      </PropertiesItem>
353
354
                                  ))
                              }
Matija Obreza's avatar
Matija Obreza committed
355
                            </Properties>
356
357
358
                          </Grid>
                      </Grid>
                      <Divider/>
Maxym Borodenko's avatar
Maxym Borodenko committed
359
360
                      <div className="pt-15 pb-15 pl-20 pr-20">
                          <h4 className="font-bold m-0">
Oleksii Savran's avatar
Oleksii Savran committed
361
                              { t('dataset.contact') }
Maxym Borodenko's avatar
Maxym Borodenko committed
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
                          </h4>
                      </div>
                      <Divider/>
                      <Grid container spacing={ 0 } className="p-20">
                          <Grid item xs={ 12 }>
                              <Grid container spacing={ 0 }>
                                  <Properties>
                                      { dataset.owner.email &&
                                          <PropertiesItem title="Email:">
                                              <div><a href={ `mailto:${dataset.owner.email}` }>{ dataset.owner.email }</a></div>
                                          </PropertiesItem> }
                                      { dataset.owner.phone && <PropertiesItem title="Phone number:">{ dataset.owner.phone }</PropertiesItem> }
                                      { dataset.owner.address && <PropertiesItem title="Address:">{ dataset.owner.address }</PropertiesItem> }
                                  </Properties>
                              </Grid>
                          </Grid>
                      </Grid>
                      <Divider/>
Maxim Babichev's avatar
Maxim Babichev committed
380
381
                      <div className="pt-15 pb-15 pl-20 pr-20">
                          <h4 className="font-bold m-0">
382
                              Other Metadata
Maxim Babichev's avatar
Maxim Babichev committed
383
                          </h4>
384
385
386
387
                      </div>
                      <Divider/>
                      <Grid container spacing={ 0 } className="p-20">
                          <Grid item xs={ 12 }>
Maxim Babichev's avatar
Maxim Babichev committed
388
389
                              <Grid container spacing={ 0 }>
                                  <Properties>
Maxym Borodenko's avatar
Maxym Borodenko committed
390
                                      <PropertiesItem title="Date of dataset:"><McpdDate value={ dataset.created }/></PropertiesItem>
Oleksii Savran's avatar
Oleksii Savran committed
391
392
393
                                      <PropertiesItem title="Related resources:">
                                          <Markdown source={ dataset.source } />
                                      </PropertiesItem>
Matija Obreza's avatar
Matija Obreza committed
394
395
396
397
398
399
                                      <PropertiesItem title="Metadata create date:">
                                          { dataset.createdDate && <PrettyDate value={ dataset.createdDate } /> }
                                      </PropertiesItem>
                                      <PropertiesItem title="Metadata updated date:">
                                          { dataset.lastModifiedDate && <PrettyDate value={ dataset.lastModifiedDate } /> }
                                      </PropertiesItem>
Maxim Babichev's avatar
Maxim Babichev committed
400
                                  </Properties>
401
402
403
404
405
406
407
408
                              </Grid>
                          </Grid>
                      </Grid>
                  </Section>
                </Grid>
              </Grid>

              <Grid container spacing={ 0 }>
409
                  { dataset.locations && dataset.locations.length > 0 && (
Maxym Borodenko's avatar
Maxym Borodenko committed
410
                      <Grid item xs={ 12 } md={ 12 } lg={ 12 } className="p-10" id="dataset-locations">
Valeriy Panov's avatar
Valeriy Panov committed
411
412
413
414
415
416
417
418
                          <Section title="Locations">
                              <div className="p-20">
                                  <LocationMap locations={ dataset.locations } classes={ {} }/>
                              </div>
                          </Section>
                      </Grid>
                  ) }

Matija Obreza's avatar
Matija Obreza committed
419
                  { dataset.descriptors && dataset.descriptors.length > 0 && (
Maxym Borodenko's avatar
Maxym Borodenko committed
420
                    <Grid item xs={ 12 } md={ 12 } lg={ 12 } className="p-10" id="dataset-traits">
421
                      <Section title="Traits observed">
Matija Obreza's avatar
Matija Obreza committed
422
                        <List>
423
                        { dataset.descriptors.map((descriptor: Descriptor) => (
Matija Obreza's avatar
Matija Obreza committed
424
                          <ListItem key={ descriptor.uuid } className="">
Matija Obreza's avatar
Matija Obreza committed
425
                            <ListItemText primary={ <DescriptorLink to={ descriptor }><Markdown source={ descriptor.title } /></DescriptorLink> }
Matija Obreza's avatar
Matija Obreza committed
426
427
                              secondary={ descriptor.description && <Markdown source={ descriptor.description } /> } />
                          </ListItem>
428
                        )) }
Matija Obreza's avatar
Matija Obreza committed
429
                        </List>
430
431
432
433
                      </Section>
                    </Grid>
                  ) }

434
                  { dataset.accessionRefs && dataset.accessionRefs.length > 0 && (
Maxym Borodenko's avatar
Maxym Borodenko committed
435
                    <Grid item xs={ 12 } md={ 12 } lg={ 12 } className="p-10" id="dataset-accessions">
436
437
                      <Section title="Accessions evaluated">
                          <div className="p-20">
438
                              <AccessionRefsTable accessionRefs={ dataset.accessionRefs } />
439
440
441
442
443
444
445
446
447
448
449
                          </div>
                      </Section>
                    </Grid>
                  ) }
              </Grid>
            </div>
        );
    }

}

Matija Obreza's avatar
Matija Obreza committed
450
export default translate()((withStyles as any)(styles)(DetailInfo));