app/ItemView/MetadataGroupView.tsx (247 lines of code) (raw):

import "date-fns"; import React, { useEffect, useState } from "react"; import { TextareaAutosize, Input, InputLabel, FormLabel, Paper, FormControl, Typography, Grid, Select, MenuItem, FormGroup, Checkbox, FormControlLabel, TextField, } from "@material-ui/core"; import { MuiPickersUtilsProvider, KeyboardTimePicker, KeyboardDatePicker, } from "@material-ui/pickers"; import DateFnsUtils from "@date-io/date-fns"; import { VidispineField, VidispineFieldGroup, } from "../vidispine/field-group/VidispineFieldGroup"; import { VidispineItem } from "../vidispine/item/VidispineItem"; import { PlutoCustomData } from "../vidispine/field-group/CustomData"; import { makeStyles } from "@material-ui/core/styles"; import ChipInput from "material-ui-chip-input"; import Autocomplete from "@material-ui/lab/Autocomplete"; import TagField from "../FieldControls/TagField"; import LookupField from "../FieldControls/LookupField"; import CheckboxField from "../FieldControls/CheckboxField"; import DropdownField from "../FieldControls/DropdownField"; import TextareaField from "../FieldControls/TextareaField"; import StringField from "../FieldControls/StringField"; import TimestampField from "../FieldControls/TimestampField"; import FieldTypeNotRecognised from "../FieldControls/FieldTypeNotRecognised"; import VidispineSearchDoc from "../vidispine/search/VidispineSearch"; enum MetadataGroupViewMode { MetadataView, MetadataEdit, SearchForm, } interface MetadataGroupViewProps { group: VidispineFieldGroup; content: VidispineItem | Map<string, string[]>; elevation: number; mode: MetadataGroupViewMode; noHeader?: boolean; valueDidChange: (name: string, values: string[]) => void; projectIdToLoad?: number; } export const metadataStylesHook = makeStyles((theme) => ({ root: { warning: { color: theme.palette.warning, }, }, metagroup: { marginTop: "1.5rem", padding: "0.75rem", }, inputField: { minWidth: "100%", maxWidth: "100%", }, disabledIcon: { opacity: "50%", }, enabledIcon: { opacity: "100%", }, })); const MetadataGroupView: React.FC<MetadataGroupViewProps> = (props) => { const classes = metadataStylesHook(); /** * returns a suitable control for the field data * @param fieldname server name of the field. * @param viewHints a ViewHints instance consisiting of the "custom data" which tells us the label content, * type of field to render, etc. * @param maybeValues an optional array of strings giving the values assigned to the field. It's up to the * specific field type how this is interpreted * @param controlId html id for the control */ const elementForDatatype = ( fieldname: string, viewHints: PlutoCustomData, maybeValues: string[] | undefined, controlId: string ) => { switch (viewHints.type) { case "tags": let valuesToUse = maybeValues; return ( <TagField fieldname={fieldname} viewHints={viewHints} controlId={controlId} parentReadonly={props.mode == MetadataGroupViewMode.MetadataView} //always force read-only if in view mode ignoreHintsReadonly={props.mode == MetadataGroupViewMode.SearchForm} //always allow edit in search form mode valueDidChange={props.valueDidChange} classes={classes} maybeValues={valuesToUse} /> ); case "lookup": return ( <LookupField fieldname={fieldname} viewHints={viewHints} controlId={controlId} parentReadonly={props.mode == MetadataGroupViewMode.MetadataView} ignoreHintsReadonly={props.mode == MetadataGroupViewMode.SearchForm} //always allow edit in search form mode valueDidChange={props.valueDidChange} classes={classes} maybeValues={maybeValues} /> ); case "checkbox": return ( <CheckboxField fieldname={fieldname} viewHints={viewHints} controlId={controlId} parentReadonly={props.mode == MetadataGroupViewMode.MetadataView} ignoreHintsReadonly={props.mode == MetadataGroupViewMode.SearchForm} //always allow edit in search form mode valueDidChange={props.valueDidChange} classes={classes} maybeValues={maybeValues} /> ); case "dropdown": return ( <DropdownField fieldname={fieldname} viewHints={viewHints} controlId={controlId} parentReadonly={props.mode == MetadataGroupViewMode.MetadataView} ignoreHintsReadonly={props.mode == MetadataGroupViewMode.SearchForm} //always allow edit in search form mode valueDidChange={props.valueDidChange} classes={classes} maybeValues={maybeValues} /> ); case "textarea": return ( <TextareaField fieldname={fieldname} viewHints={viewHints} controlId={controlId} parentReadonly={props.mode == MetadataGroupViewMode.MetadataView} ignoreHintsReadonly={props.mode == MetadataGroupViewMode.SearchForm} //always allow edit in search form mode valueDidChange={props.valueDidChange} classes={classes} maybeValues={maybeValues} /> ); case "string": return ( <StringField fieldname={fieldname} viewHints={viewHints} controlId={controlId} parentReadonly={props.mode == MetadataGroupViewMode.MetadataView} ignoreHintsReadonly={props.mode == MetadataGroupViewMode.SearchForm} //always allow edit in search form mode valueDidChange={props.valueDidChange} classes={classes} maybeValues={maybeValues} /> ); case "timestamp": //FIXME: we should present a range if in SearchForm mode return ( <TimestampField fieldname={fieldname} viewHints={viewHints} controlId={controlId} parentReadonly={props.mode == MetadataGroupViewMode.MetadataView} ignoreHintsReadonly={props.mode == MetadataGroupViewMode.SearchForm} //always allow edit in search form mode valueDidChange={props.valueDidChange} classes={classes} maybeValues={maybeValues} /> ); default: return ( <FieldTypeNotRecognised fieldname={fieldname} viewHints={viewHints} controlId={controlId} parentReadonly={props.mode == MetadataGroupViewMode.MetadataView} ignoreHintsReadonly={props.mode == MetadataGroupViewMode.SearchForm} //always allow edit in search form mode valueDidChange={props.valueDidChange} classes={classes} maybeValues={maybeValues} /> ); } }; const valuesFromContent = (field: VidispineField) => { if (props.content instanceof VidispineItem) { return props.content.getMetadataValuesInGroup( field.name, props.group.name ); } else { return props.content.get(field.name); } }; return ( <Paper elevation={props.elevation} classes={{ root: classes.metagroup }}> {props.noHeader ? null : ( <Typography variant="h3">{props.group.name}</Typography> )} <Grid container direction="row" justify="flex-start" alignItems="flex-start" spacing={2} > {props.group.field.map((entry, idx) => { const field = new VidispineField(entry); const controlId = `${props.group.name}-${idx}`; const maybeValues: string[] | undefined = valuesFromContent(field); const viewHints = field.getCustomData(); if (!viewHints) { console.log( `Field ${field.name} in ${props.group.name} has no view hints data` ); return null; } if (viewHints) { return ( <Grid item sm={6} key={idx}> {elementForDatatype( field.name, viewHints, maybeValues, controlId )} </Grid> ); } else { return null; } })} </Grid> </Paper> ); }; export { MetadataGroupViewMode }; export default MetadataGroupView;