diff --git a/src/main/MainMenu.tsx b/src/main/MainMenu.tsx index dcbd193b2..f2c5cc99f 100644 --- a/src/main/MainMenu.tsx +++ b/src/main/MainMenu.tsx @@ -17,7 +17,6 @@ import { basicButtonStyle } from "../cssStyles"; import { setIsPlaying } from "../redux/videoSlice"; import { useTranslation } from "react-i18next"; -import { resetPostRequestState as metadataResetPostRequestState } from "../redux/metadataSlice"; import { resetPostRequestState } from "../redux/workflowPostSlice"; import { setIsDisplayEditView } from "../redux/subtitleSlice"; @@ -126,7 +125,6 @@ export const MainMenuButton: React.FC = ({ dispatch(setIsPlaying(false)); // Reset states dispatch(resetPostRequestState()); - dispatch(metadataResetPostRequestState()); }; const mainMenuButtonStyle = css({ diff --git a/src/main/Metadata.tsx b/src/main/Metadata.tsx index 49cfcb3b1..e1ced778d 100644 --- a/src/main/Metadata.tsx +++ b/src/main/Metadata.tsx @@ -6,15 +6,12 @@ import { calendarStyle, errorBoxStyle, selectFieldStyle, titleStyle, titleStyleB import { useAppDispatch, useAppSelector } from "../redux/store"; import { fetchMetadata, - postMetadata, selectCatalogs, Catalog, MetadataField, setFieldValue, selectGetError, selectGetStatus, - selectPostError, - selectPostStatus, setFieldReadonly, } from "../redux/metadataSlice"; @@ -49,8 +46,6 @@ const Metadata: React.FC = () => { const catalogs = useAppSelector(selectCatalogs); const getStatus = useAppSelector(selectGetStatus); const getError = useAppSelector(selectGetError); - const postStatus = useAppSelector(selectPostStatus); - const postError = useAppSelector(selectPostError); const theme = useTheme(); // Try to fetch URL from external API @@ -433,7 +428,7 @@ const Metadata: React.FC = () => { /** * Callback for when the form is submitted - * Saves values in redux state and sends them to Opencast + * Saves values in redux state * @param values */ // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -458,8 +453,6 @@ const Metadata: React.FC = () => { } }); - // Send updated values to Opencast - dispatch(postMetadata()); }); }; @@ -730,36 +723,6 @@ const Metadata: React.FC = () => { return renderCatalog(catalog, i, {}); })} - {/* -
- {t("metadata.submit-helpertext", { buttonName: t("metadata.submit-button") })} -
- - -
- - -
*/} - -
- A problem occurred during communication with Opencast.
- Changes could not be saved to Opencast.

- {postError ? "Details: " + postError : "No error details are available."}
-
- {/* For debugging the forms current values*/} {/* {({ values }) => ( diff --git a/src/main/Save.tsx b/src/main/Save.tsx index cc78e929b..b1241c2e2 100644 --- a/src/main/Save.tsx +++ b/src/main/Save.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect } from "react"; import { css } from "@emotion/react"; import { @@ -22,8 +22,9 @@ import { CallbackButton, PageButton } from "./Finish"; import { useTranslation } from "react-i18next"; import { - postMetadata, selectPostError, selectPostStatus, setHasChanges as metadataSetHasChanges, + setHasChanges as metadataSetHasChanges, selectHasChanges as metadataSelectHasChanges, + selectCatalogs, } from "../redux/metadataSlice"; import { selectSubtitles, selectHasChanges as selectSubtitleHasChanges, @@ -45,8 +46,6 @@ const Save: React.FC = () => { const postWorkflowStatus = useAppSelector(selectStatus); const postError = useAppSelector(selectError); - const postMetadataStatus = useAppSelector(selectPostStatus); - const postMetadataError = useAppSelector(selectPostError); const theme = useTheme(); const metadataHasChanges = useAppSelector(metadataSelectHasChanges); const hasChanges = useAppSelector(selectHasChanges); @@ -62,7 +61,7 @@ const Save: React.FC = () => { const render = () => { // Post (successful) save - if (postWorkflowStatus === "success" && postMetadataStatus === "success" + if (postWorkflowStatus === "success" && !hasChanges && !metadataHasChanges && !subtitleHasChanges) { return ( <> @@ -95,12 +94,6 @@ const Save: React.FC = () => { {t("various.error-text")}
{postError ? t("various.error-details-text", { errorMessage: postError }) : t("various.error-text")}
-
- {t("various.error-text")}
- {postMetadataError ? - t("various.error-details-text", { errorMessage: postMetadataError }) : t("various.error-text") - }
-
); }; @@ -118,24 +111,23 @@ export const SaveButton: React.FC = () => { const segments = useAppSelector(selectSegments); const tracks = useAppSelector(selectTracks); const subtitles = useAppSelector(selectSubtitles); + const metadata = useAppSelector(selectCatalogs); const workflowStatus = useAppSelector(selectStatus); - const metadataStatus = useAppSelector(selectPostStatus); const theme = useTheme(); - const [metadataSaveStarted, setMetadataSaveStarted] = useState(false); // Update based on current fetching status let Icon = LuSave; let spin = false; let tooltip = null; - if (workflowStatus === "failed" || metadataStatus === "failed") { + if (workflowStatus === "failed") { Icon = LuAlertCircle; spin = false; tooltip = t("save.confirmButton-failed-tooltip"); - } else if (workflowStatus === "success" && metadataStatus === "success") { + } else if (workflowStatus === "success") { Icon = LuCheck; spin = false; tooltip = t("save.confirmButton-success-tooltip"); - } else if (workflowStatus === "loading" || metadataStatus === "loading") { + } else if (workflowStatus === "loading") { Icon = LuLoader; spin = true; tooltip = t("save.confirmButton-attempting-tooltip"); @@ -160,36 +152,23 @@ export const SaveButton: React.FC = () => { return subtitlesForPosting; }; - // Dispatches first save request - // Subsequent save requests should be wrapped in useEffect hooks, - // so they are only sent after the previous one has finished const save = () => { - setMetadataSaveStarted(true); - dispatch(postMetadata()); + dispatch(postVideoInformation({ + segments: segments, + tracks: tracks, + subtitles: prepareSubtitles(), + metadata: metadata, + })); }; - // Subsequent save request - useEffect(() => { - if (metadataStatus === "success" && metadataSaveStarted) { - setMetadataSaveStarted(false); - dispatch(postVideoInformation({ - segments: segments, - tracks: tracks, - subtitles: prepareSubtitles(), - })); - - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [metadataStatus]); - // Let users leave the page without warning after a successful save useEffect(() => { - if (workflowStatus === "success" && metadataStatus === "success") { + if (workflowStatus === "success") { dispatch(videoSetHasChanges(false)); dispatch(metadataSetHasChanges(false)); dispatch(subtitleSetHasChanges(false)); } - }, [dispatch, metadataStatus, workflowStatus]); + }, [dispatch, workflowStatus]); return ( diff --git a/src/main/WorkflowConfiguration.tsx b/src/main/WorkflowConfiguration.tsx index fabdbd4bd..1c8930cf4 100644 --- a/src/main/WorkflowConfiguration.tsx +++ b/src/main/WorkflowConfiguration.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from "react"; +import React, { useEffect } from "react"; import { css } from "@emotion/react"; import { @@ -24,10 +24,8 @@ import { setEnd } from "../redux/endSlice"; import { useTranslation } from "react-i18next"; import { - postMetadata, - selectPostError, - selectPostStatus, setHasChanges as metadataSetHasChanges, + selectCatalogs, } from "../redux/metadataSlice"; import { selectSubtitles, @@ -45,8 +43,6 @@ const WorkflowConfiguration: React.FC = () => { const postAndProcessWorkflowStatus = useAppSelector(selectStatus); const postAndProcessError = useAppSelector(selectError); - const postMetadataStatus = useAppSelector(selectPostStatus); - const postMetadataError = useAppSelector(selectPostError); const theme = useTheme(); const workflowConfigurationStyle = css({ @@ -73,12 +69,6 @@ const WorkflowConfiguration: React.FC = () => { { errorMessage: postAndProcessError }) : t("various.error-text")}
-
- {t("various.error-text")}
- {postMetadataError ? t("various.error-details-text", - { errorMessage: postMetadataError }) : - t("various.error-text")}
-
); }; @@ -96,20 +86,19 @@ export const SaveAndProcessButton: React.FC<{ text: string; }> = ({ text }) => { const segments = useAppSelector(selectSegments); const tracks = useAppSelector(selectTracks); const subtitles = useAppSelector(selectSubtitles); + const metadata = useAppSelector(selectCatalogs); const workflowStatus = useAppSelector(selectStatus); - const metadataStatus = useAppSelector(selectPostStatus); - const [metadataSaveStarted, setMetadataSaveStarted] = useState(false); const theme = useTheme(); // Let users leave the page without warning after a successful save useEffect(() => { - if (workflowStatus === "success" && metadataStatus === "success") { + if (workflowStatus === "success") { dispatch(setEnd({ hasEnded: true, value: "success" })); dispatch(videoSetHasChanges(false)); dispatch(metadataSetHasChanges(false)); dispatch(subtitleSetHasChanges(false)); } - }, [dispatch, metadataStatus, workflowStatus]); + }, [dispatch, workflowStatus]); const prepareSubtitles = () => { const subtitlesForPosting = []; @@ -124,38 +113,26 @@ export const SaveAndProcessButton: React.FC<{ text: string; }> = ({ text }) => { return subtitlesForPosting; }; - // Dispatches first save request - // Subsequent save requests should be wrapped in useEffect hooks, - // so they are only sent after the previous one has finished const saveAndProcess = () => { - setMetadataSaveStarted(true); - dispatch(postMetadata()); + dispatch(postVideoInformationWithWorkflow({ + segments: segments, + tracks: tracks, + workflow: [{ id: selectedWorkflowId }], + subtitles: prepareSubtitles(), + metadata: metadata, + })); }; - // Subsequent save request - useEffect(() => { - if (metadataStatus === "success" && metadataSaveStarted) { - setMetadataSaveStarted(false); - dispatch(postVideoInformationWithWorkflow({ - segments: segments, - tracks: tracks, - workflow: [{ id: selectedWorkflowId }], - subtitles: prepareSubtitles(), - })); - } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [metadataStatus]); - // Update based on current fetching status let Icon = LuDatabase; let spin = false; - if (workflowStatus === "failed" || metadataStatus === "failed") { + if (workflowStatus === "failed") { Icon = LuAlertCircle; spin = false; - } else if (workflowStatus === "success" && metadataStatus === "success") { + } else if (workflowStatus === "success") { Icon = LuCheck; spin = false; - } else if (workflowStatus === "loading" || metadataStatus === "loading") { + } else if (workflowStatus === "loading") { Icon = LuLoader; spin = true; diff --git a/src/redux/metadataSlice.ts b/src/redux/metadataSlice.ts index 4d7d27678..fe0424385 100644 --- a/src/redux/metadataSlice.ts +++ b/src/redux/metadataSlice.ts @@ -21,52 +21,19 @@ export interface MetadataField { collection: { [key: string]: any } | undefined, } -// interface metadata { -// title: string, -// subject: string, -// description: string, -// language: string, -// languageOptions: string[], -// rightsHolder: string, -// license: string, -// licenseOptions: string[], -// isPartOf: string, -// creator: string, -// creatorOptions: string[], -// contributor: string, -// contributorOptions: string[], -// startDate: Date, -// duration: string, -// location: string, -// source: string, -// created: Date, -// publisher: string, -// identifier: string, -// } - interface metadata { catalogs: Catalog[]; hasChanges: boolean; // Did user make changes to metadata view since last save } -interface postRequestState { - postStatus: "idle" | "loading" | "success" | "failed", - postError: string | undefined, - postErrorReason: "unknown", -} - // TODO: Create an "httpRequestState" array or something -const initialState: metadata & httpRequestState & postRequestState = { +const initialState: metadata & httpRequestState = { catalogs: [], hasChanges: false, status: "idle", error: undefined, errorReason: "unknown", - - postStatus: "idle", - postError: undefined, - postErrorReason: "unknown", }; export const fetchMetadata = createAsyncThunk("metadata/fetchMetadata", async () => { @@ -78,21 +45,6 @@ export const fetchMetadata = createAsyncThunk("metadata/fetchMetadata", async () return JSON.parse(response); }); -export const postMetadata = createAsyncThunk("metadata/postMetadata", async (_, { getState }) => { - if (!settings.id) { - throw new Error("Missing media package identifier"); - } - - // TODO: Get only metadataState instead of all states - const allStates = getState() as { metadataState: { catalogs: metadata["catalogs"]; }; }; - - await client.post(`${settings.opencast.url}/editor/${settings.id}/metadata.json`, - allStates.metadataState.catalogs - ); - - return; -}); - /** * Slice for managing a post request for saving current changes and starting a workflow */ @@ -110,9 +62,6 @@ const metadataSlice = createSlice({ setHasChanges: (state, action: PayloadAction) => { state.hasChanges = action.payload; }, - resetPostRequestState: state => { - state.postStatus = "idle"; - }, }, extraReducers: builder => { builder.addCase( @@ -130,27 +79,12 @@ const metadataSlice = createSlice({ state.status = "failed"; state.error = action.error.message; }); - builder.addCase( - postMetadata.pending, (state, _action) => { - state.postStatus = "loading"; - }); - builder.addCase( - postMetadata.fulfilled, (state, _action) => { - state.postStatus = "success"; - }); - builder.addCase( - postMetadata.rejected, (state, action) => { - state.postStatus = "failed"; - state.postError = action.error.message; - }); }, selectors: { selectCatalogs: state => state.catalogs, selectHasChanges: state => state.hasChanges, selectGetStatus: state => state.status, selectGetError: state => state.error, - selectPostStatus: state => state.postStatus, - selectPostError: state => state.postError, selectTitleFromEpisodeDc: state => { for (const catalog of state.catalogs) { if (catalog.flavor === "dublincore/episode") { @@ -167,15 +101,13 @@ const metadataSlice = createSlice({ }, }); -export const { setFieldValue, setHasChanges, setFieldReadonly, resetPostRequestState } = metadataSlice.actions; +export const { setFieldValue, setHasChanges, setFieldReadonly } = metadataSlice.actions; export const { selectCatalogs, selectHasChanges, selectGetStatus, selectGetError, - selectPostStatus, - selectPostError, selectTitleFromEpisodeDc, } = metadataSlice.selectors; diff --git a/src/redux/workflowPostAndProcessSlice.ts b/src/redux/workflowPostAndProcessSlice.ts index 92f352c60..6bb6e3491 100644 --- a/src/redux/workflowPostAndProcessSlice.ts +++ b/src/redux/workflowPostAndProcessSlice.ts @@ -22,6 +22,7 @@ export const postVideoInformationWithWorkflow = segments: convertSegments(argument.segments), tracks: argument.tracks, subtitles: argument.subtitles, + metadataJSON: JSON.stringify(argument.metadata), workflows: argument.workflow, } ); diff --git a/src/redux/workflowPostSlice.ts b/src/redux/workflowPostSlice.ts index a25f0ddcb..11564c797 100644 --- a/src/redux/workflowPostSlice.ts +++ b/src/redux/workflowPostSlice.ts @@ -20,6 +20,7 @@ export const postVideoInformation = segments: convertSegments(argument.segments), tracks: argument.tracks, subtitles: argument.subtitles, + metadataJSON: JSON.stringify(argument.metadata), } ); return response; diff --git a/src/types.ts b/src/types.ts index 06232b9f3..d54f904db 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,3 +1,5 @@ +import { Catalog } from "./redux/metadataSlice"; + export interface Segment { id: string, start: number, @@ -68,6 +70,7 @@ export interface PostEditArgument { segments: Segment[] tracks: Track[] subtitles: SubtitlesFromOpencast[] + metadata: Catalog[] } export interface PostAndProcessEditArgument extends PostEditArgument{