mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-08 11:01:35 +00:00
Merge pull request #649 from storytold/new-upload-endpoints
replaced old upload endpoint with audio/image/video endpoints, fixed …
This commit is contained in:
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<
|
||||
|
||||
+4
@@ -1,5 +1,9 @@
|
||||
@import "scss/colours.scss";
|
||||
|
||||
.fy-cover-img-empty {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.fy-cover-img-input {
|
||||
// background-color: red;
|
||||
position: relative;
|
||||
|
||||
+6
-3
@@ -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>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user