Select Git revision
functions.php
CollectionDialog.js 8.72 KiB
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import {
Button,
Chip,
Dialog,
DialogActions,
DialogTitle,
Link,
MenuList,
MenuItem,
Typography,
} from '@mui/material';
import ArrowBackIcon from '@mui/icons-material/ArrowBackSharp';
import Skeleton from '@mui/material/Skeleton';
import asArray from '../lib/asArray';
import { LabelValueMetadata } from './LabelValueMetadata';
import CollapsibleSection from '../containers/CollapsibleSection';
import ScrollIndicatedDialogContent from '../containers/ScrollIndicatedDialogContent';
import ManifestInfo from '../containers/ManifestInfo';
/**
* a dialog providing the possibility to select the collection
*/
export class CollectionDialog extends Component {
/** */
static getUseableLabel(resource, index) {
return (resource
&& resource.getLabel
&& resource.getLabel().length > 0)
? resource.getLabel().getValue()
: String(index + 1);
}
/** */
constructor(props) {
super(props);
this.state = { filter: null };
this.hideDialog = this.hideDialog.bind(this);
}
/** */
setFilter(filter) {
this.setState({ filter });
}
/** */
hideDialog() {
const {
hideCollectionDialog, windowId,
} = this.props;
hideCollectionDialog(windowId);
}
/** */
selectCollection(c) {
const {
collectionPath,
manifestId,
showCollectionDialog,
windowId,
} = this.props;
showCollectionDialog(c.id, [...collectionPath, manifestId], windowId);
}
/** */
goToPreviousCollection() {
const { collectionPath, showCollectionDialog, windowId } = this.props;
showCollectionDialog(
collectionPath[collectionPath.length - 1],
collectionPath.slice(0, -1),
windowId,
);
}
/** */
selectManifest(m) {
const {
addWindow,
collectionPath,
manifestId,
setWorkspaceAddVisibility,
updateWindow,
windowId,
} = this.props;
if (windowId) {
updateWindow(windowId, {
canvasId: null, collectionPath: [...collectionPath, manifestId], manifestId: m.id,
});
} else {
addWindow({ collectionPath: [...collectionPath, manifestId], manifestId: m.id });
}
this.hideDialog();
setWorkspaceAddVisibility(false);
}
/** */
dialogContainer() {
const { containerId, windowId } = this.props;
return document.querySelector(`#${containerId} #${windowId}`);
}
/** */
placeholder() {
const { classes } = this.props;
return (
<Dialog
className={classes.dialog}
onClose={this.hideDialog}
open
container={this.dialogContainer()}
BackdropProps={this.backdropProps()}
>
<DialogTitle id="select-collection">
<Skeleton className={classes.placeholder} variant="text" />
</DialogTitle>
<ScrollIndicatedDialogContent>
<Skeleton className={classes.placeholder} variant="text" />
<Skeleton className={classes.placeholder} variant="text" />
</ScrollIndicatedDialogContent>
</Dialog>
);
}
/** */
backdropProps() {
const { classes } = this.props;
return { classes: { root: classes.dialog } };
}
/** */
render() {
const {
classes,
collection,
error,
isMultipart,
manifest,
ready,
t,
} = this.props;
const { filter } = this.state;
if (error) return null;
// If this component is optimistically rendering ahead of the window its in
// force a re-render so that it is placed correctly. The right thing here is
// to maybe pass a ref.
if (!this.dialogContainer()) {
this.forceUpdate();
return null;
}
if (!ready) return this.placeholder();
const rights = manifest && (asArray(manifest.getProperty('rights') || manifest.getProperty('license')));
const requiredStatement = manifest
&& asArray(manifest.getRequiredStatement()).filter(l => l.getValue()).map(labelValuePair => ({
label: null,
values: labelValuePair.getValues(),
}));
const collections = manifest.getCollections();
const currentFilter = filter || (collections.length > 0 ? 'collections' : 'manifests');
return (
<Dialog
className={classes.dialog}
onClose={this.hideDialog}
container={this.dialogContainer()}
BackdropProps={this.backdropProps()}
open
>
<DialogTitle id="select-collection">
<Typography component="div" variant="overline">
{ t(isMultipart ? 'multipartCollection' : 'collection') }
</Typography>
<Typography variant="h3">
{CollectionDialog.getUseableLabel(manifest)}
</Typography>
</DialogTitle>
<ScrollIndicatedDialogContent className={classes.dialogContent}>
{ collection && (
<Button
startIcon={<ArrowBackIcon />}
onClick={() => this.goToPreviousCollection()}
>
{CollectionDialog.getUseableLabel(collection)}
</Button>
)}
<div className={classes.collectionMetadata}>
<ManifestInfo manifestId={manifest.id} />
<CollapsibleSection
id="select-collection-rights"
label={t('attributionTitle')}
>
{ requiredStatement && (
<LabelValueMetadata labelValuePairs={requiredStatement} defaultLabel={t('attribution')} />
)}
{
rights && rights.length > 0 && (
<>
<Typography variant="subtitle2" component="dt">{t('rights')}</Typography>
{ rights.map(v => (
<Typography variant="body1" component="dd" key={v}>
<Link target="_blank" rel="noopener noreferrer" href={v} underline="hover">
{v}
</Link>
</Typography>
)) }
</>
)
}
</CollapsibleSection>
</div>
<div className={classes.collectionFilter}>
{manifest.getTotalCollections() > 0 && (
<Chip clickable color={currentFilter === 'collections' ? 'primary' : 'default'} onClick={() => this.setFilter('collections')} label={t('totalCollections', { count: manifest.getTotalCollections() })} />
)}
{manifest.getTotalManifests() > 0 && (
<Chip clickable color={currentFilter === 'manifests' ? 'primary' : 'default'} onClick={() => this.setFilter('manifests')} label={t('totalManifests', { count: manifest.getTotalManifests() })} />
)}
</div>
{ currentFilter === 'collections' && (
<MenuList>
{
collections.map(c => (
<MenuItem
key={c.id}
onClick={() => { this.selectCollection(c); }}
className={classes.collectionItem}
>
{CollectionDialog.getUseableLabel(c)}
</MenuItem>
))
}
</MenuList>
)}
{ currentFilter === 'manifests' && (
<MenuList>
{
manifest.getManifests().map(m => (
<MenuItem
key={m.id}
onClick={() => { this.selectManifest(m); }}
className={classes.collectionItem}
>
{CollectionDialog.getUseableLabel(m)}
</MenuItem>
))
}
</MenuList>
)}
</ScrollIndicatedDialogContent>
<DialogActions>
<Button onClick={this.hideDialog}>
{t('close')}
</Button>
</DialogActions>
</Dialog>
);
}
}
CollectionDialog.propTypes = {
addWindow: PropTypes.func.isRequired,
classes: PropTypes.objectOf(PropTypes.string).isRequired,
collection: PropTypes.object, // eslint-disable-line react/forbid-prop-types
collectionPath: PropTypes.arrayOf(PropTypes.string),
containerId: PropTypes.string,
error: PropTypes.string,
hideCollectionDialog: PropTypes.func.isRequired,
isMultipart: PropTypes.bool,
manifest: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
manifestId: PropTypes.string.isRequired,
ready: PropTypes.bool,
setWorkspaceAddVisibility: PropTypes.func.isRequired,
showCollectionDialog: PropTypes.func.isRequired,
t: PropTypes.func.isRequired,
updateWindow: PropTypes.func.isRequired,
windowId: PropTypes.string,
};
CollectionDialog.defaultProps = {
collection: null,
collectionPath: [],
containerId: null,
error: null,
isMultipart: false,
ready: false,
windowId: null,
};