diff --git a/package.json b/package.json
index e1139fb9..edca5f15 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@vidispine/admin-tool",
- "version": "25.3.0",
+ "version": "25.3.1",
"private": true,
"dependencies": {
"@devbookhq/splitter": "^1.3.2",
diff --git a/src/components/autoimport/AutoImportRuleDisplay.jsx b/src/components/autoimport/AutoImportRuleDisplay.jsx
index 305f5031..2211c1f9 100644
--- a/src/components/autoimport/AutoImportRuleDisplay.jsx
+++ b/src/components/autoimport/AutoImportRuleDisplay.jsx
@@ -19,6 +19,7 @@ export function AutoImportRuleType({ rule }) {
<>
+
}
label="Enabled"
/>
+
+ Priority
+
+ {JobPriority.map((priority) => (
+
+ ))}
+
+
}
label="File Name As Title"
diff --git a/src/components/item/ItemSubclipCreate.jsx b/src/components/item/ItemSubclipCreate.jsx
new file mode 100644
index 00000000..93f64230
--- /dev/null
+++ b/src/components/item/ItemSubclipCreate.jsx
@@ -0,0 +1,70 @@
+import Button from '@material-ui/core/Button';
+import Dialog from '@material-ui/core/Dialog';
+import DialogActions from '@material-ui/core/DialogActions';
+import DialogContent from '@material-ui/core/DialogContent';
+import DialogTitle from '@material-ui/core/DialogTitle';
+import Divider from '@material-ui/core/Divider';
+import { compose } from 'redux';
+
+import * as formActions from '../../formactions/item';
+import withFormActions from '../../hoc/withFormActions';
+import withUI from '../../hoc/withUI';
+
+import ItemSubclipCreateForm from './ItemSubclipCreateForm';
+
+const ITEM_SUBCLIP_CREATE_FORM = 'ITEM_SUBCLIP_CREATE_FORM';
+
+function ItemSubclipCreate({
+ open,
+ onClose,
+ onSuccess,
+ onFail,
+ openSnackBar,
+ submitForm,
+ itemId,
+ initialValues,
+ form = ITEM_SUBCLIP_CREATE_FORM,
+}) {
+ const onSubmitSuccess = (response, dispatch, props) => {
+ const messageContent = 'Subclip Job Created';
+ openSnackBar({ messageContent });
+ if (onSuccess) {
+ onSuccess(response, dispatch, props);
+ }
+ onClose();
+ };
+ const onSubmitFail = (error, dispatch, props) => {
+ const messageContent = 'Error Creating Subclip';
+ openSnackBar({ messageContent, messageColor: 'secondary' });
+ if (onFail) {
+ onFail(error, dispatch, props);
+ }
+ };
+ return (
+
+ );
+}
+
+export default compose(withUI, withFormActions)(ItemSubclipCreate);
diff --git a/src/components/item/ItemSubclipCreateForm.jsx b/src/components/item/ItemSubclipCreateForm.jsx
new file mode 100644
index 00000000..46c452f6
--- /dev/null
+++ b/src/components/item/ItemSubclipCreateForm.jsx
@@ -0,0 +1,168 @@
+import FormControl from '@material-ui/core/FormControl';
+import FormControlLabel from '@material-ui/core/FormControlLabel';
+import FormHelperText from '@material-ui/core/FormHelperText';
+import InputLabel from '@material-ui/core/InputLabel';
+import MenuItem from '@material-ui/core/MenuItem';
+import Typography from '@material-ui/core/Typography';
+import { reduxForm } from 'redux-form';
+
+import JobPriority from '../../const/JobPriority';
+import { required } from '../../utils/FieldValidation';
+import { TextField, Select } from '../form';
+import { loadShapeTagOptions } from '../shapetag/ShapeTagSelect';
+import { loadStorageOptions } from '../storage/StorageSelect';
+import BoolCheckbox from '../ui/BoolCheckbox';
+import Field from '../ui/Field';
+import FieldTypeArray from '../ui/FieldTypeArray';
+import FormSection from '../ui/FormSection';
+import { KeyValuePairType } from '../ui/FormType';
+import { StatefulAsyncSelect } from '../ui/Select';
+
+const queryParams = () => (
+ <>
+
+
+
+
+
+
+ mode
+
+
+
+ Rendermode of the transcoder
+
+
+
+
+
+
+
+
+
+ priority
+
+ {JobPriority.map((priority) => (
+
+ ))}
+
+ The priority to assign to the job. Default is MEDIUM
+
+
+
+ }
+ label="holdJob"
+ fullWidth
+ />
+ Created job in a HOLD state
+
+ >
+);
+
+function ItemSubclipCreateForm({ itemId, error, handleSubmit }) {
+ return (
+
+ );
+}
+
+export default reduxForm()(ItemSubclipCreateForm);
diff --git a/src/components/item/ItemTitle.jsx b/src/components/item/ItemTitle.jsx
index 278d9aa7..c52e3611 100644
--- a/src/components/item/ItemTitle.jsx
+++ b/src/components/item/ItemTitle.jsx
@@ -59,6 +59,7 @@ function ItemTitle({
breadcrumbList,
createShapeModal,
createSequenceModal,
+ createSubclipModal,
analyzeModal,
...props
}) {
@@ -150,6 +151,9 @@ function ItemTitle({
+
diff --git a/src/components/notification/NotificationTrigger.jsx b/src/components/notification/NotificationTrigger.jsx
index f785d608..bdca8b69 100644
--- a/src/components/notification/NotificationTrigger.jsx
+++ b/src/components/notification/NotificationTrigger.jsx
@@ -153,6 +153,8 @@ function StorageTriggerType({ trigger: { storage } }) {
triggerAction = 'create';
} else if ('delete' in storage) {
triggerAction = 'delete';
+ } else if ('modify' in storage) {
+ triggerAction = 'modify';
}
return ;
}
@@ -169,6 +171,8 @@ function FileTriggerType({ trigger: { file } }) {
triggerAction = 'close';
} else if ('delete' in file) {
triggerAction = 'delete';
+ } else if ('lost' in file) {
+ triggerAction = 'lost';
}
return ;
}
@@ -227,8 +231,22 @@ function DocumentTriggerType({ trigger: { document } }) {
triggerAction = 'create';
} else if ('delete' in document) {
triggerAction = 'delete';
+ } else if ('modify' in document) {
+ triggerAction = 'modify';
}
- return ;
+ return (
+ <>
+
+ {triggerAction === 'modify' && (
+ <>
+
+
+
+
+ >
+ )}
+ >
+ );
}
function DeletionLockTriggerType({ trigger: { deletionLock } }) {
diff --git a/src/components/notification/NotificationTriggerForm.jsx b/src/components/notification/NotificationTriggerForm.jsx
index 4db805f7..82b79637 100644
--- a/src/components/notification/NotificationTriggerForm.jsx
+++ b/src/components/notification/NotificationTriggerForm.jsx
@@ -11,6 +11,17 @@ import StatefulSelect from '../ui/StatefulSelect';
import { getTriggerEntity, getJobAction } from './NotificationTrigger';
+function NotificationTriggerMetadataModifyType() {
+ return (
+ <>
+
+
+
+
+ >
+ );
+}
+
function NotificationTriggerItemType(props) {
const { initialValues = {}, valueSelector, dirty } = props;
const name = props?.id || 'notificationDocument.trigger.item';
@@ -62,13 +73,13 @@ function NotificationTriggerStorageType(props) {
const name = props?.id || 'notificationDocument.trigger.storage';
let initialvalue;
if (dirty) {
- const item = valueSelector(name);
- initialvalue = item && Object.keys(item)[0];
+ const storage = valueSelector(name);
+ initialvalue = storage && Object.keys(storage)[0];
} else {
const { notificationDocument = {} } = initialValues;
const { trigger = {} } = notificationDocument;
- const { item } = trigger;
- initialvalue = item && Object.keys(item)[0];
+ const { storage } = trigger;
+ initialvalue = storage && Object.keys(storage)[0];
}
const onChange = (event, newValue, previousValue) => {
const prevState = valueSelector(name);
@@ -96,10 +107,12 @@ function NotificationTriggerStorageType(props) {
>
+
+
>
);
@@ -110,13 +123,13 @@ function NotificationTriggerFileType(props) {
const name = props?.id || 'notificationDocument.trigger.file';
let initialvalue;
if (dirty) {
- const item = valueSelector(name);
- initialvalue = item && Object.keys(item)[0];
+ const file = valueSelector(name);
+ initialvalue = file && Object.keys(file)[0];
} else {
const { notificationDocument = {} } = initialValues;
const { trigger = {} } = notificationDocument;
- const { item } = trigger;
- initialvalue = item && Object.keys(item)[0];
+ const { file } = trigger;
+ initialvalue = file && Object.keys(file)[0];
}
const onChange = (event, newValue, previousValue) => {
const prevState = valueSelector(name);
@@ -147,12 +160,14 @@ function NotificationTriggerFileType(props) {
+
+
>
);
}
@@ -162,13 +177,13 @@ function NotificationTriggerGroupType(props) {
const name = props?.id || 'notificationDocument.trigger.group';
let initialvalue;
if (dirty) {
- const item = valueSelector(name);
- initialvalue = item && Object.keys(item)[0];
+ const group = valueSelector(name);
+ initialvalue = group && Object.keys(group)[0];
} else {
const { notificationDocument = {} } = initialValues;
const { trigger = {} } = notificationDocument;
- const { item } = trigger;
- initialvalue = item && Object.keys(item)[0];
+ const { group } = trigger;
+ initialvalue = group && Object.keys(group)[0];
}
const onChange = (event, newValue, previousValue) => {
const prevState = valueSelector(name);
@@ -210,13 +225,13 @@ function NotificationTriggerShapeType(props) {
const name = props?.id || 'notificationDocument.trigger.shape';
let initialvalue;
if (dirty) {
- const item = valueSelector(name);
- initialvalue = item && Object.keys(item)[0];
+ const shape = valueSelector(name);
+ initialvalue = shape && Object.keys(shape)[0];
} else {
const { notificationDocument = {} } = initialValues;
const { trigger = {} } = notificationDocument;
- const { item } = trigger;
- initialvalue = item && Object.keys(item)[0];
+ const { shape } = trigger;
+ initialvalue = shape && Object.keys(shape)[0];
}
const onChange = (event, newValue, previousValue) => {
const prevState = valueSelector(name);
@@ -258,13 +273,13 @@ function NotificationTriggerAccessType(props) {
const name = props?.id || 'notificationDocument.trigger.access';
let initialvalue;
if (dirty) {
- const item = valueSelector(name);
- initialvalue = item && Object.keys(item)[0];
+ const access = valueSelector(name);
+ initialvalue = access && Object.keys(access)[0];
} else {
const { notificationDocument = {} } = initialValues;
const { trigger = {} } = notificationDocument;
- const { item } = trigger;
- initialvalue = item && Object.keys(item)[0];
+ const { access } = trigger;
+ initialvalue = access && Object.keys(access)[0];
}
const onChange = (event, newValue, previousValue) => {
const prevState = valueSelector(name);
@@ -306,13 +321,13 @@ function NotificationTriggerQuotaType(props) {
const name = props?.id || 'notificationDocument.trigger.quota';
let initialvalue;
if (dirty) {
- const item = valueSelector(name);
- initialvalue = item && Object.keys(item)[0];
+ const quota = valueSelector(name);
+ initialvalue = quota && Object.keys(quota)[0];
} else {
const { notificationDocument = {} } = initialValues;
const { trigger = {} } = notificationDocument;
- const { item } = trigger;
- initialvalue = item && Object.keys(item)[0];
+ const { quota } = trigger;
+ initialvalue = quota && Object.keys(quota)[0];
}
const onChange = (event, newValue, previousValue) => {
const prevState = valueSelector(name);
@@ -354,17 +369,17 @@ function NotificationTriggerDocumentType(props) {
const name = props?.id || 'notificationDocument.trigger.document';
let initialvalue;
if (dirty) {
- const item = valueSelector(name);
- initialvalue = item && Object.keys(item)[0];
+ const document = valueSelector(name);
+ initialvalue = document && Object.keys(document)[0];
} else {
const { notificationDocument = {} } = initialValues;
const { trigger = {} } = notificationDocument;
- const { item } = trigger;
- initialvalue = item && Object.keys(item)[0];
+ const { document } = trigger;
+ initialvalue = document && Object.keys(document)[0];
}
const onChange = (event, newValue, previousValue) => {
const prevState = valueSelector(name);
- const setValue = '';
+ const setValue = newValue === 'modify' ? {} : '';
if (prevState) {
const newState = update(prevState, {
[newValue]: {
@@ -377,6 +392,23 @@ function NotificationTriggerDocumentType(props) {
props?.change(name, { [newValue]: setValue });
}
};
+ // TODO Refactor as standalone component
+ // eslint-disable-next-line react/no-unstable-nested-components
+ function ValueComponent(value) {
+ switch (value) {
+ case 'modify':
+ return (
+
+ );
+ default:
+ return null;
+ }
+ }
return (
<>
+
+
>
);
}
@@ -400,13 +436,13 @@ function NotificationTriggerDeletionLockType(props) {
const name = props?.id || 'notificationDocument.trigger.deletionLock';
let initialvalue;
if (dirty) {
- const item = valueSelector(name);
- initialvalue = item && Object.keys(item)[0];
+ const deletionLock = valueSelector(name);
+ initialvalue = deletionLock && Object.keys(deletionLock)[0];
} else {
const { notificationDocument = {} } = initialValues;
const { trigger = {} } = notificationDocument;
- const { item } = trigger;
- initialvalue = item && Object.keys(item)[0];
+ const { deletionLock } = trigger;
+ initialvalue = deletionLock && Object.keys(deletionLock)[0];
}
const onChange = (event, newValue, previousValue) => {
const prevState = valueSelector(name);
@@ -447,17 +483,6 @@ function NotificationTriggerDeletionLockType(props) {
);
}
-function NotificationTriggerMetadataModifyType() {
- return (
- <>
-
-
-
-
- >
- );
-}
-
function NotificationTriggerMetadataType(props) {
const { initialValues = {}, valueSelector, dirty } = props;
const name = props?.id || 'notificationDocument.trigger.metadata';
@@ -536,8 +561,8 @@ function NotificationTriggerCollectionType(props) {
const name = props?.id || 'notificationDocument.trigger.collection';
let initialvalue;
if (dirty) {
- const item = valueSelector(name);
- initialvalue = item && Object.keys(item)[0];
+ const collection = valueSelector(name);
+ initialvalue = collection && Object.keys(collection)[0];
} else {
const { notificationDocument = {} } = initialValues;
const { trigger = {} } = notificationDocument;
@@ -667,7 +692,7 @@ function NotificationJobTriggerType(props) {
-
+
diff --git a/src/components/ui/FilterTextField.jsx b/src/components/ui/FilterTextField.jsx
index ec122808..9d0ae00d 100644
--- a/src/components/ui/FilterTextField.jsx
+++ b/src/components/ui/FilterTextField.jsx
@@ -1,4 +1,4 @@
-import { useState } from 'react';
+import { useState, useEffect } from 'react';
import IconButton from '@material-ui/core/IconButton';
import InputAdornment from '@material-ui/core/InputAdornment';
@@ -38,16 +38,14 @@ function FilterTextField({
const filterOptions = fuzzySearch(newValue, options, minScore, optionsKey);
onChangeOptions(filterOptions);
}, DEBOUNCE_WAIT);
- const onChange = (event) => {
- setValue(event.target.value);
- const newValue = event?.target?.value;
- onFilter(newValue);
- };
+ const onChange = (event) => setValue(event.target.value);
const onReset = () => {
setValue('');
onFilter('');
};
-
+ useEffect(() => {
+ onFilter(value);
+ }, [onFilter, value, options]);
return (
generatePath('/metadata-field/:fieldName/', params),
fieldGroupList: (params) => generatePath('/field-group/', params),
fieldGroup: (params) => generatePath('/field-group/:groupName/', params),
+ job: (params) => generatePath('/job/:jobId', params),
};
diff --git a/src/containers/Auth.jsx b/src/containers/Auth.jsx
index f204d5e0..31e2a5f8 100644
--- a/src/containers/Auth.jsx
+++ b/src/containers/Auth.jsx
@@ -173,7 +173,8 @@ class Auth extends Component {
const baseURL = propsBaseURL.replace(/\/+$/, '');
const { cookies } = this.props;
cookies.set(AUTH_VIDISPINE_SERVER_URL, baseURL, { path: APP_BASENAME });
- if (this.windowVidispineUrl !== baseURL) this.useDevProxy = false;
+ if (this.windowVidispineUrl !== undefined && this.windowVidispineUrl !== baseURL)
+ this.useDevProxy = false;
if (this.useContainerProxy) {
api.defaultClient.defaults.headers[PROXY_HEADER] = baseURL;
api.defaultClient.defaults.baseURL = window.location.origin;
diff --git a/src/containers/Item.jsx b/src/containers/Item.jsx
index 1552e36e..18508c7a 100644
--- a/src/containers/Item.jsx
+++ b/src/containers/Item.jsx
@@ -14,6 +14,7 @@ import ItemImpImport from '../components/item/ItemImpImport';
import ItemRelationDialog from '../components/item/ItemRelation';
import ItemSequenceCreate from '../components/item/ItemSequenceCreate';
import ItemShapeCreate from '../components/item/ItemShapeCreate';
+import ItemSubclipCreate from '../components/item/ItemSubclipCreate';
import ItemThumbnailDialog from '../components/item/ItemThumbnail';
import ItemTitle from '../components/item/ItemTitle';
import ItemTranscode from '../components/item/ItemTranscode';
@@ -90,6 +91,7 @@ const ITEM_REMOVEALLSHAPES_DIALOG = 'ITEM_REMOVEALLSHAPES_DIALOG';
const ITEM_IMPIMPORT_DIALOG = 'ITEM_IMPIMPORT_DIALOG';
const ITEM_ANALYZE_DIALOG = 'ITEM_ANALYZE_DIALOG';
const ITEM_SEQUENCE_CREATE_DIALOG = 'ITEM_SEQUENCE_CREATE_DIALOG';
+const ITEM_SUBCLIP_CREATE_DIALOG = 'ITEM_SUBCLIP_CREATE_DIALOG';
const EXTERNALID_TAB = 'EXTERNALID_TAB';
const TAB_TITLE = [
@@ -334,6 +336,7 @@ class Item extends PureComponent {
createShapeModal={ITEM_SHAPE_CREATE_DIALOG}
analyzeModal={ITEM_ANALYZE_DIALOG}
createSequenceModal={ITEM_SEQUENCE_CREATE_DIALOG}
+ createSubclipModal={ITEM_SUBCLIP_CREATE_DIALOG}
{...props}
/>
);
@@ -419,6 +422,11 @@ class Item extends PureComponent {
}
itemId={itemId}
/>
+ history.push(routes.job({ jobId: response.data.jobId }))}
+ itemId={itemId}
+ />
{
...response,
}));
});
+
+export const onCreateItemSubclip = withSubmissionError((form, dispatch, props) => {
+ const { queryParams } = form;
+ const itemId = props.itemId || form.itemId;
+ const path = `/API/item/${itemId}/subclip`;
+ return ItemApi.createTranscode({
+ itemId,
+ queryParams,
+ path,
+ });
+});
diff --git a/src/formactions/user.js b/src/formactions/user.js
index d72f1f71..355b95d3 100644
--- a/src/formactions/user.js
+++ b/src/formactions/user.js
@@ -96,11 +96,19 @@ export function onGetUserToken(form, dispatch, props) {
if (bearer) {
headerProps.authorization = bearer.startsWith('Bearer ') ? bearer : `'Bearer ${bearer}`;
}
- if (token) {
- return onWhoAmI(form, dispatch, props);
- }
const baseURL = formBaseURL.replace(/\/+$/, '');
const proxyURL = useContainerProxy || useDevProxy ? undefined : baseURL;
+
+ if (token) {
+ return onWhoAmI(form, dispatch, props).then(({ userName }) => ({
+ data: token,
+ userName,
+ runAs,
+ baseURL,
+ token,
+ }));
+ }
+
const userName = props.userName || form.userName || headers.username;
return UserApi.getUserToken({
username: userName,