feat(gui): add error status to image card
This commit is contained in:
parent
ed8a7c8934
commit
6226778cfb
|
@ -175,8 +175,8 @@ export interface ImageResponse {
|
||||||
* Status response from the ready endpoint.
|
* Status response from the ready endpoint.
|
||||||
*/
|
*/
|
||||||
export interface ReadyResponse {
|
export interface ReadyResponse {
|
||||||
cancel: boolean;
|
cancelled: boolean;
|
||||||
error: boolean;
|
failed: boolean;
|
||||||
progress: number;
|
progress: number;
|
||||||
ready: boolean;
|
ready: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,38 +1,45 @@
|
||||||
import { doesExist, mustExist } from '@apextoaster/js-utils';
|
import { doesExist, mustExist } from '@apextoaster/js-utils';
|
||||||
import { Grid, Typography } from '@mui/material';
|
import { Grid, Typography } from '@mui/material';
|
||||||
import { useContext } from 'react';
|
import { useContext, ReactNode } from 'react';
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import { useStore } from 'zustand';
|
import { useStore } from 'zustand';
|
||||||
|
|
||||||
import { StateContext } from '../state.js';
|
import { StateContext } from '../state.js';
|
||||||
import { ImageCard } from './ImageCard.js';
|
import { ImageCard } from './card/ImageCard.js';
|
||||||
import { LoadingCard } from './LoadingCard.js';
|
import { LoadingCard } from './card/LoadingCard.js';
|
||||||
|
import { ErrorCard } from './card/RetryCard.js';
|
||||||
|
|
||||||
export function ImageHistory() {
|
export function ImageHistory() {
|
||||||
const history = useStore(mustExist(useContext(StateContext)), (state) => state.history);
|
const history = useStore(mustExist(useContext(StateContext)), (state) => state.history);
|
||||||
const limit = useStore(mustExist(useContext(StateContext)), (state) => state.limit);
|
const limit = useStore(mustExist(useContext(StateContext)), (state) => state.limit);
|
||||||
const loading = useStore(mustExist(useContext(StateContext)), (state) => state.loading);
|
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const removeHistory = useStore(mustExist(useContext(StateContext)), (state) => state.removeHistory);
|
const removeHistory = useStore(mustExist(useContext(StateContext)), (state) => state.removeHistory);
|
||||||
|
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const children = [];
|
const children: Array<[string, ReactNode]> = [];
|
||||||
|
|
||||||
if (loading.length > 0) {
|
if (history.length === 0) {
|
||||||
children.push(...loading.map((item) => <LoadingCard key={`loading-${item.image.outputs[0].key}`} index={0} loading={item.image} />));
|
children.push(['empty', <Typography>{t('history.empty')}</Typography>]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (history.length > 0) {
|
const limited = history.slice(0, limit);
|
||||||
children.push(...history.map((item) => <ImageCard key={`history-${item.outputs[0].key}`} value={item} onDelete={removeHistory} />));
|
for (const item of limited) {
|
||||||
} else {
|
const key = item.image.outputs[0].key;
|
||||||
if (doesExist(loading) === false) {
|
|
||||||
children.push(<Typography>{t('history.empty')}</Typography>);
|
if (doesExist(item.ready) && item.ready.ready) {
|
||||||
}
|
if (item.ready.cancelled || item.ready.failed) {
|
||||||
|
children.push([key, <ErrorCard key={`history-${key}`} image={item.image} ready={item.ready} />]);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const limited = children.slice(0, limit);
|
children.push([key, <ImageCard key={`history-${key}`} image={item.image} onDelete={removeHistory} />]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
return <Grid container spacing={2}>{limited.map((child, idx) => <Grid item key={idx} xs={6}>{child}</Grid>)}</Grid>;
|
children.push([key, <LoadingCard key={`history-${key}`} index={0} image={item.image} />]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return <Grid container spacing={2}>{children.map(([key, child]) => <Grid item key={key} xs={6}>{child}</Grid>)}</Grid>;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,12 @@ import { useTranslation } from 'react-i18next';
|
||||||
import { useHash } from 'react-use/lib/useHash';
|
import { useHash } from 'react-use/lib/useHash';
|
||||||
import { useStore } from 'zustand';
|
import { useStore } from 'zustand';
|
||||||
|
|
||||||
import { ImageResponse } from '../client/api.js';
|
import { ImageResponse } from '../../client/api.js';
|
||||||
import { BLEND_SOURCES, ConfigContext, StateContext } from '../state.js';
|
import { BLEND_SOURCES, ConfigContext, StateContext } from '../../state.js';
|
||||||
import { range, visibleIndex } from '../utils.js';
|
import { range, visibleIndex } from '../../utils.js';
|
||||||
|
|
||||||
export interface ImageCardProps {
|
export interface ImageCardProps {
|
||||||
value: ImageResponse;
|
image: ImageResponse;
|
||||||
|
|
||||||
onDelete?: (key: ImageResponse) => void;
|
onDelete?: (key: ImageResponse) => void;
|
||||||
}
|
}
|
||||||
|
@ -24,8 +24,8 @@ export function GridItem(props: { xs: number; children: React.ReactNode }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ImageCard(props: ImageCardProps) {
|
export function ImageCard(props: ImageCardProps) {
|
||||||
const { value } = props;
|
const { image } = props;
|
||||||
const { params, outputs, size } = value;
|
const { params, outputs, size } = image;
|
||||||
|
|
||||||
const [_hash, setHash] = useHash();
|
const [_hash, setHash] = useHash();
|
||||||
const [anchor, setAnchor] = useState<Maybe<HTMLElement>>();
|
const [anchor, setAnchor] = useState<Maybe<HTMLElement>>();
|
||||||
|
@ -83,7 +83,7 @@ export function ImageCard(props: ImageCardProps) {
|
||||||
|
|
||||||
function deleteImage() {
|
function deleteImage() {
|
||||||
if (doesExist(props.onDelete)) {
|
if (doesExist(props.onDelete)) {
|
||||||
props.onDelete(value);
|
props.onDelete(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,36 +7,34 @@ import { useTranslation } from 'react-i18next';
|
||||||
import { useMutation, useQuery } from 'react-query';
|
import { useMutation, useQuery } from 'react-query';
|
||||||
import { useStore } from 'zustand';
|
import { useStore } from 'zustand';
|
||||||
|
|
||||||
import { ImageResponse } from '../client/api.js';
|
import { ImageResponse } from '../../client/api.js';
|
||||||
import { POLL_TIME } from '../config.js';
|
import { POLL_TIME } from '../../config.js';
|
||||||
import { ClientContext, ConfigContext, StateContext } from '../state.js';
|
import { ClientContext, ConfigContext, StateContext } from '../../state.js';
|
||||||
|
|
||||||
const LOADING_PERCENT = 100;
|
const LOADING_PERCENT = 100;
|
||||||
const LOADING_OVERAGE = 99;
|
const LOADING_OVERAGE = 99;
|
||||||
|
|
||||||
export interface LoadingCardProps {
|
export interface LoadingCardProps {
|
||||||
|
image: ImageResponse;
|
||||||
index: number;
|
index: number;
|
||||||
loading: ImageResponse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LoadingCard(props: LoadingCardProps) {
|
export function LoadingCard(props: LoadingCardProps) {
|
||||||
const { index, loading } = props;
|
const { image, index } = props;
|
||||||
const { steps } = props.loading.params;
|
const { steps } = props.image.params;
|
||||||
|
|
||||||
const client = mustExist(React.useContext(ClientContext));
|
const client = mustExist(React.useContext(ClientContext));
|
||||||
const { params } = mustExist(useContext(ConfigContext));
|
const { params } = mustExist(useContext(ConfigContext));
|
||||||
|
|
||||||
const state = mustExist(useContext(StateContext));
|
const state = mustExist(useContext(StateContext));
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const clearLoading = useStore(state, (s) => s.clearLoading);
|
const removeHistory = useStore(state, (s) => s.removeHistory);
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
||||||
const pushHistory = useStore(state, (s) => s.pushHistory);
|
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const setReady = useStore(state, (s) => s.setReady);
|
const setReady = useStore(state, (s) => s.setReady);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const cancel = useMutation(() => client.cancel(loading.outputs[index].key));
|
const cancel = useMutation(() => client.cancel(image.outputs[index].key));
|
||||||
const ready = useQuery(`ready-${loading.outputs[index].key}`, () => client.ready(loading.outputs[index].key), {
|
const ready = useQuery(`ready-${image.outputs[index].key}`, () => client.ready(image.outputs[index].key), {
|
||||||
// data will always be ready without this, even if the API says its not
|
// data will always be ready without this, even if the API says its not
|
||||||
cacheTime: 0,
|
cacheTime: 0,
|
||||||
refetchInterval: POLL_TIME,
|
refetchInterval: POLL_TIME,
|
||||||
|
@ -86,17 +84,13 @@ export function LoadingCard(props: LoadingCardProps) {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (cancel.status === 'success') {
|
if (cancel.status === 'success') {
|
||||||
clearLoading(props.loading);
|
removeHistory(props.image);
|
||||||
}
|
}
|
||||||
}, [cancel.status]);
|
}, [cancel.status]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ready.status === 'success') {
|
if (ready.status === 'success' && getReady()) {
|
||||||
if (ready.data.ready) {
|
setReady(props.image, ready.data);
|
||||||
pushHistory(props.loading);
|
|
||||||
} else {
|
|
||||||
setReady(props.loading, ready.data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}, [ready.status, getReady(), getProgress()]);
|
}, [ready.status, getReady(), getProgress()]);
|
||||||
|
|
|
@ -0,0 +1,59 @@
|
||||||
|
import { mustExist } from '@apextoaster/js-utils';
|
||||||
|
import { Box, Button, Card, CardContent, Typography } from '@mui/material';
|
||||||
|
import { Stack } from '@mui/system';
|
||||||
|
import * as React from 'react';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
|
import { useMutation } from 'react-query';
|
||||||
|
import { useStore } from 'zustand';
|
||||||
|
|
||||||
|
import { ImageResponse, ReadyResponse } from '../../client/api.js';
|
||||||
|
import { ClientContext, ConfigContext, StateContext } from '../../state.js';
|
||||||
|
|
||||||
|
export interface ErrorCardProps {
|
||||||
|
image: ImageResponse;
|
||||||
|
ready: ReadyResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function ErrorCard(props: ErrorCardProps) {
|
||||||
|
const { image, ready } = props;
|
||||||
|
|
||||||
|
const client = mustExist(React.useContext(ClientContext));
|
||||||
|
const { params } = mustExist(useContext(ConfigContext));
|
||||||
|
|
||||||
|
const state = mustExist(useContext(StateContext));
|
||||||
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
|
const removeHistory = useStore(state, (s) => s.removeHistory);
|
||||||
|
const { t } = useTranslation();
|
||||||
|
|
||||||
|
// TODO: actually retry
|
||||||
|
const retry = useMutation(() => {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.log('retry', image);
|
||||||
|
return Promise.resolve(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
return <Card sx={{ maxWidth: params.width.default }}>
|
||||||
|
<CardContent sx={{ height: params.height.default }}>
|
||||||
|
<Box sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
minHeight: params.height.default,
|
||||||
|
}}>
|
||||||
|
<Stack
|
||||||
|
direction='column'
|
||||||
|
spacing={2}
|
||||||
|
sx={{ alignItems: 'center' }}
|
||||||
|
>
|
||||||
|
<Typography>{t('loading.progress', {
|
||||||
|
current: ready.progress,
|
||||||
|
total: image.params.steps,
|
||||||
|
})}</Typography>
|
||||||
|
<Button onClick={() => retry.mutate()}>{t('loading.retry')}</Button>
|
||||||
|
<Button onClick={() => removeHistory(image)}>{t('loading.remove')}</Button>
|
||||||
|
</Stack>
|
||||||
|
</Box>
|
||||||
|
</CardContent>
|
||||||
|
</Card>;
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ export function Blend() {
|
||||||
sources: mustExist(blend.sources), // TODO: show an error if this doesn't exist
|
sources: mustExist(blend.sources), // TODO: show an error if this doesn't exist
|
||||||
}, upscale);
|
}, upscale);
|
||||||
|
|
||||||
setLoading(output);
|
pushHistory(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = mustExist(useContext(ClientContext));
|
const client = mustExist(useContext(ClientContext));
|
||||||
|
@ -37,7 +37,7 @@ export function Blend() {
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const setBlend = useStore(state, (s) => s.setBlend);
|
const setBlend = useStore(state, (s) => s.setBlend);
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const setLoading = useStore(state, (s) => s.pushLoading);
|
const pushHistory = useStore(state, (s) => s.pushHistory);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const sources = mustDefault(blend.sources, []);
|
const sources = mustDefault(blend.sources, []);
|
||||||
|
|
|
@ -24,7 +24,7 @@ export function Img2Img() {
|
||||||
source: mustExist(img2img.source), // TODO: show an error if this doesn't exist
|
source: mustExist(img2img.source), // TODO: show an error if this doesn't exist
|
||||||
}, upscale);
|
}, upscale);
|
||||||
|
|
||||||
setLoading(output);
|
pushHistory(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = mustExist(useContext(ClientContext));
|
const client = mustExist(useContext(ClientContext));
|
||||||
|
@ -39,7 +39,7 @@ export function Img2Img() {
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const setImg2Img = useStore(state, (s) => s.setImg2Img);
|
const setImg2Img = useStore(state, (s) => s.setImg2Img);
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const setLoading = useStore(state, (s) => s.pushLoading);
|
const pushHistory = useStore(state, (s) => s.pushHistory);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return <Box>
|
return <Box>
|
||||||
|
|
|
@ -39,7 +39,7 @@ export function Inpaint() {
|
||||||
source: mustExist(source),
|
source: mustExist(source),
|
||||||
}, upscale);
|
}, upscale);
|
||||||
|
|
||||||
setLoading(output);
|
pushHistory(output);
|
||||||
} else {
|
} else {
|
||||||
const output = await client.inpaint(model, {
|
const output = await client.inpaint(model, {
|
||||||
...inpaint,
|
...inpaint,
|
||||||
|
@ -47,7 +47,7 @@ export function Inpaint() {
|
||||||
source: mustExist(source),
|
source: mustExist(source),
|
||||||
}, upscale);
|
}, upscale);
|
||||||
|
|
||||||
setLoading(output);
|
pushHistory(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ export function Inpaint() {
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const setInpaint = useStore(state, (s) => s.setInpaint);
|
const setInpaint = useStore(state, (s) => s.setInpaint);
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const setLoading = useStore(state, (s) => s.pushLoading);
|
const pushHistory = useStore(state, (s) => s.pushHistory);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
const query = useQueryClient();
|
const query = useQueryClient();
|
||||||
|
|
|
@ -18,7 +18,7 @@ export function Txt2Img() {
|
||||||
const { model, txt2img, upscale } = state.getState();
|
const { model, txt2img, upscale } = state.getState();
|
||||||
const output = await client.txt2img(model, txt2img, upscale);
|
const output = await client.txt2img(model, txt2img, upscale);
|
||||||
|
|
||||||
setLoading(output);
|
pushHistory(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = mustExist(useContext(ClientContext));
|
const client = mustExist(useContext(ClientContext));
|
||||||
|
@ -33,7 +33,7 @@ export function Txt2Img() {
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const setTxt2Img = useStore(state, (s) => s.setTxt2Img);
|
const setTxt2Img = useStore(state, (s) => s.setTxt2Img);
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const setLoading = useStore(state, (s) => s.pushLoading);
|
const pushHistory = useStore(state, (s) => s.pushHistory);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return <Box>
|
return <Box>
|
||||||
|
|
|
@ -21,7 +21,7 @@ export function Upscale() {
|
||||||
source: mustExist(params.source), // TODO: show an error if this doesn't exist
|
source: mustExist(params.source), // TODO: show an error if this doesn't exist
|
||||||
}, upscale);
|
}, upscale);
|
||||||
|
|
||||||
setLoading(output);
|
pushHistory(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
const client = mustExist(useContext(ClientContext));
|
const client = mustExist(useContext(ClientContext));
|
||||||
|
@ -35,7 +35,7 @@ export function Upscale() {
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const setSource = useStore(state, (s) => s.setUpscaleTab);
|
const setSource = useStore(state, (s) => s.setUpscaleTab);
|
||||||
// eslint-disable-next-line @typescript-eslint/unbound-method
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
||||||
const setLoading = useStore(state, (s) => s.pushLoading);
|
const pushHistory = useStore(state, (s) => s.pushHistory);
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
|
|
||||||
return <Box>
|
return <Box>
|
||||||
|
|
|
@ -27,7 +27,7 @@ import { Config, ConfigFiles, ConfigState, ServerParams } from './config.js';
|
||||||
*/
|
*/
|
||||||
type TabState<TabParams> = ConfigFiles<Required<TabParams>> & ConfigState<Required<TabParams>>;
|
type TabState<TabParams> = ConfigFiles<Required<TabParams>> & ConfigState<Required<TabParams>>;
|
||||||
|
|
||||||
interface LoadingItem {
|
interface HistoryItem {
|
||||||
image: ImageResponse;
|
image: ImageResponse;
|
||||||
ready: Maybe<ReadyResponse>;
|
ready: Maybe<ReadyResponse>;
|
||||||
}
|
}
|
||||||
|
@ -45,18 +45,12 @@ interface DefaultSlice {
|
||||||
}
|
}
|
||||||
|
|
||||||
interface HistorySlice {
|
interface HistorySlice {
|
||||||
history: Array<ImageResponse>;
|
history: Array<HistoryItem>;
|
||||||
limit: number;
|
limit: number;
|
||||||
loading: Array<LoadingItem>;
|
|
||||||
|
|
||||||
clearLoading(image: ImageResponse): void;
|
|
||||||
pushHistory(image: ImageResponse): void;
|
pushHistory(image: ImageResponse): void;
|
||||||
pushLoading(image: ImageResponse): void;
|
|
||||||
removeHistory(image: ImageResponse): void;
|
removeHistory(image: ImageResponse): void;
|
||||||
setLimit(limit: number): void;
|
setLimit(limit: number): void;
|
||||||
/**
|
|
||||||
* @todo should check ready and move the image from loading to history
|
|
||||||
*/
|
|
||||||
setReady(image: ImageResponse, ready: ReadyResponse): void;
|
setReady(image: ImageResponse, ready: ReadyResponse): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -164,7 +158,7 @@ export const STATE_KEY = 'onnx-web';
|
||||||
/**
|
/**
|
||||||
* Current state version for zustand persistence.
|
* Current state version for zustand persistence.
|
||||||
*/
|
*/
|
||||||
export const STATE_VERSION = 6;
|
export const STATE_VERSION = 7;
|
||||||
|
|
||||||
export const BLEND_SOURCES = 2;
|
export const BLEND_SOURCES = 2;
|
||||||
|
|
||||||
|
@ -307,42 +301,27 @@ export function createStateSlices(server: ServerParams) {
|
||||||
const createHistorySlice: Slice<HistorySlice> = (set) => ({
|
const createHistorySlice: Slice<HistorySlice> = (set) => ({
|
||||||
history: [],
|
history: [],
|
||||||
limit: DEFAULT_HISTORY.limit,
|
limit: DEFAULT_HISTORY.limit,
|
||||||
loading: [],
|
|
||||||
clearLoading(image) {
|
|
||||||
set((prev) => ({
|
|
||||||
...prev,
|
|
||||||
loading: prev.loading.filter((it) => it.image.outputs[0].key !== image.outputs[0].key),
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
pushHistory(image) {
|
pushHistory(image) {
|
||||||
set((prev) => ({
|
set((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
history: [
|
history: [
|
||||||
image,
|
|
||||||
...prev.history,
|
|
||||||
].slice(0, prev.limit + DEFAULT_HISTORY.scrollback),
|
|
||||||
loading: prev.loading.filter((it) => it.image.outputs[0].key !== image.outputs[0].key),
|
|
||||||
}));
|
|
||||||
},
|
|
||||||
pushLoading(image) {
|
|
||||||
set((prev) => ({
|
|
||||||
...prev,
|
|
||||||
loading: [
|
|
||||||
{
|
{
|
||||||
image,
|
image,
|
||||||
ready: {
|
ready: {
|
||||||
|
cancelled: false,
|
||||||
|
failed: false,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
ready: false,
|
ready: false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
...prev.loading,
|
...prev.history,
|
||||||
],
|
],
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
removeHistory(image) {
|
removeHistory(image) {
|
||||||
set((prev) => ({
|
set((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
history: prev.history.filter((it) => it.outputs !== image.outputs),
|
history: prev.history.filter((it) => it.image.outputs[0].key !== image.outputs[0].key),
|
||||||
}));
|
}));
|
||||||
},
|
},
|
||||||
setLimit(limit) {
|
setLimit(limit) {
|
||||||
|
@ -353,17 +332,17 @@ export function createStateSlices(server: ServerParams) {
|
||||||
},
|
},
|
||||||
setReady(image, ready) {
|
setReady(image, ready) {
|
||||||
set((prev) => {
|
set((prev) => {
|
||||||
const loading = [...prev.loading];
|
const history = [...prev.history];
|
||||||
const idx = loading.findIndex((it) => it.image.outputs[0].key === image.outputs[0].key);
|
const idx = history.findIndex((it) => it.image.outputs[0].key === image.outputs[0].key);
|
||||||
if (idx >= 0) {
|
if (idx >= 0) {
|
||||||
loading[idx].ready = ready;
|
history[idx].ready = ready;
|
||||||
} else {
|
} else {
|
||||||
// TODO: error
|
// TODO: error
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...prev,
|
...prev,
|
||||||
loading,
|
history,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in New Issue