From 2b562d94644c76ee064e88b7098b7f2b95c5ce02 Mon Sep 17 00:00:00 2001 From: Sean Sube Date: Wed, 10 Jan 2024 21:47:21 -0600 Subject: [PATCH] feat(gui): make layout direction and history width persist --- gui/src/components/ImageHistory.tsx | 13 ++- gui/src/components/OnnxWeb.tsx | 115 ++++++++++++++++++-------- gui/src/components/card/ErrorCard.tsx | 4 +- gui/src/components/tab/Settings.tsx | 13 ++- gui/src/constants.ts | 4 +- gui/src/main.tsx | 2 + gui/src/state/full.ts | 7 +- gui/src/state/history.ts | 1 + gui/src/strings/de.ts | 5 +- gui/src/strings/en.ts | 5 +- gui/src/strings/es.ts | 5 +- gui/src/strings/fr.ts | 5 +- 12 files changed, 127 insertions(+), 52 deletions(-) diff --git a/gui/src/components/ImageHistory.tsx b/gui/src/components/ImageHistory.tsx index 56f061a5..03c82dcd 100644 --- a/gui/src/components/ImageHistory.tsx +++ b/gui/src/components/ImageHistory.tsx @@ -1,4 +1,4 @@ -import { doesExist, mustExist } from '@apextoaster/js-utils'; +import { mustExist } from '@apextoaster/js-utils'; import { Grid, Typography } from '@mui/material'; import { ReactNode, useContext } from 'react'; import * as React from 'react'; @@ -12,7 +12,13 @@ import { ImageCard } from './card/ImageCard.js'; import { LoadingCard } from './card/LoadingCard.js'; import { JobStatus } from '../types/api-v2.js'; -export function ImageHistory() { +export interface ImageHistoryProps { + width: number; +} + +export function ImageHistory(props: ImageHistoryProps) { + const { width } = props; + const store = mustExist(useContext(StateContext)); const { history, limit } = useStore(store, selectParams, shallow); const { removeHistory } = useStore(store, selectActions, shallow); @@ -42,7 +48,8 @@ export function ImageHistory() { } } - return {children.map(([key, child]) => {child})}; + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + return {children.map(([key, child]) => {child})}; } export function selectActions(state: OnnxState) { diff --git a/gui/src/components/OnnxWeb.tsx b/gui/src/components/OnnxWeb.tsx index a593b002..53adb35a 100644 --- a/gui/src/components/OnnxWeb.tsx +++ b/gui/src/components/OnnxWeb.tsx @@ -1,7 +1,8 @@ +/* eslint-disable @typescript-eslint/no-magic-numbers */ import { mustExist } from '@apextoaster/js-utils'; import { TabContext, TabList, TabPanel } from '@mui/lab'; -import { Box, Container, CssBaseline, Divider, Tab, useMediaQuery } from '@mui/material'; -import { ThemeProvider, createTheme } from '@mui/material/styles'; +import { Box, Button, Container, CssBaseline, Divider, Stack, Tab, useMediaQuery } from '@mui/material'; +import { Breakpoint, SxProps, Theme, ThemeProvider, createTheme } from '@mui/material/styles'; import * as React from 'react'; import { useContext, useMemo } from 'react'; import { useHash } from 'react-use/lib/useHash'; @@ -29,6 +30,7 @@ export function OnnxWeb(props: OnnxWebProps) { const prefersDarkMode = useMediaQuery('(prefers-color-scheme: dark)'); const store = mustExist(useContext(StateContext)); const stateTheme = useStore(store, selectTheme); + const layout = useStore(store, selectLayout); const theme = useMemo( () => createTheme({ @@ -41,48 +43,58 @@ export function OnnxWeb(props: OnnxWebProps) { const [hash, setHash] = useHash(); + const historyStyle: SxProps = { + mx: 4, + my: 4, + ...LAYOUT_STYLES[layout.direction].history.style, + }; + return ( - + {props.motd && } - - - { - setHash(idx); - }}> - {TAB_LABELS.map((name) => )} - + + + + + { + setHash(idx); + }}> + {TAB_LABELS.map((name) => )} + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - + ); @@ -91,3 +103,34 @@ export function OnnxWeb(props: OnnxWebProps) { export function selectTheme(state: OnnxState) { return state.theme; } + +export function selectLayout(state: OnnxState) { + return { + direction: state.layout, + width: state.historyWidth, + }; +} + +export const LAYOUT_STYLES = { + horizontal: { + container: false, + direction: 'row', + divider: 'vertical', + history: { + style: { + maxHeight: '85vb', + overflowY: 'auto', + }, + width: 4, + }, + }, + vertical: { + container: 'lg' as Breakpoint, + direction: 'column', + divider: 'horizontal', + history: { + style: {}, + width: 2, + }, + }, +} as const; diff --git a/gui/src/components/card/ErrorCard.tsx b/gui/src/components/card/ErrorCard.tsx index 5126d573..eee27f3a 100644 --- a/gui/src/components/card/ErrorCard.tsx +++ b/gui/src/components/card/ErrorCard.tsx @@ -90,11 +90,9 @@ export const UNKNOWN_ERROR = `${IMAGE_ERROR}unknown`; export function getImageErrorReason(image: FailedJobResponse | UnknownJobResponse) { if (image.status === JobStatus.FAILED) { const error = image.reason; - if (doesExist(error) && error.startsWith(ANY_ERROR)) { + if (doesExist(error)) { return error; } - - return `${IMAGE_ERROR}${error}`; } return UNKNOWN_ERROR; diff --git a/gui/src/components/tab/Settings.tsx b/gui/src/components/tab/Settings.tsx index 7b25ed3b..54f7db79 100644 --- a/gui/src/components/tab/Settings.tsx +++ b/gui/src/components/tab/Settings.tsx @@ -40,13 +40,22 @@ export function Settings() { return state.setLimit(value)} /> + state.setWidth(value)} + /> + { state.setDefaults({ prompt: event.target.value, diff --git a/gui/src/constants.ts b/gui/src/constants.ts index eb718447..74018a7a 100644 --- a/gui/src/constants.ts +++ b/gui/src/constants.ts @@ -21,11 +21,11 @@ export const DEFAULT_HISTORY = { /** * The number of images to be shown. */ - limit: 4, + limit: 8, /** * The number of additional images to be kept in history, so they can scroll * back into view when you delete one. Does not include deleted images. */ - scrollback: 2, + scrollback: 4, }; diff --git a/gui/src/main.tsx b/gui/src/main.tsx index 8d367782..6e57fde0 100644 --- a/gui/src/main.tsx +++ b/gui/src/main.tsx @@ -65,6 +65,7 @@ export async function renderApp(config: Config, params: ServerParams, logger: Lo createBlendSlice, createResetSlice, createProfileSlice, + createSettingsSlice, } = createStateSlices(params); const state = createStore(persist((...slice) => ({ ...createDefaultSlice(...slice), @@ -77,6 +78,7 @@ export async function renderApp(config: Config, params: ServerParams, logger: Lo ...createBlendSlice(...slice), ...createResetSlice(...slice), ...createProfileSlice(...slice), + ...createSettingsSlice(...slice), }), { migrate(persistedState, version) { return applyStateMigrations(params, persistedState as UnknownState, version, logger); diff --git a/gui/src/state/full.ts b/gui/src/state/full.ts index 990161ae..eb127a20 100644 --- a/gui/src/state/full.ts +++ b/gui/src/state/full.ts @@ -17,6 +17,7 @@ import { InpaintSlice, createInpaintSlice } from './inpaint.js'; import { ModelSlice, createModelSlice } from './model.js'; import { ProfileSlice, createProfileSlice } from './profile.js'; import { ResetSlice, createResetSlice } from './reset.js'; +import { SettingsSlice, createSettingsSlice } from './settings.js'; import { Txt2ImgSlice, createTxt2ImgSlice } from './txt2img.js'; import { UpscaleSlice, createUpscaleSlice } from './upscale.js'; import { @@ -39,7 +40,8 @@ export type OnnxState & UpscaleSlice & BlendSlice & ResetSlice - & ProfileSlice; + & ProfileSlice + & SettingsSlice; /** * React context binding for API client. @@ -69,7 +71,7 @@ export const STATE_KEY = 'onnx-web'; /** * Current state version for zustand persistence. */ -export const STATE_VERSION = 11; +export const STATE_VERSION = 13; export function baseParamsFromServer(defaults: ServerParams): Required { return { @@ -144,6 +146,7 @@ export function createStateSlices(server: ServerParams) { createModelSlice: createModelSlice(), createProfileSlice: createProfileSlice(), createResetSlice: createResetSlice(), + createSettingsSlice: createSettingsSlice(), createTxt2ImgSlice: createTxt2ImgSlice(server, defaultParams, defaultHighres, defaultModel, defaultUpscale, defaultGrid), createUpscaleSlice: createUpscaleSlice(defaultParams, defaultHighres, defaultModel, defaultUpscale), }; diff --git a/gui/src/state/history.ts b/gui/src/state/history.ts index c71da4a1..213e42af 100644 --- a/gui/src/state/history.ts +++ b/gui/src/state/history.ts @@ -21,6 +21,7 @@ export interface HistorySlice { pushHistory(image: JobResponse, retry?: RetryParams): void; removeHistory(image: JobResponse): void; + setLimit(limit: number): void; setReady(image: JobResponse): void; } diff --git a/gui/src/strings/de.ts b/gui/src/strings/de.ts index d2fd9e37..31a4975b 100644 --- a/gui/src/strings/de.ts +++ b/gui/src/strings/de.ts @@ -212,7 +212,10 @@ export const I18N_STRINGS_DE = { }, setting: { connectServer: 'verbinden zum Server', - history: 'Bildgeschichte', + history: { + limit: 'Bildgeschichte', + width: '', + }, loadState: 'Laden', prompt: 'Standard-Eingabeaufforderung', reset: { diff --git a/gui/src/strings/en.ts b/gui/src/strings/en.ts index ad342461..30f1d75d 100644 --- a/gui/src/strings/en.ts +++ b/gui/src/strings/en.ts @@ -275,7 +275,10 @@ export const I18N_STRINGS_EN = { }, setting: { connectServer: 'Connect', - history: 'Image History', + history: { + limit: 'Image History Length', + width: 'Image History Width', + }, loadState: 'Load', prompt: 'Default Prompt', reset: { diff --git a/gui/src/strings/es.ts b/gui/src/strings/es.ts index 0c68942b..6dd12274 100644 --- a/gui/src/strings/es.ts +++ b/gui/src/strings/es.ts @@ -212,7 +212,10 @@ export const I18N_STRINGS_ES = { }, setting: { connectServer: 'Conectar al servidor', - history: 'Historia de la imagen', + history: { + limit: 'Historia de la imagen', + width: '', + }, loadState: 'Carga estado', prompt: 'Solicitud predeterminada', reset: { diff --git a/gui/src/strings/fr.ts b/gui/src/strings/fr.ts index 5fa19c0d..8f6e2b35 100644 --- a/gui/src/strings/fr.ts +++ b/gui/src/strings/fr.ts @@ -212,7 +212,10 @@ export const I18N_STRINGS_FR = { }, setting: { connectServer: '', - history: '', + history: { + limit: '', + width: '', + }, loadState: '', prompt: '', reset: {