Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Enable transcripts for video library [FC-0076] #1596

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,125 @@ exports[`TranscriptWidget component snapshots snapshot: renders ErrorAlert with
</CollapsibleFormWidget>
`;

exports[`TranscriptWidget component snapshots snapshot: renders when isLibrary is true 1`] = `
<CollapsibleFormWidget
fontSize="x-small"
isError={true}
subtitle="English"
title="Transcripts"
>
<ErrorAlert
dismissError={null}
hideHeading={true}
isError={false}
>
<FormattedMessage
defaultMessage="Failed to upload transcript. Please try again."
description="Message presented to user when transcript fails to upload"
id="authoring.videoeditor.transcript.error.uploadTranscriptError"
/>
</ErrorAlert>
<ErrorAlert
dismissError={null}
hideHeading={true}
isError={true}
>
<FormattedMessage
defaultMessage="Failed to delete transcript. Please try again."
description="Message presented to user when transcript fails to delete"
id="authoring.videoeditor.transcript.error.deleteTranscriptError"
/>
</ErrorAlert>
<Stack
gap={3}
>
<Form.Group
className="border-primary-100 border-bottom"
>
<Transcript
index={0}
language="en"
/>
<ActionRow
className="mt-3.5"
>
<Form.Checkbox
checked={false}
className="decorative-control-label"
onChange={[Function]}
>
<div
className="small text-gray-700"
>
<FormattedMessage
defaultMessage="Allow transcript downloads"
description="Label for allow transcript downloads checkbox"
id="authoring.videoeditor.transcripts.allowDownloadCheckboxLabel"
/>
</div>
</Form.Checkbox>
<OverlayTrigger
key="top"
overlay={
<Tooltip
id="tooltip-top"
>
<FormattedMessage
defaultMessage="Learners will see a link to download the transcript below the video."
description="Message for show by default checkbox"
id="authoring.videoeditor.transcripts.upload.allowDownloadTooltipMessage"
/>
</Tooltip>
}
placement="top"
>
<Icon
style={
{
"height": "16px",
"width": "16px",
}
}
/>
</OverlayTrigger>
<ActionRow.Spacer />
</ActionRow>
<Form.Checkbox
checked={false}
className="mt-3 decorative-control-label"
onChange={[Function]}
>
<div
className="small text-gray-700"
>
<FormattedMessage
defaultMessage="Show transcript in the video player by default"
description="Label for show by default checkbox"
id="authoring.videoeditor.transcripts.upload.showByDefaultCheckboxLabel"
/>
</div>
</Form.Checkbox>
</Form.Group>
<div
className="mt-2"
>
<Button
className="text-primary-500 font-weight-bold justify-content-start pl-0"
onClick={[Function]}
size="sm"
variant="link"
>
<FormattedMessage
defaultMessage="Add a transcript"
description="Label for upload button"
id="authoring.videoeditor.transcripts.upload.label"
/>
</Button>
</div>
</Stack>
</CollapsibleFormWidget>
`;

exports[`TranscriptWidget component snapshots snapshots: renders as expected with allowTranscriptDownloads true 1`] = `
<CollapsibleFormWidget
fontSize="x-small"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { connect } from 'react-redux';
import { connect, useDispatch } from 'react-redux';
import PropTypes from 'prop-types';
import {
FormattedMessage,
Expand All @@ -17,7 +17,7 @@ import {
} from '@openedx/paragon';
import { Add, InfoOutline } from '@openedx/paragon/icons';

import { actions, selectors } from '../../../../../../data/redux';
import { thunkActions, actions, selectors } from '../../../../../../data/redux';
import messages from './messages';

import { RequestKeys } from '../../../../../../data/constants/requests';
Expand Down Expand Up @@ -90,13 +90,18 @@ const TranscriptWidget = ({
updateField,
isUploadError,
isDeleteError,
isLibrary,
// injected
intl,
}) => {
const [error] = React.useContext(ErrorContext).transcripts;
const [showImportCard, setShowImportCard] = React.useState(true);
const fullTextLanguages = module.hooks.transcriptLanguages(transcripts, intl);
const hasTranscripts = module.hooks.hasTranscripts(transcripts);
const dispatch = useDispatch();
if (isLibrary) {
dispatch(thunkActions.video.updateTranscriptHandlerUrl());
}

return (
<CollapsibleFormWidget
Expand Down Expand Up @@ -197,6 +202,7 @@ TranscriptWidget.propTypes = {
updateField: PropTypes.func.isRequired,
isUploadError: PropTypes.bool.isRequired,
isDeleteError: PropTypes.bool.isRequired,
isLibrary: PropTypes.bool.isRequired,
intl: PropTypes.shape(intlShape).isRequired,
};
export const mapStateToProps = (state) => ({
Expand All @@ -207,6 +213,7 @@ export const mapStateToProps = (state) => ({
allowTranscriptImport: selectors.video.allowTranscriptImport(state),
isUploadError: selectors.requests.isFailed(state, { requestKey: RequestKeys.uploadTranscript }),
isDeleteError: selectors.requests.isFailed(state, { requestKey: RequestKeys.deleteTranscript }),
isLibrary: selectors.app.isLibrary(state),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you need to access the redux store, please use a hook instead of a prop:

const isLibrary = useSelector(selectors.app.isLibrary);

});

export const mapDispatchToProps = (dispatch) => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,14 @@ jest.mock('../../../../../../data/redux', () => ({
thunkActions: {
video: {
deleteTranscript: jest.fn().mockName('thunkActions.video.deleteTranscript'),
updateTranscriptHandlerUrl: jest.fn().mockName('thunkActions.video.updateTranscriptHandlerUrl'),
},
},

selectors: {
app: {
isLibrary: jest.fn(state => ({ isLibrary: state })),
},
video: {
transcripts: jest.fn(state => ({ transcripts: state })),
selectedVideoTranscriptUrls: jest.fn(state => ({ selectedVideoTranscriptUrls: state })),
Expand Down Expand Up @@ -103,6 +107,7 @@ describe('TranscriptWidget', () => {
updateField: jest.fn().mockName('args.updateField'),
isUploadError: false,
isDeleteError: false,
isLibrary: false,
};

describe('snapshots', () => {
Expand Down Expand Up @@ -151,6 +156,11 @@ describe('TranscriptWidget', () => {
shallow(<TranscriptWidget {...props} isDeleteError transcripts={['en']} />).snapshot,
).toMatchSnapshot();
});
test('snapshot: renders when isLibrary is true', () => {
expect(
shallow(<TranscriptWidget {...props} isDeleteError transcripts={['en']} isLibrary />).snapshot,
).toMatchSnapshot();
});
});
describe('mapStateToProps', () => {
const testState = { A: 'pple', B: 'anana', C: 'ucumber' };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ export const VideoPreviewWidget = ({
videoSource,
transcripts,
blockTitle,
isLibrary,
intl,
}) => {
const imgRef = React.useRef();
Expand Down Expand Up @@ -47,10 +46,7 @@ export const VideoPreviewWidget = ({
/>
<Stack gap={1} className="justify-content-center">
<h4 className="text-primary mb-0">{blockTitle}</h4>
{!isLibrary && (
// Since content libraries v2 don't support static assets yet, we can't include transcripts.
<LanguageNamesWidget transcripts={transcripts} />
)}
<LanguageNamesWidget transcripts={transcripts} />
{videoType && (
<Hyperlink
className="text-primary x-small"
Expand All @@ -74,15 +70,13 @@ VideoPreviewWidget.propTypes = {
thumbnail: PropTypes.string.isRequired,
transcripts: PropTypes.arrayOf(PropTypes.string).isRequired,
blockTitle: PropTypes.string.isRequired,
isLibrary: PropTypes.bool.isRequired,
};

export const mapStateToProps = (state) => ({
transcripts: selectors.video.transcripts(state),
videoSource: selectors.video.videoSource(state),
thumbnail: selectors.video.thumbnail(state),
blockTitle: selectors.app.blockTitle(state),
isLibrary: selectors.app.isLibrary(state),
});

export default injectIntl(connect(mapStateToProps)(VideoPreviewWidget));
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ describe('VideoPreviewWidget', () => {
expect(screen.queryByText('No transcripts added')).toBeInTheDocument();
});

test('hides transcripts section in preview for libraries', () => {
test('renders transcripts section in preview for libraries', () => {
render(
<VideoPreviewWidget
videoSource="some-source"
Expand All @@ -41,7 +41,7 @@ describe('VideoPreviewWidget', () => {
thumbnail=""
/>,
);
expect(screen.queryByText('No transcripts added')).not.toBeInTheDocument();
expect(screen.queryByText('No transcripts added')).toBeInTheDocument();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,7 @@ const VideoSettingsModal: React.FC<Props> = ({
<SocialShareWidget />
)}
<ThumbnailWidget />
{!isLibrary && ( // Since content libraries v2 don't support static assets yet, we can't include transcripts.
<TranscriptWidget />
)}
<TranscriptWidget />
Copy link
Contributor

@pomegranited pomegranited Jan 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(out of scope for this issue) The Transcripts part of this VideoPreviewWidget is hard to use 😞

  • Can't type in the language I want in the dropdown; I have to scroll all the way down to the language to select it.
  • No spinners shown while transcript uploads / downloads from Youtube are happening -- it just sits there looking like it's doing nothing.
    It also doesn't prevent me from clicking "Save", and so if an upload / replace / delete for a transcript fails, I don't know about it until I re-open the modal.
  • When I import transcripts from YouTube, only one of the imported transcripts (English) shows up in the preview widget.
    I have to save, and the re-edit to see all languages for the imported transcripts.
  • The "select a language then launch file upload control" behavior is non-intuitive, and may not be accessible either? I think these two components should split in two, so I can select my language / upload a file in whatever order I want to.
  • The "Download" transcript menu item tries to send me to a new page. It should open in a new window (which closes after the download completes).

Do we have budget for a follow-up task to fix this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @pomegranited for listing this issues. It will be very helpful!

Do we have budget for a follow-up task to fix this?

I think so, I have to evaluate it.

<DurationWidget />
<HandoutWidget />
<LicenseWidget />
Expand Down
1 change: 1 addition & 0 deletions src/editors/data/constants/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,5 @@ export const RequestKeys = StrictDict({
uploadAsset: 'uploadAsset',
fetchAdvancedSettings: 'fetchAdvancedSettings',
fetchVideoFeatures: 'fetchVideoFeatures',
getHandlerUrl: 'getHandlerUrl',
} as const);
Loading