Merge pull request #305 from 11cafe/fix-gallery

cleanup code, display all images search res
This commit is contained in:
Weixuan Fu
2024-03-22 17:18:19 +08:00
committed by GitHub
10 changed files with 101 additions and 90 deletions
+1 -1
View File
@@ -163,7 +163,7 @@ export namespace TwowaySyncAPI {
name: name,
json: JSON.stringify(jsonObj),
};
console.log("createWorkflow", input);
try {
const response = await fetch("/workspace/create_workflow_file", {
method: "POST",
+6 -4
View File
@@ -30,11 +30,13 @@ export default function MediaPreview({
? `/workspace/preview_media?filename=${mediaLocalPath}`
: `/workspace/view_media?filename=${mediaLocalPath}`,
);
if (!response.ok) throw new Error("Media not found");
setIsVisible(true);
if (response.status == 404) {
setIsVisible(false);
onBrokenLink?.();
return;
}
} catch (error) {
setIsVisible(false);
onBrokenLink?.();
console.error("Error checking media exists", error);
}
};
+5 -3
View File
@@ -5,6 +5,8 @@ import { CSSProperties } from "react";
type Props = {
searchValue: string;
onUpdateSearchValue: (value: string) => void;
placeholder?: string;
style?: CSSProperties;
};
const IconSearchStyle: CSSProperties = {
@@ -18,11 +20,11 @@ const IconSearchStyle: CSSProperties = {
};
export default function SearchInput(props: Props) {
const { searchValue, onUpdateSearchValue } = props;
const { searchValue, onUpdateSearchValue, style } = props;
const isSearchValueNotEmpty = searchValue !== "";
return (
<Box style={{ position: "relative" }} mb={2}>
<Box style={{ position: "relative", ...style }} mb={2}>
<IconSearch style={IconSearchStyle} />
{isSearchValueNotEmpty && (
<IconButton
@@ -40,7 +42,7 @@ export default function SearchInput(props: Props) {
/>
)}
<Input
placeholder="Search"
placeholder={props.placeholder ?? "Search"}
size={"sm"}
paddingLeft={"35px"}
paddingBlock={"5px"}
+7
View File
@@ -64,6 +64,13 @@ export class TableBase<T extends TableBaseModel> {
return list as any[];
}
async filter(filterFn: (obj: T) => boolean): Promise<T[]> {
const list = await indexdb[this.tableName]
.filter(filterFn as any)
.toArray();
return list as any[];
}
public async batchQuery(ids: string[]): Promise<T[]> {
const list = await indexdb[this.tableName].bulkGet(ids);
return list as any[];
+16 -49
View File
@@ -20,9 +20,10 @@ import { IconArrowLeft, IconX } from "@tabler/icons-react";
import { WorkspaceContext } from "../WorkspaceContext";
import { Media } from "../types/dbTypes";
import { MetaDataInfo } from "./components/GalleryLeftCarousel.tsx";
import GalleryMediaItem from "./components/GalleryMediaItem.tsx";
import SearchInput from "../components/SearchInput.tsx";
import { MediaWithMetaData } from "./components/GalleryRightTopbar.tsx";
import GalleryGridView from "./components/GalleryGridView.tsx";
import { useDebounce } from "../customHooks/useDebounce.ts";
import SearchInput from "../components/SearchInput.tsx";
export default function GalleryModal({ onclose }: { onclose: () => void }) {
const { curFlowID } = useContext(WorkspaceContext);
@@ -33,9 +34,7 @@ export default function GalleryModal({ onclose }: { onclose: () => void }) {
const [images, setImages] = useState<Media[]>([]);
const [metaData, setMetaData] = useState<MediaWithMetaData>();
const [searchValue, setSearchValue] = useState("");
const onUpdateSearchValue = (val: string) => {
setSearchValue(val);
};
const debounceSearchValue = useDebounce(searchValue, 300);
const loadData = async () => {
if (curFlowID == null) return;
@@ -57,28 +56,10 @@ export default function GalleryModal({ onclose }: { onclose: () => void }) {
});
}, []);
const calcImages = searchValue.length
? images?.filter((v) =>
/*!v?.workflowJSON || */ v.workflowJSON?.includes(searchValue ?? ""),
)
: images;
if (curFlowID == null) {
return null;
}
const onClickMedia = (media: Media) => {
if (isSelecting) {
if (selectedID.includes(media.id)) {
setSelectedID(selectedID.filter((id) => id !== media.id));
} else {
setSelectedID([...selectedID, media.id]);
}
return;
}
setMetaData(media);
// window.open(`/workspace/view_media?filename=${media.localPath}`);
};
const isAllSelected =
images.length > 0 && selectedID.length === images.length;
@@ -90,13 +71,14 @@ export default function GalleryModal({ onclose }: { onclose: () => void }) {
<HStack gap={2} mb={2}>
<Heading size={"md"} mr={2}>
Gallery - {workflowName}
<Flex gap={2} display={"inline-flex"} ml={2}>
{/* <SearchInput
searchValue={searchValue}
onUpdateSearchValue={onUpdateSearchValue}
/> */}
</Flex>
</Heading>
<SearchInput
searchValue={searchValue}
onUpdateSearchValue={(val) => setSearchValue(val)}
placeholder="Search prompt, model name, etc."
style={{ width: "300px" }}
/>
</HStack>
{isSelecting && (
<HStack gap={3}>
@@ -124,26 +106,11 @@ export default function GalleryModal({ onclose }: { onclose: () => void }) {
</ModalHeader>
<ModalCloseButton />
<ModalBody overflowY={"auto"}>
{/* {!metaData ? (
<HStack wrap={"wrap"}>
{calcImages.map((media) => {
return (
<GalleryMediaItem
key={media.id}
selectedID={selectedID}
media={media}
isSelecting={isSelecting}
onClickMedia={onClickMedia}
onRefreshImagesList={loadData}
coverPath={coverPath}
setCoverPath={setCoverPath}
/>
);
})}
</HStack>
) : ( */}
<MetaDataInfo mediaList={images} media={metaData ?? null} />
{/* )} */}
{debounceSearchValue.length ? (
<GalleryGridView searchQuery={debounceSearchValue} />
) : (
<MetaDataInfo mediaList={images} media={metaData ?? null} />
)}
</ModalBody>
</ModalContent>
</Modal>
@@ -0,0 +1,43 @@
import { useEffect, useState } from "react";
import GalleryMediaItem from "./GalleryMediaItem";
import { HStack } from "@chakra-ui/react";
import type { Media } from "../../types/dbTypes";
import { mediaTable } from "../../db-tables/WorkspaceDB";
export default function GalleryGridView({
searchQuery,
}: {
searchQuery: string;
}) {
const [medias, setMedias] = useState<Media[]>([]);
useEffect(() => {
if (searchQuery === "") {
mediaTable?.listAll().then((data) => {
setMedias(data.slice(0, 50) ?? []);
});
} else {
mediaTable
?.filter((v) => v.workflowJSON?.includes(searchQuery) ?? false)
.then((data) => {
setMedias(data);
});
}
}, [searchQuery]);
const onClickMedia = (media: Media) => {};
return (
<HStack wrap={"wrap"}>
{medias.map((media) => {
return (
<GalleryMediaItem
key={media.id}
selectedID={[]}
media={media}
isSelecting={false}
onClickMedia={onClickMedia}
/>
);
})}
</HStack>
);
}
@@ -4,6 +4,7 @@ import { Box, Flex, Grid, Image } from "@chakra-ui/react";
import Carousel from "../../components/Carousel/Carousel.tsx";
import { MetaInfoBox } from "./GalleryRightTopbar.tsx";
import MediaPreview from "../../components/MediaPreview.tsx";
import { mediaTable } from "../../db-tables/WorkspaceDB.ts";
interface MetaDataInfoProps {
media: Media | null;
@@ -53,6 +54,10 @@ export const MetaDataInfo: FC<MetaDataInfoProps> = ({ mediaList, media }) => {
mediaLocalPath={media.localPath}
size={GALLERY_IMAGE_SIZE}
objectFit="contain"
hideBrokenImage
onBrokenLink={() => {
mediaTable?.delete(media.id);
}}
/>
</Box>
))}
+2 -29
View File
@@ -27,9 +27,6 @@ interface GalleryMediaItemProps {
isSelecting: boolean;
selectedID: string[];
onClickMedia: (media: Media) => void;
onRefreshImagesList: () => void;
coverPath: string;
setCoverPath: (path: string) => void;
}
const GalleryMediaItem: React.FC<GalleryMediaItemProps> = ({
@@ -37,9 +34,6 @@ const GalleryMediaItem: React.FC<GalleryMediaItemProps> = ({
isSelecting,
selectedID,
onClickMedia,
onRefreshImagesList,
coverPath,
setCoverPath,
}) => {
const IMAGE_SIZE = 180; // Define your image size
const { curFlowID, loadFilePath } = useContext(WorkspaceContext);
@@ -47,7 +41,6 @@ const GalleryMediaItem: React.FC<GalleryMediaItemProps> = ({
if (media.localPath == null) {
return null;
}
const isCover = coverPath != null && coverPath === media.localPath;
if (curFlowID == null) {
return null;
}
@@ -65,8 +58,9 @@ const GalleryMediaItem: React.FC<GalleryMediaItemProps> = ({
mediaLocalPath={media.localPath}
size={IMAGE_SIZE}
onBrokenLink={() => {
// setIsVisible(false);
mediaTable?.delete(media.id);
}}
hideBrokenImage
autoPlay={true}
isPreview
/>
@@ -84,20 +78,6 @@ const GalleryMediaItem: React.FC<GalleryMediaItemProps> = ({
</Text>
</Tooltip>
<HStack hidden={isSelecting} gap={0}>
<Tooltip label="Set as cover">
<IconButton
size={"sm"}
variant={"ghost"}
icon={isCover ? <IconPinFilled size={19} /> : <IconPin size={19} />}
aria-label="set as cover"
onClick={() => {
workflowsTable?.updateMetaInfo(curFlowID, {
coverMediaPath: media.localPath,
});
setCoverPath(media.localPath);
}}
/>
</Tooltip>
<Button
flexGrow={1}
onClick={() =>
@@ -146,13 +126,6 @@ const GalleryMediaItem: React.FC<GalleryMediaItemProps> = ({
);
if (!res) return;
await mediaTable?.delete(media.id);
if (isCover) {
await workflowsTable?.updateMetaInfo(curFlowID, {
coverMediaPath: undefined,
});
setCoverPath("");
}
onRefreshImagesList();
}}
/>
</Tooltip>
@@ -8,7 +8,7 @@ import {
Text,
Tooltip,
} from "@chakra-ui/react";
import { IconDownload } from "@tabler/icons-react";
import { IconDownload, IconPin, IconPinFilled } from "@tabler/icons-react";
import { formatTimestamp } from "../../utils.tsx";
import MetaBox from "./MetaBox/GalleryRightMetadataForm.tsx";
@@ -46,6 +46,20 @@ export const MetaInfoBox = ({ media }: { media?: MediaWithMetaData }) => {
</>
)}
</Flex>
{/* <Tooltip label="Set as cover">
<IconButton
size={"sm"}
variant={"ghost"}
icon={isCover ? <IconPinFilled size={19} /> : <IconPin size={19} />}
aria-label="set as cover"
onClick={() => {
workflowsTable?.updateMetaInfo(curFlowID, {
coverMediaPath: media.localPath,
});
setCoverPath(media.localPath);
}}
/>
</Tooltip> */}
</SimpleGrid>
<MetaBox media={media ?? null} />
</Flex>
@@ -45,7 +45,6 @@ export default function MetaBox({ media }: { media: Media | null }) {
getMetadataFromUrl(
`/workspace/view_media?filename=${media.localPath}`,
).then((data) => {
console.log("setMediaMetaData by fetch", data);
setImagePrompt(data.prompt);
});
} else {
@@ -53,14 +52,12 @@ export default function MetaBox({ media }: { media: Media | null }) {
.graphToPrompt(app.graph)
.then((data: { output: any; workflow: any }) => {
setImagePrompt(data.output);
console.log("setMediaMetaData by graph", data);
});
}
}, [media]);
useEffect(() => {
if (!imagePrompt) return;
console.log("imagePrompt", imagePrompt);
const calcInput = calcInputListRecursive(imagePrompt);
setCalcInputList(calcInput);
}, [imagePrompt]);
@@ -74,6 +71,7 @@ export default function MetaBox({ media }: { media: Media | null }) {
?.topFieldsConfig;
if (topFieldsConfig) {
setTopFields(topFieldsConfig);
setShowAllInputs(false);
}
}
})();