mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-02-15 16:55:06 -05:00
Merge branch 'main' into scheduled-cancel
This commit is contained in:
@@ -13,18 +13,18 @@ const ClearCanvasHistoryButtonModal = () => {
|
||||
|
||||
return (
|
||||
<IAIAlertDialog
|
||||
title={t('unifiedcanvas:clearCanvasHistory')}
|
||||
title={t('unifiedCanvas.clearCanvasHistory')}
|
||||
acceptCallback={() => dispatch(clearCanvasHistory())}
|
||||
acceptButtonText={t('unifiedcanvas:clearHistory')}
|
||||
acceptButtonText={t('unifiedCanvas.clearHistory')}
|
||||
triggerComponent={
|
||||
<IAIButton size={'sm'} leftIcon={<FaTrash />} isDisabled={isStaging}>
|
||||
{t('unifiedcanvas:clearCanvasHistory')}
|
||||
<IAIButton size="sm" leftIcon={<FaTrash />} isDisabled={isStaging}>
|
||||
{t('unifiedCanvas.clearCanvasHistory')}
|
||||
</IAIButton>
|
||||
}
|
||||
>
|
||||
<p>{t('unifiedcanvas:clearCanvasHistoryMessage')}</p>
|
||||
<p>{t('unifiedCanvas.clearCanvasHistoryMessage')}</p>
|
||||
<br />
|
||||
<p>{t('unifiedcanvas:clearCanvasHistoryConfirm')}</p>
|
||||
<p>{t('unifiedCanvas.clearCanvasHistoryConfirm')}</p>
|
||||
</IAIAlertDialog>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -140,7 +140,7 @@ const IAICanvas = () => {
|
||||
<Stage
|
||||
tabIndex={-1}
|
||||
ref={canvasStageRefCallback}
|
||||
className={'inpainting-canvas-stage'}
|
||||
className="inpainting-canvas-stage"
|
||||
style={{
|
||||
...(stageCursor ? { cursor: stageCursor } : {}),
|
||||
}}
|
||||
@@ -165,19 +165,19 @@ const IAICanvas = () => {
|
||||
onWheel={handleWheel}
|
||||
draggable={(tool === 'move' || isStaging) && !isModifyingBoundingBox}
|
||||
>
|
||||
<Layer id={'grid'} visible={shouldShowGrid}>
|
||||
<Layer id="grid" visible={shouldShowGrid}>
|
||||
<IAICanvasGrid />
|
||||
</Layer>
|
||||
|
||||
<Layer
|
||||
id={'base'}
|
||||
id="base"
|
||||
ref={canvasBaseLayerRefCallback}
|
||||
listening={false}
|
||||
imageSmoothingEnabled={false}
|
||||
>
|
||||
<IAICanvasObjectRenderer />
|
||||
</Layer>
|
||||
<Layer id={'mask'} visible={isMaskEnabled} listening={false}>
|
||||
<Layer id="mask" visible={isMaskEnabled} listening={false}>
|
||||
<IAICanvasMaskLines visible={true} listening={false} />
|
||||
<IAICanvasMaskCompositer listening={false} />
|
||||
</Layer>
|
||||
|
||||
@@ -49,7 +49,7 @@ const IAICanvasBoundingBoxOverlay = () => {
|
||||
offsetY={stageCoordinates.y / stageScale}
|
||||
height={stageDimensions.height / stageScale}
|
||||
width={stageDimensions.width / stageScale}
|
||||
fill={'rgba(0,0,0,0.4)'}
|
||||
fill="rgba(0,0,0,0.4)"
|
||||
listening={false}
|
||||
visible={shouldDarkenOutsideBoundingBox}
|
||||
/>
|
||||
@@ -58,10 +58,10 @@ const IAICanvasBoundingBoxOverlay = () => {
|
||||
y={boundingBoxCoordinates.y}
|
||||
width={boundingBoxDimensions.width}
|
||||
height={boundingBoxDimensions.height}
|
||||
fill={'rgb(255,255,255)'}
|
||||
fill="rgb(255,255,255)"
|
||||
listening={false}
|
||||
visible={shouldDarkenOutsideBoundingBox}
|
||||
globalCompositeOperation={'destination-out'}
|
||||
globalCompositeOperation="destination-out"
|
||||
/>
|
||||
</Group>
|
||||
);
|
||||
|
||||
@@ -163,10 +163,10 @@ const IAICanvasMaskCompositer = (props: IAICanvasMaskCompositerProps) => {
|
||||
width={stageDimensions.width / stageScale}
|
||||
fillPatternImage={fillPatternImage}
|
||||
fillPatternOffsetY={!isNumber(offset) ? 0 : offset}
|
||||
fillPatternRepeat={'repeat'}
|
||||
fillPatternRepeat="repeat"
|
||||
fillPatternScale={{ x: 1 / stageScale, y: 1 / stageScale }}
|
||||
listening={true}
|
||||
globalCompositeOperation={'source-in'}
|
||||
globalCompositeOperation="source-in"
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -36,7 +36,7 @@ const IAICanvasLines = (props: InpaintingCanvasLinesProps) => {
|
||||
<Line
|
||||
key={i}
|
||||
points={line.points}
|
||||
stroke={'rgb(0,0,0)'} // The lines can be any color, just need alpha > 0
|
||||
stroke="rgb(0,0,0)" // The lines can be any color, just need alpha > 0
|
||||
strokeWidth={line.strokeWidth * 2}
|
||||
tension={0}
|
||||
lineCap="round"
|
||||
|
||||
@@ -93,8 +93,8 @@ const IAICanvasObjectRenderer = () => {
|
||||
y={obj.y}
|
||||
width={obj.width}
|
||||
height={obj.height}
|
||||
fill={'rgb(255, 255, 255)'}
|
||||
globalCompositeOperation={'destination-out'}
|
||||
fill="rgb(255, 255, 255)"
|
||||
globalCompositeOperation="destination-out"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ const IAICanvasStagingArea = (props: Props) => {
|
||||
width={width}
|
||||
height={height}
|
||||
strokeWidth={1}
|
||||
stroke={'white'}
|
||||
stroke="white"
|
||||
strokeScaleEnabled={false}
|
||||
/>
|
||||
<Rect
|
||||
@@ -77,7 +77,7 @@ const IAICanvasStagingArea = (props: Props) => {
|
||||
height={height}
|
||||
dash={[4, 4]}
|
||||
strokeWidth={1}
|
||||
stroke={'black'}
|
||||
stroke="black"
|
||||
strokeScaleEnabled={false}
|
||||
/>
|
||||
</Group>
|
||||
|
||||
@@ -114,42 +114,42 @@ const IAICanvasStagingAreaToolbar = () => {
|
||||
|
||||
return (
|
||||
<Flex
|
||||
pos={'absolute'}
|
||||
bottom={'1rem'}
|
||||
w={'100%'}
|
||||
align={'center'}
|
||||
justify={'center'}
|
||||
pos="absolute"
|
||||
bottom="1rem"
|
||||
w="100%"
|
||||
align="center"
|
||||
justify="center"
|
||||
filter="drop-shadow(0 0.5rem 1rem rgba(0,0,0))"
|
||||
onMouseOver={handleMouseOver}
|
||||
onMouseOut={handleMouseOut}
|
||||
>
|
||||
<ButtonGroup isAttached>
|
||||
<IAIIconButton
|
||||
tooltip={`${t('unifiedcanvas:previous')} (Left)`}
|
||||
aria-label={`${t('unifiedcanvas:previous')} (Left)`}
|
||||
tooltip={`${t('unifiedCanvas.previous')} (Left)`}
|
||||
aria-label={`${t('unifiedCanvas.previous')} (Left)`}
|
||||
icon={<FaArrowLeft />}
|
||||
onClick={handlePrevImage}
|
||||
data-selected={true}
|
||||
isDisabled={isOnFirstImage}
|
||||
/>
|
||||
<IAIIconButton
|
||||
tooltip={`${t('unifiedcanvas:next')} (Right)`}
|
||||
aria-label={`${t('unifiedcanvas:next')} (Right)`}
|
||||
tooltip={`${t('unifiedCanvas.next')} (Right)`}
|
||||
aria-label={`${t('unifiedCanvas.next')} (Right)`}
|
||||
icon={<FaArrowRight />}
|
||||
onClick={handleNextImage}
|
||||
data-selected={true}
|
||||
isDisabled={isOnLastImage}
|
||||
/>
|
||||
<IAIIconButton
|
||||
tooltip={`${t('unifiedcanvas:accept')} (Enter)`}
|
||||
aria-label={`${t('unifiedcanvas:accept')} (Enter)`}
|
||||
tooltip={`${t('unifiedCanvas.accept')} (Enter)`}
|
||||
aria-label={`${t('unifiedCanvas.accept')} (Enter)`}
|
||||
icon={<FaCheck />}
|
||||
onClick={handleAccept}
|
||||
data-selected={true}
|
||||
/>
|
||||
<IAIIconButton
|
||||
tooltip={t('unifiedcanvas:showHide')}
|
||||
aria-label={t('unifiedcanvas:showHide')}
|
||||
tooltip={t('unifiedCanvas.showHide')}
|
||||
aria-label={t('unifiedCanvas.showHide')}
|
||||
data-alert={!shouldShowStagingImage}
|
||||
icon={shouldShowStagingImage ? <FaEye /> : <FaEyeSlash />}
|
||||
onClick={() =>
|
||||
@@ -158,8 +158,8 @@ const IAICanvasStagingAreaToolbar = () => {
|
||||
data-selected={true}
|
||||
/>
|
||||
<IAIIconButton
|
||||
tooltip={t('unifiedcanvas:saveToGallery')}
|
||||
aria-label={t('unifiedcanvas:saveToGallery')}
|
||||
tooltip={t('unifiedCanvas.saveToGallery')}
|
||||
aria-label={t('unifiedCanvas.saveToGallery')}
|
||||
icon={<FaSave />}
|
||||
onClick={() =>
|
||||
dispatch(
|
||||
@@ -169,8 +169,8 @@ const IAICanvasStagingAreaToolbar = () => {
|
||||
data-selected={true}
|
||||
/>
|
||||
<IAIIconButton
|
||||
tooltip={t('unifiedcanvas:discardAll')}
|
||||
aria-label={t('unifiedcanvas:discardAll')}
|
||||
tooltip={t('unifiedCanvas.discardAll')}
|
||||
aria-label={t('unifiedCanvas.discardAll')}
|
||||
icon={<FaPlus style={{ transform: 'rotate(45deg)' }} />}
|
||||
onClick={() => dispatch(discardStagedImages())}
|
||||
data-selected={true}
|
||||
|
||||
@@ -92,8 +92,8 @@ const IAICanvasStatusText = () => {
|
||||
style={{
|
||||
color: activeLayerColor,
|
||||
}}
|
||||
>{`${t('unifiedcanvas:activeLayer')}: ${activeLayerString}`}</div>
|
||||
<div>{`${t('unifiedcanvas:canvasScale')}: ${canvasScaleString}%`}</div>
|
||||
>{`${t('unifiedCanvas.activeLayer')}: ${activeLayerString}`}</div>
|
||||
<div>{`${t('unifiedCanvas.canvasScale')}: ${canvasScaleString}%`}</div>
|
||||
{shouldPreserveMaskedArea && (
|
||||
<div
|
||||
style={{
|
||||
|
||||
@@ -172,7 +172,7 @@ const IAICanvasToolPreview = (props: GroupConfig) => {
|
||||
x={brushX}
|
||||
y={brushY}
|
||||
radius={radius}
|
||||
stroke={'rgba(255,255,255,0.4)'}
|
||||
stroke="rgba(255,255,255,0.4)"
|
||||
strokeWidth={strokeWidth * 2}
|
||||
strokeEnabled={true}
|
||||
listening={false}
|
||||
@@ -181,7 +181,7 @@ const IAICanvasToolPreview = (props: GroupConfig) => {
|
||||
x={brushX}
|
||||
y={brushY}
|
||||
radius={radius}
|
||||
stroke={'rgba(0,0,0,1)'}
|
||||
stroke="rgba(0,0,0,1)"
|
||||
strokeWidth={strokeWidth}
|
||||
strokeEnabled={true}
|
||||
listening={false}
|
||||
@@ -192,14 +192,14 @@ const IAICanvasToolPreview = (props: GroupConfig) => {
|
||||
x={brushX}
|
||||
y={brushY}
|
||||
radius={dotRadius * 2}
|
||||
fill={'rgba(255,255,255,0.4)'}
|
||||
fill="rgba(255,255,255,0.4)"
|
||||
listening={false}
|
||||
/>
|
||||
<Circle
|
||||
x={brushX}
|
||||
y={brushY}
|
||||
radius={dotRadius}
|
||||
fill={'rgba(0,0,0,1)'}
|
||||
fill="rgba(0,0,0,1)"
|
||||
listening={false}
|
||||
/>
|
||||
</Group>
|
||||
|
||||
@@ -269,12 +269,12 @@ const IAICanvasBoundingBox = (props: IAICanvasBoundingBoxPreviewProps) => {
|
||||
<Transformer
|
||||
anchorCornerRadius={3}
|
||||
anchorDragBoundFunc={anchorDragBoundFunc}
|
||||
anchorFill={'rgba(212,216,234,1)'}
|
||||
anchorFill="rgba(212,216,234,1)"
|
||||
anchorSize={15}
|
||||
anchorStroke={'rgb(42,42,42)'}
|
||||
anchorStroke="rgb(42,42,42)"
|
||||
borderDash={[4, 4]}
|
||||
borderEnabled={true}
|
||||
borderStroke={'black'}
|
||||
borderStroke="black"
|
||||
draggable={false}
|
||||
enabledAnchors={tool === 'move' ? undefined : []}
|
||||
flipEnabled={false}
|
||||
|
||||
@@ -108,8 +108,8 @@ const IAICanvasMaskOptions = () => {
|
||||
triggerComponent={
|
||||
<ButtonGroup>
|
||||
<IAIIconButton
|
||||
aria-label={t('unifiedcanvas:maskingOptions')}
|
||||
tooltip={t('unifiedcanvas:maskingOptions')}
|
||||
aria-label={t('unifiedCanvas.maskingOptions')}
|
||||
tooltip={t('unifiedCanvas.maskingOptions')}
|
||||
icon={<FaMask />}
|
||||
style={
|
||||
layer === 'mask'
|
||||
@@ -121,14 +121,14 @@ const IAICanvasMaskOptions = () => {
|
||||
</ButtonGroup>
|
||||
}
|
||||
>
|
||||
<Flex direction={'column'} gap={'0.5rem'}>
|
||||
<Flex direction="column" gap="0.5rem">
|
||||
<IAICheckbox
|
||||
label={`${t('unifiedcanvas:enableMask')} (H)`}
|
||||
label={`${t('unifiedCanvas.enableMask')} (H)`}
|
||||
isChecked={isMaskEnabled}
|
||||
onChange={handleToggleEnableMask}
|
||||
/>
|
||||
<IAICheckbox
|
||||
label={t('unifiedcanvas:preserveMaskedArea')}
|
||||
label={t('unifiedCanvas.preserveMaskedArea')}
|
||||
isChecked={shouldPreserveMaskedArea}
|
||||
onChange={(e) =>
|
||||
dispatch(setShouldPreserveMaskedArea(e.target.checked))
|
||||
@@ -139,8 +139,8 @@ const IAICanvasMaskOptions = () => {
|
||||
color={maskColor}
|
||||
onChange={(newColor) => dispatch(setMaskColor(newColor))}
|
||||
/>
|
||||
<IAIButton size={'sm'} leftIcon={<FaTrash />} onClick={handleClearMask}>
|
||||
{t('unifiedcanvas:clearMask')} (Shift+C)
|
||||
<IAIButton size="sm" leftIcon={<FaTrash />} onClick={handleClearMask}>
|
||||
{t('unifiedCanvas.clearMask')} (Shift+C)
|
||||
</IAIButton>
|
||||
</Flex>
|
||||
</IAIPopover>
|
||||
|
||||
@@ -53,8 +53,8 @@ export default function IAICanvasRedoButton() {
|
||||
|
||||
return (
|
||||
<IAIIconButton
|
||||
aria-label={`${t('unifiedcanvas:redo')} (Ctrl+Shift+Z)`}
|
||||
tooltip={`${t('unifiedcanvas:redo')} (Ctrl+Shift+Z)`}
|
||||
aria-label={`${t('unifiedCanvas.redo')} (Ctrl+Shift+Z)`}
|
||||
tooltip={`${t('unifiedCanvas.redo')} (Ctrl+Shift+Z)`}
|
||||
icon={<FaRedo />}
|
||||
onClick={handleRedo}
|
||||
isDisabled={!canRedo}
|
||||
|
||||
@@ -91,58 +91,58 @@ const IAICanvasSettingsButtonPopover = () => {
|
||||
trigger="hover"
|
||||
triggerComponent={
|
||||
<IAIIconButton
|
||||
tooltip={t('unifiedcanvas:canvasSettings')}
|
||||
aria-label={t('unifiedcanvas:canvasSettings')}
|
||||
tooltip={t('unifiedCanvas.canvasSettings')}
|
||||
aria-label={t('unifiedCanvas.canvasSettings')}
|
||||
icon={<FaWrench />}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Flex direction={'column'} gap={'0.5rem'}>
|
||||
<Flex direction="column" gap="0.5rem">
|
||||
<IAICheckbox
|
||||
label={t('unifiedcanvas:showIntermediates')}
|
||||
label={t('unifiedCanvas.showIntermediates')}
|
||||
isChecked={shouldShowIntermediates}
|
||||
onChange={(e) =>
|
||||
dispatch(setShouldShowIntermediates(e.target.checked))
|
||||
}
|
||||
/>
|
||||
<IAICheckbox
|
||||
label={t('unifiedcanvas:showGrid')}
|
||||
label={t('unifiedCanvas.showGrid')}
|
||||
isChecked={shouldShowGrid}
|
||||
onChange={(e) => dispatch(setShouldShowGrid(e.target.checked))}
|
||||
/>
|
||||
<IAICheckbox
|
||||
label={t('unifiedcanvas:snapToGrid')}
|
||||
label={t('unifiedCanvas.snapToGrid')}
|
||||
isChecked={shouldSnapToGrid}
|
||||
onChange={handleChangeShouldSnapToGrid}
|
||||
/>
|
||||
<IAICheckbox
|
||||
label={t('unifiedcanvas:darkenOutsideSelection')}
|
||||
label={t('unifiedCanvas.darkenOutsideSelection')}
|
||||
isChecked={shouldDarkenOutsideBoundingBox}
|
||||
onChange={(e) =>
|
||||
dispatch(setShouldDarkenOutsideBoundingBox(e.target.checked))
|
||||
}
|
||||
/>
|
||||
<IAICheckbox
|
||||
label={t('unifiedcanvas:autoSaveToGallery')}
|
||||
label={t('unifiedCanvas.autoSaveToGallery')}
|
||||
isChecked={shouldAutoSave}
|
||||
onChange={(e) => dispatch(setShouldAutoSave(e.target.checked))}
|
||||
/>
|
||||
<IAICheckbox
|
||||
label={t('unifiedcanvas:saveBoxRegionOnly')}
|
||||
label={t('unifiedCanvas.saveBoxRegionOnly')}
|
||||
isChecked={shouldCropToBoundingBoxOnSave}
|
||||
onChange={(e) =>
|
||||
dispatch(setShouldCropToBoundingBoxOnSave(e.target.checked))
|
||||
}
|
||||
/>
|
||||
<IAICheckbox
|
||||
label={t('unifiedcanvas:limitStrokesToBox')}
|
||||
label={t('unifiedCanvas.limitStrokesToBox')}
|
||||
isChecked={shouldRestrictStrokesToBox}
|
||||
onChange={(e) =>
|
||||
dispatch(setShouldRestrictStrokesToBox(e.target.checked))
|
||||
}
|
||||
/>
|
||||
<IAICheckbox
|
||||
label={t('unifiedcanvas:showCanvasDebugInfo')}
|
||||
label={t('unifiedCanvas.showCanvasDebugInfo')}
|
||||
isChecked={shouldShowCanvasDebugInfo}
|
||||
onChange={(e) =>
|
||||
dispatch(setShouldShowCanvasDebugInfo(e.target.checked))
|
||||
|
||||
@@ -181,38 +181,38 @@ const IAICanvasToolChooserOptions = () => {
|
||||
return (
|
||||
<ButtonGroup isAttached>
|
||||
<IAIIconButton
|
||||
aria-label={`${t('unifiedcanvas:brush')} (B)`}
|
||||
tooltip={`${t('unifiedcanvas:brush')} (B)`}
|
||||
aria-label={`${t('unifiedCanvas.brush')} (B)`}
|
||||
tooltip={`${t('unifiedCanvas.brush')} (B)`}
|
||||
icon={<FaPaintBrush />}
|
||||
data-selected={tool === 'brush' && !isStaging}
|
||||
onClick={handleSelectBrushTool}
|
||||
isDisabled={isStaging}
|
||||
/>
|
||||
<IAIIconButton
|
||||
aria-label={`${t('unifiedcanvas:eraser')} (E)`}
|
||||
tooltip={`${t('unifiedcanvas:eraser')} (E)`}
|
||||
aria-label={`${t('unifiedCanvas.eraser')} (E)`}
|
||||
tooltip={`${t('unifiedCanvas.eraser')} (E)`}
|
||||
icon={<FaEraser />}
|
||||
data-selected={tool === 'eraser' && !isStaging}
|
||||
isDisabled={isStaging}
|
||||
onClick={handleSelectEraserTool}
|
||||
/>
|
||||
<IAIIconButton
|
||||
aria-label={`${t('unifiedcanvas:fillBoundingBox')} (Shift+F)`}
|
||||
tooltip={`${t('unifiedcanvas:fillBoundingBox')} (Shift+F)`}
|
||||
aria-label={`${t('unifiedCanvas.fillBoundingBox')} (Shift+F)`}
|
||||
tooltip={`${t('unifiedCanvas.fillBoundingBox')} (Shift+F)`}
|
||||
icon={<FaFillDrip />}
|
||||
isDisabled={isStaging}
|
||||
onClick={handleFillRect}
|
||||
/>
|
||||
<IAIIconButton
|
||||
aria-label={`${t('unifiedcanvas:eraseBoundingBox')} (Del/Backspace)`}
|
||||
tooltip={`${t('unifiedcanvas:eraseBoundingBox')} (Del/Backspace)`}
|
||||
aria-label={`${t('unifiedCanvas.eraseBoundingBox')} (Del/Backspace)`}
|
||||
tooltip={`${t('unifiedCanvas.eraseBoundingBox')} (Del/Backspace)`}
|
||||
icon={<FaPlus style={{ transform: 'rotate(45deg)' }} />}
|
||||
isDisabled={isStaging}
|
||||
onClick={handleEraseBoundingBox}
|
||||
/>
|
||||
<IAIIconButton
|
||||
aria-label={`${t('unifiedcanvas:colorPicker')} (C)`}
|
||||
tooltip={`${t('unifiedcanvas:colorPicker')} (C)`}
|
||||
aria-label={`${t('unifiedCanvas.colorPicker')} (C)`}
|
||||
tooltip={`${t('unifiedCanvas.colorPicker')} (C)`}
|
||||
icon={<FaEyeDropper />}
|
||||
data-selected={tool === 'colorPicker' && !isStaging}
|
||||
isDisabled={isStaging}
|
||||
@@ -222,21 +222,16 @@ const IAICanvasToolChooserOptions = () => {
|
||||
trigger="hover"
|
||||
triggerComponent={
|
||||
<IAIIconButton
|
||||
aria-label={t('unifiedcanvas:brushOptions')}
|
||||
tooltip={t('unifiedcanvas:brushOptions')}
|
||||
aria-label={t('unifiedCanvas.brushOptions')}
|
||||
tooltip={t('unifiedCanvas.brushOptions')}
|
||||
icon={<FaSlidersH />}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Flex
|
||||
minWidth={'15rem'}
|
||||
direction={'column'}
|
||||
gap={'1rem'}
|
||||
width={'100%'}
|
||||
>
|
||||
<Flex gap={'1rem'} justifyContent="space-between">
|
||||
<Flex minWidth="15rem" direction="column" gap="1rem" width="100%">
|
||||
<Flex gap="1rem" justifyContent="space-between">
|
||||
<IAISlider
|
||||
label={t('unifiedcanvas:brushSize')}
|
||||
label={t('unifiedCanvas.brushSize')}
|
||||
value={brushSize}
|
||||
withInput
|
||||
onChange={(newSize) => dispatch(setBrushSize(newSize))}
|
||||
|
||||
@@ -232,7 +232,7 @@ const IAICanvasOutpaintingControls = () => {
|
||||
return (
|
||||
<div className="inpainting-settings">
|
||||
<IAISelect
|
||||
tooltip={`${t('unifiedcanvas:layer')} (Q)`}
|
||||
tooltip={`${t('unifiedCanvas.layer')} (Q)`}
|
||||
tooltipProps={{ hasArrow: true, placement: 'top' }}
|
||||
value={layer}
|
||||
validValues={LAYER_NAMES_DICT}
|
||||
@@ -245,15 +245,15 @@ const IAICanvasOutpaintingControls = () => {
|
||||
|
||||
<ButtonGroup isAttached>
|
||||
<IAIIconButton
|
||||
aria-label={`${t('unifiedcanvas:move')} (V)`}
|
||||
tooltip={`${t('unifiedcanvas:move')} (V)`}
|
||||
aria-label={`${t('unifiedCanvas.move')} (V)`}
|
||||
tooltip={`${t('unifiedCanvas.move')} (V)`}
|
||||
icon={<FaArrowsAlt />}
|
||||
data-selected={tool === 'move' || isStaging}
|
||||
onClick={handleSelectMoveTool}
|
||||
/>
|
||||
<IAIIconButton
|
||||
aria-label={`${t('unifiedcanvas:resetView')} (R)`}
|
||||
tooltip={`${t('unifiedcanvas:resetView')} (R)`}
|
||||
aria-label={`${t('unifiedCanvas.resetView')} (R)`}
|
||||
tooltip={`${t('unifiedCanvas.resetView')} (R)`}
|
||||
icon={<FaCrosshairs />}
|
||||
onClick={handleClickResetCanvasView}
|
||||
/>
|
||||
@@ -261,29 +261,29 @@ const IAICanvasOutpaintingControls = () => {
|
||||
|
||||
<ButtonGroup isAttached>
|
||||
<IAIIconButton
|
||||
aria-label={`${t('unifiedcanvas:mergeVisible')} (Shift+M)`}
|
||||
tooltip={`${t('unifiedcanvas:mergeVisible')} (Shift+M)`}
|
||||
aria-label={`${t('unifiedCanvas.mergeVisible')} (Shift+M)`}
|
||||
tooltip={`${t('unifiedCanvas.mergeVisible')} (Shift+M)`}
|
||||
icon={<FaLayerGroup />}
|
||||
onClick={handleMergeVisible}
|
||||
isDisabled={isStaging}
|
||||
/>
|
||||
<IAIIconButton
|
||||
aria-label={`${t('unifiedcanvas:saveToGallery')} (Shift+S)`}
|
||||
tooltip={`${t('unifiedcanvas:saveToGallery')} (Shift+S)`}
|
||||
aria-label={`${t('unifiedCanvas.saveToGallery')} (Shift+S)`}
|
||||
tooltip={`${t('unifiedCanvas.saveToGallery')} (Shift+S)`}
|
||||
icon={<FaSave />}
|
||||
onClick={handleSaveToGallery}
|
||||
isDisabled={isStaging}
|
||||
/>
|
||||
<IAIIconButton
|
||||
aria-label={`${t('unifiedcanvas:copyToClipboard')} (Cmd/Ctrl+C)`}
|
||||
tooltip={`${t('unifiedcanvas:copyToClipboard')} (Cmd/Ctrl+C)`}
|
||||
aria-label={`${t('unifiedCanvas.copyToClipboard')} (Cmd/Ctrl+C)`}
|
||||
tooltip={`${t('unifiedCanvas.copyToClipboard')} (Cmd/Ctrl+C)`}
|
||||
icon={<FaCopy />}
|
||||
onClick={handleCopyImageToClipboard}
|
||||
isDisabled={isStaging}
|
||||
/>
|
||||
<IAIIconButton
|
||||
aria-label={`${t('unifiedcanvas:downloadAsImage')} (Shift+D)`}
|
||||
tooltip={`${t('unifiedcanvas:downloadAsImage')} (Shift+D)`}
|
||||
aria-label={`${t('unifiedCanvas.downloadAsImage')} (Shift+D)`}
|
||||
tooltip={`${t('unifiedCanvas.downloadAsImage')} (Shift+D)`}
|
||||
icon={<FaDownload />}
|
||||
onClick={handleDownloadAsImage}
|
||||
isDisabled={isStaging}
|
||||
@@ -296,15 +296,15 @@ const IAICanvasOutpaintingControls = () => {
|
||||
|
||||
<ButtonGroup isAttached>
|
||||
<IAIIconButton
|
||||
aria-label={`${t('common:upload')}`}
|
||||
tooltip={`${t('common:upload')}`}
|
||||
aria-label={`${t('common.upload')}`}
|
||||
tooltip={`${t('common.upload')}`}
|
||||
icon={<FaUpload />}
|
||||
onClick={openUploader}
|
||||
isDisabled={isStaging}
|
||||
/>
|
||||
<IAIIconButton
|
||||
aria-label={`${t('unifiedcanvas:clearCanvas')}`}
|
||||
tooltip={`${t('unifiedcanvas:clearCanvas')}`}
|
||||
aria-label={`${t('unifiedCanvas.clearCanvas')}`}
|
||||
tooltip={`${t('unifiedCanvas.clearCanvas')}`}
|
||||
icon={<FaTrash />}
|
||||
onClick={handleResetCanvas}
|
||||
style={{ backgroundColor: 'var(--btn-delete-image)' }}
|
||||
|
||||
@@ -54,8 +54,8 @@ export default function IAICanvasUndoButton() {
|
||||
|
||||
return (
|
||||
<IAIIconButton
|
||||
aria-label={`${t('unifiedcanvas:undo')} (Ctrl+Z)`}
|
||||
tooltip={`${t('unifiedcanvas:undo')} (Ctrl+Z)`}
|
||||
aria-label={`${t('unifiedCanvas.undo')} (Ctrl+Z)`}
|
||||
tooltip={`${t('unifiedCanvas.undo')} (Ctrl+Z)`}
|
||||
icon={<FaUndo />}
|
||||
onClick={handleUndo}
|
||||
isDisabled={!canUndo}
|
||||
|
||||
@@ -115,7 +115,7 @@ export const mergeAndUploadCanvas =
|
||||
downloadFile(url);
|
||||
dispatch(
|
||||
addToast({
|
||||
title: i18n.t('toast:downloadImageStarted'),
|
||||
title: i18n.t('toast.downloadImageStarted'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -127,7 +127,7 @@ export const mergeAndUploadCanvas =
|
||||
copyImage(url, width, height);
|
||||
dispatch(
|
||||
addToast({
|
||||
title: i18n.t('toast:imageCopied'),
|
||||
title: i18n.t('toast.imageCopied'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -139,7 +139,7 @@ export const mergeAndUploadCanvas =
|
||||
dispatch(addImage({ image: newImage, category: 'result' }));
|
||||
dispatch(
|
||||
addToast({
|
||||
title: i18n.t('toast:imageSavedToGallery'),
|
||||
title: i18n.t('toast.imageSavedToGallery'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -158,7 +158,7 @@ export const mergeAndUploadCanvas =
|
||||
);
|
||||
dispatch(
|
||||
addToast({
|
||||
title: i18n.t('toast:canvasMerged'),
|
||||
title: i18n.t('toast.canvasMerged'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -167,6 +167,6 @@ export const mergeAndUploadCanvas =
|
||||
}
|
||||
|
||||
dispatch(setIsProcessing(false));
|
||||
dispatch(setCurrentStatus(i18n.t('common:statusConnected')));
|
||||
dispatch(setCurrentStatus(i18n.t('common.statusConnected')));
|
||||
dispatch(setIsCancelable(true));
|
||||
};
|
||||
|
||||
@@ -142,7 +142,7 @@ const CurrentImageButtons = () => {
|
||||
await navigator.clipboard.write(data);
|
||||
|
||||
toast({
|
||||
title: t('toast:imageCopied'),
|
||||
title: t('toast.imageCopied'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -156,7 +156,7 @@ const CurrentImageButtons = () => {
|
||||
)
|
||||
.then(() => {
|
||||
toast({
|
||||
title: t('toast:imageLinkCopied'),
|
||||
title: t('toast.imageLinkCopied'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -170,15 +170,15 @@ const CurrentImageButtons = () => {
|
||||
if (currentImage) {
|
||||
handleClickUseAsInitialImage();
|
||||
toast({
|
||||
title: t('toast:sentToImageToImage'),
|
||||
title: t('toast.sentToImageToImage'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
title: t('toast:imageNotLoaded'),
|
||||
description: t('toast:imageNotLoadedDesc'),
|
||||
title: t('toast.imageNotLoaded'),
|
||||
description: t('toast.imageNotLoadedDesc'),
|
||||
status: 'error',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -206,15 +206,15 @@ const CurrentImageButtons = () => {
|
||||
) {
|
||||
handleClickUseAllParameters();
|
||||
toast({
|
||||
title: t('toast:parametersSet'),
|
||||
title: t('toast.parametersSet'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
title: t('toast:parametersNotSet'),
|
||||
description: t('toast:parametersNotSetDesc'),
|
||||
title: t('toast.parametersNotSet'),
|
||||
description: t('toast.parametersNotSetDesc'),
|
||||
status: 'error',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -235,15 +235,15 @@ const CurrentImageButtons = () => {
|
||||
if (currentImage?.metadata?.image?.seed) {
|
||||
handleClickUseSeed();
|
||||
toast({
|
||||
title: t('toast:seedSet'),
|
||||
title: t('toast.seedSet'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
title: t('toast:seedNotSet'),
|
||||
description: t('toast:seedNotSetDesc'),
|
||||
title: t('toast.seedNotSet'),
|
||||
description: t('toast.seedNotSetDesc'),
|
||||
status: 'error',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -272,15 +272,15 @@ const CurrentImageButtons = () => {
|
||||
if (currentImage?.metadata?.image?.prompt) {
|
||||
handleClickUsePrompt();
|
||||
toast({
|
||||
title: t('toast:promptSet'),
|
||||
title: t('toast.promptSet'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
});
|
||||
} else {
|
||||
toast({
|
||||
title: t('toast:promptNotSet'),
|
||||
description: t('toast:promptNotSetDesc'),
|
||||
title: t('toast.promptNotSet'),
|
||||
description: t('toast.promptNotSetDesc'),
|
||||
status: 'error',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -307,7 +307,7 @@ const CurrentImageButtons = () => {
|
||||
handleClickUpscale();
|
||||
} else {
|
||||
toast({
|
||||
title: t('toast:upscalingFailed'),
|
||||
title: t('toast.upscalingFailed'),
|
||||
status: 'error',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -341,7 +341,7 @@ const CurrentImageButtons = () => {
|
||||
handleClickFixFaces();
|
||||
} else {
|
||||
toast({
|
||||
title: t('toast:faceRestoreFailed'),
|
||||
title: t('toast.faceRestoreFailed'),
|
||||
status: 'error',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -373,7 +373,7 @@ const CurrentImageButtons = () => {
|
||||
}
|
||||
|
||||
toast({
|
||||
title: t('toast:sentToUnifiedCanvas'),
|
||||
title: t('toast.sentToUnifiedCanvas'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -387,7 +387,7 @@ const CurrentImageButtons = () => {
|
||||
handleClickShowImageDetails();
|
||||
} else {
|
||||
toast({
|
||||
title: t('toast:metadataLoadFailed'),
|
||||
title: t('toast.metadataLoadFailed'),
|
||||
status: 'error',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -408,45 +408,45 @@ const CurrentImageButtons = () => {
|
||||
trigger="hover"
|
||||
triggerComponent={
|
||||
<IAIIconButton
|
||||
aria-label={`${t('parameters:sendTo')}...`}
|
||||
aria-label={`${t('parameters.sendTo')}...`}
|
||||
icon={<FaShareAlt />}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<div className="current-image-send-to-popover">
|
||||
<IAIButton
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
onClick={handleClickUseAsInitialImage}
|
||||
leftIcon={<FaShare />}
|
||||
>
|
||||
{t('parameters:sendToImg2Img')}
|
||||
{t('parameters.sendToImg2Img')}
|
||||
</IAIButton>
|
||||
<IAIButton
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
onClick={handleSendToCanvas}
|
||||
leftIcon={<FaShare />}
|
||||
>
|
||||
{t('parameters:sendToUnifiedCanvas')}
|
||||
{t('parameters.sendToUnifiedCanvas')}
|
||||
</IAIButton>
|
||||
|
||||
<IAIButton
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
onClick={handleCopyImage}
|
||||
leftIcon={<FaCopy />}
|
||||
>
|
||||
{t('parameters:copyImage')}
|
||||
{t('parameters.copyImage')}
|
||||
</IAIButton>
|
||||
<IAIButton
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
onClick={handleCopyImageLink}
|
||||
leftIcon={<FaCopy />}
|
||||
>
|
||||
{t('parameters:copyImageToLink')}
|
||||
{t('parameters.copyImageToLink')}
|
||||
</IAIButton>
|
||||
|
||||
<Link download={true} href={currentImage?.url}>
|
||||
<IAIButton leftIcon={<FaDownload />} size={'sm'} w="100%">
|
||||
{t('parameters:downloadImage')}
|
||||
<IAIButton leftIcon={<FaDownload />} size="sm" w="100%">
|
||||
{t('parameters.downloadImage')}
|
||||
</IAIButton>
|
||||
</Link>
|
||||
</div>
|
||||
@@ -455,13 +455,13 @@ const CurrentImageButtons = () => {
|
||||
icon={<FaExpand />}
|
||||
tooltip={
|
||||
!isLightboxOpen
|
||||
? `${t('parameters:openInViewer')} (Z)`
|
||||
: `${t('parameters:closeViewer')} (Z)`
|
||||
? `${t('parameters.openInViewer')} (Z)`
|
||||
: `${t('parameters.closeViewer')} (Z)`
|
||||
}
|
||||
aria-label={
|
||||
!isLightboxOpen
|
||||
? `${t('parameters:openInViewer')} (Z)`
|
||||
: `${t('parameters:closeViewer')} (Z)`
|
||||
? `${t('parameters.openInViewer')} (Z)`
|
||||
: `${t('parameters.closeViewer')} (Z)`
|
||||
}
|
||||
data-selected={isLightboxOpen}
|
||||
onClick={handleLightBox}
|
||||
@@ -471,24 +471,24 @@ const CurrentImageButtons = () => {
|
||||
<ButtonGroup isAttached={true}>
|
||||
<IAIIconButton
|
||||
icon={<FaQuoteRight />}
|
||||
tooltip={`${t('parameters:usePrompt')} (P)`}
|
||||
aria-label={`${t('parameters:usePrompt')} (P)`}
|
||||
tooltip={`${t('parameters.usePrompt')} (P)`}
|
||||
aria-label={`${t('parameters.usePrompt')} (P)`}
|
||||
isDisabled={!currentImage?.metadata?.image?.prompt}
|
||||
onClick={handleClickUsePrompt}
|
||||
/>
|
||||
|
||||
<IAIIconButton
|
||||
icon={<FaSeedling />}
|
||||
tooltip={`${t('parameters:useSeed')} (S)`}
|
||||
aria-label={`${t('parameters:useSeed')} (S)`}
|
||||
tooltip={`${t('parameters.useSeed')} (S)`}
|
||||
aria-label={`${t('parameters.useSeed')} (S)`}
|
||||
isDisabled={!currentImage?.metadata?.image?.seed}
|
||||
onClick={handleClickUseSeed}
|
||||
/>
|
||||
|
||||
<IAIIconButton
|
||||
icon={<FaAsterisk />}
|
||||
tooltip={`${t('parameters:useAll')} (A)`}
|
||||
aria-label={`${t('parameters:useAll')} (A)`}
|
||||
tooltip={`${t('parameters.useAll')} (A)`}
|
||||
aria-label={`${t('parameters.useAll')} (A)`}
|
||||
isDisabled={
|
||||
!['txt2img', 'img2img'].includes(
|
||||
currentImage?.metadata?.image?.type
|
||||
@@ -504,7 +504,7 @@ const CurrentImageButtons = () => {
|
||||
triggerComponent={
|
||||
<IAIIconButton
|
||||
icon={<FaGrinStars />}
|
||||
aria-label={t('parameters:restoreFaces')}
|
||||
aria-label={t('parameters.restoreFaces')}
|
||||
/>
|
||||
}
|
||||
>
|
||||
@@ -519,7 +519,7 @@ const CurrentImageButtons = () => {
|
||||
}
|
||||
onClick={handleClickFixFaces}
|
||||
>
|
||||
{t('parameters:restoreFaces')}
|
||||
{t('parameters.restoreFaces')}
|
||||
</IAIButton>
|
||||
</div>
|
||||
</IAIPopover>
|
||||
@@ -529,7 +529,7 @@ const CurrentImageButtons = () => {
|
||||
triggerComponent={
|
||||
<IAIIconButton
|
||||
icon={<FaExpandArrowsAlt />}
|
||||
aria-label={t('parameters:upscale')}
|
||||
aria-label={t('parameters.upscale')}
|
||||
/>
|
||||
}
|
||||
>
|
||||
@@ -544,7 +544,7 @@ const CurrentImageButtons = () => {
|
||||
}
|
||||
onClick={handleClickUpscale}
|
||||
>
|
||||
{t('parameters:upscaleImage')}
|
||||
{t('parameters.upscaleImage')}
|
||||
</IAIButton>
|
||||
</div>
|
||||
</IAIPopover>
|
||||
@@ -553,8 +553,8 @@ const CurrentImageButtons = () => {
|
||||
<ButtonGroup isAttached={true}>
|
||||
<IAIIconButton
|
||||
icon={<FaCode />}
|
||||
tooltip={`${t('parameters:info')} (I)`}
|
||||
aria-label={`${t('parameters:info')} (I)`}
|
||||
tooltip={`${t('parameters.info')} (I)`}
|
||||
aria-label={`${t('parameters.info')} (I)`}
|
||||
data-selected={shouldShowImageDetails}
|
||||
onClick={handleClickShowImageDetails}
|
||||
/>
|
||||
@@ -563,8 +563,8 @@ const CurrentImageButtons = () => {
|
||||
<DeleteImageModal image={currentImage}>
|
||||
<IAIIconButton
|
||||
icon={<FaTrash />}
|
||||
tooltip={`${t('parameters:deleteImage')} (Del)`}
|
||||
aria-label={`${t('parameters:deleteImage')} (Del)`}
|
||||
tooltip={`${t('parameters.deleteImage')} (Del)`}
|
||||
aria-label={`${t('parameters.deleteImage')} (Del)`}
|
||||
isDisabled={!currentImage || !isConnected || isProcessing}
|
||||
style={{ backgroundColor: 'var(--btn-delete-image)' }}
|
||||
/>
|
||||
|
||||
@@ -82,7 +82,7 @@ export default function CurrentImagePreview() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={'current-image-preview'}>
|
||||
<div className="current-image-preview">
|
||||
{imageToDisplay && (
|
||||
<Image
|
||||
src={imageToDisplay.url}
|
||||
|
||||
@@ -116,13 +116,13 @@ const DeleteImageModal = forwardRef(
|
||||
</AlertDialogHeader>
|
||||
|
||||
<AlertDialogBody>
|
||||
<Flex direction={'column'} gap={5}>
|
||||
<Flex direction="column" gap={5}>
|
||||
<Text>
|
||||
Are you sure? Deleted images will be sent to the Bin. You
|
||||
can restore from there if you wish to.
|
||||
</Text>
|
||||
<FormControl>
|
||||
<Flex alignItems={'center'}>
|
||||
<Flex alignItems="center">
|
||||
<FormLabel mb={0}>Don't ask me again</FormLabel>
|
||||
<Switch
|
||||
checked={!shouldConfirmOnDelete}
|
||||
|
||||
@@ -75,7 +75,7 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
}
|
||||
|
||||
toast({
|
||||
title: t('toast:promptSet'),
|
||||
title: t('toast.promptSet'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -85,7 +85,7 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
const handleUseSeed = () => {
|
||||
image.metadata && dispatch(setSeed(image.metadata.image.seed));
|
||||
toast({
|
||||
title: t('toast:seedSet'),
|
||||
title: t('toast.seedSet'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -98,7 +98,7 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
dispatch(setActiveTab('img2img'));
|
||||
}
|
||||
toast({
|
||||
title: t('toast:sentToImageToImage'),
|
||||
title: t('toast.sentToImageToImage'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -115,7 +115,7 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
}
|
||||
|
||||
toast({
|
||||
title: t('toast:sentToUnifiedCanvas'),
|
||||
title: t('toast.sentToUnifiedCanvas'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -125,7 +125,7 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
const handleUseAllParameters = () => {
|
||||
metadata && dispatch(setAllParameters(metadata));
|
||||
toast({
|
||||
title: t('toast:parametersSet'),
|
||||
title: t('toast.parametersSet'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -139,7 +139,7 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
dispatch(setActiveTab('img2img'));
|
||||
dispatch(setAllImageToImageParameters(metadata));
|
||||
toast({
|
||||
title: t('toast:initialImageSet'),
|
||||
title: t('toast.initialImageSet'),
|
||||
status: 'success',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -148,8 +148,8 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
}
|
||||
}
|
||||
toast({
|
||||
title: t('toast:initialImageNotSet'),
|
||||
description: t('toast:initialImageNotSetDesc'),
|
||||
title: t('toast.initialImageNotSet'),
|
||||
description: t('toast.initialImageNotSetDesc'),
|
||||
status: 'error',
|
||||
duration: 2500,
|
||||
isClosable: true,
|
||||
@@ -175,12 +175,12 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
>
|
||||
<ContextMenu.Trigger>
|
||||
<Box
|
||||
position={'relative'}
|
||||
position="relative"
|
||||
key={uuid}
|
||||
className="hoverable-image"
|
||||
onMouseOver={handleMouseOver}
|
||||
onMouseOut={handleMouseOut}
|
||||
userSelect={'none'}
|
||||
userSelect="none"
|
||||
draggable={true}
|
||||
onDragStart={handleDragStart}
|
||||
>
|
||||
@@ -189,15 +189,15 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
objectFit={
|
||||
shouldUseSingleGalleryColumn ? 'contain' : galleryImageObjectFit
|
||||
}
|
||||
rounded={'md'}
|
||||
rounded="md"
|
||||
src={thumbnail || url}
|
||||
loading={'lazy'}
|
||||
loading="lazy"
|
||||
/>
|
||||
<div className="hoverable-image-content" onClick={handleSelectImage}>
|
||||
{isSelected && (
|
||||
<Icon
|
||||
width={'50%'}
|
||||
height={'50%'}
|
||||
width="50%"
|
||||
height="50%"
|
||||
as={FaCheck}
|
||||
className="hoverable-image-check"
|
||||
/>
|
||||
@@ -207,10 +207,10 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
<div className="hoverable-image-delete-button">
|
||||
<DeleteImageModal image={image}>
|
||||
<IconButton
|
||||
aria-label={t('parameters:deleteImage')}
|
||||
aria-label={t('parameters.deleteImage')}
|
||||
icon={<FaTrashAlt />}
|
||||
size="xs"
|
||||
variant={'imageHoverIconButton'}
|
||||
variant="imageHoverIconButton"
|
||||
fontSize={14}
|
||||
isDisabled={!mayDeleteImage}
|
||||
/>
|
||||
@@ -221,26 +221,26 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
</ContextMenu.Trigger>
|
||||
<ContextMenu.Content
|
||||
className="hoverable-image-context-menu"
|
||||
sticky={'always'}
|
||||
sticky="always"
|
||||
onInteractOutside={(e) => {
|
||||
e.detail.originalEvent.preventDefault();
|
||||
}}
|
||||
>
|
||||
<ContextMenu.Item onClickCapture={handleLightBox}>
|
||||
{t('parameters:openInViewer')}
|
||||
{t('parameters.openInViewer')}
|
||||
</ContextMenu.Item>
|
||||
<ContextMenu.Item
|
||||
onClickCapture={handleUsePrompt}
|
||||
disabled={image?.metadata?.image?.prompt === undefined}
|
||||
>
|
||||
{t('parameters:usePrompt')}
|
||||
{t('parameters.usePrompt')}
|
||||
</ContextMenu.Item>
|
||||
|
||||
<ContextMenu.Item
|
||||
onClickCapture={handleUseSeed}
|
||||
disabled={image?.metadata?.image?.seed === undefined}
|
||||
>
|
||||
{t('parameters:useSeed')}
|
||||
{t('parameters.useSeed')}
|
||||
</ContextMenu.Item>
|
||||
<ContextMenu.Item
|
||||
onClickCapture={handleUseAllParameters}
|
||||
@@ -248,23 +248,23 @@ const HoverableImage = memo((props: HoverableImageProps) => {
|
||||
!['txt2img', 'img2img'].includes(image?.metadata?.image?.type)
|
||||
}
|
||||
>
|
||||
{t('parameters:useAll')}
|
||||
{t('parameters.useAll')}
|
||||
</ContextMenu.Item>
|
||||
<ContextMenu.Item
|
||||
onClickCapture={handleUseInitialImage}
|
||||
disabled={image?.metadata?.image?.type !== 'img2img'}
|
||||
>
|
||||
{t('parameters:useInitImg')}
|
||||
{t('parameters.useInitImg')}
|
||||
</ContextMenu.Item>
|
||||
<ContextMenu.Item onClickCapture={handleSendToImageToImage}>
|
||||
{t('parameters:sendToImg2Img')}
|
||||
{t('parameters.sendToImg2Img')}
|
||||
</ContextMenu.Item>
|
||||
<ContextMenu.Item onClickCapture={handleSendToCanvas}>
|
||||
{t('parameters:sendToUnifiedCanvas')}
|
||||
{t('parameters.sendToUnifiedCanvas')}
|
||||
</ContextMenu.Item>
|
||||
<ContextMenu.Item data-warning>
|
||||
<DeleteImageModal image={image}>
|
||||
<p>{t('parameters:deleteImage')}</p>
|
||||
<p>{t('parameters.deleteImage')}</p>
|
||||
</DeleteImageModal>
|
||||
</ContextMenu.Item>
|
||||
</ContextMenu.Content>
|
||||
|
||||
@@ -281,7 +281,7 @@ export default function ImageGallery() {
|
||||
<Resizable
|
||||
minWidth={galleryMinWidth}
|
||||
maxWidth={shouldPinGallery ? galleryMaxWidth : window.innerWidth}
|
||||
className={'image-gallery-popup'}
|
||||
className="image-gallery-popup"
|
||||
handleStyles={{
|
||||
left: {
|
||||
width: '15px',
|
||||
@@ -395,32 +395,32 @@ export default function ImageGallery() {
|
||||
{shouldShowButtons ? (
|
||||
<>
|
||||
<IAIButton
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
data-selected={currentCategory === 'result'}
|
||||
onClick={() => dispatch(setCurrentCategory('result'))}
|
||||
>
|
||||
{t('gallery:generations')}
|
||||
{t('gallery.generations')}
|
||||
</IAIButton>
|
||||
<IAIButton
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
data-selected={currentCategory === 'user'}
|
||||
onClick={() => dispatch(setCurrentCategory('user'))}
|
||||
>
|
||||
{t('gallery:uploads')}
|
||||
{t('gallery.uploads')}
|
||||
</IAIButton>
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<IAIIconButton
|
||||
aria-label={t('gallery:showGenerations')}
|
||||
tooltip={t('gallery:showGenerations')}
|
||||
aria-label={t('gallery.showGenerations')}
|
||||
tooltip={t('gallery.showGenerations')}
|
||||
data-selected={currentCategory === 'result'}
|
||||
icon={<FaImage />}
|
||||
onClick={() => dispatch(setCurrentCategory('result'))}
|
||||
/>
|
||||
<IAIIconButton
|
||||
aria-label={t('gallery:showUploads')}
|
||||
tooltip={t('gallery:showUploads')}
|
||||
aria-label={t('gallery.showUploads')}
|
||||
tooltip={t('gallery.showUploads')}
|
||||
data-selected={currentCategory === 'user'}
|
||||
icon={<FaUser />}
|
||||
onClick={() => dispatch(setCurrentCategory('user'))}
|
||||
@@ -433,14 +433,14 @@ export default function ImageGallery() {
|
||||
<IAIPopover
|
||||
isLazy
|
||||
trigger="hover"
|
||||
placement={'left'}
|
||||
placement="left"
|
||||
triggerComponent={
|
||||
<IAIIconButton
|
||||
size={'sm'}
|
||||
aria-label={t('gallery:gallerySettings')}
|
||||
size="sm"
|
||||
aria-label={t('gallery.gallerySettings')}
|
||||
icon={<FaWrench />}
|
||||
className="image-gallery-icon-btn"
|
||||
cursor={'pointer'}
|
||||
cursor="pointer"
|
||||
/>
|
||||
}
|
||||
>
|
||||
@@ -452,12 +452,12 @@ export default function ImageGallery() {
|
||||
min={32}
|
||||
max={256}
|
||||
hideTooltip={true}
|
||||
label={t('gallery:galleryImageSize')}
|
||||
label={t('gallery.galleryImageSize')}
|
||||
/>
|
||||
<IAIIconButton
|
||||
size={'sm'}
|
||||
aria-label={t('gallery:galleryImageResetSize')}
|
||||
tooltip={t('gallery:galleryImageResetSize')}
|
||||
size="sm"
|
||||
aria-label={t('gallery.galleryImageResetSize')}
|
||||
tooltip={t('gallery.galleryImageResetSize')}
|
||||
onClick={() => dispatch(setGalleryImageMinimumWidth(64))}
|
||||
icon={<BiReset />}
|
||||
data-selected={shouldPinGallery}
|
||||
@@ -466,7 +466,7 @@ export default function ImageGallery() {
|
||||
</div>
|
||||
<div>
|
||||
<IAICheckbox
|
||||
label={t('gallery:maintainAspectRatio')}
|
||||
label={t('gallery.maintainAspectRatio')}
|
||||
isChecked={galleryImageObjectFit === 'contain'}
|
||||
onChange={() =>
|
||||
dispatch(
|
||||
@@ -481,7 +481,7 @@ export default function ImageGallery() {
|
||||
</div>
|
||||
<div>
|
||||
<IAICheckbox
|
||||
label={t('gallery:autoSwitchNewImages')}
|
||||
label={t('gallery.autoSwitchNewImages')}
|
||||
isChecked={shouldAutoSwitchToNewImages}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
dispatch(
|
||||
@@ -492,7 +492,7 @@ export default function ImageGallery() {
|
||||
</div>
|
||||
<div>
|
||||
<IAICheckbox
|
||||
label={t('gallery:singleColumnLayout')}
|
||||
label={t('gallery.singleColumnLayout')}
|
||||
isChecked={shouldUseSingleGalleryColumn}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
dispatch(
|
||||
@@ -505,10 +505,10 @@ export default function ImageGallery() {
|
||||
</IAIPopover>
|
||||
|
||||
<IAIIconButton
|
||||
size={'sm'}
|
||||
className={'image-gallery-icon-btn'}
|
||||
aria-label={t('gallery:pinGallery')}
|
||||
tooltip={`${t('gallery:pinGallery')} (Shift+G)`}
|
||||
size="sm"
|
||||
className="image-gallery-icon-btn"
|
||||
aria-label={t('gallery.pinGallery')}
|
||||
tooltip={`${t('gallery.pinGallery')} (Shift+G)`}
|
||||
onClick={handleSetShouldPinGallery}
|
||||
icon={shouldPinGallery ? <BsPinAngleFill /> : <BsPinAngle />}
|
||||
/>
|
||||
@@ -539,14 +539,14 @@ export default function ImageGallery() {
|
||||
className="image-gallery-load-more-btn"
|
||||
>
|
||||
{areMoreImagesAvailable
|
||||
? t('gallery:loadMore')
|
||||
: t('gallery:allImagesLoaded')}
|
||||
? t('gallery.loadMore')
|
||||
: t('gallery.allImagesLoaded')}
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<div className="image-gallery-container-placeholder">
|
||||
<MdPhotoLibrary />
|
||||
<p>{t('gallery:noImagesInGallery')}</p>
|
||||
<p>{t('gallery.noImagesInGallery')}</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -71,8 +71,8 @@ const MetadataItem = ({
|
||||
<IconButton
|
||||
aria-label="Use this parameter"
|
||||
icon={<IoArrowUndoCircleOutline />}
|
||||
size={'xs'}
|
||||
variant={'ghost'}
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
fontSize={20}
|
||||
onClick={onClick}
|
||||
/>
|
||||
@@ -83,23 +83,23 @@ const MetadataItem = ({
|
||||
<IconButton
|
||||
aria-label={`Copy ${label}`}
|
||||
icon={<FaCopy />}
|
||||
size={'xs'}
|
||||
variant={'ghost'}
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
fontSize={14}
|
||||
onClick={() => navigator.clipboard.writeText(value.toString())}
|
||||
/>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Flex direction={labelPosition ? 'column' : 'row'}>
|
||||
<Text fontWeight={'semibold'} whiteSpace={'pre-wrap'} pr={2}>
|
||||
<Text fontWeight="semibold" whiteSpace="pre-wrap" pr={2}>
|
||||
{label}:
|
||||
</Text>
|
||||
{isLink ? (
|
||||
<Link href={value.toString()} isExternal wordBreak={'break-all'}>
|
||||
<Link href={value.toString()} isExternal wordBreak="break-all">
|
||||
{value.toString()} <ExternalLinkIcon mx="2px" />
|
||||
</Link>
|
||||
) : (
|
||||
<Text overflowY={'scroll'} wordBreak={'break-all'}>
|
||||
<Text overflowY="scroll" wordBreak="break-all">
|
||||
{value.toString()}
|
||||
</Text>
|
||||
)}
|
||||
@@ -163,10 +163,10 @@ const ImageMetadataViewer = memo(
|
||||
|
||||
return (
|
||||
<div className={`image-metadata-viewer ${styleClass}`}>
|
||||
<Flex gap={1} direction={'column'} width={'100%'}>
|
||||
<Flex gap={1} direction="column" width="100%">
|
||||
<Flex gap={2}>
|
||||
<Text fontWeight={'semibold'}>File:</Text>
|
||||
<Link href={image.url} isExternal maxW={'calc(100% - 3rem)'}>
|
||||
<Text fontWeight="semibold">File:</Text>
|
||||
<Link href={image.url} isExternal maxW="calc(100% - 3rem)">
|
||||
{image.url.length > 64
|
||||
? image.url.substring(0, 64).concat('...')
|
||||
: image.url}
|
||||
@@ -304,7 +304,7 @@ const ImageMetadataViewer = memo(
|
||||
)}
|
||||
{postprocessing && postprocessing.length > 0 && (
|
||||
<>
|
||||
<Heading size={'sm'}>Postprocessing</Heading>
|
||||
<Heading size="sm">Postprocessing</Heading>
|
||||
{postprocessing.map(
|
||||
(
|
||||
postprocess: InvokeAI.PostProcessedImageMetadata,
|
||||
@@ -313,13 +313,8 @@ const ImageMetadataViewer = memo(
|
||||
if (postprocess.type === 'esrgan') {
|
||||
const { scale, strength, denoise_str } = postprocess;
|
||||
return (
|
||||
<Flex
|
||||
key={i}
|
||||
pl={'2rem'}
|
||||
gap={1}
|
||||
direction={'column'}
|
||||
>
|
||||
<Text size={'md'}>{`${
|
||||
<Flex key={i} pl="2rem" gap={1} direction="column">
|
||||
<Text size="md">{`${
|
||||
i + 1
|
||||
}: Upscale (ESRGAN)`}</Text>
|
||||
<MetadataItem
|
||||
@@ -348,13 +343,8 @@ const ImageMetadataViewer = memo(
|
||||
} else if (postprocess.type === 'gfpgan') {
|
||||
const { strength } = postprocess;
|
||||
return (
|
||||
<Flex
|
||||
key={i}
|
||||
pl={'2rem'}
|
||||
gap={1}
|
||||
direction={'column'}
|
||||
>
|
||||
<Text size={'md'}>{`${
|
||||
<Flex key={i} pl="2rem" gap={1} direction="column">
|
||||
<Text size="md">{`${
|
||||
i + 1
|
||||
}: Face restoration (GFPGAN)`}</Text>
|
||||
|
||||
@@ -371,13 +361,8 @@ const ImageMetadataViewer = memo(
|
||||
} else if (postprocess.type === 'codeformer') {
|
||||
const { strength, fidelity } = postprocess;
|
||||
return (
|
||||
<Flex
|
||||
key={i}
|
||||
pl={'2rem'}
|
||||
gap={1}
|
||||
direction={'column'}
|
||||
>
|
||||
<Text size={'md'}>{`${
|
||||
<Flex key={i} pl="2rem" gap={1} direction="column">
|
||||
<Text size="md">{`${
|
||||
i + 1
|
||||
}: Face restoration (Codeformer)`}</Text>
|
||||
|
||||
@@ -413,30 +398,30 @@ const ImageMetadataViewer = memo(
|
||||
value={dreamPrompt}
|
||||
/>
|
||||
)}
|
||||
<Flex gap={2} direction={'column'}>
|
||||
<Flex gap={2} direction="column">
|
||||
<Flex gap={2}>
|
||||
<Tooltip label={`Copy metadata JSON`}>
|
||||
<Tooltip label="Copy metadata JSON">
|
||||
<IconButton
|
||||
aria-label="Copy metadata JSON"
|
||||
icon={<FaCopy />}
|
||||
size={'xs'}
|
||||
variant={'ghost'}
|
||||
size="xs"
|
||||
variant="ghost"
|
||||
fontSize={14}
|
||||
onClick={() =>
|
||||
navigator.clipboard.writeText(metadataJSON)
|
||||
}
|
||||
/>
|
||||
</Tooltip>
|
||||
<Text fontWeight={'semibold'}>Metadata JSON:</Text>
|
||||
<Text fontWeight="semibold">Metadata JSON:</Text>
|
||||
</Flex>
|
||||
<div className={'image-json-viewer'}>
|
||||
<div className="image-json-viewer">
|
||||
<pre>{metadataJSON}</pre>
|
||||
</div>
|
||||
</Flex>
|
||||
</>
|
||||
) : (
|
||||
<Center width={'100%'} pt={10}>
|
||||
<Text fontSize={'lg'} fontWeight="semibold">
|
||||
<Center width="100%" pt={10}>
|
||||
<Text fontSize="lg" fontWeight="semibold">
|
||||
No metadata available
|
||||
</Text>
|
||||
</Center>
|
||||
|
||||
@@ -23,8 +23,8 @@ export default function InvokeAccordionItem(props: InvokeAccordionItemProps) {
|
||||
return (
|
||||
<AccordionItem className="advanced-parameters-item">
|
||||
<AccordionButton className="advanced-parameters-header">
|
||||
<Flex width={'100%'} gap={'0.5rem'} align={'center'}>
|
||||
<Box flexGrow={1} textAlign={'left'}>
|
||||
<Flex width="100%" gap="0.5rem" align="center">
|
||||
<Box flexGrow={1} textAlign="left">
|
||||
{header}
|
||||
</Box>
|
||||
{additionalHeaderComponents}
|
||||
|
||||
@@ -68,9 +68,9 @@ const BoundingBoxSettings = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap="1rem">
|
||||
<Flex direction="column" gap={2}>
|
||||
<IAISlider
|
||||
label={t('parameters:width')}
|
||||
label={t('parameters.width')}
|
||||
min={64}
|
||||
max={1024}
|
||||
step={64}
|
||||
@@ -82,9 +82,10 @@ const BoundingBoxSettings = () => {
|
||||
inputReadOnly
|
||||
withReset
|
||||
handleReset={handleResetWidth}
|
||||
sliderMarkRightOffset={-7}
|
||||
/>
|
||||
<IAISlider
|
||||
label={t('parameters:height')}
|
||||
label={t('parameters.height')}
|
||||
min={64}
|
||||
max={1024}
|
||||
step={64}
|
||||
@@ -96,6 +97,7 @@ const BoundingBoxSettings = () => {
|
||||
inputReadOnly
|
||||
withReset
|
||||
handleReset={handleResetHeight}
|
||||
sliderMarkRightOffset={-7}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
@@ -107,7 +109,7 @@ export const BoundingBoxSettingsHeader = () => {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Box flex="1" textAlign="left">
|
||||
{t('parameters:boundingBoxHeader')}
|
||||
{t('parameters.boundingBoxHeader')}
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -107,9 +107,9 @@ const InfillAndScalingSettings = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap="1rem">
|
||||
<Flex direction="column" gap={4}>
|
||||
<IAISelect
|
||||
label={t('parameters:scaleBeforeProcessing')}
|
||||
label={t('parameters.scaleBeforeProcessing')}
|
||||
validValues={BOUNDING_BOX_SCALES_DICT}
|
||||
value={boundingBoxScale}
|
||||
onChange={handleChangeBoundingBoxScaleMethod}
|
||||
@@ -118,7 +118,7 @@ const InfillAndScalingSettings = () => {
|
||||
isInputDisabled={!isManual}
|
||||
isResetDisabled={!isManual}
|
||||
isSliderDisabled={!isManual}
|
||||
label={t('parameters:scaledWidth')}
|
||||
label={t('parameters.scaledWidth')}
|
||||
min={64}
|
||||
max={1024}
|
||||
step={64}
|
||||
@@ -130,12 +130,13 @@ const InfillAndScalingSettings = () => {
|
||||
inputReadOnly
|
||||
withReset
|
||||
handleReset={handleResetScaledWidth}
|
||||
sliderMarkRightOffset={-7}
|
||||
/>
|
||||
<IAISlider
|
||||
isInputDisabled={!isManual}
|
||||
isResetDisabled={!isManual}
|
||||
isSliderDisabled={!isManual}
|
||||
label={t('parameters:scaledHeight')}
|
||||
label={t('parameters.scaledHeight')}
|
||||
min={64}
|
||||
max={1024}
|
||||
step={64}
|
||||
@@ -147,9 +148,10 @@ const InfillAndScalingSettings = () => {
|
||||
inputReadOnly
|
||||
withReset
|
||||
handleReset={handleResetScaledHeight}
|
||||
sliderMarkRightOffset={-7}
|
||||
/>
|
||||
<IAISelect
|
||||
label={t('parameters:infillMethod')}
|
||||
label={t('parameters.infillMethod')}
|
||||
value={infillMethod}
|
||||
validValues={availableInfillMethods}
|
||||
onChange={(e) => dispatch(setInfillMethod(e.target.value))}
|
||||
@@ -159,7 +161,7 @@ const InfillAndScalingSettings = () => {
|
||||
isResetDisabled={infillMethod !== 'tile'}
|
||||
isSliderDisabled={infillMethod !== 'tile'}
|
||||
sliderMarkRightOffset={-4}
|
||||
label={t('parameters:tileSize')}
|
||||
label={t('parameters.tileSize')}
|
||||
min={16}
|
||||
max={64}
|
||||
sliderNumberInputProps={{ max: 256 }}
|
||||
|
||||
@@ -14,7 +14,7 @@ export default function SeamBlur() {
|
||||
return (
|
||||
<IAISlider
|
||||
sliderMarkRightOffset={-4}
|
||||
label={t('parameters:seamBlur')}
|
||||
label={t('parameters.seamBlur')}
|
||||
min={0}
|
||||
max={64}
|
||||
sliderNumberInputProps={{ max: 512 }}
|
||||
|
||||
@@ -6,7 +6,7 @@ import SeamStrength from './SeamStrength';
|
||||
|
||||
const SeamCorrectionSettings = () => {
|
||||
return (
|
||||
<Flex direction="column" gap="1rem">
|
||||
<Flex direction="column" gap={2}>
|
||||
<SeamSize />
|
||||
<SeamBlur />
|
||||
<SeamStrength />
|
||||
|
||||
@@ -15,7 +15,7 @@ export default function SeamSize() {
|
||||
return (
|
||||
<IAISlider
|
||||
sliderMarkRightOffset={-6}
|
||||
label={t('parameters:seamSize')}
|
||||
label={t('parameters.seamSize')}
|
||||
min={1}
|
||||
max={256}
|
||||
sliderNumberInputProps={{ max: 512 }}
|
||||
|
||||
@@ -14,7 +14,7 @@ export default function SeamSteps() {
|
||||
return (
|
||||
<IAISlider
|
||||
sliderMarkRightOffset={-4}
|
||||
label={t('parameters:seamSteps')}
|
||||
label={t('parameters.seamSteps')}
|
||||
min={1}
|
||||
max={100}
|
||||
sliderNumberInputProps={{ max: 999 }}
|
||||
|
||||
@@ -14,7 +14,7 @@ export default function SeamStrength() {
|
||||
return (
|
||||
<IAISlider
|
||||
sliderMarkRightOffset={-7}
|
||||
label={t('parameters:seamStrength')}
|
||||
label={t('parameters.seamStrength')}
|
||||
min={0.01}
|
||||
max={0.99}
|
||||
step={0.01}
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setCodeformerFidelity } from 'features/parameters/store/postprocessingSlice';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function CodeformerFidelity() {
|
||||
const isGFPGANAvailable = useAppSelector(
|
||||
(state: RootState) => state.system.isGFPGANAvailable
|
||||
);
|
||||
|
||||
const codeformerFidelity = useAppSelector(
|
||||
(state: RootState) => state.postprocessing.codeformerFidelity
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
return (
|
||||
<IAISlider
|
||||
isSliderDisabled={!isGFPGANAvailable}
|
||||
isInputDisabled={!isGFPGANAvailable}
|
||||
isResetDisabled={!isGFPGANAvailable}
|
||||
label={t('parameters.codeformerFidelity')}
|
||||
step={0.05}
|
||||
min={0}
|
||||
max={1}
|
||||
onChange={(v) => dispatch(setCodeformerFidelity(v))}
|
||||
handleReset={() => dispatch(setCodeformerFidelity(1))}
|
||||
value={codeformerFidelity}
|
||||
withReset
|
||||
withSliderMarks
|
||||
withInput
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,99 +1,23 @@
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
|
||||
import { FacetoolType } from 'features/parameters/store/postprocessingSlice';
|
||||
|
||||
import {
|
||||
setCodeformerFidelity,
|
||||
setFacetoolStrength,
|
||||
setFacetoolType,
|
||||
} from 'features/parameters/store/postprocessingSlice';
|
||||
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { FACETOOL_TYPES } from 'app/constants';
|
||||
import IAINumberInput from 'common/components/IAINumberInput';
|
||||
import IAISelect from 'common/components/IAISelect';
|
||||
import { postprocessingSelector } from 'features/parameters/store/postprocessingSelectors';
|
||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||
import { isEqual } from 'lodash';
|
||||
import { ChangeEvent } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const optionsSelector = createSelector(
|
||||
[postprocessingSelector, systemSelector],
|
||||
(
|
||||
{ facetoolStrength, facetoolType, codeformerFidelity },
|
||||
{ isGFPGANAvailable }
|
||||
) => {
|
||||
return {
|
||||
facetoolStrength,
|
||||
facetoolType,
|
||||
codeformerFidelity,
|
||||
isGFPGANAvailable,
|
||||
};
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: isEqual,
|
||||
},
|
||||
}
|
||||
);
|
||||
import { useAppSelector } from 'app/storeHooks';
|
||||
import type { RootState } from 'app/store';
|
||||
import FaceRestoreType from './FaceRestoreType';
|
||||
import FaceRestoreStrength from './FaceRestoreStrength';
|
||||
import CodeformerFidelity from './CodeformerFidelity';
|
||||
|
||||
/**
|
||||
* Displays face-fixing/GFPGAN options (strength).
|
||||
*/
|
||||
const FaceRestoreSettings = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const {
|
||||
facetoolStrength,
|
||||
facetoolType,
|
||||
codeformerFidelity,
|
||||
isGFPGANAvailable,
|
||||
} = useAppSelector(optionsSelector);
|
||||
|
||||
const handleChangeStrength = (v: number) => dispatch(setFacetoolStrength(v));
|
||||
|
||||
const handleChangeCodeformerFidelity = (v: number) =>
|
||||
dispatch(setCodeformerFidelity(v));
|
||||
|
||||
const handleChangeFacetoolType = (e: ChangeEvent<HTMLSelectElement>) =>
|
||||
dispatch(setFacetoolType(e.target.value as FacetoolType));
|
||||
|
||||
const { t } = useTranslation();
|
||||
const facetoolType = useAppSelector(
|
||||
(state: RootState) => state.postprocessing.facetoolType
|
||||
);
|
||||
|
||||
return (
|
||||
<Flex direction={'column'} gap={2}>
|
||||
<IAISelect
|
||||
label={t('parameters:type')}
|
||||
validValues={FACETOOL_TYPES.concat()}
|
||||
value={facetoolType}
|
||||
onChange={handleChangeFacetoolType}
|
||||
/>
|
||||
<IAINumberInput
|
||||
isDisabled={!isGFPGANAvailable}
|
||||
label={t('parameters:strength')}
|
||||
step={0.05}
|
||||
min={0}
|
||||
max={1}
|
||||
onChange={handleChangeStrength}
|
||||
value={facetoolStrength}
|
||||
width="90px"
|
||||
isInteger={false}
|
||||
/>
|
||||
{facetoolType === 'codeformer' && (
|
||||
<IAINumberInput
|
||||
isDisabled={!isGFPGANAvailable}
|
||||
label={t('parameters:codeformerFidelity')}
|
||||
step={0.05}
|
||||
min={0}
|
||||
max={1}
|
||||
onChange={handleChangeCodeformerFidelity}
|
||||
value={codeformerFidelity}
|
||||
width="90px"
|
||||
isInteger={false}
|
||||
/>
|
||||
)}
|
||||
<Flex direction="column" gap={2} minWidth="20rem">
|
||||
<FaceRestoreType />
|
||||
<FaceRestoreStrength />
|
||||
{facetoolType === 'codeformer' && <CodeformerFidelity />}
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setFacetoolStrength } from 'features/parameters/store/postprocessingSlice';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function FaceRestoreStrength() {
|
||||
const isGFPGANAvailable = useAppSelector(
|
||||
(state: RootState) => state.system.isGFPGANAvailable
|
||||
);
|
||||
|
||||
const facetoolStrength = useAppSelector(
|
||||
(state: RootState) => state.postprocessing.facetoolStrength
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
return (
|
||||
<IAISlider
|
||||
isSliderDisabled={!isGFPGANAvailable}
|
||||
isInputDisabled={!isGFPGANAvailable}
|
||||
isResetDisabled={!isGFPGANAvailable}
|
||||
label={t('parameters.strength')}
|
||||
step={0.05}
|
||||
min={0}
|
||||
max={1}
|
||||
onChange={(v) => dispatch(setFacetoolStrength(v))}
|
||||
handleReset={() => dispatch(setFacetoolStrength(0.75))}
|
||||
value={facetoolStrength}
|
||||
withReset
|
||||
withSliderMarks
|
||||
withInput
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { FACETOOL_TYPES } from 'app/constants';
|
||||
import { type RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISelect from 'common/components/IAISelect';
|
||||
import {
|
||||
type FacetoolType,
|
||||
setFacetoolType,
|
||||
} from 'features/parameters/store/postprocessingSlice';
|
||||
import { type ChangeEvent } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function FaceRestoreType() {
|
||||
const facetoolType = useAppSelector(
|
||||
(state: RootState) => state.postprocessing.facetoolType
|
||||
);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleChangeFacetoolType = (e: ChangeEvent<HTMLSelectElement>) =>
|
||||
dispatch(setFacetoolType(e.target.value as FacetoolType));
|
||||
|
||||
return (
|
||||
<IAISelect
|
||||
label={t('parameters.type')}
|
||||
validValues={FACETOOL_TYPES.concat()}
|
||||
value={facetoolType}
|
||||
onChange={handleChangeFacetoolType}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -19,7 +19,7 @@ export default function ImageFit() {
|
||||
|
||||
return (
|
||||
<IAISwitch
|
||||
label={t('parameters:imageFit')}
|
||||
label={t('parameters.imageFit')}
|
||||
isChecked={shouldFitToWidthHeight}
|
||||
onChange={handleChangeFit}
|
||||
/>
|
||||
|
||||
@@ -11,7 +11,7 @@ interface ImageToImageStrengthProps {
|
||||
|
||||
export default function ImageToImageStrength(props: ImageToImageStrengthProps) {
|
||||
const { t } = useTranslation();
|
||||
const { label = `${t('parameters:strength')}`, styleClass } = props;
|
||||
const { label = `${t('parameters.strength')}`, styleClass } = props;
|
||||
const img2imgStrength = useAppSelector(
|
||||
(state: RootState) => state.generation.img2imgStrength
|
||||
);
|
||||
@@ -36,7 +36,7 @@ export default function ImageToImageStrength(props: ImageToImageStrengthProps) {
|
||||
styleClass={styleClass}
|
||||
withInput
|
||||
withSliderMarks
|
||||
inputWidth={'5.5rem'}
|
||||
inputWidth="5.5rem"
|
||||
withReset
|
||||
handleReset={handleImg2ImgStrengthReset}
|
||||
/>
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import IAISwitch from 'common/components/IAISwitch';
|
||||
import SubItemHook from 'common/components/SubItemHook';
|
||||
import { postprocessingSelector } from 'features/parameters/store/postprocessingSelectors';
|
||||
import {
|
||||
setHiresFix,
|
||||
@@ -39,23 +40,27 @@ const HiresStrength = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<IAISlider
|
||||
label={t('parameters:hiresStrength')}
|
||||
step={0.01}
|
||||
min={0.01}
|
||||
max={0.99}
|
||||
onChange={handleHiresStrength}
|
||||
value={hiresStrength}
|
||||
isInteger={false}
|
||||
withInput
|
||||
withSliderMarks
|
||||
inputWidth={'5.5rem'}
|
||||
withReset
|
||||
handleReset={handleHiResStrengthReset}
|
||||
isSliderDisabled={!hiresFix}
|
||||
isInputDisabled={!hiresFix}
|
||||
isResetDisabled={!hiresFix}
|
||||
/>
|
||||
<Flex>
|
||||
<SubItemHook active={hiresFix} />
|
||||
<IAISlider
|
||||
label={t('parameters.hiresStrength')}
|
||||
step={0.01}
|
||||
min={0.01}
|
||||
max={0.99}
|
||||
onChange={handleHiresStrength}
|
||||
value={hiresStrength}
|
||||
isInteger={false}
|
||||
withInput
|
||||
withSliderMarks
|
||||
inputWidth={'5.5rem'}
|
||||
withReset
|
||||
handleReset={handleHiResStrengthReset}
|
||||
isSliderDisabled={!hiresFix}
|
||||
isInputDisabled={!hiresFix}
|
||||
isResetDisabled={!hiresFix}
|
||||
sliderMarkRightOffset={-7}
|
||||
/>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -75,10 +80,10 @@ const HiresSettings = () => {
|
||||
dispatch(setHiresFix(e.target.checked));
|
||||
|
||||
return (
|
||||
<Flex gap={2} direction={'column'}>
|
||||
<Flex rowGap="0.8rem" direction={'column'}>
|
||||
<IAISwitch
|
||||
label={t('parameters:hiresOptim')}
|
||||
fontSize={'md'}
|
||||
label={t('parameters.hiresOptim')}
|
||||
fontSize="md"
|
||||
isChecked={hiresFix}
|
||||
onChange={handleChangeHiresFix}
|
||||
/>
|
||||
|
||||
@@ -3,7 +3,7 @@ import SeamlessSettings from './SeamlessSettings';
|
||||
|
||||
const ImageToImageOutputSettings = () => {
|
||||
return (
|
||||
<Flex gap={2} direction={'column'}>
|
||||
<Flex gap={2} direction="column">
|
||||
<SeamlessSettings />
|
||||
</Flex>
|
||||
);
|
||||
|
||||
@@ -4,7 +4,7 @@ import SeamlessSettings from './SeamlessSettings';
|
||||
|
||||
const OutputSettings = () => {
|
||||
return (
|
||||
<Flex gap={2} direction={'column'}>
|
||||
<Flex gap={2} direction="column">
|
||||
<SeamlessSettings />
|
||||
<HiresSettings />
|
||||
</Flex>
|
||||
|
||||
@@ -22,10 +22,10 @@ const SeamlessSettings = () => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Flex gap={2} direction={'column'}>
|
||||
<Flex gap={2} direction="column">
|
||||
<IAISwitch
|
||||
label={t('parameters:seamlessTiling')}
|
||||
fontSize={'md'}
|
||||
label={t('parameters.seamlessTiling')}
|
||||
fontSize="md"
|
||||
isChecked={seamless}
|
||||
onChange={handleChangeSeamless}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAINumberInput from 'common/components/IAINumberInput';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setPerlin } from 'features/parameters/store/generationSlice';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -9,17 +9,18 @@ export default function Perlin() {
|
||||
const perlin = useAppSelector((state: RootState) => state.generation.perlin);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleChangePerlin = (v: number) => dispatch(setPerlin(v));
|
||||
|
||||
return (
|
||||
<IAINumberInput
|
||||
label={t('parameters:perlinNoise')}
|
||||
<IAISlider
|
||||
label={t('parameters.perlinNoise')}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.05}
|
||||
onChange={handleChangePerlin}
|
||||
onChange={(v) => dispatch(setPerlin(v))}
|
||||
handleReset={() => dispatch(setPerlin(0))}
|
||||
value={perlin}
|
||||
isInteger={false}
|
||||
withInput
|
||||
withReset
|
||||
withSliderMarks
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ export default function RandomizeSeed() {
|
||||
|
||||
return (
|
||||
<IAISwitch
|
||||
label={t('parameters:randomizeSeed')}
|
||||
label={t('parameters.randomizeSeed')}
|
||||
isChecked={shouldRandomizeSeed}
|
||||
onChange={handleChangeShouldRandomizeSeed}
|
||||
/>
|
||||
|
||||
@@ -22,7 +22,7 @@ export default function Seed() {
|
||||
|
||||
return (
|
||||
<IAINumberInput
|
||||
label={t('parameters:seed')}
|
||||
label={t('parameters.seed')}
|
||||
step={1}
|
||||
precision={0}
|
||||
flexGrow={1}
|
||||
|
||||
@@ -10,7 +10,7 @@ import Threshold from './Threshold';
|
||||
*/
|
||||
const SeedSettings = () => {
|
||||
return (
|
||||
<Flex gap={2} direction={'column'}>
|
||||
<Flex gap={2} direction="column">
|
||||
<RandomizeSeed />
|
||||
<Flex gap={2}>
|
||||
<Seed />
|
||||
|
||||
@@ -18,12 +18,12 @@ export default function ShuffleSeed() {
|
||||
|
||||
return (
|
||||
<Button
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
isDisabled={shouldRandomizeSeed}
|
||||
onClick={handleClickRandomizeSeed}
|
||||
padding="0 1.5rem"
|
||||
>
|
||||
<p>{t('parameters:shuffle')}</p>
|
||||
<p>{t('parameters.shuffle')}</p>
|
||||
</Button>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAINumberInput from 'common/components/IAINumberInput';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setThreshold } from 'features/parameters/store/generationSlice';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -11,17 +11,19 @@ export default function Threshold() {
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleChangeThreshold = (v: number) => dispatch(setThreshold(v));
|
||||
|
||||
return (
|
||||
<IAINumberInput
|
||||
label={t('parameters:noiseThreshold')}
|
||||
<IAISlider
|
||||
label={t('parameters.noiseThreshold')}
|
||||
min={0}
|
||||
max={1000}
|
||||
step={0.1}
|
||||
onChange={handleChangeThreshold}
|
||||
max={1}
|
||||
step={0.005}
|
||||
onChange={(v) => dispatch(setThreshold(v))}
|
||||
handleReset={() => dispatch(setThreshold(0))}
|
||||
value={threshold}
|
||||
isInteger={false}
|
||||
withInput
|
||||
withReset
|
||||
withSliderMarks
|
||||
inputWidth="6rem"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
import { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setUpscalingDenoising } from 'features/parameters/store/postprocessingSlice';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function UpscaleDenoisingStrength() {
|
||||
const isESRGANAvailable = useAppSelector(
|
||||
(state: RootState) => state.system.isESRGANAvailable
|
||||
);
|
||||
|
||||
const upscalingDenoising = useAppSelector(
|
||||
(state: RootState) => state.postprocessing.upscalingDenoising
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
return (
|
||||
<IAISlider
|
||||
label={t('parameters.denoisingStrength')}
|
||||
value={upscalingDenoising}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
onChange={(v) => {
|
||||
dispatch(setUpscalingDenoising(v));
|
||||
}}
|
||||
handleReset={() => dispatch(setUpscalingDenoising(0.75))}
|
||||
withSliderMarks
|
||||
withInput
|
||||
withReset
|
||||
isSliderDisabled={!isESRGANAvailable}
|
||||
isInputDisabled={!isESRGANAvailable}
|
||||
isResetDisabled={!isESRGANAvailable}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { UPSCALING_LEVELS } from 'app/constants';
|
||||
import type { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISelect from 'common/components/IAISelect';
|
||||
import {
|
||||
setUpscalingLevel,
|
||||
type UpscalingLevel,
|
||||
} from 'features/parameters/store/postprocessingSlice';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function UpscaleScale() {
|
||||
const isESRGANAvailable = useAppSelector(
|
||||
(state: RootState) => state.system.isESRGANAvailable
|
||||
);
|
||||
|
||||
const upscalingLevel = useAppSelector(
|
||||
(state: RootState) => state.postprocessing.upscalingLevel
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleChangeLevel = (e: ChangeEvent<HTMLSelectElement>) =>
|
||||
dispatch(setUpscalingLevel(Number(e.target.value) as UpscalingLevel));
|
||||
|
||||
return (
|
||||
<IAISelect
|
||||
isDisabled={!isESRGANAvailable}
|
||||
label={t('parameters.scale')}
|
||||
value={upscalingLevel}
|
||||
onChange={handleChangeLevel}
|
||||
validValues={UPSCALING_LEVELS}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,104 +1,17 @@
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
|
||||
import {
|
||||
setUpscalingDenoising,
|
||||
setUpscalingLevel,
|
||||
setUpscalingStrength,
|
||||
UpscalingLevel,
|
||||
} from 'features/parameters/store/postprocessingSlice';
|
||||
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { UPSCALING_LEVELS } from 'app/constants';
|
||||
import IAISelect from 'common/components/IAISelect';
|
||||
import { postprocessingSelector } from 'features/parameters/store/postprocessingSelectors';
|
||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||
import { isEqual } from 'lodash';
|
||||
import { ChangeEvent } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
|
||||
const parametersSelector = createSelector(
|
||||
[postprocessingSelector, systemSelector],
|
||||
|
||||
(
|
||||
{ upscalingLevel, upscalingStrength, upscalingDenoising },
|
||||
{ isESRGANAvailable }
|
||||
) => {
|
||||
return {
|
||||
upscalingLevel,
|
||||
upscalingDenoising,
|
||||
upscalingStrength,
|
||||
isESRGANAvailable,
|
||||
};
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: isEqual,
|
||||
},
|
||||
}
|
||||
);
|
||||
import UpscaleDenoisingStrength from './UpscaleDenoisingStrength';
|
||||
import UpscaleStrength from './UpscaleStrength';
|
||||
import UpscaleScale from './UpscaleScale';
|
||||
|
||||
/**
|
||||
* Displays upscaling/ESRGAN options (level and strength).
|
||||
*/
|
||||
const UpscaleSettings = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const {
|
||||
upscalingLevel,
|
||||
upscalingStrength,
|
||||
upscalingDenoising,
|
||||
isESRGANAvailable,
|
||||
} = useAppSelector(parametersSelector);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleChangeLevel = (e: ChangeEvent<HTMLSelectElement>) =>
|
||||
dispatch(setUpscalingLevel(Number(e.target.value) as UpscalingLevel));
|
||||
|
||||
const handleChangeStrength = (v: number) => dispatch(setUpscalingStrength(v));
|
||||
|
||||
return (
|
||||
<Flex flexDir="column" rowGap="1rem" minWidth="20rem">
|
||||
<IAISelect
|
||||
isDisabled={!isESRGANAvailable}
|
||||
label={t('parameters:scale')}
|
||||
value={upscalingLevel}
|
||||
onChange={handleChangeLevel}
|
||||
validValues={UPSCALING_LEVELS}
|
||||
/>
|
||||
<IAISlider
|
||||
label={t('parameters:denoisingStrength')}
|
||||
value={upscalingDenoising}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.01}
|
||||
onChange={(v) => {
|
||||
dispatch(setUpscalingDenoising(v));
|
||||
}}
|
||||
handleReset={() => dispatch(setUpscalingDenoising(0.75))}
|
||||
withSliderMarks
|
||||
withInput
|
||||
withReset
|
||||
isSliderDisabled={!isESRGANAvailable}
|
||||
isInputDisabled={!isESRGANAvailable}
|
||||
isResetDisabled={!isESRGANAvailable}
|
||||
/>
|
||||
<IAISlider
|
||||
label={`${t('parameters:upscale')} ${t('parameters:strength')}`}
|
||||
value={upscalingStrength}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.05}
|
||||
onChange={handleChangeStrength}
|
||||
handleReset={() => dispatch(setUpscalingStrength(0.75))}
|
||||
withSliderMarks
|
||||
withInput
|
||||
withReset
|
||||
isSliderDisabled={!isESRGANAvailable}
|
||||
isInputDisabled={!isESRGANAvailable}
|
||||
isResetDisabled={!isESRGANAvailable}
|
||||
/>
|
||||
<Flex flexDir="column" rowGap={2} minWidth="20rem">
|
||||
<UpscaleScale />
|
||||
<UpscaleDenoisingStrength />
|
||||
<UpscaleStrength />
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
import type { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setUpscalingStrength } from 'features/parameters/store/postprocessingSlice';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function UpscaleStrength() {
|
||||
const isESRGANAvailable = useAppSelector(
|
||||
(state: RootState) => state.system.isESRGANAvailable
|
||||
);
|
||||
const upscalingStrength = useAppSelector(
|
||||
(state: RootState) => state.postprocessing.upscalingStrength
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
return (
|
||||
<IAISlider
|
||||
label={`${t('parameters.upscale')} ${t('parameters.strength')}`}
|
||||
value={upscalingStrength}
|
||||
min={0}
|
||||
max={1}
|
||||
step={0.05}
|
||||
onChange={(v) => dispatch(setUpscalingStrength(v))}
|
||||
handleReset={() => dispatch(setUpscalingStrength(0.75))}
|
||||
withSliderMarks
|
||||
withInput
|
||||
withReset
|
||||
isSliderDisabled={!isESRGANAvailable}
|
||||
isInputDisabled={!isESRGANAvailable}
|
||||
isResetDisabled={!isESRGANAvailable}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -18,7 +18,7 @@ export default function GenerateVariationsToggle() {
|
||||
return (
|
||||
<IAISwitch
|
||||
isChecked={shouldGenerateVariations}
|
||||
width={'auto'}
|
||||
width="auto"
|
||||
onChange={handleChangeShouldGenerateVariations}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -24,7 +24,7 @@ export default function SeedWeights() {
|
||||
|
||||
return (
|
||||
<IAIInput
|
||||
label={t('parameters:seedWeights')}
|
||||
label={t('parameters.seedWeights')}
|
||||
value={seedWeights}
|
||||
isInvalid={
|
||||
shouldGenerateVariations &&
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAINumberInput from 'common/components/IAINumberInput';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setVariationAmount } from 'features/parameters/store/generationSlice';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -16,19 +16,22 @@ export default function VariationAmount() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const handleChangevariationAmount = (v: number) =>
|
||||
dispatch(setVariationAmount(v));
|
||||
|
||||
return (
|
||||
<IAINumberInput
|
||||
label={t('parameters:variationAmount')}
|
||||
<IAISlider
|
||||
label={t('parameters.variationAmount')}
|
||||
value={variationAmount}
|
||||
step={0.01}
|
||||
min={0}
|
||||
max={1}
|
||||
isDisabled={!shouldGenerateVariations}
|
||||
onChange={handleChangevariationAmount}
|
||||
isInteger={false}
|
||||
isSliderDisabled={!shouldGenerateVariations}
|
||||
isInputDisabled={!shouldGenerateVariations}
|
||||
isResetDisabled={!shouldGenerateVariations}
|
||||
onChange={(v) => dispatch(setVariationAmount(v))}
|
||||
handleReset={() => dispatch(setVariationAmount(0.1))}
|
||||
withInput
|
||||
withReset
|
||||
withSliderMarks
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import VariationAmount from './VariationAmount';
|
||||
*/
|
||||
const VariationsSettings = () => {
|
||||
return (
|
||||
<Flex gap={2} direction={'column'}>
|
||||
<Flex gap={2} direction="column">
|
||||
<VariationAmount />
|
||||
<SeedWeights />
|
||||
</Flex>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAINumberInput from 'common/components/IAINumberInput';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setCfgScale } from 'features/parameters/store/generationSlice';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -9,13 +10,31 @@ export default function MainCFGScale() {
|
||||
const cfgScale = useAppSelector(
|
||||
(state: RootState) => state.generation.cfgScale
|
||||
);
|
||||
const shouldUseSliders = useAppSelector(
|
||||
(state: RootState) => state.ui.shouldUseSliders
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleChangeCfgScale = (v: number) => dispatch(setCfgScale(v));
|
||||
|
||||
return (
|
||||
return shouldUseSliders ? (
|
||||
<IAISlider
|
||||
label={t('parameters.cfgScale')}
|
||||
step={0.5}
|
||||
min={1.01}
|
||||
max={30}
|
||||
onChange={handleChangeCfgScale}
|
||||
handleReset={() => dispatch(setCfgScale(7.5))}
|
||||
value={cfgScale}
|
||||
sliderMarkRightOffset={-5}
|
||||
sliderNumberInputProps={{ max: 200 }}
|
||||
withInput
|
||||
withReset
|
||||
withSliderMarks
|
||||
/>
|
||||
) : (
|
||||
<IAINumberInput
|
||||
label={t('parameters:cfgScale')}
|
||||
label={t('parameters.cfgScale')}
|
||||
step={0.5}
|
||||
min={1.01}
|
||||
max={200}
|
||||
|
||||
@@ -2,29 +2,50 @@ import { HEIGHTS } from 'app/constants';
|
||||
import { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISelect from 'common/components/IAISelect';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setHeight } from 'features/parameters/store/generationSlice';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import { ChangeEvent } from 'react';
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function MainHeight() {
|
||||
const height = useAppSelector((state: RootState) => state.generation.height);
|
||||
const shouldUseSliders = useAppSelector(
|
||||
(state: RootState) => state.ui.shouldUseSliders
|
||||
);
|
||||
const activeTabName = useAppSelector(activeTabNameSelector);
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleChangeHeight = (e: ChangeEvent<HTMLSelectElement>) =>
|
||||
dispatch(setHeight(Number(e.target.value)));
|
||||
|
||||
return (
|
||||
return shouldUseSliders ? (
|
||||
<IAISlider
|
||||
isSliderDisabled={activeTabName === 'unifiedCanvas'}
|
||||
isInputDisabled={activeTabName === 'unifiedCanvas'}
|
||||
isResetDisabled={activeTabName === 'unifiedCanvas'}
|
||||
label={t('parameters.height')}
|
||||
value={height}
|
||||
min={64}
|
||||
step={64}
|
||||
max={2048}
|
||||
onChange={(v) => dispatch(setHeight(v))}
|
||||
handleReset={() => dispatch(setHeight(512))}
|
||||
withInput
|
||||
withReset
|
||||
withSliderMarks
|
||||
sliderMarkRightOffset={-8}
|
||||
inputWidth="6.2rem"
|
||||
sliderNumberInputProps={{ max: 15360 }}
|
||||
/>
|
||||
) : (
|
||||
<IAISelect
|
||||
isDisabled={activeTabName === 'unifiedCanvas'}
|
||||
label={t('parameters:height')}
|
||||
label={t('parameters.height')}
|
||||
value={height}
|
||||
flexGrow={1}
|
||||
onChange={handleChangeHeight}
|
||||
onChange={(e) => dispatch(setHeight(Number(e.target.value)))}
|
||||
validValues={HEIGHTS}
|
||||
styleClass="main-settings-block"
|
||||
width="5.5rem"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,41 +1,43 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import type { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAINumberInput from 'common/components/IAINumberInput';
|
||||
import {
|
||||
GenerationState,
|
||||
setIterations,
|
||||
} from 'features/parameters/store/generationSlice';
|
||||
import { isEqual } from 'lodash';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setIterations } from 'features/parameters/store/generationSlice';
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const mainIterationsSelector = createSelector(
|
||||
[(state: RootState) => state.generation],
|
||||
(parameters: GenerationState) => {
|
||||
const { iterations } = parameters;
|
||||
|
||||
return {
|
||||
iterations,
|
||||
};
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: isEqual,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export default function MainIterations() {
|
||||
const iterations = useAppSelector(
|
||||
(state: RootState) => state.generation.iterations
|
||||
);
|
||||
|
||||
const shouldUseSliders = useAppSelector(
|
||||
(state: RootState) => state.ui.shouldUseSliders
|
||||
);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const { iterations } = useAppSelector(mainIterationsSelector);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleChangeIterations = (v: number) => dispatch(setIterations(v));
|
||||
|
||||
return (
|
||||
return shouldUseSliders ? (
|
||||
<IAISlider
|
||||
label={t('parameters.images')}
|
||||
step={1}
|
||||
min={1}
|
||||
max={16}
|
||||
onChange={handleChangeIterations}
|
||||
handleReset={() => dispatch(setIterations(1))}
|
||||
value={iterations}
|
||||
withInput
|
||||
withReset
|
||||
withSliderMarks
|
||||
sliderMarkRightOffset={-5}
|
||||
sliderNumberInputProps={{ max: 9999 }}
|
||||
/>
|
||||
) : (
|
||||
<IAINumberInput
|
||||
label={t('parameters:images')}
|
||||
label={t('parameters.images')}
|
||||
step={1}
|
||||
min={1}
|
||||
max={9999}
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { type RootState } from 'app/store';
|
||||
import { useAppSelector } from 'app/storeHooks';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import ParametersAccordion from '../ParametersAccordion';
|
||||
import MainCFGScale from './MainCFGScale';
|
||||
import MainHeight from './MainHeight';
|
||||
import MainIterations from './MainIterations';
|
||||
@@ -8,20 +13,40 @@ import MainWidth from './MainWidth';
|
||||
export const inputWidth = 'auto';
|
||||
|
||||
export default function MainSettings() {
|
||||
return (
|
||||
<div className="main-settings">
|
||||
<div className="main-settings-list">
|
||||
<div className="main-settings-row">
|
||||
const { t } = useTranslation();
|
||||
|
||||
const shouldUseSliders = useAppSelector(
|
||||
(state: RootState) => state.ui.shouldUseSliders
|
||||
);
|
||||
|
||||
const accordionItems = {
|
||||
main: {
|
||||
header: `${t('parameters.general')}`,
|
||||
feature: undefined,
|
||||
content: shouldUseSliders ? (
|
||||
<Flex flexDir="column" rowGap={2}>
|
||||
<MainIterations />
|
||||
<MainSteps />
|
||||
<MainCFGScale />
|
||||
</div>
|
||||
<div className="main-settings-row">
|
||||
<MainWidth />
|
||||
<MainHeight />
|
||||
<MainSampler />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
</Flex>
|
||||
) : (
|
||||
<Flex flexDirection="column" rowGap={2}>
|
||||
<Flex gap={2}>
|
||||
<MainIterations />
|
||||
<MainSteps />
|
||||
<MainCFGScale />
|
||||
</Flex>
|
||||
<Flex>
|
||||
<MainWidth />
|
||||
<MainHeight />
|
||||
<MainSampler />
|
||||
</Flex>
|
||||
</Flex>
|
||||
),
|
||||
},
|
||||
};
|
||||
return <ParametersAccordion accordionInfo={accordionItems} />;
|
||||
}
|
||||
|
||||
@@ -20,13 +20,14 @@ export default function MainSampler() {
|
||||
|
||||
return (
|
||||
<IAISelect
|
||||
label={t('parameters:sampler')}
|
||||
label={t('parameters.sampler')}
|
||||
value={sampler}
|
||||
onChange={handleChangeSampler}
|
||||
validValues={
|
||||
activeModel.format === 'diffusers' ? DIFFUSERS_SAMPLERS : SAMPLERS
|
||||
}
|
||||
styleClass="main-settings-block"
|
||||
minWidth="9rem"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,19 +1,38 @@
|
||||
import { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAINumberInput from 'common/components/IAINumberInput';
|
||||
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setSteps } from 'features/parameters/store/generationSlice';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function MainSteps() {
|
||||
const dispatch = useAppDispatch();
|
||||
const steps = useAppSelector((state: RootState) => state.generation.steps);
|
||||
const shouldUseSliders = useAppSelector(
|
||||
(state: RootState) => state.ui.shouldUseSliders
|
||||
);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const handleChangeSteps = (v: number) => dispatch(setSteps(v));
|
||||
|
||||
return (
|
||||
return shouldUseSliders ? (
|
||||
<IAISlider
|
||||
label={t('parameters.steps')}
|
||||
min={1}
|
||||
step={1}
|
||||
onChange={handleChangeSteps}
|
||||
handleReset={() => dispatch(setSteps(20))}
|
||||
value={steps}
|
||||
withInput
|
||||
withReset
|
||||
withSliderMarks
|
||||
sliderMarkRightOffset={-6}
|
||||
sliderNumberInputProps={{ max: 9999 }}
|
||||
/>
|
||||
) : (
|
||||
<IAINumberInput
|
||||
label={t('parameters:steps')}
|
||||
label={t('parameters.steps')}
|
||||
min={1}
|
||||
max={9999}
|
||||
step={1}
|
||||
|
||||
@@ -2,30 +2,51 @@ import { WIDTHS } from 'app/constants';
|
||||
import { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAISelect from 'common/components/IAISelect';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import { setWidth } from 'features/parameters/store/generationSlice';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import { ChangeEvent } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function MainWidth() {
|
||||
const width = useAppSelector((state: RootState) => state.generation.width);
|
||||
const shouldUseSliders = useAppSelector(
|
||||
(state: RootState) => state.ui.shouldUseSliders
|
||||
);
|
||||
const activeTabName = useAppSelector(activeTabNameSelector);
|
||||
const { t } = useTranslation();
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const handleChangeWidth = (e: ChangeEvent<HTMLSelectElement>) =>
|
||||
dispatch(setWidth(Number(e.target.value)));
|
||||
|
||||
return (
|
||||
return shouldUseSliders ? (
|
||||
<IAISlider
|
||||
isSliderDisabled={activeTabName === 'unifiedCanvas'}
|
||||
isInputDisabled={activeTabName === 'unifiedCanvas'}
|
||||
isResetDisabled={activeTabName === 'unifiedCanvas'}
|
||||
label={t('parameters.width')}
|
||||
value={width}
|
||||
min={64}
|
||||
step={64}
|
||||
max={2048}
|
||||
onChange={(v) => dispatch(setWidth(v))}
|
||||
handleReset={() => dispatch(setWidth(512))}
|
||||
withInput
|
||||
withReset
|
||||
withSliderMarks
|
||||
sliderMarkRightOffset={-8}
|
||||
inputWidth="6.2rem"
|
||||
inputReadOnly
|
||||
sliderNumberInputProps={{ max: 15360 }}
|
||||
/>
|
||||
) : (
|
||||
<IAISelect
|
||||
isDisabled={activeTabName === 'unifiedCanvas'}
|
||||
label={t('parameters:width')}
|
||||
label={t('parameters.width')}
|
||||
value={width}
|
||||
flexGrow={1}
|
||||
onChange={handleChangeWidth}
|
||||
onChange={(e) => dispatch(setWidth(Number(e.target.value)))}
|
||||
validValues={WIDTHS}
|
||||
styleClass="main-settings-block"
|
||||
width="5.5rem"
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -44,19 +44,19 @@ export default function InvokeButton(props: InvokeButton) {
|
||||
<div style={{ flexGrow: 4 }}>
|
||||
{iconButton ? (
|
||||
<IAIIconButton
|
||||
aria-label={t('parameters:invoke')}
|
||||
aria-label={t('parameters.invoke')}
|
||||
type="submit"
|
||||
icon={<FaPlay />}
|
||||
isDisabled={!isReady}
|
||||
onClick={handleClickGenerate}
|
||||
className="invoke-btn"
|
||||
tooltip={t('parameters:invoke')}
|
||||
tooltip={t('parameters.invoke')}
|
||||
tooltipProps={{ placement: 'bottom' }}
|
||||
{...rest}
|
||||
/>
|
||||
) : (
|
||||
<IAIButton
|
||||
aria-label={t('parameters:invoke')}
|
||||
aria-label={t('parameters.invoke')}
|
||||
type="submit"
|
||||
isDisabled={!isReady}
|
||||
onClick={handleClickGenerate}
|
||||
|
||||
@@ -19,8 +19,8 @@ const LoopbackButton = () => {
|
||||
|
||||
return (
|
||||
<IAIIconButton
|
||||
aria-label={t('parameters:toggleLoopback')}
|
||||
tooltip={t('parameters:toggleLoopback')}
|
||||
aria-label={t('parameters.toggleLoopback')}
|
||||
tooltip={t('parameters.toggleLoopback')}
|
||||
styleClass="loopback-btn"
|
||||
asCheckbox={true}
|
||||
isChecked={shouldLoopback}
|
||||
|
||||
@@ -20,7 +20,7 @@ const NegativePromptInput = () => {
|
||||
value={negativePrompt}
|
||||
onChange={(e) => dispatch(setNegativePrompt(e.target.value))}
|
||||
background="var(--prompt-bg-color)"
|
||||
placeholder={t('parameters:negativePrompts')}
|
||||
placeholder={t('parameters.negativePrompts')}
|
||||
_placeholder={{ fontSize: '0.8rem' }}
|
||||
borderColor="var(--border-color)"
|
||||
_hover={{
|
||||
|
||||
@@ -70,8 +70,8 @@ const PromptInput = () => {
|
||||
<Textarea
|
||||
id="prompt"
|
||||
name="prompt"
|
||||
placeholder={t('parameters:promptPlaceholder')}
|
||||
size={'lg'}
|
||||
placeholder={t('parameters.promptPlaceholder')}
|
||||
size="lg"
|
||||
value={prompt}
|
||||
onChange={handleChangePrompt}
|
||||
onKeyDown={handleKeyDown}
|
||||
|
||||
@@ -22,7 +22,7 @@ export interface PostprocessingState {
|
||||
|
||||
const initialPostprocessingState: PostprocessingState = {
|
||||
codeformerFidelity: 0.75,
|
||||
facetoolStrength: 0.8,
|
||||
facetoolStrength: 0.75,
|
||||
facetoolType: 'gfpgan',
|
||||
hiresFix: false,
|
||||
hiresStrength: 0.75,
|
||||
|
||||
@@ -23,18 +23,18 @@ const EmptyTempFolderButtonModal = () => {
|
||||
|
||||
return (
|
||||
<IAIAlertDialog
|
||||
title={t('unifiedcanvas:emptyTempImageFolder')}
|
||||
title={t('unifiedCanvas.emptyTempImageFolder')}
|
||||
acceptCallback={acceptCallback}
|
||||
acceptButtonText={t('unifiedcanvas:emptyFolder')}
|
||||
acceptButtonText={t('unifiedCanvas.emptyFolder')}
|
||||
triggerComponent={
|
||||
<IAIButton leftIcon={<FaTrash />} size={'sm'} isDisabled={isStaging}>
|
||||
{t('unifiedcanvas:emptyTempImageFolder')}
|
||||
<IAIButton leftIcon={<FaTrash />} size="sm" isDisabled={isStaging}>
|
||||
{t('unifiedCanvas.emptyTempImageFolder')}
|
||||
</IAIButton>
|
||||
}
|
||||
>
|
||||
<p>{t('unifiedcanvas:emptyTempImagesFolderMessage')}</p>
|
||||
<p>{t('unifiedCanvas.emptyTempImagesFolderMessage')}</p>
|
||||
<br />
|
||||
<p>{t('unifiedcanvas:emptyTempImagesFolderConfirm')}</p>
|
||||
<p>{t('unifiedCanvas.emptyTempImagesFolderConfirm')}</p>
|
||||
</IAIAlertDialog>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -109,7 +109,7 @@ const Console = () => {
|
||||
bottom: 0,
|
||||
zIndex: 9999,
|
||||
}}
|
||||
maxHeight={'90vh'}
|
||||
maxHeight="90vh"
|
||||
>
|
||||
<div className="console" ref={viewerRef} onScroll={handleOnScroll}>
|
||||
{log.map((entry, i) => {
|
||||
@@ -130,11 +130,11 @@ const Console = () => {
|
||||
label={shouldAutoscroll ? 'Autoscroll On' : 'Autoscroll Off'}
|
||||
>
|
||||
<IconButton
|
||||
className={'console-autoscroll-icon-button'}
|
||||
className="console-autoscroll-icon-button"
|
||||
data-autoscroll-enabled={shouldAutoscroll}
|
||||
size="sm"
|
||||
aria-label="Toggle autoscroll"
|
||||
variant={'solid'}
|
||||
variant="solid"
|
||||
icon={<FaAngleDoubleDown />}
|
||||
onClick={() => setShouldAutoscroll(!shouldAutoscroll)}
|
||||
/>
|
||||
@@ -145,11 +145,11 @@ const Console = () => {
|
||||
label={shouldShowLogViewer ? 'Hide Console' : 'Show Console'}
|
||||
>
|
||||
<IconButton
|
||||
className={'console-toggle-icon-button'}
|
||||
className="console-toggle-icon-button"
|
||||
data-error-seen={hasError || !wasErrorSeen}
|
||||
size="sm"
|
||||
position={'fixed'}
|
||||
variant={'solid'}
|
||||
position="fixed"
|
||||
variant="solid"
|
||||
aria-label="Toggle Log Viewer"
|
||||
icon={shouldShowLogViewer ? <FaMinus /> : <FaCode />}
|
||||
onClick={handleClickLogViewerToggle}
|
||||
|
||||
@@ -36,263 +36,263 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
|
||||
|
||||
const appHotkeys = [
|
||||
{
|
||||
title: t('hotkeys:invoke.title'),
|
||||
desc: t('hotkeys:invoke.desc'),
|
||||
title: t('hotkeys.invoke.title'),
|
||||
desc: t('hotkeys.invoke.desc'),
|
||||
hotkey: 'Ctrl+Enter',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:cancel.title'),
|
||||
desc: t('hotkeys:cancel.desc'),
|
||||
title: t('hotkeys.cancel.title'),
|
||||
desc: t('hotkeys.cancel.desc'),
|
||||
hotkey: 'Shift+X',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:focusPrompt.title'),
|
||||
desc: t('hotkeys:focusPrompt.desc'),
|
||||
title: t('hotkeys.focusPrompt.title'),
|
||||
desc: t('hotkeys.focusPrompt.desc'),
|
||||
hotkey: 'Alt+A',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:toggleOptions.title'),
|
||||
desc: t('hotkeys:toggleOptions.desc'),
|
||||
title: t('hotkeys.toggleOptions.title'),
|
||||
desc: t('hotkeys.toggleOptions.desc'),
|
||||
hotkey: 'O',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:pinOptions.title'),
|
||||
desc: t('hotkeys:pinOptions.desc'),
|
||||
title: t('hotkeys.pinOptions.title'),
|
||||
desc: t('hotkeys.pinOptions.desc'),
|
||||
hotkey: 'Shift+O',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:toggleViewer.title'),
|
||||
desc: t('hotkeys:toggleViewer.desc'),
|
||||
title: t('hotkeys.toggleViewer.title'),
|
||||
desc: t('hotkeys.toggleViewer.desc'),
|
||||
hotkey: 'Z',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:toggleGallery.title'),
|
||||
desc: t('hotkeys:toggleGallery.desc'),
|
||||
title: t('hotkeys.toggleGallery.title'),
|
||||
desc: t('hotkeys.toggleGallery.desc'),
|
||||
hotkey: 'G',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:maximizeWorkSpace.title'),
|
||||
desc: t('hotkeys:maximizeWorkSpace.desc'),
|
||||
title: t('hotkeys.maximizeWorkSpace.title'),
|
||||
desc: t('hotkeys.maximizeWorkSpace.desc'),
|
||||
hotkey: 'F',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:changeTabs.title'),
|
||||
desc: t('hotkeys:changeTabs.desc'),
|
||||
title: t('hotkeys.changeTabs.title'),
|
||||
desc: t('hotkeys.changeTabs.desc'),
|
||||
hotkey: '1-5',
|
||||
},
|
||||
|
||||
{
|
||||
title: t('hotkeys:consoleToggle.title'),
|
||||
desc: t('hotkeys:consoleToggle.desc'),
|
||||
title: t('hotkeys.consoleToggle.title'),
|
||||
desc: t('hotkeys.consoleToggle.desc'),
|
||||
hotkey: '`',
|
||||
},
|
||||
];
|
||||
|
||||
const generalHotkeys = [
|
||||
{
|
||||
title: t('hotkeys:setPrompt.title'),
|
||||
desc: t('hotkeys:setPrompt.desc'),
|
||||
title: t('hotkeys.setPrompt.title'),
|
||||
desc: t('hotkeys.setPrompt.desc'),
|
||||
hotkey: 'P',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:setSeed.title'),
|
||||
desc: t('hotkeys:setSeed.desc'),
|
||||
title: t('hotkeys.setSeed.title'),
|
||||
desc: t('hotkeys.setSeed.desc'),
|
||||
hotkey: 'S',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:setParameters.title'),
|
||||
desc: t('hotkeys:setParameters.desc'),
|
||||
title: t('hotkeys.setParameters.title'),
|
||||
desc: t('hotkeys.setParameters.desc'),
|
||||
hotkey: 'A',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:restoreFaces.title'),
|
||||
desc: t('hotkeys:restoreFaces.desc'),
|
||||
title: t('hotkeys.restoreFaces.title'),
|
||||
desc: t('hotkeys.restoreFaces.desc'),
|
||||
hotkey: 'Shift+R',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:upscale.title'),
|
||||
desc: t('hotkeys:upscale.desc'),
|
||||
title: t('hotkeys.upscale.title'),
|
||||
desc: t('hotkeys.upscale.desc'),
|
||||
hotkey: 'Shift+U',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:showInfo.title'),
|
||||
desc: t('hotkeys:showInfo.desc'),
|
||||
title: t('hotkeys.showInfo.title'),
|
||||
desc: t('hotkeys.showInfo.desc'),
|
||||
hotkey: 'I',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:sendToImageToImage.title'),
|
||||
desc: t('hotkeys:sendToImageToImage.desc'),
|
||||
title: t('hotkeys.sendToImageToImage.title'),
|
||||
desc: t('hotkeys.sendToImageToImage.desc'),
|
||||
hotkey: 'Shift+I',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:deleteImage.title'),
|
||||
desc: t('hotkeys:deleteImage.desc'),
|
||||
title: t('hotkeys.deleteImage.title'),
|
||||
desc: t('hotkeys.deleteImage.desc'),
|
||||
hotkey: 'Del',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:closePanels.title'),
|
||||
desc: t('hotkeys:closePanels.desc'),
|
||||
title: t('hotkeys.closePanels.title'),
|
||||
desc: t('hotkeys.closePanels.desc'),
|
||||
hotkey: 'Esc',
|
||||
},
|
||||
];
|
||||
|
||||
const galleryHotkeys = [
|
||||
{
|
||||
title: t('hotkeys:previousImage.title'),
|
||||
desc: t('hotkeys:previousImage.desc'),
|
||||
title: t('hotkeys.previousImage.title'),
|
||||
desc: t('hotkeys.previousImage.desc'),
|
||||
hotkey: 'Arrow Left',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:nextImage.title'),
|
||||
desc: t('hotkeys:nextImage.desc'),
|
||||
title: t('hotkeys.nextImage.title'),
|
||||
desc: t('hotkeys.nextImage.desc'),
|
||||
hotkey: 'Arrow Right',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:toggleGalleryPin.title'),
|
||||
desc: t('hotkeys:toggleGalleryPin.desc'),
|
||||
title: t('hotkeys.toggleGalleryPin.title'),
|
||||
desc: t('hotkeys.toggleGalleryPin.desc'),
|
||||
hotkey: 'Shift+G',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:increaseGalleryThumbSize.title'),
|
||||
desc: t('hotkeys:increaseGalleryThumbSize.desc'),
|
||||
title: t('hotkeys.increaseGalleryThumbSize.title'),
|
||||
desc: t('hotkeys.increaseGalleryThumbSize.desc'),
|
||||
hotkey: 'Shift+Up',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:decreaseGalleryThumbSize.title'),
|
||||
desc: t('hotkeys:decreaseGalleryThumbSize.desc'),
|
||||
title: t('hotkeys.decreaseGalleryThumbSize.title'),
|
||||
desc: t('hotkeys.decreaseGalleryThumbSize.desc'),
|
||||
hotkey: 'Shift+Down',
|
||||
},
|
||||
];
|
||||
|
||||
const unifiedCanvasHotkeys = [
|
||||
{
|
||||
title: t('hotkeys:selectBrush.title'),
|
||||
desc: t('hotkeys:selectBrush.desc'),
|
||||
title: t('hotkeys.selectBrush.title'),
|
||||
desc: t('hotkeys.selectBrush.desc'),
|
||||
hotkey: 'B',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:selectEraser.title'),
|
||||
desc: t('hotkeys:selectEraser.desc'),
|
||||
title: t('hotkeys.selectEraser.title'),
|
||||
desc: t('hotkeys.selectEraser.desc'),
|
||||
hotkey: 'E',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:decreaseBrushSize.title'),
|
||||
desc: t('hotkeys:decreaseBrushSize.desc'),
|
||||
title: t('hotkeys.decreaseBrushSize.title'),
|
||||
desc: t('hotkeys.decreaseBrushSize.desc'),
|
||||
hotkey: '[',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:increaseBrushSize.title'),
|
||||
desc: t('hotkeys:increaseBrushSize.desc'),
|
||||
title: t('hotkeys.increaseBrushSize.title'),
|
||||
desc: t('hotkeys.increaseBrushSize.desc'),
|
||||
hotkey: ']',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:decreaseBrushOpacity.title'),
|
||||
desc: t('hotkeys:decreaseBrushOpacity.desc'),
|
||||
title: t('hotkeys.decreaseBrushOpacity.title'),
|
||||
desc: t('hotkeys.decreaseBrushOpacity.desc'),
|
||||
hotkey: 'Shift + [',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:increaseBrushOpacity.title'),
|
||||
desc: t('hotkeys:increaseBrushOpacity.desc'),
|
||||
title: t('hotkeys.increaseBrushOpacity.title'),
|
||||
desc: t('hotkeys.increaseBrushOpacity.desc'),
|
||||
hotkey: 'Shift + ]',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:moveTool.title'),
|
||||
desc: t('hotkeys:moveTool.desc'),
|
||||
title: t('hotkeys.moveTool.title'),
|
||||
desc: t('hotkeys.moveTool.desc'),
|
||||
hotkey: 'V',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:fillBoundingBox.title'),
|
||||
desc: t('hotkeys:fillBoundingBox.desc'),
|
||||
title: t('hotkeys.fillBoundingBox.title'),
|
||||
desc: t('hotkeys.fillBoundingBox.desc'),
|
||||
hotkey: 'Shift + F',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:eraseBoundingBox.title'),
|
||||
desc: t('hotkeys:eraseBoundingBox.desc'),
|
||||
title: t('hotkeys.eraseBoundingBox.title'),
|
||||
desc: t('hotkeys.eraseBoundingBox.desc'),
|
||||
hotkey: 'Delete / Backspace',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:colorPicker.title'),
|
||||
desc: t('hotkeys:colorPicker.desc'),
|
||||
title: t('hotkeys.colorPicker.title'),
|
||||
desc: t('hotkeys.colorPicker.desc'),
|
||||
hotkey: 'C',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:toggleSnap.title'),
|
||||
desc: t('hotkeys:toggleSnap.desc'),
|
||||
title: t('hotkeys.toggleSnap.title'),
|
||||
desc: t('hotkeys.toggleSnap.desc'),
|
||||
hotkey: 'N',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:quickToggleMove.title'),
|
||||
desc: t('hotkeys:quickToggleMove.desc'),
|
||||
title: t('hotkeys.quickToggleMove.title'),
|
||||
desc: t('hotkeys.quickToggleMove.desc'),
|
||||
hotkey: 'Hold Space',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:toggleLayer.title'),
|
||||
desc: t('hotkeys:toggleLayer.desc'),
|
||||
title: t('hotkeys.toggleLayer.title'),
|
||||
desc: t('hotkeys.toggleLayer.desc'),
|
||||
hotkey: 'Q',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:clearMask.title'),
|
||||
desc: t('hotkeys:clearMask.desc'),
|
||||
title: t('hotkeys.clearMask.title'),
|
||||
desc: t('hotkeys.clearMask.desc'),
|
||||
hotkey: 'Shift+C',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:hideMask.title'),
|
||||
desc: t('hotkeys:hideMask.desc'),
|
||||
title: t('hotkeys.hideMask.title'),
|
||||
desc: t('hotkeys.hideMask.desc'),
|
||||
hotkey: 'H',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:showHideBoundingBox.title'),
|
||||
desc: t('hotkeys:showHideBoundingBox.desc'),
|
||||
title: t('hotkeys.showHideBoundingBox.title'),
|
||||
desc: t('hotkeys.showHideBoundingBox.desc'),
|
||||
hotkey: 'Shift+H',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:mergeVisible.title'),
|
||||
desc: t('hotkeys:mergeVisible.desc'),
|
||||
title: t('hotkeys.mergeVisible.title'),
|
||||
desc: t('hotkeys.mergeVisible.desc'),
|
||||
hotkey: 'Shift+M',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:saveToGallery.title'),
|
||||
desc: t('hotkeys:saveToGallery.desc'),
|
||||
title: t('hotkeys.saveToGallery.title'),
|
||||
desc: t('hotkeys.saveToGallery.desc'),
|
||||
hotkey: 'Shift+S',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:copyToClipboard.title'),
|
||||
desc: t('hotkeys:copyToClipboard.desc'),
|
||||
title: t('hotkeys.copyToClipboard.title'),
|
||||
desc: t('hotkeys.copyToClipboard.desc'),
|
||||
hotkey: 'Ctrl+C',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:downloadImage.title'),
|
||||
desc: t('hotkeys:downloadImage.desc'),
|
||||
title: t('hotkeys.downloadImage.title'),
|
||||
desc: t('hotkeys.downloadImage.desc'),
|
||||
hotkey: 'Shift+D',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:undoStroke.title'),
|
||||
desc: t('hotkeys:undoStroke.desc'),
|
||||
title: t('hotkeys.undoStroke.title'),
|
||||
desc: t('hotkeys.undoStroke.desc'),
|
||||
hotkey: 'Ctrl+Z',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:redoStroke.title'),
|
||||
desc: t('hotkeys:redoStroke.desc'),
|
||||
title: t('hotkeys.redoStroke.title'),
|
||||
desc: t('hotkeys.redoStroke.desc'),
|
||||
hotkey: 'Ctrl+Shift+Z, Ctrl+Y',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:resetView.title'),
|
||||
desc: t('hotkeys:resetView.desc'),
|
||||
title: t('hotkeys.resetView.title'),
|
||||
desc: t('hotkeys.resetView.desc'),
|
||||
hotkey: 'R',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:previousStagingImage.title'),
|
||||
desc: t('hotkeys:previousStagingImage.desc'),
|
||||
title: t('hotkeys.previousStagingImage.title'),
|
||||
desc: t('hotkeys.previousStagingImage.desc'),
|
||||
hotkey: 'Arrow Left',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:nextStagingImage.title'),
|
||||
desc: t('hotkeys:nextStagingImage.desc'),
|
||||
title: t('hotkeys.nextStagingImage.title'),
|
||||
desc: t('hotkeys.nextStagingImage.desc'),
|
||||
hotkey: 'Arrow Right',
|
||||
},
|
||||
{
|
||||
title: t('hotkeys:acceptStagingImage.title'),
|
||||
desc: t('hotkeys:acceptStagingImage.desc'),
|
||||
title: t('hotkeys.acceptStagingImage.title'),
|
||||
desc: t('hotkeys.acceptStagingImage.desc'),
|
||||
hotkey: 'Enter',
|
||||
},
|
||||
];
|
||||
@@ -331,7 +331,7 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
|
||||
<Accordion allowMultiple>
|
||||
<AccordionItem>
|
||||
<AccordionButton className="hotkeys-modal-button">
|
||||
<h2>{t('hotkeys:appHotkeys')}</h2>
|
||||
<h2>{t('hotkeys.appHotkeys')}</h2>
|
||||
<AccordionIcon />
|
||||
</AccordionButton>
|
||||
<AccordionPanel>
|
||||
@@ -341,7 +341,7 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
|
||||
|
||||
<AccordionItem>
|
||||
<AccordionButton className="hotkeys-modal-button">
|
||||
<h2>{t('hotkeys:generalHotkeys')}</h2>
|
||||
<h2>{t('hotkeys.generalHotkeys')}</h2>
|
||||
<AccordionIcon />
|
||||
</AccordionButton>
|
||||
<AccordionPanel>
|
||||
@@ -351,7 +351,7 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
|
||||
|
||||
<AccordionItem>
|
||||
<AccordionButton className="hotkeys-modal-button">
|
||||
<h2>{t('hotkeys:galleryHotkeys')}</h2>
|
||||
<h2>{t('hotkeys.galleryHotkeys')}</h2>
|
||||
<AccordionIcon />
|
||||
</AccordionButton>
|
||||
<AccordionPanel>
|
||||
@@ -361,7 +361,7 @@ export default function HotkeysModal({ children }: HotkeysModalProps) {
|
||||
|
||||
<AccordionItem>
|
||||
<AccordionButton className="hotkeys-modal-button">
|
||||
<h2>{t('hotkeys:unifiedCanvasHotkeys')}</h2>
|
||||
<h2>{t('hotkeys.unifiedCanvasHotkeys')}</h2>
|
||||
<AccordionIcon />
|
||||
</AccordionButton>
|
||||
<AccordionPanel>
|
||||
|
||||
@@ -9,20 +9,20 @@ import { FaLanguage } from 'react-icons/fa';
|
||||
|
||||
export default function LanguagePicker() {
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
const LANGUAGES = {
|
||||
en: t('common:langEnglish'),
|
||||
nl: t('common:langDutch'),
|
||||
fr: t('common:langFrench'),
|
||||
de: t('common:langGerman'),
|
||||
it: t('common:langItalian'),
|
||||
ja: t('common:langJapanese'),
|
||||
pl: t('common:langPolish'),
|
||||
pt_br: t('common:langBrPortuguese'),
|
||||
ru: t('common:langRussian'),
|
||||
zh_cn: t('common:langSimplifiedChinese'),
|
||||
es: t('common:langSpanish'),
|
||||
ua: t('common:langUkranian'),
|
||||
ar: t('common.langArabic', { lng: 'ar' }),
|
||||
nl: t('common.langDutch', { lng: 'nl' }),
|
||||
en: t('common.langEnglish', { lng: 'en' }),
|
||||
fr: t('common.langFrench', { lng: 'fr' }),
|
||||
de: t('common.langGerman', { lng: 'de' }),
|
||||
it: t('common.langItalian', { lng: 'it' }),
|
||||
ja: t('common.langJapanese', { lng: 'ja' }),
|
||||
pl: t('common.langPolish', { lng: 'pl' }),
|
||||
pt_Br: t('common.langBrPortuguese', { lng: 'pt_Br' }),
|
||||
ru: t('common.langRussian', { lng: 'ru' }),
|
||||
zh_Cn: t('common.langSimplifiedChinese', { lng: 'zh_Cn' }),
|
||||
es: t('common.langSpanish', { lng: 'es' }),
|
||||
uk: t('common.langUkranian', { lng: 'ua' }),
|
||||
};
|
||||
|
||||
const renderLanguagePicker = () => {
|
||||
@@ -35,7 +35,6 @@ export default function LanguagePicker() {
|
||||
onClick={() => i18n.changeLanguage(lang)}
|
||||
className="modal-close-btn lang-select-btn"
|
||||
aria-label={LANGUAGES[lang as keyof typeof LANGUAGES]}
|
||||
tooltip={LANGUAGES[lang as keyof typeof LANGUAGES]}
|
||||
size="sm"
|
||||
minWidth="200px"
|
||||
>
|
||||
@@ -52,10 +51,10 @@ export default function LanguagePicker() {
|
||||
trigger="hover"
|
||||
triggerComponent={
|
||||
<IAIIconButton
|
||||
aria-label={t('common:languagePickerLabel')}
|
||||
tooltip={t('common:languagePickerLabel')}
|
||||
aria-label={t('common.languagePickerLabel')}
|
||||
tooltip={t('common.languagePickerLabel')}
|
||||
icon={<FaLanguage />}
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
variant="link"
|
||||
data-variant="link"
|
||||
fontSize={26}
|
||||
|
||||
@@ -47,7 +47,7 @@ export default function AddCheckpointModel() {
|
||||
|
||||
function baseValidation(value: string) {
|
||||
let error;
|
||||
if (hasWhiteSpace(value)) error = t('modelmanager:cannotUseSpaces');
|
||||
if (hasWhiteSpace(value)) error = t('modelManager.cannotUseSpaces');
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -73,8 +73,8 @@ export default function AddCheckpointModel() {
|
||||
return (
|
||||
<>
|
||||
<IAIIconButton
|
||||
aria-label={t('common:back')}
|
||||
tooltip={t('common:back')}
|
||||
aria-label={t('common.back')}
|
||||
tooltip={t('common.back')}
|
||||
onClick={() => dispatch(setAddNewModelUIOption(null))}
|
||||
width="max-content"
|
||||
position="absolute"
|
||||
@@ -87,7 +87,7 @@ export default function AddCheckpointModel() {
|
||||
|
||||
<SearchModels />
|
||||
<IAICheckbox
|
||||
label={t('modelmanager:addManually')}
|
||||
label={t('modelManager.addManually')}
|
||||
isChecked={addManually}
|
||||
onChange={() => setAddmanually(!addManually)}
|
||||
/>
|
||||
@@ -99,9 +99,9 @@ export default function AddCheckpointModel() {
|
||||
>
|
||||
{({ handleSubmit, errors, touched }) => (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<VStack rowGap={'0.5rem'}>
|
||||
<Text fontSize={20} fontWeight="bold" alignSelf={'start'}>
|
||||
{t('modelmanager:manual')}
|
||||
<VStack rowGap="0.5rem">
|
||||
<Text fontSize={20} fontWeight="bold" alignSelf="start">
|
||||
{t('modelManager.manual')}
|
||||
</Text>
|
||||
{/* Name */}
|
||||
<FormControl
|
||||
@@ -109,9 +109,9 @@ export default function AddCheckpointModel() {
|
||||
isRequired
|
||||
>
|
||||
<FormLabel htmlFor="name" fontSize="sm">
|
||||
{t('modelmanager:name')}
|
||||
{t('modelManager.name')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="name"
|
||||
@@ -124,7 +124,7 @@ export default function AddCheckpointModel() {
|
||||
<FormErrorMessage>{errors.name}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:nameValidationMsg')}
|
||||
{t('modelManager.nameValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -136,9 +136,9 @@ export default function AddCheckpointModel() {
|
||||
isRequired
|
||||
>
|
||||
<FormLabel htmlFor="description" fontSize="sm">
|
||||
{t('modelmanager:description')}
|
||||
{t('modelManager.description')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="description"
|
||||
@@ -150,7 +150,7 @@ export default function AddCheckpointModel() {
|
||||
<FormErrorMessage>{errors.description}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:descriptionValidationMsg')}
|
||||
{t('modelManager.descriptionValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -162,9 +162,9 @@ export default function AddCheckpointModel() {
|
||||
isRequired
|
||||
>
|
||||
<FormLabel htmlFor="config" fontSize="sm">
|
||||
{t('modelmanager:config')}
|
||||
{t('modelManager.config')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="config"
|
||||
@@ -176,7 +176,7 @@ export default function AddCheckpointModel() {
|
||||
<FormErrorMessage>{errors.config}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:configValidationMsg')}
|
||||
{t('modelManager.configValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -188,9 +188,9 @@ export default function AddCheckpointModel() {
|
||||
isRequired
|
||||
>
|
||||
<FormLabel htmlFor="config" fontSize="sm">
|
||||
{t('modelmanager:modelLocation')}
|
||||
{t('modelManager.modelLocation')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="weights"
|
||||
@@ -202,7 +202,7 @@ export default function AddCheckpointModel() {
|
||||
<FormErrorMessage>{errors.weights}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:modelLocationValidationMsg')}
|
||||
{t('modelManager.modelLocationValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -211,9 +211,9 @@ export default function AddCheckpointModel() {
|
||||
{/* VAE */}
|
||||
<FormControl isInvalid={!!errors.vae && touched.vae}>
|
||||
<FormLabel htmlFor="vae" fontSize="sm">
|
||||
{t('modelmanager:vaeLocation')}
|
||||
{t('modelManager.vaeLocation')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="vae"
|
||||
@@ -225,19 +225,19 @@ export default function AddCheckpointModel() {
|
||||
<FormErrorMessage>{errors.vae}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:vaeLocationValidationMsg')}
|
||||
{t('modelManager.vaeLocationValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
</FormControl>
|
||||
|
||||
<HStack width={'100%'}>
|
||||
<HStack width="100%">
|
||||
{/* Width */}
|
||||
<FormControl isInvalid={!!errors.width && touched.width}>
|
||||
<FormLabel htmlFor="width" fontSize="sm">
|
||||
{t('modelmanager:width')}
|
||||
{t('modelManager.width')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field id="width" name="width">
|
||||
{({
|
||||
field,
|
||||
@@ -265,7 +265,7 @@ export default function AddCheckpointModel() {
|
||||
<FormErrorMessage>{errors.width}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:widthValidationMsg')}
|
||||
{t('modelManager.widthValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -274,9 +274,9 @@ export default function AddCheckpointModel() {
|
||||
{/* Height */}
|
||||
<FormControl isInvalid={!!errors.height && touched.height}>
|
||||
<FormLabel htmlFor="height" fontSize="sm">
|
||||
{t('modelmanager:height')}
|
||||
{t('modelManager.height')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field id="height" name="height">
|
||||
{({
|
||||
field,
|
||||
@@ -304,7 +304,7 @@ export default function AddCheckpointModel() {
|
||||
<FormErrorMessage>{errors.height}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:heightValidationMsg')}
|
||||
{t('modelManager.heightValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -316,7 +316,7 @@ export default function AddCheckpointModel() {
|
||||
className="modal-close-btn"
|
||||
isLoading={isProcessing}
|
||||
>
|
||||
{t('modelmanager:addModel')}
|
||||
{t('modelManager.addModel')}
|
||||
</IAIButton>
|
||||
</VStack>
|
||||
</form>
|
||||
|
||||
@@ -54,7 +54,7 @@ export default function AddDiffusersModel() {
|
||||
|
||||
function baseValidation(value: string) {
|
||||
let error;
|
||||
if (hasWhiteSpace(value)) error = t('modelmanager:cannotUseSpaces');
|
||||
if (hasWhiteSpace(value)) error = t('modelManager.cannotUseSpaces');
|
||||
return error;
|
||||
}
|
||||
|
||||
@@ -88,8 +88,8 @@ export default function AddDiffusersModel() {
|
||||
return (
|
||||
<Flex>
|
||||
<IAIIconButton
|
||||
aria-label={t('common:back')}
|
||||
tooltip={t('common:back')}
|
||||
aria-label={t('common.back')}
|
||||
tooltip={t('common.back')}
|
||||
onClick={() => dispatch(setAddNewModelUIOption(null))}
|
||||
width="max-content"
|
||||
position="absolute"
|
||||
@@ -105,7 +105,7 @@ export default function AddDiffusersModel() {
|
||||
>
|
||||
{({ handleSubmit, errors, touched }) => (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<VStack rowGap={'0.5rem'}>
|
||||
<VStack rowGap="0.5rem">
|
||||
<FormItemWrapper>
|
||||
{/* Name */}
|
||||
<FormControl
|
||||
@@ -113,9 +113,9 @@ export default function AddDiffusersModel() {
|
||||
isRequired
|
||||
>
|
||||
<FormLabel htmlFor="name" fontSize="sm">
|
||||
{t('modelmanager:name')}
|
||||
{t('modelManager.name')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="name"
|
||||
@@ -129,7 +129,7 @@ export default function AddDiffusersModel() {
|
||||
<FormErrorMessage>{errors.name}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:nameValidationMsg')}
|
||||
{t('modelManager.nameValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -143,9 +143,9 @@ export default function AddDiffusersModel() {
|
||||
isRequired
|
||||
>
|
||||
<FormLabel htmlFor="description" fontSize="sm">
|
||||
{t('modelmanager:description')}
|
||||
{t('modelManager.description')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="description"
|
||||
@@ -158,7 +158,7 @@ export default function AddDiffusersModel() {
|
||||
<FormErrorMessage>{errors.description}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:descriptionValidationMsg')}
|
||||
{t('modelManager.descriptionValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -167,22 +167,22 @@ export default function AddDiffusersModel() {
|
||||
|
||||
<FormItemWrapper>
|
||||
<Text fontWeight="bold" fontSize="sm">
|
||||
{t('modelmanager:formMessageDiffusersModelLocation')}
|
||||
{t('modelManager.formMessageDiffusersModelLocation')}
|
||||
</Text>
|
||||
<Text
|
||||
fontSize="sm"
|
||||
fontStyle="italic"
|
||||
color="var(--text-color-secondary)"
|
||||
>
|
||||
{t('modelmanager:formMessageDiffusersModelLocationDesc')}
|
||||
{t('modelManager.formMessageDiffusersModelLocationDesc')}
|
||||
</Text>
|
||||
|
||||
{/* Path */}
|
||||
<FormControl isInvalid={!!errors.path && touched.path}>
|
||||
<FormLabel htmlFor="path" fontSize="sm">
|
||||
{t('modelmanager:modelLocation')}
|
||||
{t('modelManager.modelLocation')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="path"
|
||||
@@ -194,7 +194,7 @@ export default function AddDiffusersModel() {
|
||||
<FormErrorMessage>{errors.path}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:modelLocationValidationMsg')}
|
||||
{t('modelManager.modelLocationValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -203,9 +203,9 @@ export default function AddDiffusersModel() {
|
||||
{/* Repo ID */}
|
||||
<FormControl isInvalid={!!errors.repo_id && touched.repo_id}>
|
||||
<FormLabel htmlFor="repo_id" fontSize="sm">
|
||||
{t('modelmanager:repo_id')}
|
||||
{t('modelManager.repo_id')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="repo_id"
|
||||
@@ -217,7 +217,7 @@ export default function AddDiffusersModel() {
|
||||
<FormErrorMessage>{errors.repo_id}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:repoIDValidationMsg')}
|
||||
{t('modelManager.repoIDValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -227,22 +227,22 @@ export default function AddDiffusersModel() {
|
||||
<FormItemWrapper>
|
||||
{/* VAE Path */}
|
||||
<Text fontWeight="bold">
|
||||
{t('modelmanager:formMessageDiffusersVAELocation')}
|
||||
{t('modelManager.formMessageDiffusersVAELocation')}
|
||||
</Text>
|
||||
<Text
|
||||
fontSize="sm"
|
||||
fontStyle="italic"
|
||||
color="var(--text-color-secondary)"
|
||||
>
|
||||
{t('modelmanager:formMessageDiffusersVAELocationDesc')}
|
||||
{t('modelManager.formMessageDiffusersVAELocationDesc')}
|
||||
</Text>
|
||||
<FormControl
|
||||
isInvalid={!!errors.vae?.path && touched.vae?.path}
|
||||
>
|
||||
<FormLabel htmlFor="vae.path" fontSize="sm">
|
||||
{t('modelmanager:vaeLocation')}
|
||||
{t('modelManager.vaeLocation')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="vae.path"
|
||||
@@ -254,7 +254,7 @@ export default function AddDiffusersModel() {
|
||||
<FormErrorMessage>{errors.vae?.path}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:vaeLocationValidationMsg')}
|
||||
{t('modelManager.vaeLocationValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -265,9 +265,9 @@ export default function AddDiffusersModel() {
|
||||
isInvalid={!!errors.vae?.repo_id && touched.vae?.repo_id}
|
||||
>
|
||||
<FormLabel htmlFor="vae.repo_id" fontSize="sm">
|
||||
{t('modelmanager:vaeRepoID')}
|
||||
{t('modelManager.vaeRepoID')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="vae.repo_id"
|
||||
@@ -279,7 +279,7 @@ export default function AddDiffusersModel() {
|
||||
<FormErrorMessage>{errors.vae?.repo_id}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:vaeRepoIDValidationMsg')}
|
||||
{t('modelManager.vaeRepoIDValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -291,7 +291,7 @@ export default function AddDiffusersModel() {
|
||||
className="modal-close-btn"
|
||||
isLoading={isProcessing}
|
||||
>
|
||||
{t('modelmanager:addModel')}
|
||||
{t('modelManager.addModel')}
|
||||
</IAIButton>
|
||||
</VStack>
|
||||
</form>
|
||||
|
||||
@@ -68,15 +68,15 @@ export default function AddModel() {
|
||||
return (
|
||||
<>
|
||||
<IAIButton
|
||||
aria-label={t('modelmanager:addNewModel')}
|
||||
tooltip={t('modelmanager:addNewModel')}
|
||||
aria-label={t('modelManager.addNewModel')}
|
||||
tooltip={t('modelManager.addNewModel')}
|
||||
onClick={onOpen}
|
||||
className="modal-close-btn"
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
>
|
||||
<Flex columnGap={'0.5rem'} alignItems="center">
|
||||
<Flex columnGap="0.5rem" alignItems="center">
|
||||
<FaPlus />
|
||||
{t('modelmanager:addNew')}
|
||||
{t('modelManager.addNew')}
|
||||
</Flex>
|
||||
</IAIButton>
|
||||
|
||||
@@ -87,18 +87,22 @@ export default function AddModel() {
|
||||
closeOnOverlayClick={false}
|
||||
>
|
||||
<ModalOverlay />
|
||||
<ModalContent className="modal add-model-modal" fontFamily="Inter">
|
||||
<ModalHeader>{t('modelmanager:addNewModel')}</ModalHeader>
|
||||
<ModalContent
|
||||
className="modal add-model-modal"
|
||||
fontFamily="Inter"
|
||||
margin="auto"
|
||||
>
|
||||
<ModalHeader>{t('modelManager.addNewModel')}</ModalHeader>
|
||||
<ModalCloseButton marginTop="0.3rem" />
|
||||
<ModalBody className="add-model-modal-body">
|
||||
{addNewModelUIOption == null && (
|
||||
<Flex columnGap="1rem">
|
||||
<AddModelBox
|
||||
text={t('modelmanager:addCheckpointModel')}
|
||||
text={t('modelManager.addCheckpointModel')}
|
||||
onClick={() => dispatch(setAddNewModelUIOption('ckpt'))}
|
||||
/>
|
||||
<AddModelBox
|
||||
text={t('modelmanager:addDiffuserModel')}
|
||||
text={t('modelManager.addDiffuserModel')}
|
||||
onClick={() => dispatch(setAddNewModelUIOption('diffusers'))}
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
@@ -27,6 +27,7 @@ import type { InvokeModelConfigProps } from 'app/invokeai';
|
||||
import type { RootState } from 'app/store';
|
||||
import type { FieldInputProps, FormikProps } from 'formik';
|
||||
import { isEqual, pickBy } from 'lodash';
|
||||
import ModelConvert from './ModelConvert';
|
||||
|
||||
const selector = createSelector(
|
||||
[systemSelector],
|
||||
@@ -101,10 +102,11 @@ export default function CheckpointModelEdit() {
|
||||
|
||||
return openModel ? (
|
||||
<Flex flexDirection="column" rowGap="1rem" width="100%">
|
||||
<Flex alignItems="center">
|
||||
<Flex alignItems="center" gap={4} justifyContent="space-between">
|
||||
<Text fontSize="lg" fontWeight="bold">
|
||||
{openModel}
|
||||
</Text>
|
||||
<ModelConvert model={openModel} />
|
||||
</Flex>
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
@@ -119,16 +121,16 @@ export default function CheckpointModelEdit() {
|
||||
>
|
||||
{({ handleSubmit, errors, touched }) => (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<VStack rowGap={'0.5rem'} alignItems="start">
|
||||
<VStack rowGap="0.5rem" alignItems="start">
|
||||
{/* Description */}
|
||||
<FormControl
|
||||
isInvalid={!!errors.description && touched.description}
|
||||
isRequired
|
||||
>
|
||||
<FormLabel htmlFor="description" fontSize="sm">
|
||||
{t('modelmanager:description')}
|
||||
{t('modelManager.description')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="description"
|
||||
@@ -140,7 +142,7 @@ export default function CheckpointModelEdit() {
|
||||
<FormErrorMessage>{errors.description}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:descriptionValidationMsg')}
|
||||
{t('modelManager.descriptionValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -152,9 +154,9 @@ export default function CheckpointModelEdit() {
|
||||
isRequired
|
||||
>
|
||||
<FormLabel htmlFor="config" fontSize="sm">
|
||||
{t('modelmanager:config')}
|
||||
{t('modelManager.config')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="config"
|
||||
@@ -166,7 +168,7 @@ export default function CheckpointModelEdit() {
|
||||
<FormErrorMessage>{errors.config}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:configValidationMsg')}
|
||||
{t('modelManager.configValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -178,9 +180,9 @@ export default function CheckpointModelEdit() {
|
||||
isRequired
|
||||
>
|
||||
<FormLabel htmlFor="config" fontSize="sm">
|
||||
{t('modelmanager:modelLocation')}
|
||||
{t('modelManager.modelLocation')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="weights"
|
||||
@@ -192,7 +194,7 @@ export default function CheckpointModelEdit() {
|
||||
<FormErrorMessage>{errors.weights}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:modelLocationValidationMsg')}
|
||||
{t('modelManager.modelLocationValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -201,9 +203,9 @@ export default function CheckpointModelEdit() {
|
||||
{/* VAE */}
|
||||
<FormControl isInvalid={!!errors.vae && touched.vae}>
|
||||
<FormLabel htmlFor="vae" fontSize="sm">
|
||||
{t('modelmanager:vaeLocation')}
|
||||
{t('modelManager.vaeLocation')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="vae"
|
||||
@@ -215,19 +217,19 @@ export default function CheckpointModelEdit() {
|
||||
<FormErrorMessage>{errors.vae}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:vaeLocationValidationMsg')}
|
||||
{t('modelManager.vaeLocationValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
</FormControl>
|
||||
|
||||
<HStack width={'100%'}>
|
||||
<HStack width="100%">
|
||||
{/* Width */}
|
||||
<FormControl isInvalid={!!errors.width && touched.width}>
|
||||
<FormLabel htmlFor="width" fontSize="sm">
|
||||
{t('modelmanager:width')}
|
||||
{t('modelManager.width')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field id="width" name="width">
|
||||
{({
|
||||
field,
|
||||
@@ -254,7 +256,7 @@ export default function CheckpointModelEdit() {
|
||||
<FormErrorMessage>{errors.width}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:widthValidationMsg')}
|
||||
{t('modelManager.widthValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -263,9 +265,9 @@ export default function CheckpointModelEdit() {
|
||||
{/* Height */}
|
||||
<FormControl isInvalid={!!errors.height && touched.height}>
|
||||
<FormLabel htmlFor="height" fontSize="sm">
|
||||
{t('modelmanager:height')}
|
||||
{t('modelManager.height')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field id="height" name="height">
|
||||
{({
|
||||
field,
|
||||
@@ -292,7 +294,7 @@ export default function CheckpointModelEdit() {
|
||||
<FormErrorMessage>{errors.height}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:heightValidationMsg')}
|
||||
{t('modelManager.heightValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -304,7 +306,7 @@ export default function CheckpointModelEdit() {
|
||||
className="modal-close-btn"
|
||||
isLoading={isProcessing}
|
||||
>
|
||||
{t('modelmanager:updateModel')}
|
||||
{t('modelManager.updateModel')}
|
||||
</IAIButton>
|
||||
</VStack>
|
||||
</form>
|
||||
|
||||
@@ -128,16 +128,16 @@ export default function DiffusersModelEdit() {
|
||||
>
|
||||
{({ handleSubmit, errors, touched }) => (
|
||||
<form onSubmit={handleSubmit}>
|
||||
<VStack rowGap={'0.5rem'} alignItems="start">
|
||||
<VStack rowGap="0.5rem" alignItems="start">
|
||||
{/* Description */}
|
||||
<FormControl
|
||||
isInvalid={!!errors.description && touched.description}
|
||||
isRequired
|
||||
>
|
||||
<FormLabel htmlFor="description" fontSize="sm">
|
||||
{t('modelmanager:description')}
|
||||
{t('modelManager.description')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="description"
|
||||
@@ -149,7 +149,7 @@ export default function DiffusersModelEdit() {
|
||||
<FormErrorMessage>{errors.description}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:descriptionValidationMsg')}
|
||||
{t('modelManager.descriptionValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -161,9 +161,9 @@ export default function DiffusersModelEdit() {
|
||||
isRequired
|
||||
>
|
||||
<FormLabel htmlFor="path" fontSize="sm">
|
||||
{t('modelmanager:modelLocation')}
|
||||
{t('modelManager.modelLocation')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="path"
|
||||
@@ -175,7 +175,7 @@ export default function DiffusersModelEdit() {
|
||||
<FormErrorMessage>{errors.path}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:modelLocationValidationMsg')}
|
||||
{t('modelManager.modelLocationValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -184,9 +184,9 @@ export default function DiffusersModelEdit() {
|
||||
{/* Repo ID */}
|
||||
<FormControl isInvalid={!!errors.repo_id && touched.repo_id}>
|
||||
<FormLabel htmlFor="repo_id" fontSize="sm">
|
||||
{t('modelmanager:repo_id')}
|
||||
{t('modelManager.repo_id')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="repo_id"
|
||||
@@ -198,7 +198,7 @@ export default function DiffusersModelEdit() {
|
||||
<FormErrorMessage>{errors.repo_id}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:repoIDValidationMsg')}
|
||||
{t('modelManager.repoIDValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -209,9 +209,9 @@ export default function DiffusersModelEdit() {
|
||||
isInvalid={!!errors.vae?.path && touched.vae?.path}
|
||||
>
|
||||
<FormLabel htmlFor="vae.path" fontSize="sm">
|
||||
{t('modelmanager:vaeLocation')}
|
||||
{t('modelManager.vaeLocation')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="vae.path"
|
||||
@@ -223,7 +223,7 @@ export default function DiffusersModelEdit() {
|
||||
<FormErrorMessage>{errors.vae?.path}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:vaeLocationValidationMsg')}
|
||||
{t('modelManager.vaeLocationValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -234,9 +234,9 @@ export default function DiffusersModelEdit() {
|
||||
isInvalid={!!errors.vae?.repo_id && touched.vae?.repo_id}
|
||||
>
|
||||
<FormLabel htmlFor="vae.repo_id" fontSize="sm">
|
||||
{t('modelmanager:vaeRepoID')}
|
||||
{t('modelManager.vaeRepoID')}
|
||||
</FormLabel>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<Field
|
||||
as={IAIInput}
|
||||
id="vae.repo_id"
|
||||
@@ -248,7 +248,7 @@ export default function DiffusersModelEdit() {
|
||||
<FormErrorMessage>{errors.vae?.repo_id}</FormErrorMessage>
|
||||
) : (
|
||||
<FormHelperText margin={0}>
|
||||
{t('modelmanager:vaeRepoIDValidationMsg')}
|
||||
{t('modelManager.vaeRepoIDValidationMsg')}
|
||||
</FormHelperText>
|
||||
)}
|
||||
</VStack>
|
||||
@@ -259,7 +259,7 @@ export default function DiffusersModelEdit() {
|
||||
className="modal-close-btn"
|
||||
isLoading={isProcessing}
|
||||
>
|
||||
{t('modelmanager:updateModel')}
|
||||
{t('modelManager.updateModel')}
|
||||
</IAIButton>
|
||||
</VStack>
|
||||
</form>
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
import {
|
||||
Flex,
|
||||
Modal,
|
||||
ModalCloseButton,
|
||||
ModalContent,
|
||||
ModalHeader,
|
||||
ModalOverlay,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Text,
|
||||
Tooltip,
|
||||
useDisclosure,
|
||||
} from '@chakra-ui/react';
|
||||
import { mergeDiffusersModels } from 'app/socketio/actions';
|
||||
import { type RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAIButton from 'common/components/IAIButton';
|
||||
import IAIInput from 'common/components/IAIInput';
|
||||
import IAISelect from 'common/components/IAISelect';
|
||||
import { diffusersModelsSelector } from 'features/system/store/systemSelectors';
|
||||
import { useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import * as InvokeAI from 'app/invokeai';
|
||||
import IAISlider from 'common/components/IAISlider';
|
||||
import IAICheckbox from 'common/components/IAICheckbox';
|
||||
|
||||
export default function MergeModels() {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { isOpen, onOpen, onClose } = useDisclosure();
|
||||
|
||||
const diffusersModels = useAppSelector(diffusersModelsSelector);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
const [modelOne, setModelOne] = useState<string>(
|
||||
Object.keys(diffusersModels)[0]
|
||||
);
|
||||
const [modelTwo, setModelTwo] = useState<string>(
|
||||
Object.keys(diffusersModels)[1]
|
||||
);
|
||||
const [modelThree, setModelThree] = useState<string>('none');
|
||||
|
||||
const [mergedModelName, setMergedModelName] = useState<string>('');
|
||||
const [modelMergeAlpha, setModelMergeAlpha] = useState<number>(0.5);
|
||||
|
||||
const [modelMergeInterp, setModelMergeInterp] = useState<
|
||||
'weighted_sum' | 'sigmoid' | 'inv_sigmoid' | 'add_difference'
|
||||
>('weighted_sum');
|
||||
|
||||
const [modelMergeSaveLocType, setModelMergeSaveLocType] = useState<
|
||||
'root' | 'custom'
|
||||
>('root');
|
||||
|
||||
const [modelMergeCustomSaveLoc, setModelMergeCustomSaveLoc] =
|
||||
useState<string>('');
|
||||
|
||||
const [modelMergeForce, setModelMergeForce] = useState<boolean>(false);
|
||||
|
||||
const modelOneList = Object.keys(diffusersModels).filter((model) => {
|
||||
if (model !== modelTwo && model !== modelThree) return model;
|
||||
});
|
||||
|
||||
const modelTwoList = Object.keys(diffusersModels).filter((model) => {
|
||||
if (model !== modelOne && model !== modelThree) return model;
|
||||
});
|
||||
|
||||
const modelThreeList = [
|
||||
'none',
|
||||
...Object.keys(diffusersModels).filter((model) => {
|
||||
if (model !== modelOne && model !== modelTwo) return model;
|
||||
}),
|
||||
];
|
||||
|
||||
const isProcessing = useAppSelector(
|
||||
(state: RootState) => state.system.isProcessing
|
||||
);
|
||||
|
||||
const mergeModelsHandler = () => {
|
||||
let modelsToMerge: string[] = [modelOne, modelTwo, modelThree];
|
||||
modelsToMerge = modelsToMerge.filter((model) => model !== 'none');
|
||||
|
||||
const mergeModelsInfo: InvokeAI.InvokeModelMergingProps = {
|
||||
models_to_merge: modelsToMerge,
|
||||
merged_model_name:
|
||||
mergedModelName !== '' ? mergedModelName : modelsToMerge.join('-'),
|
||||
alpha: modelMergeAlpha,
|
||||
interp: modelMergeInterp,
|
||||
model_merge_save_path:
|
||||
modelMergeSaveLocType === 'root' ? null : modelMergeCustomSaveLoc,
|
||||
force: modelMergeForce,
|
||||
};
|
||||
|
||||
dispatch(mergeDiffusersModels(mergeModelsInfo));
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<IAIButton onClick={onOpen} className="modal-close-btn" size="sm">
|
||||
<Flex columnGap="0.5rem" alignItems="center">
|
||||
{t('modelManager.mergeModels')}
|
||||
</Flex>
|
||||
</IAIButton>
|
||||
|
||||
<Modal
|
||||
isOpen={isOpen}
|
||||
onClose={onClose}
|
||||
size="4xl"
|
||||
closeOnOverlayClick={false}
|
||||
>
|
||||
<ModalOverlay />
|
||||
<ModalContent className="modal" fontFamily="Inter" margin="auto">
|
||||
<ModalHeader>{t('modelManager.mergeModels')}</ModalHeader>
|
||||
<ModalCloseButton />
|
||||
<Flex flexDirection="column" padding="1rem" rowGap={4}>
|
||||
<Flex
|
||||
flexDirection="column"
|
||||
marginBottom="1rem"
|
||||
padding="1rem"
|
||||
borderRadius="0.3rem"
|
||||
backgroundColor="var(--background-color)"
|
||||
rowGap={1}
|
||||
>
|
||||
<Text>{t('modelManager.modelMergeHeaderHelp1')}</Text>
|
||||
<Text fontSize="0.9rem" color="var(--text-color-secondary)">
|
||||
{t('modelManager.modelMergeHeaderHelp2')}
|
||||
</Text>
|
||||
</Flex>
|
||||
<Flex columnGap={4}>
|
||||
<IAISelect
|
||||
label={t('modelManager.modelOne')}
|
||||
validValues={modelOneList}
|
||||
onChange={(e) => setModelOne(e.target.value)}
|
||||
/>
|
||||
<IAISelect
|
||||
label={t('modelManager.modelTwo')}
|
||||
validValues={modelTwoList}
|
||||
onChange={(e) => setModelTwo(e.target.value)}
|
||||
/>
|
||||
<IAISelect
|
||||
label={t('modelManager.modelThree')}
|
||||
validValues={modelThreeList}
|
||||
onChange={(e) => {
|
||||
if (e.target.value !== 'none') {
|
||||
setModelThree(e.target.value);
|
||||
setModelMergeInterp('add_difference');
|
||||
} else {
|
||||
setModelThree('none');
|
||||
setModelMergeInterp('weighted_sum');
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
<IAIInput
|
||||
label={t('modelManager.mergedModelName')}
|
||||
value={mergedModelName}
|
||||
onChange={(e) => setMergedModelName(e.target.value)}
|
||||
/>
|
||||
|
||||
<Flex
|
||||
flexDir="column"
|
||||
backgroundColor="var(--background-color)"
|
||||
padding="1rem 1rem"
|
||||
borderRadius="0.2rem"
|
||||
rowGap={2}
|
||||
>
|
||||
<IAISlider
|
||||
label={t('modelManager.alpha')}
|
||||
min={0.01}
|
||||
max={0.99}
|
||||
step={0.01}
|
||||
value={modelMergeAlpha}
|
||||
onChange={(v) => setModelMergeAlpha(v)}
|
||||
withInput
|
||||
withReset
|
||||
handleReset={() => setModelMergeAlpha(0.5)}
|
||||
withSliderMarks
|
||||
sliderMarkRightOffset={-7}
|
||||
/>
|
||||
<Text fontSize="0.9rem" color="var(--text-color-secondary)">
|
||||
{t('modelManager.modelMergeAlphaHelp')}
|
||||
</Text>
|
||||
</Flex>
|
||||
|
||||
<Flex
|
||||
columnGap={4}
|
||||
backgroundColor="var(--background-color)"
|
||||
padding="1rem 1rem"
|
||||
borderRadius="0.2rem"
|
||||
>
|
||||
<Text
|
||||
fontWeight="bold"
|
||||
fontSize="0.9rem"
|
||||
color="var(--text-color-secondary)"
|
||||
>
|
||||
{t('modelManager.interpolationType')}
|
||||
</Text>
|
||||
<RadioGroup
|
||||
value={modelMergeInterp}
|
||||
onChange={(
|
||||
v:
|
||||
| 'weighted_sum'
|
||||
| 'sigmoid'
|
||||
| 'inv_sigmoid'
|
||||
| 'add_difference'
|
||||
) => setModelMergeInterp(v)}
|
||||
>
|
||||
<Flex columnGap={4}>
|
||||
{modelThree === 'none' ? (
|
||||
<>
|
||||
<Radio value="weighted_sum">weighted_sum</Radio>
|
||||
<Radio value="sigmoid">sigmoid</Radio>
|
||||
<Radio value="inv_sigmoid">inv_sigmoid</Radio>
|
||||
</>
|
||||
) : (
|
||||
<Radio value="add_difference">
|
||||
<Tooltip
|
||||
label={t(
|
||||
'modelmanager:modelMergeInterpAddDifferenceHelp'
|
||||
)}
|
||||
>
|
||||
add_difference
|
||||
</Tooltip>
|
||||
</Radio>
|
||||
)}
|
||||
</Flex>
|
||||
</RadioGroup>
|
||||
</Flex>
|
||||
|
||||
<Flex
|
||||
gap={4}
|
||||
flexDirection="column"
|
||||
backgroundColor="var(--background-color)"
|
||||
padding="1rem 1rem"
|
||||
borderRadius="0.2rem"
|
||||
>
|
||||
<Flex columnGap={4}>
|
||||
<Text
|
||||
fontWeight="bold"
|
||||
fontSize="0.9rem"
|
||||
color="var(--text-color-secondary)"
|
||||
>
|
||||
{t('modelManager.mergedModelSaveLocation')}
|
||||
</Text>
|
||||
<RadioGroup
|
||||
value={modelMergeSaveLocType}
|
||||
onChange={(v: 'root' | 'custom') =>
|
||||
setModelMergeSaveLocType(v)
|
||||
}
|
||||
>
|
||||
<Flex columnGap={4}>
|
||||
<Radio value="root">
|
||||
{t('modelManager.invokeAIFolder')}
|
||||
</Radio>
|
||||
<Radio value="custom">{t('modelManager.custom')}</Radio>
|
||||
</Flex>
|
||||
</RadioGroup>
|
||||
</Flex>
|
||||
|
||||
{modelMergeSaveLocType === 'custom' && (
|
||||
<IAIInput
|
||||
label={t('modelManager.mergedModelCustomSaveLocation')}
|
||||
value={modelMergeCustomSaveLoc}
|
||||
onChange={(e) => setModelMergeCustomSaveLoc(e.target.value)}
|
||||
/>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
<IAICheckbox
|
||||
label={t('modelManager.ignoreMismatch')}
|
||||
isChecked={modelMergeForce}
|
||||
onChange={(e) => setModelMergeForce(e.target.checked)}
|
||||
fontWeight="bold"
|
||||
/>
|
||||
|
||||
<IAIButton
|
||||
onClick={mergeModelsHandler}
|
||||
isLoading={isProcessing}
|
||||
isDisabled={
|
||||
modelMergeSaveLocType === 'custom' &&
|
||||
modelMergeCustomSaveLoc === ''
|
||||
}
|
||||
className="modal modal-close-btn"
|
||||
>
|
||||
{t('modelManager.merge')}
|
||||
</IAIButton>
|
||||
</Flex>
|
||||
</ModalContent>
|
||||
</Modal>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
import {
|
||||
Flex,
|
||||
ListItem,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Text,
|
||||
UnorderedList,
|
||||
Tooltip,
|
||||
} from '@chakra-ui/react';
|
||||
import { convertToDiffusers } from 'app/socketio/actions';
|
||||
import { RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAIAlertDialog from 'common/components/IAIAlertDialog';
|
||||
import IAIButton from 'common/components/IAIButton';
|
||||
import IAIInput from 'common/components/IAIInput';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
interface ModelConvertProps {
|
||||
model: string;
|
||||
}
|
||||
|
||||
export default function ModelConvert(props: ModelConvertProps) {
|
||||
const { model } = props;
|
||||
|
||||
const model_list = useAppSelector(
|
||||
(state: RootState) => state.system.model_list
|
||||
);
|
||||
|
||||
const retrievedModel = model_list[model];
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const isProcessing = useAppSelector(
|
||||
(state: RootState) => state.system.isProcessing
|
||||
);
|
||||
|
||||
const isConnected = useAppSelector(
|
||||
(state: RootState) => state.system.isConnected
|
||||
);
|
||||
|
||||
const [saveLocation, setSaveLocation] = useState<string>('same');
|
||||
const [customSaveLocation, setCustomSaveLocation] = useState<string>('');
|
||||
|
||||
useEffect(() => {
|
||||
setSaveLocation('same');
|
||||
}, [model]);
|
||||
|
||||
const modelConvertCancelHandler = () => {
|
||||
setSaveLocation('same');
|
||||
};
|
||||
|
||||
const modelConvertHandler = () => {
|
||||
const modelToConvert = {
|
||||
model_name: model,
|
||||
save_location: saveLocation,
|
||||
custom_location:
|
||||
saveLocation === 'custom' && customSaveLocation !== ''
|
||||
? customSaveLocation
|
||||
: null,
|
||||
};
|
||||
dispatch(convertToDiffusers(modelToConvert));
|
||||
};
|
||||
|
||||
return (
|
||||
<IAIAlertDialog
|
||||
title={`${t('modelManager.convert')} ${model}`}
|
||||
acceptCallback={modelConvertHandler}
|
||||
cancelCallback={modelConvertCancelHandler}
|
||||
acceptButtonText={`${t('modelManager.convert')}`}
|
||||
triggerComponent={
|
||||
<IAIButton
|
||||
size={'sm'}
|
||||
aria-label={t('modelManager.convertToDiffusers')}
|
||||
isDisabled={
|
||||
retrievedModel.status === 'active' || isProcessing || !isConnected
|
||||
}
|
||||
className=" modal-close-btn"
|
||||
marginRight="2rem"
|
||||
>
|
||||
🧨 {t('modelManager.convertToDiffusers')}
|
||||
</IAIButton>
|
||||
}
|
||||
motionPreset="slideInBottom"
|
||||
>
|
||||
<Flex flexDirection="column" rowGap={4}>
|
||||
<Text>{t('modelManager.convertToDiffusersHelpText1')}</Text>
|
||||
<UnorderedList>
|
||||
<ListItem>{t('modelManager.convertToDiffusersHelpText2')}</ListItem>
|
||||
<ListItem>{t('modelManager.convertToDiffusersHelpText3')}</ListItem>
|
||||
<ListItem>{t('modelManager.convertToDiffusersHelpText4')}</ListItem>
|
||||
<ListItem>{t('modelManager.convertToDiffusersHelpText5')}</ListItem>
|
||||
</UnorderedList>
|
||||
<Text>{t('modelManager.convertToDiffusersHelpText6')}</Text>
|
||||
</Flex>
|
||||
|
||||
<Flex flexDir="column" gap={4}>
|
||||
<Flex marginTop="1rem" flexDir="column" gap={2}>
|
||||
<Text fontWeight="bold">
|
||||
{t('modelManager.convertToDiffusersSaveLocation')}
|
||||
</Text>
|
||||
<RadioGroup value={saveLocation} onChange={(v) => setSaveLocation(v)}>
|
||||
<Flex gap={4}>
|
||||
<Radio value="same">
|
||||
<Tooltip label="Save converted model in the same folder">
|
||||
{t('modelManager.sameFolder')}
|
||||
</Tooltip>
|
||||
</Radio>
|
||||
|
||||
<Radio value="root">
|
||||
<Tooltip label="Save converted model in the InvokeAI root folder">
|
||||
{t('modelManager.invokeRoot')}
|
||||
</Tooltip>
|
||||
</Radio>
|
||||
|
||||
<Radio value="custom">
|
||||
<Tooltip label="Save converted model in a custom folder">
|
||||
{t('modelManager.custom')}
|
||||
</Tooltip>
|
||||
</Radio>
|
||||
</Flex>
|
||||
</RadioGroup>
|
||||
</Flex>
|
||||
|
||||
{saveLocation === 'custom' && (
|
||||
<Flex flexDirection="column" rowGap={2}>
|
||||
<Text
|
||||
fontWeight="bold"
|
||||
fontSize="sm"
|
||||
color="var(--text-color-secondary)"
|
||||
>
|
||||
{t('modelManager.customSaveLocation')}
|
||||
</Text>
|
||||
<IAIInput
|
||||
value={customSaveLocation}
|
||||
onChange={(e) => {
|
||||
if (e.target.value !== '')
|
||||
setCustomSaveLocation(e.target.value);
|
||||
}}
|
||||
width="25rem"
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
</IAIAlertDialog>
|
||||
);
|
||||
}
|
||||
@@ -14,6 +14,7 @@ import { systemSelector } from 'features/system/store/systemSelectors';
|
||||
import type { SystemState } from 'features/system/store/systemSlice';
|
||||
import { isEqual, map } from 'lodash';
|
||||
import type { ChangeEvent, ReactNode } from 'react';
|
||||
import MergeModels from './MergeModels';
|
||||
|
||||
const modelListSelector = createSelector(
|
||||
systemSelector,
|
||||
@@ -139,7 +140,7 @@ const ModelList = () => {
|
||||
width="max-content"
|
||||
fontSize="14"
|
||||
>
|
||||
{t('modelmanager:checkpointModels')}
|
||||
{t('modelManager.checkpointModels')}
|
||||
</Text>
|
||||
{ckptModelListItemsToRender}
|
||||
</Box>
|
||||
@@ -153,7 +154,7 @@ const ModelList = () => {
|
||||
width="max-content"
|
||||
fontSize="14"
|
||||
>
|
||||
{t('modelmanager:diffusersModels')}
|
||||
{t('modelManager.diffusersModels')}
|
||||
</Text>
|
||||
{diffusersModelListItemsToRender}
|
||||
</Box>
|
||||
@@ -176,39 +177,42 @@ const ModelList = () => {
|
||||
}, [models, searchText, t, isSelectedFilter]);
|
||||
|
||||
return (
|
||||
<Flex flexDirection={'column'} rowGap="2rem" width="50%" minWidth="50%">
|
||||
<Flex justifyContent={'space-between'}>
|
||||
<Text fontSize={'1.4rem'} fontWeight="bold">
|
||||
{t('modelmanager:availableModels')}
|
||||
<Flex flexDirection="column" rowGap="2rem" width="50%" minWidth="50%">
|
||||
<Flex justifyContent="space-between">
|
||||
<Text fontSize="1.4rem" fontWeight="bold">
|
||||
{t('modelManager.availableModels')}
|
||||
</Text>
|
||||
<AddModel />
|
||||
<Flex gap={2}>
|
||||
<AddModel />
|
||||
<MergeModels />
|
||||
</Flex>
|
||||
</Flex>
|
||||
|
||||
<IAIInput
|
||||
onChange={handleSearchFilter}
|
||||
label={t('modelmanager:search')}
|
||||
label={t('modelManager.search')}
|
||||
/>
|
||||
|
||||
<Flex
|
||||
flexDirection={'column'}
|
||||
flexDirection="column"
|
||||
gap={1}
|
||||
maxHeight={window.innerHeight - 360}
|
||||
overflow={'scroll'}
|
||||
overflow="scroll"
|
||||
paddingRight="1rem"
|
||||
>
|
||||
<Flex columnGap="0.5rem">
|
||||
<ModelFilterButton
|
||||
label={t('modelmanager:allModels')}
|
||||
label={t('modelManager.allModels')}
|
||||
onClick={() => setIsSelectedFilter('all')}
|
||||
isActive={isSelectedFilter === 'all'}
|
||||
/>
|
||||
<ModelFilterButton
|
||||
label={t('modelmanager:checkpointModels')}
|
||||
label={t('modelManager.checkpointModels')}
|
||||
onClick={() => setIsSelectedFilter('ckpt')}
|
||||
isActive={isSelectedFilter === 'ckpt'}
|
||||
/>
|
||||
<ModelFilterButton
|
||||
label={t('modelmanager:diffusersModels')}
|
||||
label={t('modelManager.diffusersModels')}
|
||||
onClick={() => setIsSelectedFilter('diffusers')}
|
||||
isActive={isSelectedFilter === 'diffusers'}
|
||||
/>
|
||||
|
||||
@@ -56,7 +56,7 @@ export default function ModelListItem(props: ModelListItemProps) {
|
||||
|
||||
return (
|
||||
<Flex
|
||||
alignItems={'center'}
|
||||
alignItems="center"
|
||||
padding="0.5rem 0.5rem"
|
||||
borderRadius="0.2rem"
|
||||
backgroundColor={name === openModel ? 'var(--accent-color)' : ''}
|
||||
@@ -69,47 +69,48 @@ export default function ModelListItem(props: ModelListItemProps) {
|
||||
>
|
||||
<Box onClick={openModelHandler} cursor="pointer">
|
||||
<Tooltip label={description} hasArrow placement="bottom">
|
||||
<Text fontWeight={'bold'}>{name}</Text>
|
||||
<Text fontWeight="bold">{name}</Text>
|
||||
</Tooltip>
|
||||
</Box>
|
||||
<Spacer onClick={openModelHandler} cursor="pointer" />
|
||||
<Flex gap={2} alignItems="center">
|
||||
<Text color={statusTextColor()}>{status}</Text>
|
||||
<Button
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
onClick={handleChangeModel}
|
||||
isDisabled={status === 'active' || isProcessing || !isConnected}
|
||||
className="modal-close-btn"
|
||||
>
|
||||
{t('modelmanager:load')}
|
||||
{t('modelManager.load')}
|
||||
</Button>
|
||||
|
||||
<IAIIconButton
|
||||
icon={<EditIcon />}
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
onClick={openModelHandler}
|
||||
aria-label="Modify Config"
|
||||
isDisabled={status === 'active' || isProcessing || !isConnected}
|
||||
className=" modal-close-btn"
|
||||
/>
|
||||
<IAIAlertDialog
|
||||
title={t('modelmanager:deleteModel')}
|
||||
title={t('modelManager.deleteModel')}
|
||||
acceptCallback={handleModelDelete}
|
||||
acceptButtonText={t('modelmanager:delete')}
|
||||
acceptButtonText={t('modelManager.delete')}
|
||||
triggerComponent={
|
||||
<IAIIconButton
|
||||
icon={<DeleteIcon />}
|
||||
size={'sm'}
|
||||
aria-label={t('modelmanager:deleteConfig')}
|
||||
size="sm"
|
||||
aria-label={t('modelManager.deleteConfig')}
|
||||
isDisabled={status === 'active' || isProcessing || !isConnected}
|
||||
className=" modal-close-btn"
|
||||
style={{ backgroundColor: 'var(--btn-delete-image)' }}
|
||||
/>
|
||||
}
|
||||
>
|
||||
<Flex rowGap={'1rem'} flexDirection="column">
|
||||
<p style={{ fontWeight: 'bold' }}>{t('modelmanager:deleteMsg1')}</p>
|
||||
<Flex rowGap="1rem" flexDirection="column">
|
||||
<p style={{ fontWeight: 'bold' }}>{t('modelManager.deleteMsg1')}</p>
|
||||
<p style={{ color: 'var(--text-color-secondary' }}>
|
||||
{t('modelmanager:deleteMsg2')}
|
||||
{t('modelManager.deleteMsg2')}
|
||||
</p>
|
||||
</Flex>
|
||||
</IAIAlertDialog>
|
||||
|
||||
@@ -56,13 +56,9 @@ export default function ModelManagerModal({
|
||||
<ModalContent className="modal" fontFamily="Inter">
|
||||
<ModalCloseButton className="modal-close-btn" />
|
||||
<ModalHeader fontWeight="bold">
|
||||
{t('modelmanager:modelManager')}
|
||||
{t('modelManager.modelManager')}
|
||||
</ModalHeader>
|
||||
<Flex
|
||||
padding={'0 1.5rem 1.5rem 1.5rem'}
|
||||
width="100%"
|
||||
columnGap={'2rem'}
|
||||
>
|
||||
<Flex padding="0 1.5rem 1.5rem 1.5rem" width="100%" columnGap="2rem">
|
||||
<ModelList />
|
||||
{openModel && model_list[openModel]['format'] === 'diffusers' ? (
|
||||
<DiffusersModelEdit />
|
||||
|
||||
@@ -3,7 +3,16 @@ import IAICheckbox from 'common/components/IAICheckbox';
|
||||
import IAIIconButton from 'common/components/IAIIconButton';
|
||||
import React from 'react';
|
||||
|
||||
import { Box, Flex, FormControl, HStack, Text, VStack } from '@chakra-ui/react';
|
||||
import {
|
||||
Box,
|
||||
Flex,
|
||||
FormControl,
|
||||
HStack,
|
||||
Radio,
|
||||
RadioGroup,
|
||||
Text,
|
||||
VStack,
|
||||
} from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import { systemSelector } from 'features/system/store/systemSelectors';
|
||||
@@ -43,18 +52,18 @@ function ModelExistsTag() {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Box
|
||||
position={'absolute'}
|
||||
position="absolute"
|
||||
zIndex={2}
|
||||
right={4}
|
||||
top={4}
|
||||
fontSize="0.7rem"
|
||||
fontWeight={'bold'}
|
||||
backgroundColor={'var(--accent-color)'}
|
||||
padding={'0.2rem 0.5rem'}
|
||||
fontWeight="bold"
|
||||
backgroundColor="var(--accent-color)"
|
||||
padding="0.2rem 0.5rem"
|
||||
borderRadius="0.2rem"
|
||||
alignItems={'center'}
|
||||
alignItems="center"
|
||||
>
|
||||
{t('modelmanager:modelExists')}
|
||||
{t('modelManager.modelExists')}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -87,7 +96,7 @@ function SearchModelEntry({
|
||||
value={model.name}
|
||||
label={
|
||||
<>
|
||||
<VStack alignItems={'start'}>
|
||||
<VStack alignItems="start">
|
||||
<p style={{ fontWeight: 'bold' }}>{model.name}</p>
|
||||
<p style={{ fontStyle: 'italic' }}>{model.location}</p>
|
||||
</VStack>
|
||||
@@ -96,9 +105,9 @@ function SearchModelEntry({
|
||||
isChecked={modelsToAdd.includes(model.name)}
|
||||
isDisabled={existingModels.includes(model.location)}
|
||||
onChange={foundModelsChangeHandler}
|
||||
padding={'1rem'}
|
||||
backgroundColor={'var(--background-color)'}
|
||||
borderRadius={'0.5rem'}
|
||||
padding="1rem"
|
||||
backgroundColor="var(--background-color)"
|
||||
borderRadius="0.5rem"
|
||||
_checked={{
|
||||
backgroundColor: 'var(--accent-color)',
|
||||
color: 'var(--text-color)',
|
||||
@@ -135,6 +144,8 @@ export default function SearchModels() {
|
||||
);
|
||||
|
||||
const [modelsToAdd, setModelsToAdd] = React.useState<string[]>([]);
|
||||
const [modelType, setModelType] = React.useState<string>('v1');
|
||||
const [pathToConfig, setPathToConfig] = React.useState<string>('');
|
||||
|
||||
const resetSearchModelHandler = () => {
|
||||
dispatch(setSearchFolder(null));
|
||||
@@ -167,11 +178,19 @@ export default function SearchModels() {
|
||||
const modelsToBeAdded = foundModels?.filter((foundModel) =>
|
||||
modelsToAdd.includes(foundModel.name)
|
||||
);
|
||||
|
||||
const configFiles = {
|
||||
v1: 'configs/stable-diffusion/v1-inference.yaml',
|
||||
v2: 'configs/stable-diffusion/v2-inference-v.yaml',
|
||||
inpainting: 'configs/stable-diffusion/v1-inpainting-inference.yaml',
|
||||
custom: pathToConfig,
|
||||
};
|
||||
|
||||
modelsToBeAdded?.forEach((model) => {
|
||||
const modelFormat = {
|
||||
name: model.name,
|
||||
description: '',
|
||||
config: 'configs/stable-diffusion/v1-inference.yaml',
|
||||
config: configFiles[modelType as keyof typeof configFiles],
|
||||
weights: model.location,
|
||||
vae: '',
|
||||
width: 512,
|
||||
@@ -224,12 +243,12 @@ export default function SearchModels() {
|
||||
<>
|
||||
{searchFolder ? (
|
||||
<Flex
|
||||
flexDirection={'column'}
|
||||
padding={'1rem'}
|
||||
backgroundColor={'var(--background-color)'}
|
||||
flexDirection="column"
|
||||
padding="1rem"
|
||||
backgroundColor="var(--background-color)"
|
||||
borderRadius="0.5rem"
|
||||
rowGap={'0.5rem'}
|
||||
position={'relative'}
|
||||
rowGap="0.5rem"
|
||||
position="relative"
|
||||
>
|
||||
<p
|
||||
style={{
|
||||
@@ -241,7 +260,7 @@ export default function SearchModels() {
|
||||
borderRadius: '0.2rem',
|
||||
}}
|
||||
>
|
||||
{t('modelmanager:checkpointFolder')}
|
||||
{t('modelManager.checkpointFolder')}
|
||||
</p>
|
||||
<p
|
||||
style={{ fontWeight: 'bold', fontSize: '0.8rem', maxWidth: '80%' }}
|
||||
@@ -249,19 +268,19 @@ export default function SearchModels() {
|
||||
{searchFolder}
|
||||
</p>
|
||||
<IAIIconButton
|
||||
aria-label={t('modelmanager:scanAgain')}
|
||||
tooltip={t('modelmanager:scanAgain')}
|
||||
aria-label={t('modelManager.scanAgain')}
|
||||
tooltip={t('modelManager.scanAgain')}
|
||||
icon={<BiReset />}
|
||||
position={'absolute'}
|
||||
position="absolute"
|
||||
right={16}
|
||||
fontSize={18}
|
||||
disabled={isProcessing}
|
||||
onClick={() => dispatch(searchForModels(searchFolder))}
|
||||
/>
|
||||
<IAIIconButton
|
||||
aria-label={t('modelmanager:clearCheckpointFolder')}
|
||||
aria-label={t('modelManager.clearCheckpointFolder')}
|
||||
icon={<FaPlus style={{ transform: 'rotate(45deg)' }} />}
|
||||
position={'absolute'}
|
||||
position="absolute"
|
||||
right={5}
|
||||
onClick={resetSearchModelHandler}
|
||||
/>
|
||||
@@ -284,13 +303,13 @@ export default function SearchModels() {
|
||||
type="text"
|
||||
width="lg"
|
||||
size="md"
|
||||
label={t('modelmanager:checkpointFolder')}
|
||||
label={t('modelManager.checkpointFolder')}
|
||||
/>
|
||||
</FormControl>
|
||||
<IAIIconButton
|
||||
icon={<MdFindInPage />}
|
||||
aria-label={t('modelmanager:findModels')}
|
||||
tooltip={t('modelmanager:findModels')}
|
||||
aria-label={t('modelManager.findModels')}
|
||||
tooltip={t('modelManager.findModels')}
|
||||
type="submit"
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
@@ -300,31 +319,31 @@ export default function SearchModels() {
|
||||
</Formik>
|
||||
)}
|
||||
{foundModels && (
|
||||
<Flex flexDirection={'column'} rowGap={'1rem'}>
|
||||
<Flex justifyContent={'space-between'} alignItems="center">
|
||||
<Flex flexDirection="column" rowGap="1rem">
|
||||
<Flex justifyContent="space-between" alignItems="center">
|
||||
<p>
|
||||
{t('modelmanager:modelsFound')}: {foundModels.length}
|
||||
{t('modelManager.modelsFound')}: {foundModels.length}
|
||||
</p>
|
||||
<p>
|
||||
{t('modelmanager:selected')}: {modelsToAdd.length}
|
||||
{t('modelManager.selected')}: {modelsToAdd.length}
|
||||
</p>
|
||||
</Flex>
|
||||
<Flex columnGap={'0.5rem'} justifyContent={'space-between'}>
|
||||
<Flex columnGap={'0.5rem'}>
|
||||
<Flex columnGap="0.5rem" justifyContent="space-between">
|
||||
<Flex columnGap="0.5rem">
|
||||
<IAIButton
|
||||
isDisabled={modelsToAdd.length === foundModels.length}
|
||||
onClick={addAllToSelected}
|
||||
>
|
||||
{t('modelmanager:selectAll')}
|
||||
{t('modelManager.selectAll')}
|
||||
</IAIButton>
|
||||
<IAIButton
|
||||
isDisabled={modelsToAdd.length === 0}
|
||||
onClick={removeAllFromSelected}
|
||||
>
|
||||
{t('modelmanager:deselectAll')}
|
||||
{t('modelManager.deselectAll')}
|
||||
</IAIButton>
|
||||
<IAICheckbox
|
||||
label={t('modelmanager:showExisting')}
|
||||
label={t('modelManager.showExisting')}
|
||||
isChecked={shouldShowExistingModelsInSearch}
|
||||
onChange={() =>
|
||||
dispatch(
|
||||
@@ -343,9 +362,58 @@ export default function SearchModels() {
|
||||
modelsToAdd.length > 0 ? 'var(--accent-color) !important' : ''
|
||||
}
|
||||
>
|
||||
{t('modelmanager:addSelected')}
|
||||
{t('modelManager.addSelected')}
|
||||
</IAIButton>
|
||||
</Flex>
|
||||
|
||||
<Flex
|
||||
gap={4}
|
||||
backgroundColor="var(--background-color)"
|
||||
padding="1rem 1rem"
|
||||
borderRadius="0.2rem"
|
||||
flexDirection="column"
|
||||
>
|
||||
<Flex gap={4}>
|
||||
<Text fontWeight="bold" color="var(--text-color-secondary)">
|
||||
Pick Model Type:
|
||||
</Text>
|
||||
<RadioGroup
|
||||
value={modelType}
|
||||
onChange={(v) => setModelType(v)}
|
||||
defaultValue="v1"
|
||||
name="model_type"
|
||||
>
|
||||
<Flex gap={4}>
|
||||
<Radio value="v1">{t('modelManager.v1')}</Radio>
|
||||
<Radio value="v2">{t('modelManager.v2')}</Radio>
|
||||
<Radio value="inpainting">
|
||||
{t('modelManager.inpainting')}
|
||||
</Radio>
|
||||
<Radio value="custom">{t('modelManager.customConfig')}</Radio>
|
||||
</Flex>
|
||||
</RadioGroup>
|
||||
</Flex>
|
||||
|
||||
{modelType === 'custom' && (
|
||||
<Flex flexDirection="column" rowGap={2}>
|
||||
<Text
|
||||
fontWeight="bold"
|
||||
fontSize="sm"
|
||||
color="var(--text-color-secondary)"
|
||||
>
|
||||
{t('modelManager.pathToCustomConfig')}
|
||||
</Text>
|
||||
<IAIInput
|
||||
value={pathToConfig}
|
||||
onChange={(e) => {
|
||||
if (e.target.value !== '') setPathToConfig(e.target.value);
|
||||
}}
|
||||
width="42.5rem"
|
||||
/>
|
||||
</Flex>
|
||||
)}
|
||||
</Flex>
|
||||
|
||||
<Flex
|
||||
rowGap="1rem"
|
||||
flexDirection="column"
|
||||
@@ -369,7 +437,7 @@ export default function SearchModels() {
|
||||
marginTop="1rem"
|
||||
width="max-content"
|
||||
>
|
||||
{t('modelmanager:selectAndAdd')}
|
||||
{t('modelManager.selectAndAdd')}
|
||||
</Text>
|
||||
)
|
||||
) : (
|
||||
@@ -381,7 +449,7 @@ export default function SearchModels() {
|
||||
textAlign="center"
|
||||
backgroundColor="var(--status-bad-color)"
|
||||
>
|
||||
{t('modelmanager:noModelsFound')}
|
||||
{t('modelManager.noModelsFound')}
|
||||
</Text>
|
||||
)}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@
|
||||
|
||||
div {
|
||||
background-color: var(--progress-bar-color);
|
||||
transition: width 0.2s ease-in-out;
|
||||
|
||||
&[data-indeterminate] {
|
||||
background-color: unset;
|
||||
background-image: linear-gradient(
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
} from '@chakra-ui/react';
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { IN_PROGRESS_IMAGE_TYPES } from 'app/constants';
|
||||
import { RootState } from 'app/store';
|
||||
import { type RootState } from 'app/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import IAINumberInput from 'common/components/IAINumberInput';
|
||||
import IAISelect from 'common/components/IAISelect';
|
||||
@@ -27,9 +27,14 @@ import {
|
||||
setShouldConfirmOnDelete,
|
||||
setShouldDisplayGuides,
|
||||
setShouldDisplayInProgressType,
|
||||
type SystemState,
|
||||
} from 'features/system/store/systemSlice';
|
||||
import { uiSelector } from 'features/ui/store/uiSelectors';
|
||||
import { setShouldUseCanvasBetaLayout } from 'features/ui/store/uiSlice';
|
||||
import {
|
||||
setShouldUseCanvasBetaLayout,
|
||||
setShouldUseSliders,
|
||||
} from 'features/ui/store/uiSlice';
|
||||
import { type UIState } from 'features/ui/store/uiTypes';
|
||||
import { isEqual, map } from 'lodash';
|
||||
import { persistor } from 'persistor';
|
||||
import { ChangeEvent, cloneElement, ReactElement } from 'react';
|
||||
@@ -37,7 +42,7 @@ import { useTranslation } from 'react-i18next';
|
||||
|
||||
const selector = createSelector(
|
||||
[systemSelector, uiSelector],
|
||||
(system, ui) => {
|
||||
(system: SystemState, ui: UIState) => {
|
||||
const {
|
||||
shouldDisplayInProgressType,
|
||||
shouldConfirmOnDelete,
|
||||
@@ -47,7 +52,7 @@ const selector = createSelector(
|
||||
enableImageDebugging,
|
||||
} = system;
|
||||
|
||||
const { shouldUseCanvasBetaLayout } = ui;
|
||||
const { shouldUseCanvasBetaLayout, shouldUseSliders } = ui;
|
||||
|
||||
return {
|
||||
shouldDisplayInProgressType,
|
||||
@@ -57,6 +62,7 @@ const selector = createSelector(
|
||||
saveIntermediatesInterval,
|
||||
enableImageDebugging,
|
||||
shouldUseCanvasBetaLayout,
|
||||
shouldUseSliders,
|
||||
};
|
||||
},
|
||||
{
|
||||
@@ -100,6 +106,7 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
saveIntermediatesInterval,
|
||||
enableImageDebugging,
|
||||
shouldUseCanvasBetaLayout,
|
||||
shouldUseSliders,
|
||||
} = useAppSelector(selector);
|
||||
|
||||
/**
|
||||
@@ -133,7 +140,7 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
<ModalOverlay />
|
||||
<ModalContent className="modal settings-modal">
|
||||
<ModalHeader className="settings-modal-header">
|
||||
{t('common:settingsLabel')}
|
||||
{t('common.settingsLabel')}
|
||||
</ModalHeader>
|
||||
<ModalCloseButton className="modal-close-btn" />
|
||||
<ModalBody className="settings-modal-content">
|
||||
@@ -143,7 +150,7 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
style={{ gridAutoFlow: 'row', rowGap: '0.5rem' }}
|
||||
>
|
||||
<IAISelect
|
||||
label={t('settings:displayInProgress')}
|
||||
label={t('settings.displayInProgress')}
|
||||
validValues={IN_PROGRESS_IMAGE_TYPES}
|
||||
value={shouldDisplayInProgressType}
|
||||
onChange={(e: ChangeEvent<HTMLSelectElement>) =>
|
||||
@@ -156,7 +163,7 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
/>
|
||||
{shouldDisplayInProgressType === 'full-res' && (
|
||||
<IAINumberInput
|
||||
label={t('settings:saveSteps')}
|
||||
label={t('settings.saveSteps')}
|
||||
min={1}
|
||||
max={steps}
|
||||
step={1}
|
||||
@@ -169,7 +176,7 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
</div>
|
||||
<IAISwitch
|
||||
styleClass="settings-modal-item"
|
||||
label={t('settings:confirmOnDelete')}
|
||||
label={t('settings.confirmOnDelete')}
|
||||
isChecked={shouldConfirmOnDelete}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
dispatch(setShouldConfirmOnDelete(e.target.checked))
|
||||
@@ -177,7 +184,7 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
/>
|
||||
<IAISwitch
|
||||
styleClass="settings-modal-item"
|
||||
label={t('settings:displayHelpIcons')}
|
||||
label={t('settings.displayHelpIcons')}
|
||||
isChecked={shouldDisplayGuides}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
dispatch(setShouldDisplayGuides(e.target.checked))
|
||||
@@ -185,19 +192,27 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
/>
|
||||
<IAISwitch
|
||||
styleClass="settings-modal-item"
|
||||
label={t('settings:useCanvasBeta')}
|
||||
label={t('settings.useCanvasBeta')}
|
||||
isChecked={shouldUseCanvasBetaLayout}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
dispatch(setShouldUseCanvasBetaLayout(e.target.checked))
|
||||
}
|
||||
/>
|
||||
<IAISwitch
|
||||
styleClass="settings-modal-item"
|
||||
label={t('settings.useSlidersForAll')}
|
||||
isChecked={shouldUseSliders}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
dispatch(setShouldUseSliders(e.target.checked))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="settings-modal-items">
|
||||
<h2 style={{ fontWeight: 'bold' }}>Developer</h2>
|
||||
<IAISwitch
|
||||
styleClass="settings-modal-item"
|
||||
label={t('settings:enableImageDebugging')}
|
||||
label={t('settings.enableImageDebugging')}
|
||||
isChecked={enableImageDebugging}
|
||||
onChange={(e: ChangeEvent<HTMLInputElement>) =>
|
||||
dispatch(setEnableImageDebugging(e.target.checked))
|
||||
@@ -206,18 +221,18 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
</div>
|
||||
|
||||
<div className="settings-modal-reset">
|
||||
<Heading size={'md'}>{t('settings:resetWebUI')}</Heading>
|
||||
<Heading size="md">{t('settings.resetWebUI')}</Heading>
|
||||
<Button colorScheme="red" onClick={handleClickResetWebUI}>
|
||||
{t('settings:resetWebUI')}
|
||||
{t('settings.resetWebUI')}
|
||||
</Button>
|
||||
<Text>{t('settings:resetWebUIDesc1')}</Text>
|
||||
<Text>{t('settings:resetWebUIDesc2')}</Text>
|
||||
<Text>{t('settings.resetWebUIDesc1')}</Text>
|
||||
<Text>{t('settings.resetWebUIDesc2')}</Text>
|
||||
</div>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<Button onClick={onSettingsModalClose} className="modal-close-btn">
|
||||
{t('common:close')}
|
||||
{t('common.close')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
@@ -232,9 +247,9 @@ const SettingsModal = ({ children }: SettingsModalProps) => {
|
||||
<ModalOverlay bg="blackAlpha.300" backdropFilter="blur(40px)" />
|
||||
<ModalContent>
|
||||
<ModalBody pb={6} pt={6}>
|
||||
<Flex justifyContent={'center'}>
|
||||
<Text fontSize={'lg'}>
|
||||
<Text>{t('settings:resetComplete')}</Text>
|
||||
<Flex justifyContent="center">
|
||||
<Text fontSize="lg">
|
||||
<Text>{t('settings.resetComplete')}</Text>
|
||||
</Text>
|
||||
</Flex>
|
||||
</ModalBody>
|
||||
|
||||
@@ -54,9 +54,9 @@ const SiteHeader = () => {
|
||||
|
||||
<ModelManagerModal>
|
||||
<IAIIconButton
|
||||
aria-label={t('modelmanager:modelManager')}
|
||||
tooltip={t('modelmanager:modelManager')}
|
||||
size={'sm'}
|
||||
aria-label={t('modelManager.modelManager')}
|
||||
tooltip={t('modelManager.modelManager')}
|
||||
size="sm"
|
||||
variant="link"
|
||||
data-variant="link"
|
||||
fontSize={20}
|
||||
@@ -66,9 +66,9 @@ const SiteHeader = () => {
|
||||
|
||||
<HotkeysModal>
|
||||
<IAIIconButton
|
||||
aria-label={t('common:hotkeysLabel')}
|
||||
tooltip={t('common:hotkeysLabel')}
|
||||
size={'sm'}
|
||||
aria-label={t('common.hotkeysLabel')}
|
||||
tooltip={t('common.hotkeysLabel')}
|
||||
size="sm"
|
||||
variant="link"
|
||||
data-variant="link"
|
||||
fontSize={20}
|
||||
@@ -81,12 +81,12 @@ const SiteHeader = () => {
|
||||
<LanguagePicker />
|
||||
|
||||
<IAIIconButton
|
||||
aria-label={t('common:reportBugLabel')}
|
||||
tooltip={t('common:reportBugLabel')}
|
||||
aria-label={t('common.reportBugLabel')}
|
||||
tooltip={t('common.reportBugLabel')}
|
||||
variant="link"
|
||||
data-variant="link"
|
||||
fontSize={20}
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
icon={
|
||||
<Link isExternal href="http://github.com/invoke-ai/InvokeAI/issues">
|
||||
<FaBug />
|
||||
@@ -95,12 +95,12 @@ const SiteHeader = () => {
|
||||
/>
|
||||
|
||||
<IAIIconButton
|
||||
aria-label={t('common:githubLabel')}
|
||||
tooltip={t('common:githubLabel')}
|
||||
aria-label={t('common.githubLabel')}
|
||||
tooltip={t('common.githubLabel')}
|
||||
variant="link"
|
||||
data-variant="link"
|
||||
fontSize={20}
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
icon={
|
||||
<Link isExternal href="http://github.com/invoke-ai/InvokeAI">
|
||||
<FaGithub />
|
||||
@@ -109,12 +109,12 @@ const SiteHeader = () => {
|
||||
/>
|
||||
|
||||
<IAIIconButton
|
||||
aria-label={t('common:discordLabel')}
|
||||
tooltip={t('common:discordLabel')}
|
||||
aria-label={t('common.discordLabel')}
|
||||
tooltip={t('common.discordLabel')}
|
||||
variant="link"
|
||||
data-variant="link"
|
||||
fontSize={20}
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
icon={
|
||||
<Link isExternal href="https://discord.gg/ZmtBAhwWhy">
|
||||
<FaDiscord />
|
||||
@@ -124,12 +124,12 @@ const SiteHeader = () => {
|
||||
|
||||
<SettingsModal>
|
||||
<IAIIconButton
|
||||
aria-label={t('common:settingsLabel')}
|
||||
tooltip={t('common:settingsLabel')}
|
||||
aria-label={t('common.settingsLabel')}
|
||||
tooltip={t('common.settingsLabel')}
|
||||
variant="link"
|
||||
data-variant="link"
|
||||
fontSize={22}
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
icon={<MdSettings />}
|
||||
/>
|
||||
</SettingsModal>
|
||||
|
||||
@@ -47,11 +47,11 @@ const StatusIndicator = () => {
|
||||
let statusMessage = currentStatus;
|
||||
|
||||
const intermediateStatuses = [
|
||||
t('common:statusGenerating'),
|
||||
t('common:statusPreparing'),
|
||||
t('common:statusSavingImage'),
|
||||
t('common:statusRestoringFaces'),
|
||||
t('common:statusUpscaling'),
|
||||
t('common.statusGenerating'),
|
||||
t('common.statusPreparing'),
|
||||
t('common.statusSavingImage'),
|
||||
t('common.statusRestoringFaces'),
|
||||
t('common.statusUpscaling'),
|
||||
];
|
||||
|
||||
if (intermediateStatuses.includes(statusMessage)) {
|
||||
|
||||
@@ -19,9 +19,9 @@ export default function ThemeChanger() {
|
||||
);
|
||||
|
||||
const THEMES = {
|
||||
dark: t('common:darkTheme'),
|
||||
light: t('common:lightTheme'),
|
||||
green: t('common:greenTheme'),
|
||||
dark: t('common.darkTheme'),
|
||||
light: t('common.lightTheme'),
|
||||
green: t('common.greenTheme'),
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -46,7 +46,7 @@ export default function ThemeChanger() {
|
||||
width: '6rem',
|
||||
}}
|
||||
leftIcon={currentTheme === theme ? <FaCheck /> : undefined}
|
||||
size={'sm'}
|
||||
size="sm"
|
||||
onClick={() => handleChangeTheme(theme)}
|
||||
key={theme}
|
||||
>
|
||||
@@ -63,8 +63,8 @@ export default function ThemeChanger() {
|
||||
trigger="hover"
|
||||
triggerComponent={
|
||||
<IAIIconButton
|
||||
aria-label={t('common:themeLabel')}
|
||||
size={'sm'}
|
||||
aria-label={t('common.themeLabel')}
|
||||
size="sm"
|
||||
variant="link"
|
||||
data-variant="link"
|
||||
fontSize={20}
|
||||
@@ -72,7 +72,7 @@ export default function ThemeChanger() {
|
||||
/>
|
||||
}
|
||||
>
|
||||
<VStack align={'stretch'}>{renderThemeOptions()}</VStack>
|
||||
<VStack align="stretch">{renderThemeOptions()}</VStack>
|
||||
</IAIPopover>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { RootState } from 'app/store';
|
||||
import { isEqual, reduce } from 'lodash';
|
||||
import { isEqual, reduce, pickBy } from 'lodash';
|
||||
|
||||
export const systemSelector = (state: RootState) => state.system;
|
||||
|
||||
@@ -28,3 +28,23 @@ export const activeModelSelector = createSelector(
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export const diffusersModelsSelector = createSelector(
|
||||
systemSelector,
|
||||
(system) => {
|
||||
const { model_list } = system;
|
||||
|
||||
const diffusersModels = pickBy(model_list, (model, key) => {
|
||||
if (model.format === 'diffusers') {
|
||||
return { name: key, ...model };
|
||||
}
|
||||
});
|
||||
|
||||
return diffusersModels;
|
||||
},
|
||||
{
|
||||
memoizeOptions: {
|
||||
resultEqualityCheck: isEqual,
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
@@ -75,7 +75,7 @@ const initialSystemState: SystemState = {
|
||||
currentIteration: 0,
|
||||
totalIterations: 0,
|
||||
currentStatus: i18n.isInitialized
|
||||
? i18n.t('common:statusDisconnected')
|
||||
? i18n.t('common.statusDisconnected')
|
||||
: 'Disconnected',
|
||||
currentStatusHasSteps: false,
|
||||
model: '',
|
||||
@@ -128,15 +128,15 @@ export const systemSlice = createSlice({
|
||||
state.currentIteration = 0;
|
||||
state.totalIterations = 0;
|
||||
state.currentStatusHasSteps = false;
|
||||
state.currentStatus = i18n.t('common:statusError');
|
||||
state.currentStatus = i18n.t('common.statusError');
|
||||
state.wasErrorSeen = false;
|
||||
},
|
||||
errorSeen: (state) => {
|
||||
state.hasError = false;
|
||||
state.wasErrorSeen = true;
|
||||
state.currentStatus = state.isConnected
|
||||
? i18n.t('common:statusConnected')
|
||||
: i18n.t('common:statusDisconnected');
|
||||
? i18n.t('common.statusConnected')
|
||||
: i18n.t('common.statusDisconnected');
|
||||
},
|
||||
addLogEntry: (
|
||||
state,
|
||||
@@ -197,7 +197,7 @@ export const systemSlice = createSlice({
|
||||
state.currentIteration = 0;
|
||||
state.totalIterations = 0;
|
||||
state.currentStatusHasSteps = false;
|
||||
state.currentStatus = i18n.t('common:statusProcessingCanceled');
|
||||
state.currentStatus = i18n.t('common.statusProcessingCanceled');
|
||||
},
|
||||
generationRequested: (state) => {
|
||||
state.isProcessing = true;
|
||||
@@ -207,7 +207,7 @@ export const systemSlice = createSlice({
|
||||
state.currentIteration = 0;
|
||||
state.totalIterations = 0;
|
||||
state.currentStatusHasSteps = false;
|
||||
state.currentStatus = i18n.t('common:statusPreparing');
|
||||
state.currentStatus = i18n.t('common.statusPreparing');
|
||||
},
|
||||
setModelList: (
|
||||
state,
|
||||
@@ -219,7 +219,19 @@ export const systemSlice = createSlice({
|
||||
state.isCancelable = action.payload;
|
||||
},
|
||||
modelChangeRequested: (state) => {
|
||||
state.currentStatus = i18n.t('common:statusLoadingModel');
|
||||
state.currentStatus = i18n.t('common.statusLoadingModel');
|
||||
state.isCancelable = false;
|
||||
state.isProcessing = true;
|
||||
state.currentStatusHasSteps = false;
|
||||
},
|
||||
modelConvertRequested: (state) => {
|
||||
state.currentStatus = i18n.t('common.statusConvertingModel');
|
||||
state.isCancelable = false;
|
||||
state.isProcessing = true;
|
||||
state.currentStatusHasSteps = false;
|
||||
},
|
||||
modelMergingRequested: (state) => {
|
||||
state.currentStatus = i18n.t('common.statusMergingModels');
|
||||
state.isCancelable = false;
|
||||
state.isProcessing = true;
|
||||
state.currentStatusHasSteps = false;
|
||||
@@ -281,6 +293,8 @@ export const {
|
||||
setModelList,
|
||||
setIsCancelable,
|
||||
modelChangeRequested,
|
||||
modelConvertRequested,
|
||||
modelMergingRequested,
|
||||
setSaveIntermediatesInterval,
|
||||
setEnableImageDebugging,
|
||||
generationRequested,
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import ImageFit from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageFit';
|
||||
import ImageToImageStrength from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageStrength';
|
||||
import ParametersAccordion from 'features/parameters/components/ParametersAccordion';
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export default function ImageToImageOptions() {
|
||||
const { t } = useTranslation();
|
||||
const imageToImageAccordionItems = {
|
||||
imageToImage: {
|
||||
header: `${t('parameters.imageToImage')}`,
|
||||
feature: undefined,
|
||||
content: (
|
||||
<Flex gap={2} flexDir="column">
|
||||
<ImageToImageStrength
|
||||
label={t('parameters.img2imgStrength')}
|
||||
styleClass="main-settings-block image-to-image-strength-main-option"
|
||||
/>
|
||||
<ImageFit />
|
||||
</Flex>
|
||||
),
|
||||
},
|
||||
};
|
||||
return <ParametersAccordion accordionInfo={imageToImageAccordionItems} />;
|
||||
}
|
||||
@@ -1,10 +1,7 @@
|
||||
import { Flex } from '@chakra-ui/react';
|
||||
import { Feature } from 'app/features';
|
||||
import { useAppDispatch, useAppSelector } from 'app/storeHooks';
|
||||
import FaceRestoreSettings from 'features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreSettings';
|
||||
import FaceRestoreToggle from 'features/parameters/components/AdvancedParameters/FaceRestore/FaceRestoreToggle';
|
||||
import ImageFit from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageFit';
|
||||
import ImageToImageStrength from 'features/parameters/components/AdvancedParameters/ImageToImage/ImageToImageStrength';
|
||||
import ImageToImageOutputSettings from 'features/parameters/components/AdvancedParameters/Output/ImageToImageOutputSettings';
|
||||
import SeedSettings from 'features/parameters/components/AdvancedParameters/Seed/SeedSettings';
|
||||
import UpscaleSettings from 'features/parameters/components/AdvancedParameters/Upscale/UpscaleSettings';
|
||||
@@ -16,57 +13,44 @@ import ParametersAccordion from 'features/parameters/components/ParametersAccord
|
||||
import ProcessButtons from 'features/parameters/components/ProcessButtons/ProcessButtons';
|
||||
import NegativePromptInput from 'features/parameters/components/PromptInput/NegativePromptInput';
|
||||
import PromptInput from 'features/parameters/components/PromptInput/PromptInput';
|
||||
import { setHiresFix } from 'features/parameters/store/postprocessingSlice';
|
||||
import InvokeOptionsPanel from 'features/ui/components/InvokeParametersPanel';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import { useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import ImageToImageOptions from './ImageToImageOptions';
|
||||
|
||||
export default function ImageToImagePanel() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const imageToImageAccordions = {
|
||||
seed: {
|
||||
header: `${t('parameters:seed')}`,
|
||||
header: `${t('parameters.seed')}`,
|
||||
feature: Feature.SEED,
|
||||
content: <SeedSettings />,
|
||||
},
|
||||
variations: {
|
||||
header: `${t('parameters:variations')}`,
|
||||
header: `${t('parameters.variations')}`,
|
||||
feature: Feature.VARIATIONS,
|
||||
content: <VariationsSettings />,
|
||||
additionalHeaderComponents: <GenerateVariationsToggle />,
|
||||
},
|
||||
face_restore: {
|
||||
header: `${t('parameters:faceRestoration')}`,
|
||||
header: `${t('parameters.faceRestoration')}`,
|
||||
feature: Feature.FACE_CORRECTION,
|
||||
content: <FaceRestoreSettings />,
|
||||
additionalHeaderComponents: <FaceRestoreToggle />,
|
||||
},
|
||||
upscale: {
|
||||
header: `${t('parameters:upscaling')}`,
|
||||
header: `${t('parameters.upscaling')}`,
|
||||
feature: Feature.UPSCALE,
|
||||
content: <UpscaleSettings />,
|
||||
additionalHeaderComponents: <UpscaleToggle />,
|
||||
},
|
||||
other: {
|
||||
header: `${t('parameters:otherOptions')}`,
|
||||
header: `${t('parameters.otherOptions')}`,
|
||||
feature: Feature.OTHER,
|
||||
content: <ImageToImageOutputSettings />,
|
||||
},
|
||||
};
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const activeTabName = useAppSelector(activeTabNameSelector);
|
||||
|
||||
useEffect(() => {
|
||||
if (activeTabName === 'img2img') {
|
||||
const handleChangeHiresFix = () => dispatch(setHiresFix(false));
|
||||
handleChangeHiresFix();
|
||||
}
|
||||
}, [activeTabName, dispatch]);
|
||||
|
||||
return (
|
||||
<InvokeOptionsPanel>
|
||||
<Flex flexDir="column" rowGap="0.5rem">
|
||||
@@ -75,11 +59,7 @@ export default function ImageToImagePanel() {
|
||||
</Flex>
|
||||
<ProcessButtons />
|
||||
<MainSettings />
|
||||
<ImageToImageStrength
|
||||
label={t('parameters:img2imgStrength')}
|
||||
styleClass="main-settings-block image-to-image-strength-main-option"
|
||||
/>
|
||||
<ImageFit />
|
||||
<ImageToImageOptions />
|
||||
<ParametersAccordion accordionInfo={imageToImageAccordions} />
|
||||
</InvokeOptionsPanel>
|
||||
);
|
||||
|
||||
@@ -18,8 +18,8 @@ export default function InitImagePreview() {
|
||||
|
||||
const alertMissingInitImage = () => {
|
||||
toast({
|
||||
title: t('toast:parametersFailed'),
|
||||
description: t('toast:parametersFailedDesc'),
|
||||
title: t('toast.parametersFailed'),
|
||||
description: t('toast.parametersFailedDesc'),
|
||||
status: 'error',
|
||||
isClosable: true,
|
||||
});
|
||||
@@ -29,15 +29,15 @@ export default function InitImagePreview() {
|
||||
return (
|
||||
<>
|
||||
<div className="init-image-preview-header">
|
||||
<h2>{t('parameters:initialImage')}</h2>
|
||||
<h2>{t('parameters.initialImage')}</h2>
|
||||
<ImageUploaderIconButton />
|
||||
</div>
|
||||
{initialImage && (
|
||||
<div className="init-image-preview">
|
||||
<Image
|
||||
fit={'contain'}
|
||||
maxWidth={'100%'}
|
||||
maxHeight={'100%'}
|
||||
fit="contain"
|
||||
maxWidth="100%"
|
||||
maxHeight="100%"
|
||||
src={
|
||||
typeof initialImage === 'string' ? initialImage : initialImage.url
|
||||
}
|
||||
|
||||
@@ -9,10 +9,10 @@ export default function InitialImageOverlay() {
|
||||
|
||||
return initialImage ? (
|
||||
<Image
|
||||
fit={'contain'}
|
||||
fit="contain"
|
||||
src={typeof initialImage === 'string' ? initialImage : initialImage.url}
|
||||
rounded={'md'}
|
||||
className={'checkerboard'}
|
||||
rounded="md"
|
||||
className="checkerboard"
|
||||
/>
|
||||
) : null;
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
.parameters-panel {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
row-gap: 1rem;
|
||||
row-gap: 0.5rem;
|
||||
height: 100%;
|
||||
@include HideScrollbar;
|
||||
background-color: var(--background-color);
|
||||
|
||||
@@ -31,44 +31,44 @@ export interface InvokeTabInfo {
|
||||
|
||||
export const tabDict: Record<InvokeTabName, InvokeTabInfo> = {
|
||||
txt2img: {
|
||||
title: <TextToImageIcon fill={'black'} boxSize={'2.5rem'} />,
|
||||
title: <TextToImageIcon fill="black" boxSize="2.5rem" />,
|
||||
workarea: <TextToImageWorkarea />,
|
||||
tooltip: 'Text To Image',
|
||||
},
|
||||
img2img: {
|
||||
title: <ImageToImageIcon fill={'black'} boxSize={'2.5rem'} />,
|
||||
title: <ImageToImageIcon fill="black" boxSize="2.5rem" />,
|
||||
workarea: <ImageToImageWorkarea />,
|
||||
tooltip: 'Image To Image',
|
||||
},
|
||||
unifiedCanvas: {
|
||||
title: <UnifiedCanvasIcon fill={'black'} boxSize={'2.5rem'} />,
|
||||
title: <UnifiedCanvasIcon fill="black" boxSize="2.5rem" />,
|
||||
workarea: <UnifiedCanvasWorkarea />,
|
||||
tooltip: 'Unified Canvas',
|
||||
},
|
||||
nodes: {
|
||||
title: <NodesIcon fill={'black'} boxSize={'2.5rem'} />,
|
||||
title: <NodesIcon fill="black" boxSize="2.5rem" />,
|
||||
workarea: <NodesWIP />,
|
||||
tooltip: 'Nodes',
|
||||
},
|
||||
postprocess: {
|
||||
title: <PostprocessingIcon fill={'black'} boxSize={'2.5rem'} />,
|
||||
title: <PostprocessingIcon fill="black" boxSize="2.5rem" />,
|
||||
workarea: <PostProcessingWIP />,
|
||||
tooltip: 'Post Processing',
|
||||
},
|
||||
training: {
|
||||
title: <TrainingIcon fill={'black'} boxSize={'2.5rem'} />,
|
||||
title: <TrainingIcon fill="black" boxSize="2.5rem" />,
|
||||
workarea: <TrainingWIP />,
|
||||
tooltip: 'Training',
|
||||
},
|
||||
};
|
||||
|
||||
function updateTabTranslations() {
|
||||
tabDict.txt2img.tooltip = i18n.t('common:text2img');
|
||||
tabDict.img2img.tooltip = i18n.t('common:img2img');
|
||||
tabDict.unifiedCanvas.tooltip = i18n.t('common:unifiedCanvas');
|
||||
tabDict.nodes.tooltip = i18n.t('common:nodes');
|
||||
tabDict.postprocess.tooltip = i18n.t('common:postProcessing');
|
||||
tabDict.training.tooltip = i18n.t('common:training');
|
||||
tabDict.txt2img.tooltip = i18n.t('common.text2img');
|
||||
tabDict.img2img.tooltip = i18n.t('common.img2img');
|
||||
tabDict.unifiedCanvas.tooltip = i18n.t('common.unifiedCanvas');
|
||||
tabDict.nodes.tooltip = i18n.t('common.nodes');
|
||||
tabDict.postprocess.tooltip = i18n.t('common.postProcessing');
|
||||
tabDict.training.tooltip = i18n.t('common.training');
|
||||
}
|
||||
|
||||
export default function InvokeTabs() {
|
||||
@@ -122,7 +122,7 @@ export default function InvokeTabs() {
|
||||
key={key}
|
||||
hasArrow
|
||||
label={tabDict[key as keyof typeof tabDict].tooltip}
|
||||
placement={'right'}
|
||||
placement="right"
|
||||
>
|
||||
<Tab>{tabDict[key as keyof typeof tabDict].title}</Tab>
|
||||
</Tooltip>
|
||||
@@ -147,7 +147,7 @@ export default function InvokeTabs() {
|
||||
<Tabs
|
||||
isLazy
|
||||
className="app-tabs"
|
||||
variant={'unstyled'}
|
||||
variant="unstyled"
|
||||
defaultIndex={activeTab}
|
||||
index={activeTab}
|
||||
onChange={(index: number) => {
|
||||
|
||||
@@ -21,30 +21,30 @@ export default function TextToImagePanel() {
|
||||
|
||||
const textToImageAccordions = {
|
||||
seed: {
|
||||
header: `${t('parameters:seed')}`,
|
||||
header: `${t('parameters.seed')}`,
|
||||
feature: Feature.SEED,
|
||||
content: <SeedSettings />,
|
||||
},
|
||||
variations: {
|
||||
header: `${t('parameters:variations')}`,
|
||||
header: `${t('parameters.variations')}`,
|
||||
feature: Feature.VARIATIONS,
|
||||
content: <VariationsSettings />,
|
||||
additionalHeaderComponents: <GenerateVariationsToggle />,
|
||||
},
|
||||
face_restore: {
|
||||
header: `${t('parameters:faceRestoration')}`,
|
||||
header: `${t('parameters.faceRestoration')}`,
|
||||
feature: Feature.FACE_CORRECTION,
|
||||
content: <FaceRestoreSettings />,
|
||||
additionalHeaderComponents: <FaceRestoreToggle />,
|
||||
},
|
||||
upscale: {
|
||||
header: `${t('parameters:upscaling')}`,
|
||||
header: `${t('parameters.upscaling')}`,
|
||||
feature: Feature.UPSCALE,
|
||||
content: <UpscaleSettings />,
|
||||
additionalHeaderComponents: <UpscaleToggle />,
|
||||
},
|
||||
other: {
|
||||
header: `${t('parameters:otherOptions')}`,
|
||||
header: `${t('parameters.otherOptions')}`,
|
||||
feature: Feature.OTHER,
|
||||
content: <OutputSettings />,
|
||||
},
|
||||
|
||||
@@ -45,21 +45,16 @@ const UnifiedCanvasDisplayBeta = () => {
|
||||
}, [dispatch]);
|
||||
|
||||
return (
|
||||
<div className={'workarea-single-view'}>
|
||||
<div className="workarea-single-view">
|
||||
<Flex
|
||||
flexDirection={'row'}
|
||||
flexDirection="row"
|
||||
width="100%"
|
||||
height="100%"
|
||||
columnGap={'1rem'}
|
||||
columnGap="1rem"
|
||||
padding="1rem"
|
||||
>
|
||||
<UnifiedCanvasToolbarBeta />
|
||||
<Flex
|
||||
width="100%"
|
||||
height="100%"
|
||||
flexDirection={'column'}
|
||||
rowGap={'1rem'}
|
||||
>
|
||||
<Flex width="100%" height="100%" flexDirection="column" rowGap="1rem">
|
||||
<UnifiedCanvasToolSettingsBeta />
|
||||
{doesCanvasNeedScaling ? <IAICanvasResizer /> : <IAICanvas />}
|
||||
</Flex>
|
||||
|
||||
@@ -4,7 +4,7 @@ import UnifiedCanvasLimitStrokesToBox from './UnifiedCanvasLimitStrokesToBox';
|
||||
|
||||
export default function UnifiedCanvasBaseBrushSettings() {
|
||||
return (
|
||||
<Flex gap={'1rem'} alignItems="center">
|
||||
<Flex gap="1rem" alignItems="center">
|
||||
<UnifiedCanvasBrushSettings />
|
||||
<UnifiedCanvasLimitStrokesToBox />
|
||||
</Flex>
|
||||
|
||||
@@ -4,7 +4,7 @@ import UnifiedCanvasColorPicker from './UnifiedCanvasColorPicker';
|
||||
|
||||
export default function UnifiedCanvasBrushSettings() {
|
||||
return (
|
||||
<Flex columnGap={'1rem'} alignItems="center">
|
||||
<Flex columnGap="1rem" alignItems="center">
|
||||
<UnifiedCanvasBrushSize />
|
||||
<UnifiedCanvasColorPicker />
|
||||
</Flex>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user