Skip to content

Commit 9924392

Browse files
authored
Allow tracks in event asset upload (#698)
* Allow tracks in event asset upload Old logic dictates that media of type track cannot be in the asset upload tab of the event details or new event wizard. Since subtitles are now tracks, this logic finally breaks. Instead of relying on checking for type track to differentiate between options for source upload and asset upload, this commit instead uses the key in the list provider that is there for this exact purpose. * Fix import statement * Add new optional keys for displaying asset upload Adds support for `showForNewEvents` and `showForExistingEvents`, two keys that specifically specify whether an asset upload option should show up for new events or existing events. Previously, an asset upload option would always show for new and existing events, but now this can be configured in detail.
1 parent c57779c commit 9924392

12 files changed

Lines changed: 119 additions & 109 deletions

File tree

src/components/events/partials/ModalTabsAndPages/EventDetailsAssetsAddAsset.tsx

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,12 @@ import EventDetailsTabHierarchyNavigation from "./EventDetailsTabHierarchyNaviga
33
import Notifications from "../../../shared/Notifications";
44
import { style_button_spacing } from "../../../../utils/eventDetailsUtils";
55
import { Formik, FormikProps } from "formik";
6-
import { getAssetUploadOptions } from "../../../../selectors/eventSelectors";
76
import { translateOverrideFallback } from "../../../../utils/utils";
87
import { useAppDispatch, useAppSelector } from "../../../../store";
98
import { setModalAssetsTabHierarchy, updateAssets } from "../../../../slices/eventDetailsSlice";
109
import { AssetTabHierarchy } from "../modals/EventDetails";
1110
import { useTranslation } from "react-i18next";
11+
import { getUploadAssetOptions } from "../../../../selectors/eventDetailsSelectors";
1212
import ButtonLikeAnchor from "../../../shared/ButtonLikeAnchor";
1313
import ModalContentTable from "../../../shared/modals/ModalContentTable";
1414

@@ -23,15 +23,10 @@ const EventDetailsAssetsAddAsset = ({
2323
const { t } = useTranslation();
2424
const dispatch = useAppDispatch();
2525

26-
const uploadAssetOptions = useAppSelector(state => getAssetUploadOptions(state));
26+
const uploadAssetOptions = useAppSelector(state => getUploadAssetOptions(state));
2727

2828
const initialValues: { [key: string]: File } = {};
2929

30-
// Get upload assets that are not of type track
31-
const uploadAssets = uploadAssetOptions.filter(
32-
(asset) => asset.type !== "track"
33-
);
34-
3530
const openSubTab = (subTabName: AssetTabHierarchy) => {
3631
dispatch(setModalAssetsTabHierarchy(subTabName));
3732
};
@@ -81,14 +76,14 @@ const EventDetailsAssetsAddAsset = ({
8176
{/* file select for upload for different types of assets */}
8277
<table className="main-tbl">
8378
<tbody>
84-
{uploadAssets.length === 0 ? (
79+
{uploadAssetOptions && uploadAssetOptions.length === 0 ? (
8580
<tr>
8681
<td>
8782
{t("EVENTS.EVENTS.NEW.UPLOAD_ASSET.NO_OPTIONS")}
8883
</td>
8984
</tr>
9085
) : (
91-
uploadAssets.map((asset, key) => (
86+
uploadAssetOptions && uploadAssetOptions.map((asset, key) => (
9287
<tr key={key}>
9388
<td>
9489
{" "}

src/components/events/partials/ModalTabsAndPages/EventDetailsAssetsTab.tsx

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,9 +162,7 @@ const EventDetailsAssetsTab = ({
162162
<th className="medium">
163163
{!isFetchingAssetUploadOptions &&
164164
!!uploadAssetOptions &&
165-
uploadAssetOptions.filter(
166-
(asset) => asset.type !== "track"
167-
).length > 0 &&
165+
uploadAssetOptions.length > 0 &&
168166
!transactionsReadOnly &&
169167
hasAccess(
170168
"ROLE_UI_EVENTS_DETAILS_ASSETS_EDIT",

src/components/events/partials/ModalTabsAndPages/NewAssetUploadPage.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,6 @@ const NewAssetUploadPage = <T extends RequiredFormProps>({
3030

3131
const uploadAssetOptions = useAppSelector(state => getAssetUploadOptions(state));
3232

33-
// Get upload assets that are not of type track
34-
const uploadAssets = uploadAssetOptions.filter(
35-
(asset) => asset.type !== "track"
36-
);
37-
3833
// if user not chose upload in step before, the skip this step
3934
if (formik.values.sourceMode !== "UPLOAD") {
4035
nextPage(formik.values);
@@ -61,14 +56,14 @@ const NewAssetUploadPage = <T extends RequiredFormProps>({
6156
<div className="obj-container">
6257
<table className="main-tbl">
6358
<tbody>
64-
{uploadAssets.length === 0 ? (
59+
{uploadAssetOptions.length === 0 ? (
6560
<tr>
6661
<td>
6762
{t("EVENTS.EVENTS.NEW.UPLOAD_ASSET.NO_OPTIONS")}
6863
</td>
6964
</tr>
7065
) : (
71-
uploadAssets.map((asset, key) => (
66+
uploadAssetOptions.map((asset, key) => (
7267
<tr key={key}>
7368
<td>
7469
{" "}

src/components/events/partials/wizards/NewEventSummary.tsx

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,26 +58,21 @@ const NewEventSummary = <T extends RequiredFormProps>({
5858
const extendedMetadata = useAppSelector(state => getExtendedEventMetadata(state));
5959
const workflowDef = useAppSelector(state => getWorkflowDef(state));
6060

61-
// Get upload assets that are not of type track
62-
const uploadAssetsOptionsNonTrack = uploadAssetOptions.filter(
63-
(asset) => asset.type !== "track"
64-
);
65-
6661
// upload asset that user has provided
6762
let uploadAssetsNonTrack: {
6863
name: string,
6964
translate?: string,
7065
value: any,
7166
}[] = [];
72-
for (let i = 0; uploadAssetsOptionsNonTrack.length > i; i++) {
73-
let fieldValue = formik.values[uploadAssetsOptionsNonTrack[i].id];
67+
for (let i = 0; uploadAssetOptions.length > i; i++) {
68+
let fieldValue = formik.values[uploadAssetOptions[i].id];
7469
if (!!fieldValue) {
75-
const displayOverride = uploadAssetsOptionsNonTrack[i].displayOverride as ParseKeys
70+
const displayOverride = uploadAssetOptions[i].displayOverride as ParseKeys
7671
uploadAssetsNonTrack = uploadAssetsNonTrack.concat({
77-
name: uploadAssetsOptionsNonTrack[i].id,
72+
name: uploadAssetOptions[i].id,
7873
translate: !!displayOverride
7974
? t(displayOverride)
80-
: translateOverrideFallback(uploadAssetsOptionsNonTrack[i], t),
75+
: translateOverrideFallback(uploadAssetOptions[i], t),
8176
value: fieldValue,
8277
});
8378
}

src/components/events/partials/wizards/NewEventWizard.tsx

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@ import {
1414
getAssetUploadOptions,
1515
getEventMetadata,
1616
getExtendedEventMetadata,
17+
getSourceUploadOptions,
1718
} from "../../../../selectors/eventSelectors";
1819
import { useAppDispatch, useAppSelector } from "../../../../store";
1920
import { getOrgProperties, getUserInformation } from "../../../../selectors/userInfoSelectors";
20-
import { MetadataCatalog, UploadAssetOption, postNewEvent } from "../../../../slices/eventSlice";
21+
import { MetadataCatalog, UploadOption, postNewEvent } from "../../../../slices/eventSlice";
2122
import { UserInfoState } from "../../../../slices/userInfoSlice";
2223
import { removeNotificationWizardForm } from "../../../../slices/notificationSlice";
2324
import NewMetadataCommonPage from "../ModalTabsAndPages/NewMetadataCommonPage";
@@ -34,7 +35,8 @@ const NewEventWizard: React.FC<{
3435
}) => {
3536
const dispatch = useAppDispatch();
3637

37-
const uploadAssetOptions = useAppSelector(state => getAssetUploadOptions(state));
38+
const uploadSourceOptions = useAppSelector(state => getSourceUploadOptions(state));
39+
const assetUploadOptions = useAppSelector(state => getAssetUploadOptions(state));
3840
const metadataFields = useAppSelector(state => getEventMetadata(state));
3941
const extendedMetadata = useAppSelector(state => getExtendedEventMetadata(state));
4042
const user = useAppSelector(state => getUserInformation(state));
@@ -56,7 +58,7 @@ const NewEventWizard: React.FC<{
5658
const initialValues = getInitialValues(
5759
metadataFields,
5860
extendedMetadata,
59-
uploadAssetOptions,
61+
uploadSourceOptions,
6062
user,
6163
);
6264

@@ -88,9 +90,7 @@ const NewEventWizard: React.FC<{
8890
{
8991
translation: "EVENTS.EVENTS.NEW.UPLOAD_ASSET.CAPTION",
9092
name: "upload-asset",
91-
hidden:
92-
uploadAssetOptions.filter((asset) => asset.type !== "track").length ===
93-
0,
93+
hidden: assetUploadOptions.length === 0,
9494
},
9595
{
9696
translation: "EVENTS.EVENTS.NEW.PROCESSING.CAPTION",
@@ -250,7 +250,7 @@ const NewEventWizard: React.FC<{
250250
const getInitialValues = (
251251
metadataFields: MetadataCatalog,
252252
extendedMetadata: MetadataCatalog[],
253-
uploadAssetOptions: UploadAssetOption[],
253+
uploadSourceOptions: UploadOption[],
254254
user: UserInfoState
255255
) => {
256256
let initialValues = initialFormValuesNewEvents;
@@ -289,20 +289,16 @@ const getInitialValues = (
289289
}
290290

291291
// Add possible files that can be uploaded in source step
292-
if (!!uploadAssetOptions) {
292+
if (!!uploadSourceOptions) {
293293
initialValues.uploadAssetsTrack = [];
294294
// Sort by displayOrder
295-
uploadAssetOptions = uploadAssetOptions.slice().sort((a, b) => a.displayOrder - b.displayOrder)
295+
uploadSourceOptions = uploadSourceOptions.slice().sort((a, b) => a.displayOrder - b.displayOrder)
296296
// initial value of upload asset needs to be null, because object (file) is saved there
297-
for (const option of uploadAssetOptions) {
298-
if (option.type === "track") {
299-
initialValues.uploadAssetsTrack.push({
300-
...option,
301-
file: undefined,
302-
});
303-
} else {
304-
initialValues[option.id] = null;
305-
}
297+
for (const option of uploadSourceOptions) {
298+
initialValues.uploadAssetsTrack.push({
299+
...option,
300+
file: undefined,
301+
});
306302
};
307303
}
308304

src/i18n/org/opencastproject/adminui/languages/lang-en_US.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,8 @@
573573
"CAPTIONS_WEBVTT": "Captions WebVTT",
574574
"PREVIEW_IMAGE": "Preview image",
575575
"SMIL": "Smil catalog",
576-
"TRACK_PARTS": "Track parts"
576+
"TRACK_PARTS": "Track parts",
577+
"SUBTITLES": "Subtitles"
577578
}
578579
},
579580
"ACCESS": {

src/selectors/eventDetailsSelectors.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ export const isTransactionReadOnly = (state: RootState) =>
4040
state.eventDetails.transactionsReadOnly;
4141
export const getUploadAssetOptions = (state: RootState) =>
4242
state.eventDetails.uploadAssetOptions;
43+
export const getUploadSourceOptions = (state: RootState) =>
44+
state.eventDetails.uploadSourceOptions;
4345
export const getAssetAttachments = (state: RootState) =>
4446
state.eventDetails.assetAttachments;
4547
export const getAssetAttachmentDetails = (state: RootState) =>

src/selectors/eventSelectors.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export const getSchedulingSeriesOptions = (state: RootState) =>
1717
state.events.schedulingInfo.seriesOptions;
1818
export const getTotalEvents = (state: RootState) => state.events.total;
1919
export const getAssetUploadOptions = (state: RootState) => state.events.uploadAssetOptions;
20+
export const getSourceUploadOptions = (state: RootState) => state.events.uploadSourceOptions;
2021
export const isFetchingAssetUploadOptions = (state: RootState) =>
2122
state.events.isFetchingAssetUploadOptions;
2223
export const getAssetUploadWorkflow = (state: RootState) =>

src/slices/eventDetailsSlice.ts

Lines changed: 43 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { createAppAsyncThunk } from '../createAsyncThunkWithTypes';
2727
import { DataResolution, Statistics, TimeMode, fetchStatistics, fetchStatisticsValueUpdate } from './statisticsSlice';
2828
import { enrichPublications } from '../thunks/assetsThunks';
2929
import { TransformedAcl } from './aclDetailsSlice';
30-
import { MetadataCatalog } from './eventSlice';
30+
import { MetadataCatalog, UploadOption } from './eventSlice';
3131
import { Event } from "./eventSlice";
3232
import {
3333
AssetTabHierarchy,
@@ -116,16 +116,6 @@ type Device = {
116116
// url: string,
117117
}
118118

119-
export type UploadAssetOption = {
120-
id: string,
121-
title: string, // translation key
122-
type: string, // "track", "attachment" etc.
123-
flavorType: string,
124-
flavorSubType: string,
125-
accept: string,
126-
displayOrder: number,
127-
}
128-
129119
export type Publication = {
130120
enabled: boolean,
131121
icon?: string,
@@ -229,7 +219,8 @@ type EventDetailsState = {
229219
publications: number,
230220
},
231221
transactionsReadOnly: boolean,
232-
uploadAssetOptions: UploadAssetOption[] | undefined,
222+
uploadSourceOptions: UploadOption[] | undefined,
223+
uploadAssetOptions: UploadOption[] | undefined,
233224
assetAttachments: Array< Assets & {
234225
type: string,
235226
}>,
@@ -464,6 +455,7 @@ const initialState: EventDetailsState = {
464455
publications: 0,
465456
},
466457
transactionsReadOnly: false,
458+
uploadSourceOptions: [],
467459
uploadAssetOptions: [],
468460
assetAttachments: [],
469461
assetAttachmentDetails: {
@@ -672,20 +664,26 @@ export const fetchAssets = createAppAsyncThunk('eventDetails/fetchAssets', async
672664
);
673665
const resourceOptionsListResponse = await resourceOptionsListRequest.data;
674666

675-
let uploadAssetOptions: UploadAssetOption[] | undefined = [];
676667
const optionsData = formatUploadAssetOptions(resourceOptionsListResponse);
677668

678-
for (const option of optionsData.options) {
679-
if (option.type !== "track") {
680-
uploadAssetOptions.push({ ...option });
681-
}
669+
if (transactionsReadOnly) {
670+
dispatch(
671+
addNotification({
672+
type: "warning",
673+
key: "ACTIVE_TRANSACTION",
674+
duration: -1,
675+
parameter: undefined,
676+
context: NOTIFICATION_CONTEXT
677+
})
678+
);
682679
}
683680

684-
// if no asset options, undefine the option variable
685-
uploadAssetOptions =
686-
uploadAssetOptions.length > 0 ? uploadAssetOptions : undefined;
687-
688-
return { assets, transactionsReadOnly, uploadAssetOptions }
681+
return {
682+
assets,
683+
transactionsReadOnly,
684+
uploadAssetOptions: optionsData.assetOptions,
685+
uploadSourceOptions: optionsData.sourceOptions
686+
}
689687
});
690688

691689
const formatUploadAssetOptions = (optionsData: { [key: string]: string }) => {
@@ -694,12 +692,17 @@ const formatUploadAssetOptions = (optionsData: { [key: string]: string }) => {
694692
const workflowPrefix = "EVENTS.EVENTS.NEW.UPLOAD_ASSET.WORKFLOWDEFID";
695693

696694
let optionsResult: {
695+
assetOptions: UploadOption[],
696+
sourceOptions: UploadOption[],
697697
workflow?: string,
698-
options: UploadAssetOption[],
699698
} = {
700-
options: []
699+
assetOptions: [],
700+
sourceOptions: [],
701+
workflow: "",
701702
};
702-
let uploadOptions = [];
703+
704+
let uploadAssets: UploadOption[] = [];
705+
let uploadSource: UploadOption[] = [];
703706

704707
for (const [key, value] of Object.entries(optionsData)) {
705708
if (key.charAt(0) !== "$") {
@@ -708,18 +711,26 @@ const formatUploadAssetOptions = (optionsData: { [key: string]: string }) => {
708711
key.indexOf(optionPrefixSource) >= 0
709712
) {
710713
// parse upload asset options
711-
let options: UploadAssetOption = JSON.parse(value);
714+
let options: UploadOption = JSON.parse(value);
712715
if (!options["title"]) {
713716
options["title"] = key;
714717
}
715-
uploadOptions.push({ ...options });
718+
if ((options["showForExistingEvents"] !== undefined && (key.indexOf(optionPrefixAsset) >= 0 && options["showForExistingEvents"]))
719+
|| (options["showForExistingEvents"] === undefined && (key.indexOf(optionPrefixAsset) >= 0))) {
720+
uploadAssets.push({ ...options });
721+
}
722+
if ((options["showForExistingEvents"] !== undefined && (key.indexOf(optionPrefixSource) >= 0 && options["showForExistingEvents"]))
723+
|| (options["showForExistingEvents"] === undefined && (key.indexOf(optionPrefixSource) >= 0))) {
724+
uploadSource.push({ ...options });
725+
}
716726
} else if (key.indexOf(workflowPrefix) >= 0) {
717727
// parse upload workflow definition id
718-
optionsResult["workflow"] = value;
728+
optionsResult.workflow = value;
719729
}
720730
}
721731
}
722-
optionsResult["options"] = uploadOptions;
732+
optionsResult.assetOptions = uploadAssets;
733+
optionsResult.sourceOptions = uploadSource;
723734

724735
return optionsResult;
725736
};
@@ -1619,7 +1630,7 @@ export const updateAssets = createAppAsyncThunk('eventDetails/updateAssets', asy
16191630
let formData = new FormData();
16201631

16211632
let assets: {
1622-
options: UploadAssetOption[],
1633+
options: UploadOption[],
16231634
} = {
16241635
options: [],
16251636
};
@@ -1922,12 +1933,14 @@ const eventDetailsSlice = createSlice({
19221933
assets: EventDetailsState["assets"],
19231934
transactionsReadOnly: EventDetailsState["transactionsReadOnly"],
19241935
uploadAssetOptions: EventDetailsState["uploadAssetOptions"],
1936+
uploadSourceOptions: EventDetailsState["uploadSourceOptions"],
19251937
}>) => {
19261938
state.statusAssets = 'succeeded';
19271939
const eventDetails = action.payload;
19281940
state.assets = eventDetails.assets;
19291941
state.transactionsReadOnly = eventDetails.transactionsReadOnly;
19301942
state.uploadAssetOptions = eventDetails.uploadAssetOptions;
1943+
state.uploadSourceOptions = eventDetails.uploadSourceOptions;
19311944
})
19321945
.addCase(fetchAssets.rejected, (state, action) => {
19331946
state.statusAssets = 'failed';

0 commit comments

Comments
 (0)