mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-11 04:16:55 +00:00
added previews/downloads to InferenceJobsList
This commit is contained in:
1 parent
d4b61743e7
commit
303d8d2b66
11 files changed
+215
-42
No files matched your search
@@ -2,12 +2,16 @@ import { FetchStatus } from "./_common/SharedFetchTypes";
|
||||
import { MediaFileType, GetMediaByUser } from "./media_files";
|
||||
import { Weight, ListWeights, ListFeaturedWeights } from "./weights";
|
||||
import { GetBookmarksByUser } from "./bookmarks/GetBookmarksByUser";
|
||||
import { MediaFileClass } from "./enums/MediaFileClass";
|
||||
import { BucketConfig } from "./BucketConfig";
|
||||
|
||||
export type { MediaFileType, Weight };
|
||||
export {
|
||||
BucketConfig,
|
||||
FetchStatus,
|
||||
GetBookmarksByUser,
|
||||
GetMediaByUser,
|
||||
ListWeights,
|
||||
ListFeaturedWeights,
|
||||
MediaFileClass,
|
||||
};
|
||||
@@ -10,6 +10,7 @@ export default function Button({
|
||||
buttonRef,
|
||||
label,
|
||||
icon,
|
||||
onClick,
|
||||
small,
|
||||
variant: variantProps = "primary",
|
||||
to,
|
||||
@@ -74,6 +75,7 @@ export default function Button({
|
||||
square ? (small ? "button-square-small" : "button-square") : ""
|
||||
} button-${variant} ${full ? "w-100" : ""}`,
|
||||
disabled: disabled || isLoading,
|
||||
onClick,
|
||||
};
|
||||
|
||||
delete rest.className;
|
||||
@@ -95,18 +97,14 @@ export default function Button({
|
||||
);
|
||||
|
||||
const WrappedButton = to ? (
|
||||
<Link to={to} {...commonProps}>
|
||||
{ButtonContent}
|
||||
</Link>
|
||||
<Link {...{ ...commonProps, to }}>{ButtonContent}</Link>
|
||||
) : href ? (
|
||||
<a
|
||||
href={href}
|
||||
target={target}
|
||||
rel="noopener noreferrer"
|
||||
download={
|
||||
download ? (typeof download === "string" ? download : true) : undefined
|
||||
}
|
||||
{...commonProps}
|
||||
{...{ ...commonProps, href, target }}
|
||||
>
|
||||
{ButtonContent}
|
||||
</a>
|
||||
|
||||
@@ -5,6 +5,7 @@ export default interface ButtonProps
|
||||
extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
buttonRef?: any;
|
||||
label?: string | null;
|
||||
onClick?: (e: any) => any;
|
||||
icon?: IconDefinition;
|
||||
small?: boolean;
|
||||
variant?: string;
|
||||
|
||||
+40
-10
@@ -55,10 +55,11 @@ $primary-transparent: rgba($primary, 0.75);
|
||||
|
||||
.fy-inference-jobs-list-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 2.25rem fit-content(100px) minmax(0, 1fr) minmax(
|
||||
grid-template-columns: min-content fit-content(100px) minmax(0, 1fr) minmax(
|
||||
min-content,
|
||||
1fr
|
||||
);
|
||||
// grid-template-rows: 4rem;
|
||||
gap: 1rem 0;
|
||||
|
||||
.work-indicator {
|
||||
@@ -75,7 +76,7 @@ $primary-transparent: rgba($primary, 0.75);
|
||||
|
||||
.fy-inference-job-hover-on,
|
||||
.fy-inference-job-hover-off {
|
||||
padding: 0.5rem;
|
||||
padding: 0.75rem;
|
||||
|
||||
// &:first-of-type { }
|
||||
}
|
||||
@@ -83,6 +84,12 @@ $primary-transparent: rgba($primary, 0.75);
|
||||
.fy-inference-job-success {
|
||||
cursor: pointer;
|
||||
|
||||
button {
|
||||
height: 2.25rem;
|
||||
width: 2.25rem;
|
||||
margin: auto 0 auto 1rem;
|
||||
}
|
||||
|
||||
&.fy-inference-job-hover-on {
|
||||
background-color: $panel-inner;
|
||||
}
|
||||
@@ -90,8 +97,8 @@ $primary-transparent: rgba($primary, 0.75);
|
||||
|
||||
.fy-inference-job-indicator {
|
||||
border-radius: 0.5rem 0 0 0.5rem;
|
||||
margin-left: -0.5rem;
|
||||
padding-right: 0;
|
||||
// margin-left: -0.5rem;
|
||||
// padding-right: 0;
|
||||
|
||||
.fy-inference-job-indicator-container {
|
||||
// background-color: red;
|
||||
@@ -162,7 +169,7 @@ $primary-transparent: rgba($primary, 0.75);
|
||||
}
|
||||
|
||||
.fy-inference-job-action-frame {
|
||||
margin-right: -0.5rem;
|
||||
// margin-right: -0.5rem;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
// width: fit-content;
|
||||
@@ -175,12 +182,8 @@ $primary-transparent: rgba($primary, 0.75);
|
||||
cursor: pointer;
|
||||
margin: auto;
|
||||
white-space: nowrap;
|
||||
// padding-left: .75rem;
|
||||
// display: flex;
|
||||
// align-items: center;
|
||||
border-radius: 0.5rem;
|
||||
// line-height: 1em;
|
||||
margin: auto 0 auto auto;
|
||||
margin: auto 0 auto 1rem;
|
||||
}
|
||||
|
||||
.job-status-complete-success {
|
||||
@@ -222,6 +225,33 @@ $primary-transparent: rgba($primary, 0.75);
|
||||
// height: 2.25rem;
|
||||
}
|
||||
}
|
||||
|
||||
.fy-inference-job-preview {
|
||||
// background-color: red;
|
||||
// grid-column-start: 1;
|
||||
// grid-column-end: five;
|
||||
|
||||
.fy-inference-job-preview-thumb {
|
||||
// background-color: blue;
|
||||
// margin: 3rem 0;
|
||||
height: 3.25rem;
|
||||
width: fit-content;
|
||||
overflow: hidden;
|
||||
aspect-ratio: 4/3;
|
||||
position: relative;
|
||||
|
||||
.fy-inference-job-preview-static,
|
||||
.fy-inference-job-preview-gif {
|
||||
position: absolute;
|
||||
border-radius: 0.5rem;
|
||||
width: auto;
|
||||
height: 100%;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.fy-job-queue-ticker {
|
||||
|
||||
+62
-15
@@ -5,17 +5,21 @@ import {
|
||||
FrontendInferenceJobType,
|
||||
InferenceJob,
|
||||
} from "@storyteller/components/src/jobs/InferenceJob";
|
||||
import { MediaFile } from "@storyteller/components/src/api/media_files/GetMedia";
|
||||
import {
|
||||
CancelJob,
|
||||
CancelJobResponse,
|
||||
} from "@storyteller/components/src/api/jobs/CancelJob";
|
||||
import { useHover, useSlides } from "hooks";
|
||||
import { MediaURLs, useHover, useMedia, useSlides } from "hooks";
|
||||
import {
|
||||
JobState,
|
||||
jobStateCanChange,
|
||||
} from "@storyteller/components/src/jobs/JobStates";
|
||||
import { Button } from "components/common";
|
||||
import { useHistory } from "react-router-dom";
|
||||
import { STYLES_BY_KEY } from "common/StyleOptions";
|
||||
import JobResultPreview from "./JobResultPreview";
|
||||
import { faArrowDownToLine } from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
interface JobListItem extends InferenceJob {
|
||||
failures: (fail: string) => string;
|
||||
@@ -28,18 +32,56 @@ interface JobListItem extends InferenceJob {
|
||||
|
||||
const BaseAction = ({
|
||||
canStop = false,
|
||||
hover = false,
|
||||
mediaFile,
|
||||
maybeResultToken = "",
|
||||
success = false,
|
||||
toggleSlide = () => {},
|
||||
urls,
|
||||
}: {
|
||||
canStop: boolean;
|
||||
hover: boolean;
|
||||
mediaFile: MediaFile;
|
||||
maybeResultToken: string;
|
||||
success: boolean;
|
||||
toggleSlide: () => void;
|
||||
urls: MediaURLs;
|
||||
}) =>
|
||||
canStop || success ? (
|
||||
<svg
|
||||
{...{
|
||||
className: `fy-inference-job-action${success ? "-success" : ""}`,
|
||||
...(success ? {} : { onClick: toggleSlide }),
|
||||
}}
|
||||
>
|
||||
<ArrowX {...{ checked: success }} />
|
||||
</svg>
|
||||
<>
|
||||
<JobResultPreview
|
||||
{...{
|
||||
hover,
|
||||
mediaFile,
|
||||
mediaToken: maybeResultToken,
|
||||
show: success,
|
||||
urls,
|
||||
}}
|
||||
/>
|
||||
{success && (
|
||||
<Button
|
||||
{...{
|
||||
href: urls.file,
|
||||
icon: faArrowDownToLine,
|
||||
onClick: (e: any) => {
|
||||
e.stopPropagation();
|
||||
},
|
||||
square: true,
|
||||
small: true,
|
||||
target: "_blank",
|
||||
variant: "secondary",
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
<svg
|
||||
{...{
|
||||
className: `fy-inference-job-action${success ? "-success" : ""}`,
|
||||
...(success ? {} : { onClick: toggleSlide }),
|
||||
}}
|
||||
>
|
||||
<ArrowX {...{ checked: success }} />
|
||||
</svg>
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
);
|
||||
@@ -164,12 +206,22 @@ export default function JobItem({
|
||||
}
|
||||
};
|
||||
|
||||
const { mediaFile, urls } = useMedia({ mediaToken: maybeResultToken || "" });
|
||||
|
||||
const slides = useSlides({
|
||||
index,
|
||||
slides: [
|
||||
{
|
||||
component: BaseAction,
|
||||
props: { success, toggleSlide, canStop: canStop() },
|
||||
props: {
|
||||
canStop: canStop(),
|
||||
hover,
|
||||
maybeResultToken,
|
||||
mediaFile,
|
||||
success,
|
||||
toggleSlide,
|
||||
urls,
|
||||
},
|
||||
},
|
||||
{ component: StopConfirm, props: { stopClick, toggleSlide } },
|
||||
],
|
||||
@@ -229,11 +281,6 @@ export default function JobItem({
|
||||
<div {...{ ...outerProps(`fy-inference-job-action-frame`), ...hoverSet }}>
|
||||
{slides}
|
||||
</div>
|
||||
{
|
||||
// <div {...{ className: "fy-inference-job-previews" }}>
|
||||
// { }
|
||||
// </div>
|
||||
}
|
||||
</>
|
||||
);
|
||||
}
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
import React from "react";
|
||||
import { MediaURLs } from "hooks";
|
||||
// import { MediaFileClass } from "../enums/MediaFileClass";
|
||||
import { MediaFileClass } from "@storyteller/components/src/api";
|
||||
|
||||
import { a, TransitionFn, useTransition } from "@react-spring/web";
|
||||
import { MediaFile } from "@storyteller/components/src/api/media_files/GetMedia";
|
||||
|
||||
interface JobResultPreviewProps {
|
||||
hover: boolean;
|
||||
mediaFile: MediaFile;
|
||||
show?: boolean;
|
||||
urls: MediaURLs;
|
||||
}
|
||||
|
||||
export default function JobResultPreview({
|
||||
hover,
|
||||
mediaFile,
|
||||
show,
|
||||
urls,
|
||||
}: JobResultPreviewProps) {
|
||||
const transitions: TransitionFn<boolean, { opacity: number }> = useTransition(
|
||||
hover,
|
||||
{
|
||||
config: { mass: 1, tension: 80, friction: 10 },
|
||||
from: { opacity: 0 },
|
||||
enter: { opacity: 1 },
|
||||
leave: { opacity: 0 },
|
||||
}
|
||||
);
|
||||
|
||||
const previewSwitch = () => {
|
||||
switch (mediaFile?.media_class) {
|
||||
case MediaFileClass.Image:
|
||||
return <div>Image</div>;
|
||||
case MediaFileClass.Video:
|
||||
return (
|
||||
<div {...{ className: "fy-inference-job-preview-thumb" }}>
|
||||
<a.img
|
||||
{...{
|
||||
className: "fy-inference-job-preview-static",
|
||||
src: urls.thumb(),
|
||||
}}
|
||||
/>
|
||||
{transitions((style, isHovering) =>
|
||||
isHovering ? (
|
||||
<a.img
|
||||
{...{
|
||||
className: "fy-inference-job-preview-gif",
|
||||
src: urls.gif(),
|
||||
style,
|
||||
}}
|
||||
/>
|
||||
) : null
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
return show ? (
|
||||
<div {...{ className: "fy-inference-job-preview" }}>{previewSwitch()}</div>
|
||||
) : null;
|
||||
}
|
||||
@@ -12,7 +12,7 @@ import useChanger from "./useChanger";
|
||||
import useCoverImgUpload from "./useCoverImgUpload";
|
||||
import useDebounce from "./useDebounce";
|
||||
import useFile from "./useFile";
|
||||
import useHover from "./useHover";
|
||||
import useHover, { HoverValues } from "./useHover";
|
||||
import useId from "./useId";
|
||||
import useIdempotency from "./useIdempotency";
|
||||
import useInferenceJobs from "./useInferenceJobs";
|
||||
@@ -22,7 +22,7 @@ import useJobStatus from "./useJobStatus";
|
||||
import useLazyLists from "./useLazyLists";
|
||||
import useListContent from "./useListContent";
|
||||
import useLocalize from "./useLocalize";
|
||||
import useMedia from "./useMedia";
|
||||
import useMedia, { MediaURLs } from "./useMedia";
|
||||
import useMediaUploader from "./useMediaUploader";
|
||||
import useModal from "./useModal";
|
||||
import useModalState, { ModalConfig, ModalWidth } from "./useModalState";
|
||||
@@ -83,9 +83,11 @@ export type {
|
||||
AnimationEvents,
|
||||
BatchInputProps,
|
||||
CameraState,
|
||||
HoverValues,
|
||||
MakeBookmarksProps,
|
||||
MakeBatchPropsParams,
|
||||
MakeRatingsProps,
|
||||
MediaURLs,
|
||||
ModalConfig,
|
||||
ModalWidth,
|
||||
};
|
||||
+13
-3
@@ -1,14 +1,24 @@
|
||||
import { useState } from "react";
|
||||
|
||||
type hoverEventFn = (e?: any) => void;
|
||||
|
||||
interface UseHoverParams {
|
||||
onMouseEnter?: (e?: any) => void;
|
||||
onMouseLeave?: (e?: any) => void;
|
||||
onMouseEnter?: hoverEventFn;
|
||||
onMouseLeave?: hoverEventFn;
|
||||
}
|
||||
|
||||
export type HoverValues = [
|
||||
boolean,
|
||||
{
|
||||
onMouseEnter: hoverEventFn;
|
||||
onMouseLeave: hoverEventFn;
|
||||
},
|
||||
];
|
||||
|
||||
export default function useHover({
|
||||
onMouseEnter = () => {},
|
||||
onMouseLeave = () => {},
|
||||
}: UseHoverParams) {
|
||||
}: UseHoverParams): HoverValues {
|
||||
const [hover, hoverSet] = useState(false);
|
||||
const onHover = (x: boolean) => (e: any) => {
|
||||
hoverSet(x);
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from './useHover';
|
||||
+21
-4
@@ -11,6 +11,14 @@ import { DeleteMedia } from "@storyteller/components/src/api/media_files/DeleteM
|
||||
import { FetchStatus } from "@storyteller/components/src/api/_common/SharedFetchTypes";
|
||||
import { BucketConfig } from "@storyteller/components/src/api/BucketConfig";
|
||||
|
||||
type ThumbFn = (width?: number, quality?: number) => string;
|
||||
|
||||
export interface MediaURLs {
|
||||
file: string;
|
||||
gif: ThumbFn;
|
||||
thumb: ThumbFn;
|
||||
}
|
||||
|
||||
export default function useMedia({
|
||||
debug = "",
|
||||
mediaToken = "",
|
||||
@@ -42,11 +50,19 @@ export default function useMedia({
|
||||
status === FetchStatus.in_progress ||
|
||||
writeStatus === FetchStatus.in_progress;
|
||||
|
||||
// const bucketConfig = new BucketConfig();
|
||||
const bucketConfig = new BucketConfig();
|
||||
|
||||
const bucketUrl = media?.public_bucket_path
|
||||
? new BucketConfig().getGcsUrl(media.public_bucket_path)
|
||||
: "";
|
||||
const publicBucketPath = media?.public_bucket_path || "";
|
||||
|
||||
const bucketUrl = bucketConfig.getGcsUrl(publicBucketPath);
|
||||
|
||||
const urls = {
|
||||
file: bucketConfig.getGcsUrl(publicBucketPath),
|
||||
gif: (width = 360, quality = 20) =>
|
||||
bucketConfig.getCdnUrl(publicBucketPath + "-thumb.gif", width, quality),
|
||||
thumb: (width = 600, quality = 100) =>
|
||||
bucketConfig.getCdnUrl(publicBucketPath + "-thumb.jpg", width, quality),
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
// this condidition handles all media file fetches
|
||||
@@ -96,6 +112,7 @@ export default function useMedia({
|
||||
reload,
|
||||
status,
|
||||
statusSet,
|
||||
urls,
|
||||
writeStatus,
|
||||
};
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from './useMedia';
|
||||
Reference in new issue
Block a user