Skip to content

Commit 2c61f2b

Browse files
committed
Adds collection sequence view
1 parent 01da678 commit 2c61f2b

File tree

7 files changed

+360
-1
lines changed

7 files changed

+360
-1
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
import Accordion from '@material-ui/core/Accordion';
2+
import AccordionActions from '@material-ui/core/AccordionActions';
3+
import AccordionDetails from '@material-ui/core/AccordionDetails';
4+
import AccordionSummary from '@material-ui/core/AccordionSummary';
5+
import Button from '@material-ui/core/Button';
6+
import Divider from '@material-ui/core/Divider';
7+
import Typography from '@material-ui/core/Typography';
8+
import { compose } from 'redux';
9+
10+
import * as formActions from '../../formactions/collection';
11+
import withFormActions from '../../hoc/withFormActions';
12+
import withSnackbar from '../../hoc/withSnackbar';
13+
14+
import CollectionSequenceParamsForm from './CollectionSequenceParamsForm';
15+
16+
export const COLLECTION_SEQUENCE_PARAMS_FORM = 'COLLECTION_SEQUENCE_PARAMS_FORM';
17+
18+
function CollectionSequenceParams({
19+
onSubmit,
20+
onSuccess,
21+
onFail,
22+
openSnackBar,
23+
submitForm,
24+
resetForm,
25+
...formProps
26+
}) {
27+
const onSubmitSuccess = (response, dispatch, props) => {
28+
if (onSuccess) {
29+
onSuccess(response, dispatch, props);
30+
}
31+
};
32+
const onSubmitFail = (error, dispatch, props) => {
33+
const messageContent = 'Error Loading Collection Sequence';
34+
openSnackBar({ messageContent, messageColor: 'secondary' });
35+
if (onFail) {
36+
onFail(error, dispatch, props);
37+
}
38+
};
39+
return (
40+
<Accordion>
41+
<AccordionSummary>
42+
<Typography variant="subtitle2" color="textSecondary">
43+
Collection Sequence Options
44+
</Typography>
45+
</AccordionSummary>
46+
<AccordionDetails>
47+
<CollectionSequenceParamsForm
48+
form={COLLECTION_SEQUENCE_PARAMS_FORM}
49+
onSubmit={formActions.onGetCollectionSequence}
50+
onSubmitSuccess={onSubmitSuccess}
51+
onSubmitFail={onSubmitFail}
52+
initialValues={{ queryParams: { mode: 'COLLECTION_ORDER' } }}
53+
style={{ width: '100%' }}
54+
{...formProps}
55+
/>
56+
</AccordionDetails>
57+
<Divider />
58+
<AccordionActions>
59+
<Button size="small" onClick={() => resetForm(COLLECTION_SEQUENCE_PARAMS_FORM)}>
60+
Reset
61+
</Button>
62+
<Button
63+
size="small"
64+
color="primary"
65+
onClick={() => submitForm(COLLECTION_SEQUENCE_PARAMS_FORM)}
66+
>
67+
Update
68+
</Button>
69+
</AccordionActions>
70+
</Accordion>
71+
);
72+
}
73+
74+
export default compose(withSnackbar, withFormActions)(CollectionSequenceParams);
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import FormControl from '@material-ui/core/FormControl';
2+
import InputLabel from '@material-ui/core/InputLabel';
3+
import MenuItem from '@material-ui/core/MenuItem';
4+
import Typography from '@material-ui/core/Typography';
5+
import { reduxForm } from 'redux-form';
6+
7+
import { Select } from '../form';
8+
import { loadMetadataFieldOptions } from '../metadatafield/MetadataFieldSelect';
9+
import Field from '../ui/Field';
10+
import FormSection from '../ui/FormSection';
11+
import { StatefulAsyncSelect } from '../ui/Select';
12+
13+
export const queryParams = () => (
14+
<>
15+
<FormControl fullWidth>
16+
<InputLabel htmlFor="mode">mode</InputLabel>
17+
<Field name="mode" component={Select}>
18+
<MenuItem value="COLLECTION_ORDER">COLLECTION_ORDER</MenuItem>
19+
<MenuItem value="ITEM_START_TC">ITEM_START_TC</MenuItem>
20+
<MenuItem value="METADATA">METADATA</MenuItem>
21+
</Field>
22+
</FormControl>
23+
<Field
24+
name="field"
25+
component={StatefulAsyncSelect}
26+
loadOptions={loadMetadataFieldOptions}
27+
cacheOptions
28+
isClearable
29+
fullWidth
30+
creatable
31+
/>
32+
<FormControl fullWidth>
33+
<InputLabel htmlFor="sort">sort</InputLabel>
34+
<Field name="sort" component={Select}>
35+
<MenuItem value="asc">Ascending</MenuItem>
36+
<MenuItem value="desc">Descending</MenuItem>
37+
</Field>
38+
</FormControl>
39+
</>
40+
);
41+
42+
function CollectionSequenceParamsForm({ error, handleSubmit, ...props }) {
43+
return (
44+
<form onSubmit={handleSubmit} {...props}>
45+
{error && <Typography color="error">{error}</Typography>}
46+
<FormSection name="queryParams" component={queryParams} />
47+
<button type="submit" hidden />
48+
</form>
49+
);
50+
}
51+
52+
export default reduxForm()(CollectionSequenceParamsForm);
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import { TranscodePresetType, TimeCodeType } from '../shapetag/ShapeTagDisplay';
2+
import { KeyValuePairType } from '../ui/DisplayType';
3+
import TextGrid from '../ui/TextGrid';
4+
import TypeArray from '../ui/TypeArray';
5+
import TypeSection from '../ui/TypeSection';
6+
7+
function EffectPointType({ value = {} }) {
8+
return (
9+
<>
10+
<TextGrid title="value" value={value.value} hover hideNoValue />
11+
<TextGrid title="position" value={value.position} hover hideNoValue />
12+
</>
13+
);
14+
}
15+
16+
function EffectParameterType({ value = {} }) {
17+
return (
18+
<>
19+
<TextGrid title="name" value={value.name} hover hideNoValue />
20+
<TypeArray title="point" component={EffectPointType} value={value.point} />
21+
</>
22+
);
23+
}
24+
25+
function EffectType({ value = {} }) {
26+
return (
27+
<>
28+
<TextGrid title="name" value={value.name} hover hideNoValue />
29+
<TextGrid title="id" value={value.id} hover hideNoValue />
30+
<TypeSection title="timeBase" component={TimeCodeType} value={value.timeBase} hideNoValue />
31+
<TypeArray title="parameter" component={EffectParameterType} value={value.parameter} />
32+
</>
33+
);
34+
}
35+
36+
function SequenceMediaType({ value = {} }) {
37+
return (
38+
<>
39+
<TextGrid title="externalVideoMedia" value={value.externalVideoMedia} hover hideNoValue />
40+
<TextGrid title="item" value={value.item} hover hideNoValue variant="itemId" />
41+
<TextGrid title="sourceTrack" value={value.sourceTrack} hover hideNoValue />
42+
<TypeSection title="in" component={TimeCodeType} value={value.in} hideNoValue />
43+
<TypeSection title="out" component={TimeCodeType} value={value.out} hideNoValue />
44+
<TypeSection title="sourceIn" component={TimeCodeType} value={value.sourceIn} hideNoValue />
45+
<TypeSection title="sourceOut" component={TimeCodeType} value={value.sourceOut} hideNoValue />
46+
<TypeArray title="effect" component={EffectType} value={value.effect} />
47+
<TextGrid title="reference" value={value.reference} hover hideNoValue />
48+
</>
49+
);
50+
}
51+
52+
function SequenceTransitionType({ value = {} }) {
53+
return (
54+
<>
55+
<TypeSection title="in" component={TimeCodeType} value={value.in} hideNoValue />
56+
<TypeSection title="out" component={TimeCodeType} value={value.out} hideNoValue />
57+
<TextGrid title="wipe" value={value.wipe} hover hideNoValue />
58+
<TextGrid title="transition" value={value.transition} hover hideNoValue />
59+
<TextGrid title="horizRepeat" value={value.horizRepeat} hover hideNoValue />
60+
<TextGrid title="vertRepeat" value={value.vertRepeat} hover hideNoValue />
61+
<TextGrid title="startPercentage" value={value.startPercentage} hover hideNoValue />
62+
<TextGrid title="endPercentage" value={value.endPercentage} hover hideNoValue />
63+
<TextGrid title="reverse" value={value.reverse} hover hideNoValue />
64+
<TextGrid title="borderWidth" value={value.borderWidth} hover hideNoValue />
65+
<TextGrid title="borderColor" value={value.borderColor} hover hideNoValue />
66+
<TextGrid title="color" value={value.color} hover hideNoValue />
67+
</>
68+
);
69+
}
70+
71+
function SequenceTrackType({ value = {} }) {
72+
return (
73+
<>
74+
<TextGrid title="audio" value={value.audio} hover hideNoValue />
75+
<TypeArray title="segment" component={SequenceMediaType} value={value.segment} />
76+
<TypeArray title="transition" component={SequenceTransitionType} value={value.transition} />
77+
</>
78+
);
79+
}
80+
81+
function SequenceType({ value = {} }) {
82+
return (
83+
<>
84+
<TextGrid title="id" value={value.id} hover hideNoValue />
85+
<TypeArray title="track" component={SequenceTrackType} value={value.track} />
86+
<TypeSection
87+
title="override"
88+
component={TranscodePresetType}
89+
hideNoValue
90+
value={value.override}
91+
/>
92+
<TypeArray
93+
title="setting"
94+
value={value.setting}
95+
component={KeyValuePairType}
96+
hover
97+
hideNoValue
98+
/>
99+
</>
100+
);
101+
}
102+
103+
function SequenceDisplay({ sequenceDocument }) {
104+
return <TypeSection value={sequenceDocument} component={SequenceType} />;
105+
}
106+
107+
export default SequenceDisplay;

