mirror of
https://github.com/invoke-ai/InvokeAI.git
synced 2026-04-23 03:00:31 -04:00
feat(ui): update floating buttons & other incidental UI tweaks
This commit is contained in:
@@ -948,6 +948,7 @@
|
||||
"seamLowThreshold": "Low",
|
||||
"seed": "Seed",
|
||||
"seedWeights": "Seed Weights",
|
||||
"imageActions": "Image Actions",
|
||||
"sendTo": "Send to",
|
||||
"sendToImg2Img": "Send to Image to Image",
|
||||
"sendToUnifiedCanvas": "Send To Unified Canvas",
|
||||
@@ -960,7 +961,7 @@
|
||||
"tileSize": "Tile Size",
|
||||
"toggleLoopback": "Toggle Loopback",
|
||||
"type": "Type",
|
||||
"upscale": "Upscale",
|
||||
"upscale": "Upscale (Shift + U)",
|
||||
"upscaleImage": "Upscale Image",
|
||||
"upscaling": "Upscaling",
|
||||
"useAll": "Use All",
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { createSelector } from '@reduxjs/toolkit';
|
||||
import { stateSelector } from 'app/store/store';
|
||||
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
|
||||
import { useQueueBack } from 'features/queue/hooks/useQueueBack';
|
||||
import { useQueueFront } from 'features/queue/hooks/useQueueFront';
|
||||
import {
|
||||
ctrlKeyPressed,
|
||||
metaKeyPressed,
|
||||
@@ -33,6 +35,39 @@ const globalHotkeysSelector = createSelector(
|
||||
const GlobalHotkeys: React.FC = () => {
|
||||
const dispatch = useAppDispatch();
|
||||
const { shift, ctrl, meta } = useAppSelector(globalHotkeysSelector);
|
||||
const {
|
||||
queueBack,
|
||||
isDisabled: isDisabledQueueBack,
|
||||
isLoading: isLoadingQueueBack,
|
||||
} = useQueueBack();
|
||||
|
||||
useHotkeys(
|
||||
['ctrl+enter', 'meta+enter'],
|
||||
queueBack,
|
||||
{
|
||||
enabled: () => !isDisabledQueueBack && !isLoadingQueueBack,
|
||||
preventDefault: true,
|
||||
enableOnFormTags: ['input', 'textarea', 'select'],
|
||||
},
|
||||
[queueBack, isDisabledQueueBack, isLoadingQueueBack]
|
||||
);
|
||||
|
||||
const {
|
||||
queueFront,
|
||||
isDisabled: isDisabledQueueFront,
|
||||
isLoading: isLoadingQueueFront,
|
||||
} = useQueueFront();
|
||||
|
||||
useHotkeys(
|
||||
['ctrl+shift+enter', 'meta+shift+enter'],
|
||||
queueFront,
|
||||
{
|
||||
enabled: () => !isDisabledQueueFront && !isLoadingQueueFront,
|
||||
preventDefault: true,
|
||||
enableOnFormTags: ['input', 'textarea', 'select'],
|
||||
},
|
||||
[queueFront, isDisabledQueueFront, isLoadingQueueFront]
|
||||
);
|
||||
|
||||
useHotkeys(
|
||||
'*',
|
||||
|
||||
@@ -37,9 +37,8 @@ import {
|
||||
FaHourglassHalf,
|
||||
FaQuoteRight,
|
||||
FaSeedling,
|
||||
FaShareAlt,
|
||||
} from 'react-icons/fa';
|
||||
import { MdDeviceHub } from 'react-icons/md';
|
||||
import { FaCircleNodes, FaEllipsis } from 'react-icons/fa6';
|
||||
import {
|
||||
useGetImageDTOQuery,
|
||||
useGetImageMetadataFromFileQuery,
|
||||
@@ -255,10 +254,10 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
||||
<Menu>
|
||||
<MenuButton
|
||||
as={IAIIconButton}
|
||||
aria-label={`${t('parameters.sendTo')}...`}
|
||||
tooltip={`${t('parameters.sendTo')}...`}
|
||||
aria-label={t('parameters.imageActions')}
|
||||
tooltip={t('parameters.imageActions')}
|
||||
isDisabled={!imageDTO}
|
||||
icon={<FaShareAlt />}
|
||||
icon={<FaEllipsis />}
|
||||
/>
|
||||
<MenuList motionProps={menuListMotionProps}>
|
||||
{imageDTO && <SingleSelectionMenuItems imageDTO={imageDTO} />}
|
||||
@@ -269,7 +268,7 @@ const CurrentImageButtons = (props: CurrentImageButtonsProps) => {
|
||||
<ButtonGroup isAttached={true} isDisabled={shouldDisableToolbarButtons}>
|
||||
<IAIIconButton
|
||||
isLoading={isLoading}
|
||||
icon={<MdDeviceHub />}
|
||||
icon={<FaCircleNodes />}
|
||||
tooltip={`${t('nodes.loadWorkflow')} (W)`}
|
||||
aria-label={`${t('nodes.loadWorkflow')} (W)`}
|
||||
isDisabled={!workflow}
|
||||
|
||||
@@ -16,6 +16,7 @@ import { useFeatureStatus } from 'features/system/hooks/useFeatureStatus';
|
||||
import { useCopyImageToClipboard } from 'features/ui/hooks/useCopyImageToClipboard';
|
||||
import { setActiveTab } from 'features/ui/store/uiSlice';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { flushSync } from 'react-dom';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import {
|
||||
FaAsterisk,
|
||||
@@ -28,7 +29,8 @@ import {
|
||||
FaShare,
|
||||
FaTrash,
|
||||
} from 'react-icons/fa';
|
||||
import { MdDeviceHub, MdStar, MdStarBorder } from 'react-icons/md';
|
||||
import { FaCircleNodes } from 'react-icons/fa6';
|
||||
import { MdStar, MdStarBorder } from 'react-icons/md';
|
||||
import {
|
||||
useGetImageMetadataFromFileQuery,
|
||||
useStarImagesMutation,
|
||||
@@ -37,7 +39,6 @@ import {
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import { configSelector } from '../../../system/store/configSelectors';
|
||||
import { sentImageToCanvas, sentImageToImg2Img } from '../../store/actions';
|
||||
import { flushSync } from 'react-dom';
|
||||
|
||||
type SingleSelectionMenuItemsProps = {
|
||||
imageDTO: ImageDTO;
|
||||
@@ -180,7 +181,7 @@ const SingleSelectionMenuItems = (props: SingleSelectionMenuItemsProps) => {
|
||||
{t('parameters.downloadImage')}
|
||||
</MenuItem>
|
||||
<MenuItem
|
||||
icon={isLoading ? <SpinnerIcon /> : <MdDeviceHub />}
|
||||
icon={isLoading ? <SpinnerIcon /> : <FaCircleNodes />}
|
||||
onClickCapture={handleLoadWorkflow}
|
||||
isDisabled={isLoading || !workflow}
|
||||
>
|
||||
|
||||
@@ -7,7 +7,7 @@ import IAIPopover from 'common/components/IAIPopover';
|
||||
import { useIsQueueMutationInProgress } from 'features/queue/hooks/useIsQueueMutationInProgress';
|
||||
import { memo, useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaExpandArrowsAlt } from 'react-icons/fa';
|
||||
import { FaExpand } from 'react-icons/fa';
|
||||
import { ImageDTO } from 'services/api/types';
|
||||
import ParamESRGANModel from './ParamRealESRGANModel';
|
||||
|
||||
@@ -34,8 +34,9 @@ const ParamUpscalePopover = (props: Props) => {
|
||||
onClose={onClose}
|
||||
triggerComponent={
|
||||
<IAIIconButton
|
||||
tooltip={t('parameters.upscale')}
|
||||
onClick={onOpen}
|
||||
icon={<FaExpandArrowsAlt />}
|
||||
icon={<FaExpand />}
|
||||
aria-label={t('parameters.upscale')}
|
||||
/>
|
||||
}
|
||||
|
||||
@@ -3,12 +3,14 @@ import { useTranslation } from 'react-i18next';
|
||||
import { FaTimes } from 'react-icons/fa';
|
||||
import { useCancelCurrentQueueItem } from '../hooks/useCancelCurrentQueueItem';
|
||||
import QueueButton from './common/QueueButton';
|
||||
import { ChakraProps } from '@chakra-ui/react';
|
||||
|
||||
type Props = {
|
||||
asIconButton?: boolean;
|
||||
sx?: ChakraProps['sx'];
|
||||
};
|
||||
|
||||
const CancelCurrentQueueItemButton = ({ asIconButton }: Props) => {
|
||||
const CancelCurrentQueueItemButton = ({ asIconButton, sx }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { cancelQueueItem, isLoading, currentQueueItemId } =
|
||||
useCancelCurrentQueueItem();
|
||||
@@ -23,6 +25,7 @@ const CancelCurrentQueueItemButton = ({ asIconButton }: Props) => {
|
||||
icon={<FaTimes />}
|
||||
onClick={cancelQueueItem}
|
||||
colorScheme="error"
|
||||
sx={sx}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -3,12 +3,14 @@ import { useTranslation } from 'react-i18next';
|
||||
import { FaTrash } from 'react-icons/fa';
|
||||
import { useClearQueue } from '../hooks/useClearQueue';
|
||||
import QueueButton from './common/QueueButton';
|
||||
import { ChakraProps } from '@chakra-ui/react';
|
||||
|
||||
type Props = {
|
||||
asIconButton?: boolean;
|
||||
sx?: ChakraProps['sx'];
|
||||
};
|
||||
|
||||
const ClearQueueButton = ({ asIconButton }: Props) => {
|
||||
const ClearQueueButton = ({ asIconButton, sx }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { clearQueue, isLoading, queueStatus } = useClearQueue();
|
||||
|
||||
@@ -22,6 +24,7 @@ const ClearQueueButton = ({ asIconButton }: Props) => {
|
||||
icon={<FaTrash />}
|
||||
onClick={clearQueue}
|
||||
colorScheme="error"
|
||||
sx={sx}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,24 +1,31 @@
|
||||
import IAIButton from 'common/components/IAIButton';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaPlus } from 'react-icons/fa';
|
||||
import { useQueueBack } from '../hooks/useQueueBack';
|
||||
import EnqueueButtonTooltip from './QueueButtonTooltip';
|
||||
import QueueButton from './common/QueueButton';
|
||||
import { ChakraProps } from '@chakra-ui/react';
|
||||
|
||||
const QueueBackButton = () => {
|
||||
type Props = {
|
||||
asIconButton?: boolean;
|
||||
sx?: ChakraProps['sx'];
|
||||
};
|
||||
|
||||
const QueueBackButton = ({ asIconButton, sx }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { queueBack, isLoading, isDisabled } = useQueueBack();
|
||||
return (
|
||||
<IAIButton
|
||||
<QueueButton
|
||||
asIconButton={asIconButton}
|
||||
colorScheme="accent"
|
||||
label={t('queue.queueBack')}
|
||||
isDisabled={isDisabled}
|
||||
isLoading={isLoading}
|
||||
colorScheme="accent"
|
||||
onClick={queueBack}
|
||||
tooltip={<EnqueueButtonTooltip />}
|
||||
flexGrow={3}
|
||||
minW={44}
|
||||
>
|
||||
{t('queue.queueBack')}
|
||||
</IAIButton>
|
||||
icon={<FaPlus />}
|
||||
sx={sx}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ const QueueControls = () => {
|
||||
<Flex gap={2} w="full">
|
||||
<ButtonGroup isAttached flexGrow={2}>
|
||||
<QueueBackButton />
|
||||
<QueueFrontButton />
|
||||
<QueueFrontButton asIconButton />
|
||||
<CancelCurrentQueueItemButton asIconButton />
|
||||
</ButtonGroup>
|
||||
<ButtonGroup isAttached>
|
||||
|
||||
@@ -1,22 +1,30 @@
|
||||
import IAIIconButton from 'common/components/IAIIconButton';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaBoltLightning } from 'react-icons/fa6';
|
||||
import { useQueueFront } from '../hooks/useQueueFront';
|
||||
import EnqueueButtonTooltip from './QueueButtonTooltip';
|
||||
import QueueButton from './common/QueueButton';
|
||||
import { ChakraProps } from '@chakra-ui/react';
|
||||
|
||||
const QueueFrontButton = () => {
|
||||
type Props = {
|
||||
asIconButton?: boolean;
|
||||
sx?: ChakraProps['sx'];
|
||||
};
|
||||
|
||||
const QueueFrontButton = ({ asIconButton, sx }: Props) => {
|
||||
const { t } = useTranslation();
|
||||
const { queueFront, isLoading, isDisabled } = useQueueFront();
|
||||
return (
|
||||
<IAIIconButton
|
||||
<QueueButton
|
||||
asIconButton={asIconButton}
|
||||
colorScheme="base"
|
||||
aria-label={t('queue.queueFront')}
|
||||
label={t('queue.queueFront')}
|
||||
isDisabled={isDisabled}
|
||||
isLoading={isLoading}
|
||||
onClick={queueFront}
|
||||
tooltip={<EnqueueButtonTooltip prepend />}
|
||||
icon={<FaBoltLightning />}
|
||||
sx={sx}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { ThemeTypings } from '@chakra-ui/react';
|
||||
import { ChakraProps, ThemeTypings } from '@chakra-ui/react';
|
||||
import IAIButton from 'common/components/IAIButton';
|
||||
import IAIIconButton from 'common/components/IAIIconButton';
|
||||
import { ReactElement, memo } from 'react';
|
||||
import { ReactElement, ReactNode, memo } from 'react';
|
||||
|
||||
type Props = {
|
||||
label: string;
|
||||
tooltip: string;
|
||||
tooltip: ReactNode;
|
||||
icon: ReactElement;
|
||||
onClick: () => void;
|
||||
isDisabled?: boolean;
|
||||
@@ -13,6 +13,7 @@ type Props = {
|
||||
asIconButton?: boolean;
|
||||
isLoading?: boolean;
|
||||
loadingText?: string;
|
||||
sx?: ChakraProps['sx'];
|
||||
};
|
||||
|
||||
const QueueButton = ({
|
||||
@@ -25,6 +26,7 @@ const QueueButton = ({
|
||||
asIconButton,
|
||||
isLoading,
|
||||
loadingText,
|
||||
sx,
|
||||
}: Props) => {
|
||||
if (asIconButton) {
|
||||
return (
|
||||
@@ -36,6 +38,7 @@ const QueueButton = ({
|
||||
isDisabled={isDisabled}
|
||||
colorScheme={colorScheme}
|
||||
isLoading={isLoading}
|
||||
sx={sx}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -51,6 +54,7 @@ const QueueButton = ({
|
||||
isLoading={isLoading}
|
||||
loadingText={loadingText ?? label}
|
||||
flexGrow={1}
|
||||
sx={sx}
|
||||
>
|
||||
{label}
|
||||
</IAIButton>
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useIsReadyToEnqueue } from 'common/hooks/useIsReadyToEnqueue';
|
||||
import { clampSymmetrySteps } from 'features/parameters/store/generationSlice';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useEnqueueBatchMutation } from 'services/api/endpoints/queue';
|
||||
|
||||
export const useQueueBack = () => {
|
||||
@@ -23,16 +22,5 @@ export const useQueueBack = () => {
|
||||
dispatch(enqueueRequested({ tabName, prepend: false }));
|
||||
}, [dispatch, isDisabled, tabName]);
|
||||
|
||||
useHotkeys(
|
||||
['ctrl+enter', 'meta+enter'],
|
||||
queueBack,
|
||||
{
|
||||
enabled: () => !isDisabled && !isLoading,
|
||||
preventDefault: true,
|
||||
enableOnFormTags: ['input', 'textarea', 'select'],
|
||||
},
|
||||
[tabName, isDisabled, isLoading]
|
||||
);
|
||||
|
||||
return { queueBack, isLoading, isDisabled };
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@ import { useIsReadyToEnqueue } from 'common/hooks/useIsReadyToEnqueue';
|
||||
import { clampSymmetrySteps } from 'features/parameters/store/generationSlice';
|
||||
import { activeTabNameSelector } from 'features/ui/store/uiSelectors';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useEnqueueBatchMutation } from 'services/api/endpoints/queue';
|
||||
|
||||
export const useQueueFront = () => {
|
||||
@@ -23,16 +22,5 @@ export const useQueueFront = () => {
|
||||
dispatch(enqueueRequested({ tabName, prepend: true }));
|
||||
}, [dispatch, isDisabled, tabName]);
|
||||
|
||||
useHotkeys(
|
||||
['ctrl+shift+enter', 'meta+shift+enter'],
|
||||
queueFront,
|
||||
{
|
||||
enabled: () => !isDisabled && !isLoading,
|
||||
preventDefault: true,
|
||||
enableOnFormTags: ['input', 'textarea', 'select'],
|
||||
},
|
||||
[isLoading, isDisabled, tabName]
|
||||
);
|
||||
|
||||
return { queueFront, isLoading, isDisabled };
|
||||
};
|
||||
|
||||
@@ -44,9 +44,7 @@ const FloatingGalleryButton = ({
|
||||
p: 0,
|
||||
px: 3,
|
||||
h: 48,
|
||||
borderStartEndRadius: 0,
|
||||
borderEndEndRadius: 0,
|
||||
shadow: '2xl',
|
||||
borderEndRadius: 0,
|
||||
}}
|
||||
/>
|
||||
</Flex>
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
import { ChakraProps, Flex, Portal } from '@chakra-ui/react';
|
||||
import { ButtonGroup, ChakraProps, Flex, Portal } from '@chakra-ui/react';
|
||||
import IAIIconButton from 'common/components/IAIIconButton';
|
||||
import CancelCurrentQueueItemButton from 'features/queue/components/CancelCurrentQueueItemButton';
|
||||
import ClearQueueButton from 'features/queue/components/ClearQueueButton';
|
||||
import QueueBackButton from 'features/queue/components/QueueBackButton';
|
||||
import { RefObject, memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
@@ -7,9 +10,8 @@ import { FaSlidersH } from 'react-icons/fa';
|
||||
import { ImperativePanelHandle } from 'react-resizable-panels';
|
||||
|
||||
const floatingButtonStyles: ChakraProps['sx'] = {
|
||||
borderStartStartRadius: 0,
|
||||
borderEndStartRadius: 0,
|
||||
shadow: '2xl',
|
||||
borderStartRadius: 0,
|
||||
flexGrow: 1,
|
||||
};
|
||||
|
||||
type Props = {
|
||||
@@ -41,14 +43,23 @@ const FloatingSidePanelButtons = ({
|
||||
insetInlineStart="5.13rem"
|
||||
direction="column"
|
||||
gap={2}
|
||||
h={48}
|
||||
>
|
||||
<IAIIconButton
|
||||
tooltip="Show Side Panel (O, T)"
|
||||
aria-label={t('common.showOptionsPanel')}
|
||||
onClick={handleShowSidePanel}
|
||||
sx={floatingButtonStyles}
|
||||
icon={<FaSlidersH />}
|
||||
/>
|
||||
<ButtonGroup isAttached orientation="vertical" flexGrow={3}>
|
||||
<IAIIconButton
|
||||
tooltip="Show Side Panel (O, T)"
|
||||
aria-label={t('common.showOptionsPanel')}
|
||||
onClick={handleShowSidePanel}
|
||||
sx={floatingButtonStyles}
|
||||
icon={<FaSlidersH />}
|
||||
/>
|
||||
<QueueBackButton asIconButton sx={floatingButtonStyles} />
|
||||
<CancelCurrentQueueItemButton
|
||||
asIconButton
|
||||
sx={floatingButtonStyles}
|
||||
/>
|
||||
</ButtonGroup>
|
||||
<ClearQueueButton asIconButton sx={floatingButtonStyles} />
|
||||
</Flex>
|
||||
</Portal>
|
||||
);
|
||||
|
||||
@@ -21,9 +21,9 @@ import { isEqual } from 'lodash-es';
|
||||
import { MouseEvent, ReactNode, memo, useCallback, useMemo } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { FaCube, FaFont, FaImage } from 'react-icons/fa';
|
||||
import { FaListOl } from 'react-icons/fa6';
|
||||
import { MdDeviceHub, MdGridOn } from 'react-icons/md';
|
||||
import { FaCube, FaFont, FaImage, FaStream } from 'react-icons/fa';
|
||||
import { FaCircleNodes } from 'react-icons/fa6';
|
||||
import { MdGridOn } from 'react-icons/md';
|
||||
import { Panel, PanelGroup } from 'react-resizable-panels';
|
||||
import { usePanel } from '../hooks/usePanel';
|
||||
import { usePanelStorage } from '../hooks/usePanelStorage';
|
||||
@@ -71,7 +71,9 @@ const tabs: InvokeTabInfo[] = [
|
||||
{
|
||||
id: 'nodes',
|
||||
translationKey: 'common.nodes',
|
||||
icon: <Icon as={MdDeviceHub} sx={{ boxSize: 6, pointerEvents: 'none' }} />,
|
||||
icon: (
|
||||
<Icon as={FaCircleNodes} sx={{ boxSize: 6, pointerEvents: 'none' }} />
|
||||
),
|
||||
content: <NodesTab />,
|
||||
},
|
||||
{
|
||||
@@ -83,7 +85,7 @@ const tabs: InvokeTabInfo[] = [
|
||||
{
|
||||
id: 'queue',
|
||||
translationKey: 'queue.queue',
|
||||
icon: <Icon as={FaListOl} sx={{ boxSize: 6, pointerEvents: 'none' }} />,
|
||||
icon: <Icon as={FaStream} sx={{ boxSize: 6, pointerEvents: 'none' }} />,
|
||||
content: <QueueTab />,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -8868,12 +8868,6 @@ export type components = {
|
||||
/** Ui Order */
|
||||
ui_order?: number;
|
||||
};
|
||||
/**
|
||||
* StableDiffusionOnnxModelFormat
|
||||
* @description An enumeration.
|
||||
* @enum {string}
|
||||
*/
|
||||
StableDiffusionOnnxModelFormat: "olive" | "onnx";
|
||||
/**
|
||||
* ControlNetModelFormat
|
||||
* @description An enumeration.
|
||||
@@ -8898,6 +8892,12 @@ export type components = {
|
||||
* @enum {string}
|
||||
*/
|
||||
StableDiffusion2ModelFormat: "checkpoint" | "diffusers";
|
||||
/**
|
||||
* StableDiffusionOnnxModelFormat
|
||||
* @description An enumeration.
|
||||
* @enum {string}
|
||||
*/
|
||||
StableDiffusionOnnxModelFormat: "olive" | "onnx";
|
||||
};
|
||||
responses: never;
|
||||
parameters: never;
|
||||
|
||||
Reference in New Issue
Block a user