From 95dafe66f872bb69cdff902c9e8486d92bcfb6c7 Mon Sep 17 00:00:00 2001 From: Egor Date: Thu, 21 Aug 2025 16:14:01 -0700 Subject: [PATCH] refactoring out duplicate code --- .cspell/project-terms.txt | 37 ++-- src/components/CheckboxWithTooltip.tsx | 31 +++ src/components/ModelFileField.tsx | 90 ++++++++ src/components/SectionHeader.tsx | 23 ++ src/components/screens/Launch/AdvancedTab.tsx | 198 +++++++----------- .../screens/Launch/ImageGenerationTab.tsx | 126 ++--------- src/components/screens/Launch/NetworkTab.tsx | 94 +++------ 7 files changed, 290 insertions(+), 309 deletions(-) create mode 100644 src/components/CheckboxWithTooltip.tsx create mode 100644 src/components/ModelFileField.tsx create mode 100644 src/components/SectionHeader.tsx diff --git a/.cspell/project-terms.txt b/.cspell/project-terms.txt index 6d8c536..92f6aa7 100644 --- a/.cspell/project-terms.txt +++ b/.cspell/project-terms.txt @@ -1,44 +1,40 @@ AMDGPU APPIMAGE -BLAS -CUDA -GGUF -KOBOLDAI -KOBOLDCPP -OLDPC -ROCM -SDXL -SPACEBAR -Consolas -Cooldown -Dolfino -Flashattention -KoboldCpp -Lowvram -Segoe -Tauri asar +Autoencoder +BLAS clblast clinfo +Consolas contextsize +Cooldown cublas cuda +CUDA +Dolfino finetuned flashattention +Flashattention friendlykobold geforce ggml gguf +GGUF gpulayers hipblas kcpps kcppt koboldai +KOBOLDAI koboldcpp +KoboldCpp +KOBOLDCPP lora lowvram +Lowvram maximizable minimizable +MMAP mmproj mmq multiuser @@ -51,12 +47,14 @@ noshift nsis nvidia oldpc +OLDPC opencl pkexec quantmatmul radeon remotetunnel rocm +ROCM rocminfo safetensors sdclipg @@ -66,8 +64,12 @@ sdmodel sdphotomaker sdui sdvae +SDXL +Segoe sonarjs +SPACEBAR taskkill +Tauri togglefullscreen treemap trycloudflare @@ -81,4 +83,3 @@ vulkan vulkaninfo wayland websearch -MMAP diff --git a/src/components/CheckboxWithTooltip.tsx b/src/components/CheckboxWithTooltip.tsx new file mode 100644 index 0000000..606b8af --- /dev/null +++ b/src/components/CheckboxWithTooltip.tsx @@ -0,0 +1,31 @@ +import { Checkbox, Group } from '@mantine/core'; +import { InfoTooltip } from '@/components/InfoTooltip'; +import styles from '@/styles/layout.module.css'; + +interface CheckboxWithTooltipProps { + checked: boolean; + onChange: (checked: boolean) => void; + label: string; + tooltip: string; + disabled?: boolean; +} + +export const CheckboxWithTooltip = ({ + checked, + onChange, + label, + tooltip, + disabled = false, +}: CheckboxWithTooltipProps) => ( +
+ + onChange(event.currentTarget.checked)} + label={label} + disabled={disabled} + /> + + +
+); diff --git a/src/components/ModelFileField.tsx b/src/components/ModelFileField.tsx new file mode 100644 index 0000000..cd67fda --- /dev/null +++ b/src/components/ModelFileField.tsx @@ -0,0 +1,90 @@ +import { Group, TextInput, Button } from '@mantine/core'; +import { File, Search } from 'lucide-react'; +import { SectionHeader } from '@/components/SectionHeader'; +import { getInputValidationState } from '@/utils'; +import styles from '@/styles/layout.module.css'; + +interface ModelFileFieldProps { + label: string; + value: string; + placeholder: string; + tooltip?: string; + onChange: (value: string) => void; + onSelectFile: () => void; + showSearchHF?: boolean; + searchUrl?: string; +} + +export const ModelFileField = ({ + label, + value, + placeholder, + tooltip, + onChange, + onSelectFile, + showSearchHF = false, + searchUrl = 'https://huggingface.co/models?pipeline_tag=text-to-image&library=gguf&sort=trending', +}: ModelFileFieldProps) => { + const validationState = getInputValidationState(value); + + const getInputColor = () => { + switch (validationState) { + case 'valid': + return 'green'; + case 'invalid': + return 'red'; + default: + return undefined; + } + }; + + const getHelperText = () => { + if (!value.trim()) return undefined; + + if (validationState === 'invalid') { + return 'Enter a valid URL or file path'; + } + + return undefined; + }; + + return ( +
+ + +
+ onChange(event.currentTarget.value)} + color={getInputColor()} + error={validationState === 'invalid' ? getHelperText() : undefined} + /> +
+ + {showSearchHF && ( + + )} +
+
+ ); +}; diff --git a/src/components/SectionHeader.tsx b/src/components/SectionHeader.tsx new file mode 100644 index 0000000..a2473b4 --- /dev/null +++ b/src/components/SectionHeader.tsx @@ -0,0 +1,23 @@ +import { Group, Text } from '@mantine/core'; +import { InfoTooltip } from '@/components/InfoTooltip'; + +interface SectionHeaderProps { + title: string; + tooltip?: string; + fontWeight?: number; + marginBottom?: string; +} + +export const SectionHeader = ({ + title, + tooltip, + fontWeight = 600, + marginBottom = 'md', +}: SectionHeaderProps) => ( + + + {title} + + {tooltip && } + +); diff --git a/src/components/screens/Launch/AdvancedTab.tsx b/src/components/screens/Launch/AdvancedTab.tsx index ec226ea..de7bd5e 100644 --- a/src/components/screens/Launch/AdvancedTab.tsx +++ b/src/components/screens/Launch/AdvancedTab.tsx @@ -1,8 +1,8 @@ -import { Stack, Checkbox, Group, Text, TextInput } from '@mantine/core'; +import { Stack, Group, Text, TextInput } from '@mantine/core'; import { useState, useEffect } from 'react'; import { InfoTooltip } from '@/components/InfoTooltip'; +import { CheckboxWithTooltip } from '@/components/CheckboxWithTooltip'; import { useLaunchConfig } from '@/hooks/useLaunchConfig'; -import styles from '@/styles/layout.module.css'; export const AdvancedTab = () => { const { @@ -68,101 +68,61 @@ export const AdvancedTab = () => { -
- - - handleNoshiftChange(!event.currentTarget.checked) - } - label="Context Shift" - /> - - -
+ handleNoshiftChange(!checked)} + label="Context Shift" + tooltip="Use Context Shifting to reduce reprocessing." + /> -
- - - handleNoshiftChange(event.currentTarget.checked) - } - label="No Shift" - /> - - -
+
-
- - - handleFlashattentionChange(event.currentTarget.checked) - } - label="Flash Attention" - /> - - -
+ -
- - - handleLowvramChange(event.currentTarget.checked) - } - label="Low VRAM" - disabled={backend !== 'cuda' && backend !== 'rocm'} - /> - - -
+ + +
-
- - - handleQuantmatmulChange(event.currentTarget.checked) - } - label="QuantMatMul" - disabled={backend !== 'cuda' && backend !== 'rocm'} - /> - - -
- -
- - - handleUsemmapChange(event.currentTarget.checked) - } - label="MMAP" - /> - - -
+
@@ -175,45 +135,29 @@ export const AdvancedTab = () => { -
- - - handleNoavx2Change(event.currentTarget.checked) - } - label="Disable AVX2" - disabled={isLoading || !backendSupport?.noavx2} - /> - - -
+ -
- - - handleFailsafeChange(event.currentTarget.checked) - } - label="Failsafe" - disabled={isLoading || !backendSupport?.failsafe} - /> - - -
+
diff --git a/src/components/screens/Launch/ImageGenerationTab.tsx b/src/components/screens/Launch/ImageGenerationTab.tsx index 9c4c01a..e6bd7f8 100644 --- a/src/components/screens/Launch/ImageGenerationTab.tsx +++ b/src/components/screens/Launch/ImageGenerationTab.tsx @@ -1,10 +1,9 @@ -import { Stack, Text, Group, TextInput, Button, Select } from '@mantine/core'; +import { Stack, Select } from '@mantine/core'; import { useState } from 'react'; -import { File, Search } from 'lucide-react'; -import { InfoTooltip } from '@/components/InfoTooltip'; -import { getInputValidationState, IMAGE_MODEL_PRESETS } from '@/utils'; +import { SectionHeader } from '@/components/SectionHeader'; +import { ModelFileField } from '@/components/ModelFileField'; +import { IMAGE_MODEL_PRESETS } from '@/utils'; import { useLaunchConfig } from '@/hooks/useLaunchConfig'; -import styles from '@/styles/layout.module.css'; export const ImageGenerationTab = () => { const { @@ -34,100 +33,15 @@ export const ImageGenerationTab = () => { const [selectedPreset, setSelectedPreset] = useState(null); - const ModelField = ({ - label, - value, - placeholder, - tooltip, - onChange, - onSelectFile, - showSearchHF = false, - }: { - label: string; - value: string; - placeholder: string; - tooltip?: string; - onChange: (value: string) => void; - onSelectFile: () => void; - showSearchHF?: boolean; - }) => { - const validationState = getInputValidationState(value); - - const getInputColor = () => { - switch (validationState) { - case 'valid': - return 'green'; - case 'invalid': - return 'red'; - default: - return undefined; - } - }; - - const getHelperText = () => { - if (!value.trim()) return undefined; - - if (validationState === 'invalid') { - return 'Enter a valid URL or file path'; - } - - return undefined; - }; - - return ( -
- - - {label} - - {tooltip && } - - -
- onChange(event.currentTarget.value)} - color={getInputColor()} - error={ - validationState === 'invalid' ? getHelperText() : undefined - } - /> -
- - {showSearchHF && ( - - )} -
-
- ); - }; - return (
- - - Model Preset - - - +