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

Split "manage single video" page into multiple pages #595

Merged
Merged
23 changes: 19 additions & 4 deletions frontend/src/i18n/locales/de.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ general:
logo-alt: Das Logo von „{{title}}“
no-root-children: Noch keine Seiten ...
failed-to-load-thumbnail: Konnte Vorschaubild nicht laden
yes: Ja
no: Nein
form:
select:
no-options: Keine Optionen
Expand Down Expand Up @@ -140,6 +142,8 @@ video:
title: Video einbetten
caption: Untertitel
manage: Verwalten
start: Anfang
end: Ende

series:
series: Serie
Expand Down Expand Up @@ -234,17 +238,28 @@ manage:
title: Titel
created: Erstellt
no-description: Keine Beschreibung
video-details: 'Videodetails: „{{title}}“'
technical-details: Technische Details
opencast-id: Opencast-ID
available-resolutions: Verfügbare Auflösungen
page-showing-video-ids: '{{start}}–{{end}} von {{total}}'
no-videos-found: Keine Videos gefunden.
share-direct-link: Via Direktlink teilen
open-in-editor: Im Videoeditor öffnen
referencing-pages: Referenzierende Seiten
referencing-pages-explanation: 'Dieses Video wird von den folgenden Seiten referenziert:'
no-referencing-pages: Dieses Video wird von keiner Seite referenziert.
details:
title: Videodetails
thumbnail:
title: Vorschaubild
acl:
title: Zugangsbeschränkung
technical-details:
title: Technische Details
tracks: Video/Audio-Spuren
unknown-mimetype: Unbekannter MIME type
JulianKniephoff marked this conversation as resolved.
Show resolved Hide resolved
opencast-id: Opencast-ID
other-info: Andere Informationen
JulianKniephoff marked this conversation as resolved.
Show resolved Hide resolved
synced: Synchronisiert?
part-of: 'Teil von:'
is-live: Live?

are-you-sure: Sind Sie sich sicher?

Expand Down
23 changes: 19 additions & 4 deletions frontend/src/i18n/locales/en.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ general:
logo-alt: Logo of “{{title}}”
no-root-children: No pages yet ...
failed-to-load-thumbnail: Failed to load thumbnail
yes: "Yes"
no: "No"
form:
select:
no-options: No options
Expand Down Expand Up @@ -137,6 +139,8 @@ video:
title: Embed video
caption: Caption
manage: Manage
start: Anfang
end: Ende
JulianKniephoff marked this conversation as resolved.
Show resolved Hide resolved

series:
series: Series
Expand Down Expand Up @@ -227,17 +231,28 @@ manage:
title: Title
created: Created
no-description: No description
video-details: 'Video Details: “{{title}}”'
technical-details: Technical details
opencast-id: Opencast ID
available-resolutions: Available resolutions
page-showing-video-ids: '{{start}}–{{end}} of {{total}}'
no-videos-found: No videos found.
share-direct-link: Share via direct link
open-in-editor: Open in video editor
referencing-pages: Referencing pages
referencing-pages-explanation: 'This video is referenced on the following pages:'
no-referencing-pages: No pages reference this video.
details:
title: Video details
thumbnail:
title: Thumbnail
acl:
title: Manage Access
JulianKniephoff marked this conversation as resolved.
Show resolved Hide resolved
technical-details:
title: Technical details
tracks: Video/audio tracks
unknown-mimetype: Unknown MIME type
opencast-id: Opencast ID
other-info: Other information
JulianKniephoff marked this conversation as resolved.
Show resolved Hide resolved
synced: Synchronized?
part-of: 'Part of:'
is-live: Live?

are-you-sure: Are you sure?

Expand Down
6 changes: 4 additions & 2 deletions frontend/src/router.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@ import { RealmRoute } from "./routes/Realm";
import { DirectOpencastVideoRoute, DirectVideoRoute, VideoRoute } from "./routes/Video";
import { DirectSeriesOCRoute, DirectSeriesRoute } from "./routes/Series";
import { ManageVideosRoute } from "./routes/manage/Video";
import { ManageSingleVideoRoute } from "./routes/manage/Video/Single";
import { UploadRoute } from "./routes/Upload";
import { SearchRoute } from "./routes/Search";
import { InvalidUrlRoute } from "./routes/InvalidUrl";
import { BlockEmbedRoute, EmbedVideoRoute } from "./routes/Embed";
import { ManageVideoDetailsRoute } from "./routes/manage/Video/Details";
import { ManageVideoTechnicalDetailsRoute } from "./routes/manage/Video/TechnicalDetails";



