Merge pull request #649 from storytold/new-upload-endpoints

replaced old upload endpoint with audio/image/video endpoints, fixed …
This commit is contained in:
Victor O authored and GitHub committed 2024-08-01 16:41:55 -07:00
commit 48f00d9ced
11 files changed
+223 -123

No files matched your search

@@ -0,0 +1,17 @@
import MakeMultipartRequest from "../MakeMultipartRequest";
export interface UploadAudioMediaRequest {
file: any;
maybe_title?: string;
maybe_visibility?: "public" | "private";
uuid_idempotency_token: string;
}
export interface UploadAudioMediaResponse {
media_file_token: string;
success: boolean;
}
export const UploadAudioMedia = (request: UploadAudioMediaRequest) => {
return MakeMultipartRequest("/v1/media_files/upload/audio", request);
};
@@ -0,0 +1,18 @@
import MakeMultipartRequest from "../MakeMultipartRequest";
export interface UploadImageMediaRequest {
file: any;
is_intermediate_system_file?: boolean;
maybe_title?: string;
maybe_visibility?: "public" | "private";
uuid_idempotency_token: string;
}
export interface UploadImageMediaResponse {
media_file_token: string;
success: boolean;
}
export const UploadImageMedia = (request: UploadImageMediaRequest) => {
return MakeMultipartRequest("/v1/media_files/upload/image", request);
};
@@ -0,0 +1,20 @@
import MakeMultipartRequest from "../MakeMultipartRequest";
export interface UploadVideoMediaRequest {
file: any;
is_intermediate_system_file?: boolean;
maybe_scene_source_media_file_token?: string;
maybe_style_name?: string;
maybe_title?: string;
maybe_visibility?: "public" | "private";
uuid_idempotency_token: string;
}
export interface UploadVideoMediaResponse {
media_file_token: string;
success: boolean;
}
export const UploadVideoMedia = (request: UploadVideoMediaRequest) => {
return MakeMultipartRequest("/v1/media_files/upload/video", request);
};
@@ -30,9 +30,8 @@ export interface Weight {
export interface GetWeightRequest {}
export interface GetWeightResponse {
export interface GetWeightResponse extends Weight {
success: boolean;
weight?: Weight;
}
export const GetWeight = MakeRequest<
@@ -1,5 +1,9 @@
@import "scss/colours.scss";
.fy-cover-img-empty {
width: 100%;
}
.fy-cover-img-input {
// background-color: red;
position: relative;
@@ -52,14 +52,17 @@ export default function CoverImageInput({
status,
...rest
}: Props) {
const [editingImg, editingImgSet] = useState(0);
const transitions = useTransition(editingImg, basicTransition({}));
const [editingImg, editingImgSet] = useState(currentPath ? 0 : 1);
const transitions = useTransition(
editingImg,
basicTransition({ enter: { opacity: 1.0, position: "absolute" } })
);
return (
<div {...{ className: "fy-cover-img-input" }}>
{transitions((style, i) =>
!currentPath || i ? (
<a.div {...{ style }}>
<a.div {...{ className: "fy-cover-img-empty", style }}>
<ImageInput
{...{ ...rest, disabled: status > 1, placeholderIcon: faImage }}
>
@@ -1,10 +1,12 @@
import { useState } from 'react';
import { UploadMedia, UploadMediaResponse } from "@storyteller/components/src/api/media_files/UploadMedia";
import { useState } from "react";
import {
UploadImageMedia,
UploadImageMediaResponse,
} from "@storyteller/components/src/api/media_files/UploadImageMedia";
import { FetchStatus } from "@storyteller/components/src/api/_common/SharedFetchTypes";
import { v4 as uuidv4 } from "uuid";
import { useFile } from "hooks";
export default function useCoverImgUpload() {
const fileProps = useFile({});
const [token, tokenSet] = useState("");
@@ -13,12 +15,10 @@ export default function useCoverImgUpload() {
const upload = (e: any) => {
if (fileProps.file && status < 2) {
statusSet(FetchStatus.in_progress);
UploadMedia({
UploadImageMedia({
uuid_idempotency_token: uuidv4(),
file: fileProps.file,
source: "file",
})
.then((res: UploadMediaResponse) => {
}).then((res: UploadImageMediaResponse) => {
if ("media_file_token" in res) {
statusSet(FetchStatus.success);
tokenSet(res.media_file_token);
@@ -28,4 +28,4 @@ export default function useCoverImgUpload() {
};
return { fileProps, status, token, upload };
};
}
@@ -6,7 +6,9 @@ import {
MediaFilters,
UploaderResponse,
} from "components/entities/EntityTypes";
import { UploadMedia } from "@storyteller/components/src/api/media_files/UploadMedia";
import { UploadAudioMedia } from "@storyteller/components/src/api/media_files/UploadAudioMedia";
import { UploadImageMedia } from "@storyteller/components/src/api/media_files/UploadImageMedia";
import { UploadVideoMedia } from "@storyteller/components/src/api/media_files/UploadVideoMedia";
import { UploadEngineAsset } from "@storyteller/components/src/api/media_files/UploadEngineAsset";
import { MediaFileSubtype } from "@storyteller/components/src/api/enums/MediaFileSubtype";
import { GetFileTypeByExtension as extension } from "@storyteller/components/src/utils/GetFileTypeByExtension";
@@ -29,35 +31,6 @@ export default function useMediaUploader({ autoUpload, onSuccess = n }: Props) {
MediaFileSubtype | undefined
>();
const createUpload = (inputFile: File, todo = n) => {
statusSet(FetchStatus.in_progress);
const fileExtension = extension(inputFile.name || "");
const isEngineAsset = isSelectedType(
MediaFilters.engine_asset,
fileExtension
);
const baseConfig = { uuid_idempotency_token: uuidv4(), file: inputFile };
const engineConfig = {
...baseConfig,
media_file_subtype: engineSubtype,
media_file_class: mediaClass,
};
const mediaConfig = { ...baseConfig, source: "file" };
const uploader = isEngineAsset
? UploadEngineAsset(engineConfig)
: UploadMedia(mediaConfig);
if (inputFile) {
uploader.then((res: UploaderResponse) => {
if ("media_file_token" in res) {
statusSet(FetchStatus.success);
onSuccess(res);
todo();
}
});
}
};
const { file, clear, inputProps } = useFile({
...(autoUpload
? {
@@ -68,6 +41,42 @@ export default function useMediaUploader({ autoUpload, onSuccess = n }: Props) {
: {}),
});
const createUpload = (inputFile: File, todo = n) => {
statusSet(FetchStatus.in_progress);
const fileExtension = extension(inputFile.name || "");
const isAudio = isSelectedType(MediaFilters.audio, fileExtension);
const isEngineAsset = isSelectedType(
MediaFilters.engine_asset,
fileExtension
);
const isImage = isSelectedType(MediaFilters.image, fileExtension);
// const isVideo = isSelectedType(MediaFilters.video, fileExtension);
const baseConfig = { uuid_idempotency_token: uuidv4(), file: inputFile };
const engineConfig = {
...baseConfig,
media_file_subtype: engineSubtype,
media_file_class: mediaClass,
};
const mediaConfig = { ...baseConfig, source: "file" };
const uploader = () => {
if (isAudio) return UploadAudioMedia(mediaConfig);
if (isEngineAsset) return UploadEngineAsset(engineConfig);
if (isImage) return UploadImageMedia(mediaConfig);
else return UploadVideoMedia(mediaConfig);
};
if (inputFile) {
uploader().then((res: UploaderResponse) => {
if ("media_file_token" in res) {
statusSet(FetchStatus.success);
onSuccess(res);
todo();
}
});
}
};
const upload = () => {
createUpload(file, clear);
};
@@ -1,27 +1,35 @@
import { useEffect, useState } from "react";
import { useHistory } from "react-router-dom";
import { FetchStatus } from "@storyteller/components/src/api/_common/SharedFetchTypes";
import { GetWeight, Weight } from "@storyteller/components/src/api/weights/GetWeight";
import {
GetWeight,
Weight,
} from "@storyteller/components/src/api/weights/GetWeight";
import { UpdateWeight } from "@storyteller/components/src/api/weights/UpdateWeight";
import { DeleteWeight } from "@storyteller/components/src/api/weights/DeleteWeight";
import { useCoverImgUpload } from "hooks";
interface Props {
onSuccess?: (res: Weight) => any,
onRemove?: (x: any) => void,
token: string
onSuccess?: (res: Weight) => any;
onRemove?: (x: any) => void;
token: string;
}
const n = (x?: any) => {};
export default function useWeightFetch({ onRemove = n, onSuccess = n, token }: Props) {
export default function useWeightFetch({
onRemove = n,
onSuccess = n,
token,
}: Props) {
const [data, setData] = useState<Weight | undefined | null>(null);
const [status, statusSet] = useState(FetchStatus.ready);
const [writeStatus, writeStatusSet] = useState(FetchStatus.paused);
const [title, titleSet] = useState("");
const [visibility, visibilitySet] = useState("public");
const [descriptionMD, descriptionMDSet] = useState("");
const isLoading = status === FetchStatus.ready || status === FetchStatus.in_progress;
const isLoading =
status === FetchStatus.ready || status === FetchStatus.in_progress;
const fetchError = status === FetchStatus.error;
const history = useHistory();
const coverImg = useCoverImgUpload();
@@ -37,8 +45,10 @@ export default function useWeightFetch({ onRemove = n, onSuccess = n, token }: P
const update = () => {
writeStatusSet(FetchStatus.in_progress);
UpdateWeight(token,{
...coverImg.token ? { cover_image_media_file_token: coverImg.token } : {},
UpdateWeight(token, {
...(coverImg.token
? { cover_image_media_file_token: coverImg.token }
: {}),
description_markdown: descriptionMD,
description_rendered_html: data?.description_rendered_html || "",
title,
@@ -65,14 +75,18 @@ export default function useWeightFetch({ onRemove = n, onSuccess = n, token }: P
onRemove(res);
});
};
useEffect(() => {
if (token && !data && status === FetchStatus.ready) {
statusSet(FetchStatus.in_progress);
GetWeight(token, {})
.then((res: any) => {
if (res.success) {
let { creator_set_visibility, description_markdown, title: resTitle } = res;
let {
creator_set_visibility,
description_markdown,
title: resTitle,
} = res;
statusSet(FetchStatus.success);
titleSet(resTitle);
@@ -80,7 +94,9 @@ export default function useWeightFetch({ onRemove = n, onSuccess = n, token }: P
visibilitySet(creator_set_visibility);
onSuccess(res);
setData(res);
} else { statusSet(FetchStatus.error); }
} else {
statusSet(FetchStatus.error);
}
})
.catch(err => {
statusSet(FetchStatus.error);
@@ -88,5 +104,18 @@ export default function useWeightFetch({ onRemove = n, onSuccess = n, token }: P
}
}, [status, onSuccess, token, data]);
return { coverImg, data, fetchError, isLoading, descriptionMD, onChange, remove, status, title, update, visibility, writeStatus };
};
return {
coverImg,
data,
fetchError,
isLoading,
descriptionMD,
onChange,
remove,
status,
title,
update,
visibility,
writeStatus,
};
}
@@ -10,7 +10,6 @@ import { Button, Container, Panel } from "components/common";
import PageHeader from "components/layout/PageHeader";
// import { useHistory, useParams } from "react-router-dom";
// import { v4 as uuidv4 } from "uuid";
// import { UploadMedia } from "@storyteller/components/src/api/media_files/UploadMedia";
// import { FrontendInferenceJobType } from "@storyteller/components/src/jobs/InferenceJob";
import FbxToGltfJobList from "./components/FbxToGltfJobList";
import // EnqueueFbxToGltf,
@@ -65,74 +65,76 @@ export default function WeightEditPage({
let weightToken = weight?.creator?.user_token;
if (isLoading) {
return <Panel padding={true}>
<div className="d-flex flex-column gap-3">
<Skeleton type="short" />
<Skeleton height="40px" />
<Skeleton type="short" />
<Skeleton height="40px" />
<div className="d-flex justify-content-end mt-3 gap-2">
<Skeleton height="40px" width="120px" />
<Skeleton height="40px" width="120px" />
return (
<Panel padding={true}>
<div className="d-flex flex-column gap-3">
<Skeleton type="short" />
<Skeleton height="40px" />
<Skeleton type="short" />
<Skeleton height="40px" />
<div className="d-flex justify-content-end mt-3 gap-2">
<Skeleton height="40px" width="120px" />
<Skeleton height="40px" width="120px" />
</div>
</div>
</div>
</Panel>;
</Panel>
);
} else {
if (!weightToken) {
return (
<Container type="panel">
<PageHeader
titleIcon={faCircleExclamation}
title="Access Denied"
subText="This weight does not exist or is not owned by you."
panel={true}
extension={
<div className="d-flex">
<Button
label="Back to homepage"
to={`/weight/{}`}
className="d-flex"
/>
</div>
}
/>
</Container>
);
}
if (!weightToken) {
return (
<Container type="panel">
<PageHeader
titleIcon={faCircleExclamation}
title="Access Denied"
subText="This weight does not exist or is not owned by you."
panel={true}
extension={
<div className="d-flex">
<Button
label="Back to homepage"
to={`/weight/{}`}
className="d-flex"
/>
</div>
}
/>
</Container>
);
}
if (!canEditTtsModel(user?.user_token || "")) {
return (
<Container type="panel">
<PageHeader
titleIcon={faCircleExclamation}
title="Access Denied"
subText="You do not have permission to edit this model."
panel={true}
extension={
<div className="d-flex">
<Button
label="Back to homepage"
to={`/weight/{}`}
className="d-flex"
/>
</div>
}
/>
</Container>
);
}
if (!canEditTtsModel(user?.user_token || "")) {
return (
<Container type="panel">
<PageHeader
titleIcon={faCircleExclamation}
title="Access Denied"
subText="You do not have permission to edit this model."
panel={true}
extension={
<div className="d-flex">
<Button
label="Back to homepage"
to={`/weight/{}`}
className="d-flex"
/>
</div>
}
/>
</Container>
);
}
return (
<Container type="panel" className="mb-5">
<PageHeader
title="Edit Weight"
titleIcon={faWaveform}
subText="Make changes to your weight details"
panel={false}
showBackButton={true}
backbuttonLabel="Back"
backbuttonTo={`/weight/${weight_token}`}
/>
return (
<Container type="panel" className="mb-5">
<PageHeader
title="Edit Weight"
titleIcon={faWaveform}
subText="Make changes to your weight details"
panel={false}
showBackButton={true}
backbuttonLabel="Back"
backbuttonTo={`/weight/${weight_token}`}
/>
<SplitPanel {...{ busy: writeStatus > 0, dividerFooter: true }}>
<SplitPanel.Body padding={true}>
<div {...{ className: "weight-editor row gy-3 gx-4" }}>
@@ -198,7 +200,7 @@ export default function WeightEditPage({
</div>
</SplitPanel.Footer>
</SplitPanel>
</Container>
);
</Container>
);
}
}