diff --git a/ui/frontend/build_src/src/components/atoms/clearQueue/index.tsx b/ui/frontend/build_src/src/components/atoms/clearQueue/index.tsx deleted file mode 100644 index 1818672d..00000000 --- a/ui/frontend/build_src/src/components/atoms/clearQueue/index.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from "react"; -import { doStopImage } from "../../../api"; -import { useImageQueue } from "../../../stores/imageQueueStore"; -import { BrandedButton } from "../../../styles/shared.css"; - -import { useCreateUI } from "../../../components/organisms/creationPanel/creationPanelUIStore"; - -export default function ClearQueue() { - - const hasQueue = useImageQueue((state) => state.hasQueuedImages()); - const clearQueue = useImageQueue((state) => state.clearQueue); - - const showQueue = useCreateUI((state) => state.showQueue); - const toggleQueue = useCreateUI((state) => state.toggleQueue); - - - const stopAll = async () => { - console.log("stopAll"); - try { - clearQueue(); - const res = await doStopImage(); - } catch (e) { - console.log(e); - } - }; - - return ( - <> - - - - ); -} \ No newline at end of file diff --git a/ui/frontend/build_src/src/components/molecules/clearQueue/index.tsx b/ui/frontend/build_src/src/components/molecules/clearQueue/index.tsx new file mode 100644 index 00000000..77a0479e --- /dev/null +++ b/ui/frontend/build_src/src/components/molecules/clearQueue/index.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import { doStopImage } from "../../../api"; +import { useRequestQueue } from "../../../stores/requestQueueStore"; +import { BrandedButton } from "../../../styles/shared.css"; + +export default function ClearQueue() { + + const hasQueue = useRequestQueue((state) => state.hasPendingQueue()); + const clearQueue = useRequestQueue((state) => state.clearQueue); + + const stopAll = async () => { + try { + clearQueue(); + const res = await doStopImage(); + } catch (e) { + console.log(e); + } + }; + + return ( + + ); +} \ No newline at end of file diff --git a/ui/frontend/build_src/src/components/atoms/makeButton/index.tsx b/ui/frontend/build_src/src/components/molecules/makeButton/index.tsx similarity index 90% rename from ui/frontend/build_src/src/components/atoms/makeButton/index.tsx rename to ui/frontend/build_src/src/components/molecules/makeButton/index.tsx index caf5d295..d0364947 100644 --- a/ui/frontend/build_src/src/components/atoms/makeButton/index.tsx +++ b/ui/frontend/build_src/src/components/molecules/makeButton/index.tsx @@ -2,7 +2,11 @@ import React, { useEffect, useRef } from "react"; import { useImageCreate } from "../../../stores/imageCreateStore"; -import { useImageQueue } from "../../../stores/imageQueueStore"; +import { + QueueStatus, + useRequestQueue +} from "../../../stores/requestQueueStore"; + import { FetchingStates, useImageFetching @@ -42,10 +46,10 @@ export default function MakeButton() { const isSoundEnabled = useImageCreate((state) => state.isSoundEnabled()); - const addNewImage = useImageQueue((state) => state.addNewImage); - const hasQueue = useImageQueue((state) => state.hasQueuedImages()); - const removeFirstInQueue = useImageQueue((state) => state.removeFirstInQueue); - const { id, options } = useImageQueue((state) => state.firstInQueue()); + const addtoQueue = useRequestQueue((state) => state.addtoQueue); + const hasQueue = useRequestQueue((state) => state.hasPendingQueue()); + const { id, options } = useRequestQueue((state) => state.firstInQueue()); + const updateQueueStatus = useRequestQueue((state) => state.updateStatus); const status = useImageFetching((state) => state.status); const setStatus = useImageFetching((state) => state.setStatus); @@ -64,7 +68,11 @@ export default function MakeButton() { try { const parsed = JSON.parse(jsonStr); const { status, request, output: outputs } = parsed as ImageReturnType; + + if (status === 'succeeded') { + + updateQueueStatus(id, QueueStatus.complete); outputs.forEach((output: any, index: number) => { const { data, seed } = output as ImageOutput; @@ -79,10 +87,12 @@ export default function MakeButton() { else { console.warn(`Unexpected status: ${status}`); + updateQueueStatus(id, QueueStatus.error); } } catch (e) { + updateQueueStatus(id, QueueStatus.error); console.log("Error HACKING JSON: ", e) } } @@ -143,7 +153,7 @@ export default function MakeButton() { } } catch (e) { - console.log('EXPECTED PARSE ERRROR') + // console.log('EXPECTED PARSE ERRROR') finalJSON += jsonStr; } @@ -152,8 +162,8 @@ export default function MakeButton() { const startStream = async (id: string, req: ImageRequest) => { - try { + updateQueueStatus(id, QueueStatus.processing); resetForFetching(); const res = await doMakeImage(req); const reader = res.body?.getReader(); @@ -164,6 +174,7 @@ export default function MakeButton() { } catch (e) { console.log('TOP LINE STREAM ERROR') + updateQueueStatus(id, QueueStatus.error); console.log(e); } @@ -201,7 +212,7 @@ export default function MakeButton() { seed = useRandomSeed(); } // add the request to the queue - addNewImage(uuidv4(), { + addtoQueue(uuidv4(), { ...req, // updated the number of images to make num_outputs: num, @@ -224,7 +235,7 @@ export default function MakeButton() { useEffect(() => { const makeImages = async (options: ImageRequest) => { - removeFirstInQueue(); + // removeFirstInQueue(); await startStream(id ?? "", options); } @@ -238,6 +249,7 @@ export default function MakeButton() { console.log('req is undefined'); return; } + makeImages(options).catch((e) => { console.log('HAS QUEUE ERROR'); console.log(e); diff --git a/ui/frontend/build_src/src/components/atoms/makeButton/makeButton.css.ts b/ui/frontend/build_src/src/components/molecules/makeButton/makeButton.css.ts similarity index 100% rename from ui/frontend/build_src/src/components/atoms/makeButton/makeButton.css.ts rename to ui/frontend/build_src/src/components/molecules/makeButton/makeButton.css.ts diff --git a/ui/frontend/build_src/src/components/atoms/modifierTag/index.tsx b/ui/frontend/build_src/src/components/molecules/modifierTag/index.tsx similarity index 100% rename from ui/frontend/build_src/src/components/atoms/modifierTag/index.tsx rename to ui/frontend/build_src/src/components/molecules/modifierTag/index.tsx diff --git a/ui/frontend/build_src/src/components/atoms/modifierTag/modifierTags.css.ts b/ui/frontend/build_src/src/components/molecules/modifierTag/modifierTags.css.ts similarity index 100% rename from ui/frontend/build_src/src/components/atoms/modifierTag/modifierTags.css.ts rename to ui/frontend/build_src/src/components/molecules/modifierTag/modifierTags.css.ts diff --git a/ui/frontend/build_src/src/components/atoms/stopButton/index.tsx b/ui/frontend/build_src/src/components/molecules/stopButton/index.tsx similarity index 100% rename from ui/frontend/build_src/src/components/atoms/stopButton/index.tsx rename to ui/frontend/build_src/src/components/molecules/stopButton/index.tsx diff --git a/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/activeTags/index.tsx b/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/activeTags/index.tsx index 57b0fd60..6789c4fd 100644 --- a/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/activeTags/index.tsx +++ b/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/activeTags/index.tsx @@ -1,7 +1,7 @@ import React from "react"; import { useImageCreate } from "../../../../../stores/imageCreateStore"; -import ModifierTag from "../../../../atoms/modifierTag"; +import ModifierTag from "../../../../molecules/modifierTag"; export default function ActiveTags() { const selectedtags = useImageCreate((state) => state.selectedTags()); diff --git a/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/creationActions/index.tsx b/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/creationActions/index.tsx index 8fb3cf16..dda996b9 100644 --- a/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/creationActions/index.tsx +++ b/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/creationActions/index.tsx @@ -1,8 +1,10 @@ import React from "react"; -import MakeButton from "../../../../atoms/makeButton"; -import StopButton from "../../../../atoms/stopButton"; -import ClearQueue from "../../../../atoms/clearQueue"; +import MakeButton from "../../../../molecules/makeButton"; +// import StopButton from "../../../../molecules/stopButton"; +// import ClearQueue from "../../../../molecules/clearQueue"; + +import ShowQueue from "../showQueue"; import { StopContainer @@ -12,10 +14,11 @@ export default function CreationActions() { return (
-
+ + {/*
-
+
*/}
); } \ No newline at end of file diff --git a/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/index.tsx b/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/index.tsx index b4097453..63a154ac 100644 --- a/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/index.tsx +++ b/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/index.tsx @@ -37,12 +37,6 @@ export default function BasicCreation() { - {/* -
- - -
*/} - diff --git a/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/showQueue/index.tsx b/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/showQueue/index.tsx new file mode 100644 index 00000000..cae54ce5 --- /dev/null +++ b/ui/frontend/build_src/src/components/organisms/creationPanel/basicCreation/showQueue/index.tsx @@ -0,0 +1,21 @@ +import React from "react"; + +import { useCreateUI } from "../../creationPanelUIStore"; + +export default function ShowQueue() { + + const showQueue = useCreateUI((state) => state.showQueue); + const toggleQueue = useCreateUI((state) => state.toggleQueue); + + return ( + + ); +} \ No newline at end of file diff --git a/ui/frontend/build_src/src/components/organisms/creationPanel/creationPanel.css.ts b/ui/frontend/build_src/src/components/organisms/creationPanel/creationPanel.css.ts index 5ac371c0..b8495f5e 100644 --- a/ui/frontend/build_src/src/components/organisms/creationPanel/creationPanel.css.ts +++ b/ui/frontend/build_src/src/components/organisms/creationPanel/creationPanel.css.ts @@ -1,11 +1,12 @@ import { style } from "@vanilla-extract/css"; - +import { PanelBox } from "../../../styles/shared.css"; export const CreationPaneMain = style({ position: "relative", width: "100%", height: "100%", padding: "0 10px", overflowY: "auto", + overflowX: "hidden", }); export const InpaintingSlider = style({ @@ -16,10 +17,11 @@ export const InpaintingSlider = style({ backgroundColor: "rgba(0, 0, 0, 0.5)", }); -export const QueueSlider = style({ +export const QueueSlider = style([PanelBox, { position: "absolute", top: "10px", left: "400px", zIndex: 1, - backgroundColor: "rgba(0, 0, 0, 0.5)", -}); \ No newline at end of file + maxHeight: "90%", + overflowY: "auto", +}]); \ No newline at end of file diff --git a/ui/frontend/build_src/src/components/organisms/creationPanel/imageModifiers/index.tsx b/ui/frontend/build_src/src/components/organisms/creationPanel/imageModifiers/index.tsx index a0cc296b..c9343d58 100644 --- a/ui/frontend/build_src/src/components/organisms/creationPanel/imageModifiers/index.tsx +++ b/ui/frontend/build_src/src/components/organisms/creationPanel/imageModifiers/index.tsx @@ -15,7 +15,7 @@ import { import { ModifierObject, useImageCreate } from "../../../../stores/imageCreateStore"; import { useCreateUI } from "../creationPanelUIStore"; -import ModifierTag from "../../../atoms/modifierTag"; +import ModifierTag from "../../../molecules/modifierTag"; interface ModifierListProps { category: string; diff --git a/ui/frontend/build_src/src/components/organisms/creationPanel/index.tsx b/ui/frontend/build_src/src/components/organisms/creationPanel/index.tsx index 141e0001..ec7a0e13 100644 --- a/ui/frontend/build_src/src/components/organisms/creationPanel/index.tsx +++ b/ui/frontend/build_src/src/components/organisms/creationPanel/index.tsx @@ -11,7 +11,7 @@ import QueueDisplay from "../queueDisplay"; // import { useImageCreate } from "@stores/imageCreateStore.ts"; import { useImageCreate } from "../../../stores/imageCreateStore"; -import { useImageQueue } from "../../../stores/imageQueueStore"; +import { useRequestQueue } from "../../../stores/requestQueueStore"; import { useCreateUI } from "./creationPanelUIStore"; @@ -24,12 +24,11 @@ import { } from "./creationPanel.css"; - export default function CreationPanel() { const isInPaintingMode = useImageCreate((state) => state.isInpainting); const showQueue = useCreateUI((state) => state.showQueue); - const hasQueue = useImageQueue((state) => state.hasQueuedImages()); + const hasQueue = useRequestQueue((state) => state.hasAnyQueue()); // console.log('hasQueue', hasQueue); console.log('showQueue', showQueue); @@ -48,7 +47,7 @@ export default function CreationPanel() { )} - {(showQueue) && ( + {(showQueue && hasQueue) && (
diff --git a/ui/frontend/build_src/src/components/organisms/queueDisplay/index.tsx b/ui/frontend/build_src/src/components/organisms/queueDisplay/index.tsx index 46e0cc82..b0ed115a 100644 --- a/ui/frontend/build_src/src/components/organisms/queueDisplay/index.tsx +++ b/ui/frontend/build_src/src/components/organisms/queueDisplay/index.tsx @@ -1,24 +1,45 @@ import React from "react"; +import { ImageRequest } from "../../../api"; -import { useImageQueue } from "../../../stores/imageQueueStore"; - +import { QueuedRequest, useRequestQueue } from "../../../stores/requestQueueStore"; import { - QueueDisplayMain + QueueDisplayMain, + QueueListButtons, + CompleteButtton, + ErrorButton } from "./queueDisplay.css"; + +import ClearQueue from "../../molecules/clearQueue"; import QueueItem from "./queueItem"; + export default function QueueDisplay() { - const images = useImageQueue((state) => state.images); - console.log('images', images); + const requests: QueuedRequest[] = useRequestQueue((state) => state.requests); + const removeCompleted = useRequestQueue((state) => state.removeCompleted); + const removeErrored = useRequestQueue((state) => state.removeErrored); + const clearCompleted = () => { + console.log('clear completed'); + removeCompleted(); + } + + const clearErrored = () => { + console.log('clear errored'); + removeErrored(); + } return (
- {images.map((image) => { - return ; + +
+ + +
+ {requests.map((request) => { + return ; })}
); diff --git a/ui/frontend/build_src/src/components/organisms/queueDisplay/queueDisplay.css.ts b/ui/frontend/build_src/src/components/organisms/queueDisplay/queueDisplay.css.ts index f2d6d204..c052afb4 100644 --- a/ui/frontend/build_src/src/components/organisms/queueDisplay/queueDisplay.css.ts +++ b/ui/frontend/build_src/src/components/organisms/queueDisplay/queueDisplay.css.ts @@ -1,10 +1,39 @@ -import { style } from "@vanilla-extract/css"; +import { style, globalStyle } from "@vanilla-extract/css"; + +import { BrandedButton } from "../../../styles/shared.css"; + +import { vars } from "../../../styles/theme/index.css"; export const QueueDisplayMain = style({ display: "flex", flexDirection: "column", width: '400px', height: '100%', - backgroundColor: 'rgba(0, 0, 0, 0.5)', - }); + +export const QueueListButtons = style({ + display: "flex", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + marginBottom: vars.spacing.medium, + marginTop: vars.spacing.medium, +}); + +globalStyle(`${QueueListButtons} button`, { + flexGrow: 1, +}); + +globalStyle(`${QueueListButtons} button:first-child`, { + marginRight: vars.spacing.medium, +}); + + +// TODO these should be a button recipe? +export const CompleteButtton = style([BrandedButton, { + +}]); + +export const ErrorButton = style([BrandedButton, { + +}]); \ No newline at end of file diff --git a/ui/frontend/build_src/src/components/organisms/queueDisplay/queueItem/index.tsx b/ui/frontend/build_src/src/components/organisms/queueDisplay/queueItem/index.tsx index 15d95508..289c5f7f 100644 --- a/ui/frontend/build_src/src/components/organisms/queueDisplay/queueItem/index.tsx +++ b/ui/frontend/build_src/src/components/organisms/queueDisplay/queueItem/index.tsx @@ -1,20 +1,37 @@ import React from "react"; -import { - QueueItemMain -} from "./queueItem.css"; - import { ImageRequest } from '../../../../api' +import { QueueStatus, QueuedRequest, useRequestQueue } from '../../../../stores/requestQueueStore'; + +import StopButton from '../../../molecules/stopButton'; + +import { + QueueItemMain, + QueueButtons, + CompleteButtton, + PauseButton, + ResumeButton, + CancelButton, + RetryButton, + SendToTopButton, +} from "./queueItem.css"; + + interface QueueItemProps { - info: ImageRequest + request: QueuedRequest; } -export default function QueueItem({ info }: QueueItemProps) { +export default function QueueItem({ request }: QueueItemProps) { - console.log('info', info); + // console.log('info', info); + // console.log('status', status); + + const removeItem = useRequestQueue((state) => state.removeItem); + const updateStatus = useRequestQueue((state) => state.updateStatus); + const sendPendingToTop = useRequestQueue((state) => state.sendPendingToTop); const { id, @@ -23,16 +40,64 @@ export default function QueueItem({ info }: QueueItemProps) { seed, sampler, }, - // status, - } = info; + status, + } = request; + + const removeFromQueue = () => { + console.log('remove from queue'); + removeItem(id); + } + + const pauseItem = () => { + console.log('pause item'); + updateStatus(id, QueueStatus.paused); + } + + const retryRequest = () => { + console.log('retry request'); + updateStatus(id, QueueStatus.pending); + } + + const sendToTop = () => { + console.log('send to top'); + sendPendingToTop(id); + } return ( -
-
{id}
+
+ {/* @ts-expect-error */} +
{status}
{prompt}
{seed}
{sampler}
+
+ + {status === QueueStatus.processing && ( + + )} + + {status === QueueStatus.complete && ( + + )} + + {status === QueueStatus.pending && ( + <> + + + + + )} + + {status === QueueStatus.paused && ( + + )} + + {status === QueueStatus.error && ( + + )} +
+
); } \ No newline at end of file diff --git a/ui/frontend/build_src/src/components/organisms/queueDisplay/queueItem/queueItem.css.ts b/ui/frontend/build_src/src/components/organisms/queueDisplay/queueItem/queueItem.css.ts index 6fd48e1c..c51c57f8 100644 --- a/ui/frontend/build_src/src/components/organisms/queueDisplay/queueItem/queueItem.css.ts +++ b/ui/frontend/build_src/src/components/organisms/queueDisplay/queueItem/queueItem.css.ts @@ -1,9 +1,68 @@ -import { style } from "@vanilla-extract/css"; +import { style, globalStyle } from "@vanilla-extract/css"; +import { vars } from "../../../../styles/theme/index.css"; + +import { BrandedButton } from "../../../../styles/shared.css"; + +import { QueueStatus } from "../../../../stores/requestQueueStore"; + export const QueueItemMain = style({ display: "flex", flexDirection: "column", width: "100%", padding: "0.5rem", -}); \ No newline at end of file +}); + +globalStyle(`${QueueItemMain}.${QueueStatus.processing}`, { + backgroundColor: vars.colors.warning, +}); + +globalStyle(`${QueueItemMain}.${QueueStatus.pending}`, { + backgroundColor: vars.colors.backgroundDark, +}); + +globalStyle(`${QueueItemMain}.${QueueStatus.paused}`, { + backgroundColor: vars.colors.backgroundAlt, +}); + +globalStyle(`${QueueItemMain}.${QueueStatus.complete}`, { + backgroundColor: vars.colors.success, +}); + +globalStyle(`${QueueItemMain}.${QueueStatus.error}`, { + backgroundColor: vars.colors.error, +}); + +export const QueueButtons = style({ + display: "flex", + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", +}); + + +// TODO these should be a button recipe? +export const CompleteButtton = style([BrandedButton, { + +}]); + +export const PauseButton = style([BrandedButton, { + +}]); + +export const ResumeButton = style([BrandedButton, { + +}]); + +export const CancelButton = style([BrandedButton, { + +}]); + +export const RetryButton = style([BrandedButton, { + +}]); + +export const SendToTopButton = style([BrandedButton, { + +}]); diff --git a/ui/frontend/build_src/src/stores/imageFetchingStore.ts b/ui/frontend/build_src/src/stores/imageFetchingStore.ts index 7fc1c9d6..42391a31 100644 --- a/ui/frontend/build_src/src/stores/imageFetchingStore.ts +++ b/ui/frontend/build_src/src/stores/imageFetchingStore.ts @@ -27,7 +27,6 @@ interface ImageFetchingState { setStartTime: () => void; setNowTime: () => void; resetForFetching: () => void; - } export const useImageFetching = create((set) => ({ diff --git a/ui/frontend/build_src/src/stores/imageQueueStore.ts b/ui/frontend/build_src/src/stores/imageQueueStore.ts deleted file mode 100644 index a3ef7e21..00000000 --- a/ui/frontend/build_src/src/stores/imageQueueStore.ts +++ /dev/null @@ -1,78 +0,0 @@ -import create from "zustand"; -import produce from "immer"; -import { useRandomSeed } from "../utils"; - -import { ImageRequest } from "../api"; - -interface QueueItem { - id?: string; - options?: ImageRequest; - status?: "pending" | "complete" | "error"; -} - -interface ImageQueueState { - images: QueueItem[]; - completedImageIds: string[]; - addNewImage: (id: string, imgRec: ImageRequest) => void; - hasQueuedImages: () => boolean; - firstInQueue: () => QueueItem; - removeFirstInQueue: () => void; - clearQueue: () => void; - clearCachedIds: () => void; -} - -export const useImageQueue = create((set, get) => ({ - images: [], - completedImageIds: [], - // use produce to make sure we don't mutate state - addNewImage: (id: string, imgRec: ImageRequest) => { - set( - produce((state) => { - const item: QueueItem = { id, options: imgRec, status: "pending" }; - state.images.push(item); - }) - ); - }, - - hasQueuedImages: () => { - return get().images.length > 0; - }, - - firstInQueue: () => { - const { images } = get(); - if (images.length > 0) { - return images[0]; - } - // // cast an empty object to QueueItem - const empty: QueueItem = {}; - return empty; - - }, - - removeFirstInQueue: () => { - set( - produce((state) => { - const image = state.images.shift(); - if (void 0 !== image) { - state.completedImageIds.push(image.id); - } - }) - ); - }, - - clearQueue: () => { - set( - produce((state) => { - state.images = []; - }) - ); - }, - - clearCachedIds: () => { - set( - produce((state) => { - state.completedImageIds = []; - }) - ); - }, -})); diff --git a/ui/frontend/build_src/src/stores/requestQueueStore.ts b/ui/frontend/build_src/src/stores/requestQueueStore.ts new file mode 100644 index 00000000..75de334a --- /dev/null +++ b/ui/frontend/build_src/src/stores/requestQueueStore.ts @@ -0,0 +1,143 @@ +import create from "zustand"; +import produce from "immer"; + +import { ImageRequest } from "../api"; + +export enum QueueStatus { + pending = "pending", + processing = "processing", + complete = "complete", + paused = "paused", + error = "error", +} + +export interface QueuedRequest { + id: string; + options: ImageRequest; + status: QueueStatus[keyof QueueStatus]; + //"pending" | "processing" | "complete" | "error"; +} + +interface RequestQueueState { + requests: QueuedRequest[]; + addtoQueue: (id: string, imgRec: ImageRequest) => void; + pendingRequests: () => QueuedRequest[]; + hasPendingQueue: () => boolean; + hasAnyQueue: () => boolean; + firstInQueue: () => QueuedRequest; + updateStatus: (id: string, status: QueueStatus[keyof QueueStatus]) => void; + sendPendingToTop: (id: string) => void; + removeItem: (id: string) => void; + removeCompleted: () => void; + removeErrored: () => void; + clearQueue: () => void; + +} + +export const useRequestQueue = create((set, get) => ({ + requests: [], + // use produce to make sure we don't mutate state + addtoQueue: (id: string, imgRec: ImageRequest) => { + set( + produce((state) => { + const item: QueuedRequest = { id, options: imgRec, status: QueueStatus.pending }; + state.requests.push(item); + }) + ); + }, + + pendingRequests: () => { + return get().requests.filter((item) => item.status === QueueStatus.pending); + }, + + hasPendingQueue: () => { + return get().pendingRequests().length > 0; + }, + + hasAnyQueue: () => { + return get().requests.length > 0; + }, + + firstInQueue: () => { + const pending = get().pendingRequests()[0]; + + if (pending === undefined) { + // eslint-disable-next-line @typescript-eslint/consistent-type-assertions + const temp: QueuedRequest = { id: "", options: ({} as ImageRequest), status: QueueStatus.pending }; + return temp; + } + return pending; + }, + + updateStatus: (id: string, status: QueueStatus[keyof QueueStatus]) => { + set( + produce((state) => { + const item = state.requests.find((item: QueuedRequest) => item.id === id); + if (void 0 !== item) { + item.status = status; + } + }) + ); + }, + + sendPendingToTop: (id: string) => { + set( + produce((state) => { + const item = state.requests.find((item: QueuedRequest) => item.id === id); + if (void 0 !== item) { + const index = state.requests.indexOf(item); + // insert infront of the pending requests + const pending = get().pendingRequests(); + const pendingIndex = state.requests.indexOf(pending[0]); + console.log() + state.requests.splice(index, 1); + state.requests.splice(pendingIndex, 0, item); + } + }) + ); + }, + + removeItem: (id: string) => { + set( + produce((state) => { + const index = state.requests.findIndex((item: QueuedRequest) => item.id === id); + if (index > -1) { + state.requests.splice(index, 1); + } + }) + ); + }, + + removeCompleted: () => { + set( + produce((state) => { + const completed = state.requests.filter((item: QueuedRequest) => item.status === QueueStatus.complete); + completed.forEach((item: QueuedRequest) => { + const index = state.requests.indexOf(item); + state.requests.splice(index, 1); + }); + }) + ); + }, + + removeErrored: () => { + set( + produce((state) => { + const errored = state.requests.filter((item: QueuedRequest) => item.status === QueueStatus.error); + errored.forEach((item: QueuedRequest) => { + const index = state.requests.indexOf(item); + state.requests.splice(index, 1); + }); + }) + ); + }, + + + clearQueue: () => { + set( + produce((state) => { + state.requests = []; + }) + ); + }, +}));