Expand All @@ -41,7 +42,8 @@ const {
DirectSeriesOCRoute,
ManageRoute,
ManageVideosRoute,
ManageSingleVideoRoute,
ManageVideoDetailsRoute,
ManageVideoTechnicalDetailsRoute,
ManageRealmRoute,
UploadRoute,
AddChildRoute,
Expand Down
154 changes: 154 additions & 0 deletions frontend/src/routes/manage/Video/Details.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
import { useTranslation } from "react-i18next";
import { FiExternalLink } from "react-icons/fi";

import { Link } from "../../../router";
import { NotAuthorized } from "../../../ui/error";
import { Form } from "../../../ui/Form";
import { CopyableInput, Input, TextArea } from "../../../ui/Input";
import { InputContainer, TitleLabel } from "../../../ui/metadata";
import { useUser } from "../../../User";
import { LinkButton } from "../../../ui/Button";
import CONFIG from "../../../config";
import { Breadcrumbs } from "../../../ui/Breadcrumbs";
import { PageTitle } from "../../../layout/header/ui";
import { AuthorizedEvent, makeManageVideoRoute, PAGE_WIDTH } from "./Shared";


export const ManageVideoDetailsRoute = makeManageVideoRoute(
"details",
"",
event => <Page event={event} />,
);

type Props = {
event: AuthorizedEvent;
};

const Page: React.FC<Props> = ({ event }) => {
const { t } = useTranslation();

const breadcrumbs = [
{ label: t("manage.management"), link: "/~manage" },
{ label: t("manage.my-videos.title"), link: "/~manage/videos" },
];

const user = useUser();
if (user === "none" || user === "unknown") {
return <NotAuthorized />;
}
const editorUrl = `${CONFIG.opencast.editorUrl}?mediaPackageId=${event.opencastId}`;
JulianKniephoff marked this conversation as resolved.
Show resolved Hide resolved

return <>
<Breadcrumbs path={breadcrumbs} tail={event.title} />
<PageTitle title={t("manage.my-videos.details.title")} />
<section css={{
width: PAGE_WIDTH,
maxWidth: "100%",
marginBottom: 32,
}}>
<UpdatedCreatedInfo event={event} />
<div css={{ margin: "8px 2px", flex: "1 0 auto" }}>
{user.canUseEditor && event.canWrite && (
<LinkButton to={editorUrl} css={{ marginBottom: 16 }} target="_blank">
{t("manage.my-videos.open-in-editor")} <FiExternalLink size={16} />
</LinkButton>
)}
<DirectLink event={event} />
<MetadataSection event={event} />
</div>
</section>
<section css={{ marginBottom: 32 }}>
<HostRealms event={event} />
</section>
</>;
};

const DirectLink: React.FC<Props> = ({ event }) => {
const { t } = useTranslation();
const url = new URL(`/!v/${event.id.slice(2)}`, document.baseURI);

return (
<div css={{ marginBottom: 40 }}>
<div css={{ marginBottom: 4 }}>
{t("manage.my-videos.share-direct-link") + ":"}
</div>
<CopyableInput
value={url.href}
css={{ width: "100%", fontFamily: "monospace", fontSize: 14 }}
/>
</div>
);
};

/** Shows the `created` and `updated` timestamps. */
const UpdatedCreatedInfo: React.FC<Props> = ({ event }) => {
const { t, i18n } = useTranslation();
const created = new Date(event.created).toLocaleString(i18n.language);
const updated = event.syncedData?.updated == null
? null
: new Date(event.syncedData.updated).toLocaleString(i18n.language);

return (
<div css={{ marginBottom: 16, fontSize: 14 }}>
<DateValue label={t("video.created")} value={created} />
{updated && <DateValue label={t("video.updated")} value={updated} />}
</div>
);
};

type DateValueProps = {
label: string;
value: string;
};

const DateValue: React.FC<DateValueProps> = ({ label, value }) => (
<span css={{ "&:not(:last-child):after": { content: "'•'", margin: "0 12px" } }}>
<span css={{ color: "var(--grey40)", lineHeight: 1 }}>{label + ":"}</span>
<span css={{ marginLeft: 6, marginTop: 4 }}>{value}</span>
</span>
);

const MetadataSection: React.FC<Props> = ({ event }) => {
const { t } = useTranslation();

return (
<Form noValidate>
<InputContainer>
<TitleLabel htmlFor="title-field" />
<Input
id="title-field"
value={event.title}
disabled
css={{ width: "100%" }}
/>
</InputContainer>

<InputContainer>
<label htmlFor="description-field">
JulianKniephoff marked this conversation as resolved.
Show resolved Hide resolved
{t("upload.metadata.description")}
</label>
<TextArea id="description-field" disabled value={event.description ?? ""} />
</InputContainer>
</Form>
);
};

const HostRealms: React.FC<Props> = ({ event }) => {
const { t } = useTranslation();

return <>
<h2 css={{ fontSize: 20, marginBottom: 8 }}>{t("manage.my-videos.referencing-pages")}</h2>
{event.hostRealms.length === 0
? <i>{t("manage.my-videos.no-referencing-pages")}</i>
: <>
<p>{t("manage.my-videos.referencing-pages-explanation")}</p>
<ul>{event.hostRealms.map(realm => <li key={realm.id}>
<Link to={realm.path}>{
realm.isRoot
? <i>{t("general.homepage")}</i>
: realm.name
}</Link>
</li>)}</ul>
</>}
</>;
};
Loading