src/components/shapetag/ShapeTagDisplay.jsx

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ function RationalType({ value = {} }) {
8888

8989
const TimeBaseType = RationalType;
9090

91-
function TimeCodeType({ value = {} }) {
91+
export function TimeCodeType({ value = {} }) {
9292
return (
9393
<>
9494
<TextGrid title="samples" value={value.samples} hover hideNoValue />
@@ -528,6 +528,20 @@ export function ShapeTagScriptDisplay({ transcodePresetDocument }) {
528528
return <TypeSection component={ScriptSection} value={transcodePresetDocument} />;
529529
}
530530

531+
export function TranscodePresetType({ value = {} }) {
532+
return (
533+
<>
534+
<TypeSection component={ContainerSection} value={value} />
535+
<TypeSection component={AudioSection} value={value} />
536+
<TypeSection component={VideoSection} value={value} />
537+
<TypeSection component={ThumbnailSection} value={value} />
538+
<TypeSection component={OverlaySection} value={value} />
539+
<TypeSection component={AdvancedSection} value={value} />
540+
<TypeSection component={ScriptSection} value={value} />
541+
</>
542+
);
543+
}
544+
531545
export default function ShapeTagDisplay({ transcodePresetDocument }) {
532546
return (
533547
<>

src/containers/Collection.jsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import CollectionCollection from './collection/CollectionCollection';
2525
import CollectionContent from './collection/CollectionContent';
2626
import CollectionMetadata from './collection/CollectionMetadata';
2727
import CollectionMetadataChangeSetList from './collection/CollectionMetadataChangeSetList';
28+
import CollectionSequence from './collection/CollectionSequence';
2829
import DeletionLockList from './DeletionLockList';
2930
import MetadataGraph from './MetadataGraph';
3031
import NotificationEntity from './NotificationEntity';
@@ -48,6 +49,7 @@ const COLLECTION_ENTITY_ADD_DIALOG = 'COLLECTION_ENTITY_ADD_DIALOG';
4849
const COLLECTION_FOLDERMAP_DIALOG = 'COLLECTION_FOLDERMAP_DIALOG';
4950
const ACCESSGRAPH_TAB = 'ACCESSGRAPH_TAB';
5051
const METADATAGRAPH_TAB = 'METADATAGRAPH_TAB';
52+
const SEQUENCE_TAB = 'SEQUENCE_TAB';
5153

5254
const TAB_TITLE = [
5355
{
@@ -121,6 +123,13 @@ const TAB_TITLE = [
121123
path: '/collection/:collectionId/metadata/graph/',
122124
entity: 'collection',
123125
},
126+
{
127+
tab: SEQUENCE_TAB,
128+
listText: 'Sequence',
129+
component: CollectionSequence,
130+
path: '/collection/:collectionId/sequence-document/',
131+
entity: 'collection',
132+
},
124133
];
125134

126135
const listComponentRoute = ({ collectionId }) => (
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { PureComponent } from 'react';
2+
3+
import { compose } from 'redux';
4+
5+
import CollectionSequenceParams, {
6+
COLLECTION_SEQUENCE_PARAMS_FORM,
7+
} from '../../components/collection/CollectionSequenceParams';
8+
import SequenceDisplay from '../../components/sequence/SequenceDisplay';
9+
import withCard from '../../hoc/withCard';
10+
import withFormActions from '../../hoc/withFormActions';
11+
import withUI from '../../hoc/withUI';
12+
13+
const SequenceDisplayCard = withCard(SequenceDisplay);
14+
15+
class CollectionSequence extends PureComponent {
16+
constructor(props) {
17+
super(props);
18+
this.onRefresh = this.onRefresh.bind(this);
19+
this.onRefreshError = this.onRefreshError.bind(this);
20+
this.state = {
21+
sequenceDocument: undefined,
22+
};
23+
}
24+
25+
componentDidMount() {
26+
const { collectionId } = this.props;
27+
document.title = `VidiCore Admin | Collection | ${collectionId} | Sequence`;
28+
this.onRefresh();
29+
}
30+
31+
UNSAFE_componentWillReceiveProps({ collectionId }) {
32+
const { collectionId: prevCollectionId } = this.props;
33+
if (prevCollectionId !== collectionId) {
34+
this.onRefresh();
35+
document.title = `VidiCore Admin | Collection | ${collectionId} | Sequence`;
36+
}
37+
}
38+
39+
onRefreshError() {
40+
const { openSnackBar } = this.props;
41+
const messageContent = 'Error Loading Collection Sequence';
42+
openSnackBar({ messageContent, messageColor: 'secondary' });
43+
}
44+
45+
onRefresh() {
46+
const { submitForm } = this.props;
47+
submitForm(COLLECTION_SEQUENCE_PARAMS_FORM);
48+
}
49+
50+
render() {
51+
const {
52+
collectionId,
53+
titleComponent: TitleComponent,
54+
tabComponent: TabComponent,
55+
title,
56+
} = this.props;
57+
const { sequenceDocument } = this.state;
58+
return (
59+
<>
60+
{TitleComponent && (
61+
<TitleComponent
62+
code={sequenceDocument}
63+
codeModal="SequenceDocument"
64+
onRefresh={this.onRefresh}
65+
title={title}
66+
/>
67+
)}
68+
{TabComponent && <TabComponent />}
69+
<CollectionSequenceParams
70+
collectionId={collectionId}
71+
onSuccess={(response) => this.setState({ sequenceDocument: response.data })}
72+
/>
73+
{sequenceDocument && (
74+
<SequenceDisplayCard
75+
collectionId={collectionId}
76+
sequenceDocument={sequenceDocument}
77+
onSuccess={this.onRefresh}
78+
/>
79+
)}
80+
</>
81+
);
82+
}
83+
}
84+
85+
export default compose(withFormActions, withUI)(CollectionSequence);

0 commit comments

Comments
 (0)