mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-04 09:28:11 +00:00
fixed bug where entity input uploaded files would not display after clearing a previous selection, also added busy states
This commit is contained in:
1 parent
a9a4c39e3f
commit
b4c85b287d
4 files changed
+96
-34
No files matched your search
@@ -21,6 +21,7 @@ interface EntityInputProps {
|
||||
accept?: AcceptTypes | AcceptTypes[];
|
||||
aspectRatio?: "square" | "landscape" | "portrait";
|
||||
className?: string;
|
||||
debug?: string;
|
||||
label?: string;
|
||||
name?: string;
|
||||
onChange?: any;
|
||||
@@ -136,6 +137,7 @@ export default function EntityInput({
|
||||
accept,
|
||||
aspectRatio = "square",
|
||||
className,
|
||||
debug,
|
||||
label,
|
||||
name = "",
|
||||
onChange,
|
||||
@@ -149,7 +151,14 @@ export default function EntityInput({
|
||||
const presetToken = search ? urlSearch.get("preset_token") : "";
|
||||
const queryUser = search ? urlSearch.get("query_user") : "";
|
||||
const [mediaToken, mediaTokenSet] = useState(presetToken || value || "");
|
||||
const { media, mediaSet, prompt } = useMedia({
|
||||
const {
|
||||
busy: mediaBusy,
|
||||
media,
|
||||
mediaSet,
|
||||
prompt,
|
||||
reload,
|
||||
} = useMedia({
|
||||
debug,
|
||||
mediaToken: mediaToken || value,
|
||||
});
|
||||
const [updated, updatedSet] = useState(false);
|
||||
@@ -163,9 +172,12 @@ export default function EntityInput({
|
||||
onChange({ target: { name, value: token } });
|
||||
};
|
||||
|
||||
const { inputProps } = useMediaUploader({
|
||||
const { busy: uploaderBusy, inputProps } = useMediaUploader({
|
||||
autoUpload: true,
|
||||
onSuccess: (res: UploaderResponse) => selectToken(res.media_file_token),
|
||||
onSuccess: (res: UploaderResponse) => {
|
||||
reload();
|
||||
selectToken(res.media_file_token);
|
||||
},
|
||||
});
|
||||
|
||||
const onSelect = (data: MediaFile) => {
|
||||
@@ -173,10 +185,18 @@ export default function EntityInput({
|
||||
selectToken(data.token);
|
||||
};
|
||||
|
||||
const busy = false;
|
||||
const busy = mediaBusy || uploaderBusy;
|
||||
const index = busy ? 0 : media ? 1 : 2;
|
||||
const [animating, animatingSet] = useState(false);
|
||||
|
||||
if (debug)
|
||||
console.log(`🐞 EntityInput Debug at ${debug}`, {
|
||||
index,
|
||||
busy,
|
||||
media,
|
||||
view: ["busy slide", "full slide", "empty slide"][index],
|
||||
});
|
||||
|
||||
const transitions = useTransition(index, {
|
||||
config: { mass: 1, tension: 80, friction: 10 },
|
||||
from: { opacity: 0, transform: `translateX(${5}rem)` },
|
||||
@@ -219,7 +239,8 @@ export default function EntityInput({
|
||||
return [
|
||||
<AnimatedSlide
|
||||
{...{
|
||||
className: "fy-entity-input-busy",
|
||||
className:
|
||||
"fy-entity-input-busy d-flex justify-content-center align-items-center",
|
||||
render: MediaBusy,
|
||||
...sharedProps,
|
||||
}}
|
||||
|
||||
@@ -9,9 +9,9 @@ import {
|
||||
} from "@storyteller/components/src/api/prompts/GetPrompts";
|
||||
import { DeleteMedia } from "@storyteller/components/src/api/media_files/DeleteMedia";
|
||||
import { FetchStatus } from "@storyteller/components/src/api/_common/SharedFetchTypes";
|
||||
import { usePrevious } from "hooks";
|
||||
|
||||
export default function useMedia({
|
||||
debug = "",
|
||||
mediaToken = "",
|
||||
onSuccess = (res: MediaFile) => {},
|
||||
onRemove = (res: any) => {},
|
||||
@@ -20,6 +20,7 @@ export default function useMedia({
|
||||
const [writeStatus, writeStatusSet] = useState(FetchStatus.paused);
|
||||
const [media, mediaSet] = useState<MediaFile | undefined>();
|
||||
const [prompt, promptSet] = useState<Prompt | undefined>();
|
||||
|
||||
const remove = (as_mod: boolean) => {
|
||||
writeStatusSet(FetchStatus.in_progress);
|
||||
DeleteMedia(mediaToken, {
|
||||
@@ -31,19 +32,20 @@ export default function useMedia({
|
||||
});
|
||||
};
|
||||
|
||||
const previousToken = usePrevious(mediaToken);
|
||||
|
||||
const reload = () => {
|
||||
statusSet(FetchStatus.ready);
|
||||
mediaSet(undefined);
|
||||
};
|
||||
|
||||
const busy =
|
||||
status === FetchStatus.in_progress ||
|
||||
writeStatus === FetchStatus.in_progress;
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
status === FetchStatus.ready &&
|
||||
mediaToken &&
|
||||
(!media || previousToken !== mediaToken)
|
||||
) {
|
||||
// this condidition handles all media file fetches
|
||||
// it is triggered when status is ready and there is a media token but no media
|
||||
|
||||
if (status === FetchStatus.ready && mediaToken && !media) {
|
||||
statusSet(FetchStatus.in_progress);
|
||||
GetMedia(mediaToken, {})
|
||||
.then(res => {
|
||||
@@ -51,6 +53,7 @@ export default function useMedia({
|
||||
statusSet(FetchStatus.success);
|
||||
onSuccess(res.media_file);
|
||||
mediaSet(res.media_file);
|
||||
|
||||
if (res.media_file.maybe_prompt_token) {
|
||||
GetPrompts(res.media_file.maybe_prompt_token, {}).then(
|
||||
promptRes => {
|
||||
@@ -67,13 +70,16 @@ export default function useMedia({
|
||||
});
|
||||
}
|
||||
|
||||
// this triggers a media refetch when there is media, but the hook mediaToken param is updated
|
||||
|
||||
if (media && media.token !== mediaToken) {
|
||||
mediaSet(undefined);
|
||||
statusSet(FetchStatus.ready);
|
||||
}
|
||||
}, [media, mediaToken, previousToken, prompt, onSuccess, status, statusSet]);
|
||||
}, [media, mediaToken, prompt, onSuccess, status, statusSet]);
|
||||
|
||||
return {
|
||||
busy,
|
||||
media,
|
||||
mediaFile: media,
|
||||
mediaSet,
|
||||
@@ -81,6 +87,7 @@ export default function useMedia({
|
||||
remove,
|
||||
reload,
|
||||
status,
|
||||
statusSet,
|
||||
writeStatus,
|
||||
};
|
||||
}
|
||||
@@ -1,36 +1,56 @@
|
||||
import { useState } from "react";
|
||||
import { useFile } from "hooks";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { isSelectedType, MediaFilters, UploaderResponse } from "components/entities/EntityTypes";
|
||||
import {
|
||||
isSelectedType,
|
||||
MediaFilters,
|
||||
UploaderResponse,
|
||||
} from "components/entities/EntityTypes";
|
||||
import { UploadMedia } from "@storyteller/components/src/api/media_files/UploadMedia";
|
||||
import { UploadEngineAsset }from "@storyteller/components/src/api/media_files/UploadEngineAsset";
|
||||
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";
|
||||
import { MediaFileClass } from "@storyteller/components/src/api/enums/MediaFileClass";
|
||||
import { FetchStatus } from "@storyteller/components/src/api/_common/SharedFetchTypes";
|
||||
|
||||
interface Props {
|
||||
autoUpload?: boolean,
|
||||
autoUpload?: boolean;
|
||||
onSuccess?: (res: UploaderResponse) => any;
|
||||
}
|
||||
|
||||
const n = () => {};
|
||||
|
||||
export default function useMediaUploader({ autoUpload, onSuccess = n }: Props) {
|
||||
const [mediaClass,mediaClassSet] = useState<MediaFileClass>(MediaFileClass.Unknown);
|
||||
const [engineSubtype,engineSubtypeSet] = useState<MediaFileSubtype | undefined>();
|
||||
const [status, statusSet] = useState(FetchStatus.ready);
|
||||
const [mediaClass, mediaClassSet] = useState<MediaFileClass>(
|
||||
MediaFileClass.Unknown
|
||||
);
|
||||
const [engineSubtype, engineSubtypeSet] = useState<
|
||||
MediaFileSubtype | undefined
|
||||
>();
|
||||
|
||||
const createUpload = (inputFile: File, todo = n ) => {
|
||||
const createUpload = (inputFile: File, todo = n) => {
|
||||
statusSet(FetchStatus.in_progress);
|
||||
const fileExtension = extension(inputFile.name || "");
|
||||
const isEngineAsset = isSelectedType(MediaFilters.engine_asset, fileExtension);
|
||||
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 engineConfig = {
|
||||
...baseConfig,
|
||||
media_file_subtype: engineSubtype,
|
||||
media_file_class: mediaClass,
|
||||
};
|
||||
const mediaConfig = { ...baseConfig, source: "file" };
|
||||
const uploader = isEngineAsset ? UploadEngineAsset(engineConfig) : UploadMedia(mediaConfig);
|
||||
const uploader = isEngineAsset
|
||||
? UploadEngineAsset(engineConfig)
|
||||
: UploadMedia(mediaConfig);
|
||||
|
||||
if (inputFile) {
|
||||
uploader
|
||||
.then((res: UploaderResponse) => {
|
||||
uploader.then((res: UploaderResponse) => {
|
||||
if ("media_file_token" in res) {
|
||||
statusSet(FetchStatus.success);
|
||||
onSuccess(res);
|
||||
todo();
|
||||
}
|
||||
@@ -39,16 +59,27 @@ export default function useMediaUploader({ autoUpload, onSuccess = n }: Props) {
|
||||
};
|
||||
|
||||
const { file, clear, inputProps } = useFile({
|
||||
...autoUpload ? { onChange: (inputFile: File) => createUpload(inputFile,clear) } : {}
|
||||
...(autoUpload
|
||||
? {
|
||||
onChange: (inputFile: File) => {
|
||||
if (inputFile) createUpload(inputFile, clear);
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
|
||||
const upload = () => createUpload(file,clear);
|
||||
const upload = () => {
|
||||
createUpload(file, clear);
|
||||
};
|
||||
|
||||
const engineSubtypeChange = ({ target }: { target: any }) => engineSubtypeSet(target.value);
|
||||
const engineSubtypeChange = ({ target }: { target: any }) =>
|
||||
engineSubtypeSet(target.value);
|
||||
|
||||
const mediaClassChange = ({ target }: { target: any }) => mediaClassSet(target.value);
|
||||
const mediaClassChange = ({ target }: { target: any }) =>
|
||||
mediaClassSet(target.value);
|
||||
|
||||
return {
|
||||
busy: status === FetchStatus.in_progress,
|
||||
clear,
|
||||
engineSubtype,
|
||||
engineSubtypeChange,
|
||||
@@ -57,10 +88,12 @@ export default function useMediaUploader({ autoUpload, onSuccess = n }: Props) {
|
||||
file,
|
||||
inputProps,
|
||||
isAudio: isSelectedType(MediaFilters.audio, extension(file?.name || "")),
|
||||
isEngineAsset: isSelectedType(MediaFilters.engine_asset, extension(file?.name || "")),
|
||||
isEngineAsset: isSelectedType(
|
||||
MediaFilters.engine_asset,
|
||||
extension(file?.name || "")
|
||||
),
|
||||
isImage: isSelectedType(MediaFilters.image, extension(file?.name || "")),
|
||||
isVideo: isSelectedType(MediaFilters.video, extension(file?.name || "")),
|
||||
upload
|
||||
}
|
||||
|
||||
};
|
||||
upload,
|
||||
};
|
||||
}
|
||||
@@ -127,6 +127,7 @@ export default function AIFaceMirror({ sessionSubscriptionsWrapper }: Props) {
|
||||
{...{
|
||||
accept: ["video"],
|
||||
aspectRatio: "landscape",
|
||||
// debug: "AFM driver input",
|
||||
name: "faceDriverToken",
|
||||
value: faceDriverToken,
|
||||
onChange: ({ target }: { target: any }) => {
|
||||
|
||||
Reference in new issue
Block a user