From 769eea6bba107c6a0e65bfdd2be860f738dfd58a Mon Sep 17 00:00:00 2001 From: James Perrin Date: Tue, 10 Dec 2024 18:14:20 +0000 Subject: [PATCH] WIP --- src/i18n/locales/en-US.json | 4 +++- src/main/Save.tsx | 12 +++++++++--- src/main/WorkflowSelection.tsx | 20 +++++++++++++++++--- src/redux/videoSlice.ts | 14 ++++++++++++++ 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index a26b7d4fa..feb60d116 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json @@ -72,7 +72,9 @@ "success-tooltip-aria": "Saved successfully", "saveArea-tooltip": "Save Area", "confirm-success": "Okay", - "cancel-save": "Don't save" + "cancel-save": "Don't save", + "invalid-headline-text": "Invalid Edits", + "invalid-text": "The segments do not create a valid video. Either change or discard your edits if you wish to proceed. If you wanted to delete this video use the Opencast Admin UI. Contact {{ contact }} for further help." }, "discard": { diff --git a/src/main/Save.tsx b/src/main/Save.tsx index d65ad2a33..4351b14f6 100644 --- a/src/main/Save.tsx +++ b/src/main/Save.tsx @@ -15,6 +15,8 @@ import { selectSegments, selectTracks, setHasChanges as videoSetHasChanges, + selectValidSegments, + validateSegments, } from "../redux/videoSlice"; import { postVideoInformation, selectStatus, selectError } from "../redux/workflowPostSlice"; @@ -53,6 +55,10 @@ const Save: React.FC = () => { const hasChanges = useAppSelector(selectHasChanges); const subtitleHasChanges = useAppSelector(selectSubtitleHasChanges); + const dispatch = useAppDispatch(); + dispatch(validateSegments()); + const validSegments = useAppSelector(selectValidSegments); + const saveStyle = css({ height: "100%", display: finishState !== "Save changes" ? "none" : "flex", @@ -77,11 +83,11 @@ const Save: React.FC = () => { return ( <> - {t("save.info-text")} + {validSegments ? t("save.info-text") : t("save.invalid-text", { contact: settings.help.contact })}
- + {validSegments && }
); @@ -90,7 +96,7 @@ const Save: React.FC = () => { return (
-

{t("save.headline-text")}

+

{validSegments ? t("save.headline-text") : t("save.invalid-headline-text")}

{render()}
{t("various.error-text", { contact: settings.help.contact })}
diff --git a/src/main/WorkflowSelection.tsx b/src/main/WorkflowSelection.tsx index 45f6e2e08..9253a5b7b 100644 --- a/src/main/WorkflowSelection.tsx +++ b/src/main/WorkflowSelection.tsx @@ -10,14 +10,14 @@ import { selectFinishState, selectPageNumber } from "../redux/finishSlice"; import { PageButton } from "./Finish"; import { LuChevronLeft } from "react-icons/lu"; import { SaveAndProcessButton } from "./WorkflowConfiguration"; +import { selectValidSegments, validateSegments } from "../redux/videoSlice"; import { selectStatus, selectError } from "../redux/workflowPostAndProcessSlice"; import { selectStatus as saveSelectStatus, selectError as saveSelectError } from "../redux/workflowPostSlice"; import { httpRequestState, Workflow } from "../types"; import { SaveButton } from "./Save"; import { EmotionJSX } from "@emotion/react/types/jsx-namespace"; -import { useTranslation } from "react-i18next"; -import { Trans } from "react-i18next"; +import { useTranslation, Trans } from "react-i18next"; import { FormControlLabel, Radio, RadioGroup } from "@mui/material"; import { useTheme } from "../themes"; import { settings } from "../config"; @@ -47,6 +47,9 @@ const WorkflowSelection: React.FC = () => { const saveStatus = useAppSelector(saveSelectStatus); const saveError = useAppSelector(saveSelectError); + dispatch(validateSegments()); + const validSegments = useAppSelector(selectValidSegments); + const workflowSelectionStyle = css({ padding: "20px", display: (finishState === "Start processing" && pageNumber === 1) ? "flex" : "none", @@ -117,7 +120,18 @@ const WorkflowSelection: React.FC = () => { // Fills the layout template with values based on how many workflows are available const renderSelection = () => { - if (workflows.length <= 0) { + if (!validSegments) { + return ( + render( + t("save.invalid-headline-text"), + {t("save.invalid-text", { contact: settings.help.contact })}, + false, +
, + saveStatus, + saveError + ) + ); + } else if (workflows.length <= 0) { return ( render( t("workflowSelection.saveAndProcess-text"), diff --git a/src/redux/videoSlice.ts b/src/redux/videoSlice.ts index cd89d525e..009f4ba8d 100644 --- a/src/redux/videoSlice.ts +++ b/src/redux/videoSlice.ts @@ -18,6 +18,7 @@ export interface video { tracks: Track[], subtitlesFromOpencast: SubtitlesFromOpencast[], activeSegmentIndex: number, // Index of the segment that is currenlty hovered + validSegments: boolean, // Whether the segment will result in a valid video edit selectedWorkflowId: string, // Id of the currently selected workflow aspectRatios: { width: number, height: number; }[], // Aspect ratios of every video hasChanges: boolean, // Did user make changes in cutting view since last save @@ -52,6 +53,7 @@ export const initialState: video & httpRequestState = { tracks: [], subtitlesFromOpencast: [], activeSegmentIndex: 0, + validSegments: true, selectedWorkflowId: "", previewTriggered: false, clickTriggered: false, @@ -178,6 +180,15 @@ const videoSlice = createSlice({ updateCurrentlyAt(state, state.segments[nextSegmentIndex].start); state.jumpTriggered = true; }, + validateSegments: state => { + // Test if whole video has been deleted + if (state.segments.length === 1 && state.segments[0].deleted && state.segments[0].start === 0 && + state.segments[0].end === state.duration) { + state.validSegments = false; + } else { + state.validSegments = true; + } + }, addSegment: (state, action: PayloadAction) => { state.segments.push(action.payload); }, @@ -351,6 +362,7 @@ const videoSlice = createSlice({ selectCurrentlyAtInSeconds: state => state.currentlyAt / 1000, selectSegments: state => state.segments, selectActiveSegmentIndex: state => state.activeSegmentIndex, + selectValidSegments: state => state.validSegments, selectIsCurrentSegmentAlive: state => !state.segments[state.activeSegmentIndex].deleted, selectSelectedWorkflowId: state => state.selectedWorkflowId, selectHasChanges: state => state.hasChanges, @@ -520,6 +532,7 @@ export const { setJumpTriggered, jumpToPreviousSegment, jumpToNextSegment, + validateSegments, } = videoSlice.actions; export const selectVideos = createSelector( @@ -540,6 +553,7 @@ export const { selectCurrentlyAtInSeconds, selectSegments, selectActiveSegmentIndex, + selectValidSegments, selectIsCurrentSegmentAlive, selectSelectedWorkflowId, selectHasChanges,