Skip to content

Commit 3dff87a

Browse files
feat(ui): better layout for generator load from file buttons
1 parent b14bf1e commit 3dff87a

7 files changed

+110
-186
lines changed

invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/FloatGeneratorParseStringSettings.tsx

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Flex, FormControl, FormLabel, Input, Textarea } from '@invoke-ai/ui-library';
2-
import { LoadTextFromFileIconButton } from 'features/nodes/components/flow/nodes/Invocation/fields/inputs/LoadTextFromFileIconButton';
1+
import { Flex, FormControl, FormLabel, Input } from '@invoke-ai/ui-library';
2+
import { GeneratorTextareaWithFileUpload } from 'features/nodes/components/flow/nodes/Invocation/fields/inputs/GeneratorTextareaWithFileUpload';
33
import type { FloatGeneratorParseString } from 'features/nodes/types/field';
44
import type { ChangeEvent } from 'react';
55
import { memo, useCallback } from 'react';
@@ -20,15 +20,8 @@ export const FloatGeneratorParseStringSettings = memo(({ state, onChange }: Floa
2020
);
2121

2222
const onChangeInput = useCallback(
23-
(e: ChangeEvent<HTMLTextAreaElement>) => {
24-
onChange({ ...state, input: e.target.value });
25-
},
26-
[onChange, state]
27-
);
28-
29-
const onLoadFile = useCallback(
30-
(value: string) => {
31-
onChange({ ...state, input: value });
23+
(input: string) => {
24+
onChange({ ...state, input });
3225
},
3326
[onChange, state]
3427
);
@@ -39,19 +32,7 @@ export const FloatGeneratorParseStringSettings = memo(({ state, onChange }: Floa
3932
<FormLabel>{t('nodes.splitOn')}</FormLabel>
4033
<Input value={state.splitOn} onChange={onChangeSplitOn} />
4134
</FormControl>
42-
<FormControl orientation="vertical" position="relative">
43-
<FormLabel>{t('common.input')}</FormLabel>
44-
<Textarea
45-
className="nowheel nodrag nopan"
46-
value={state.input}
47-
onChange={onChangeInput}
48-
p={2}
49-
resize="none"
50-
rows={5}
51-
fontSize="sm"
52-
/>
53-
<LoadTextFromFileIconButton position="absolute" top={10} right={2} onLoadFile={onLoadFile} />
54-
</FormControl>
35+
<GeneratorTextareaWithFileUpload value={state.input} onChange={onChangeInput} />
5536
</Flex>
5637
);
5738
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { FormControl, FormLabel, IconButton, Spacer, Textarea } from '@invoke-ai/ui-library';
2+
import { toast } from 'features/toast/toast';
3+
import { isString } from 'lodash-es';
4+
import type { ChangeEvent } from 'react';
5+
import { memo, useCallback } from 'react';
6+
import { useDropzone } from 'react-dropzone';
7+
import { useTranslation } from 'react-i18next';
8+
import { PiUploadFill } from 'react-icons/pi';
9+
10+
const MAX_SIZE = 1024 * 128; // 128KB, we don't want to load huge files into node values...
11+
12+
type Props = {
13+
value: string;
14+
onChange: (value: string) => void;
15+
};
16+
17+
export const GeneratorTextareaWithFileUpload = memo(({ value, onChange }: Props) => {
18+
const { t } = useTranslation();
19+
const onDropAccepted = useCallback(
20+
(files: File[]) => {
21+
const file = files[0];
22+
if (!file) {
23+
return;
24+
}
25+
const reader = new FileReader();
26+
reader.onload = () => {
27+
const result = reader.result;
28+
if (!isString(result)) {
29+
return;
30+
}
31+
onChange(result);
32+
};
33+
reader.onerror = () => {
34+
toast({
35+
title: 'Failed to load file',
36+
status: 'error',
37+
});
38+
};
39+
reader.readAsText(file);
40+
},
41+
[onChange]
42+
);
43+
44+
const { getInputProps, getRootProps } = useDropzone({
45+
accept: { 'text/csv': ['.csv'], 'text/plain': ['.txt'] },
46+
maxSize: MAX_SIZE,
47+
onDropAccepted,
48+
noDrag: true,
49+
multiple: false,
50+
});
51+
52+
const onChangeInput = useCallback(
53+
(e: ChangeEvent<HTMLTextAreaElement>) => {
54+
onChange(e.target.value);
55+
},
56+
[onChange]
57+
);
58+
59+
return (
60+
<FormControl orientation="vertical" position="relative" alignItems="stretch">
61+
<FormLabel m={0} display="flex" alignItems="center">
62+
{t('common.input')}
63+
<Spacer />
64+
<IconButton
65+
tooltip="Load from file"
66+
aria-label="Load from file"
67+
icon={<PiUploadFill />}
68+
variant="link"
69+
{...getRootProps()}
70+
/>
71+
<input {...getInputProps()} />
72+
</FormLabel>
73+
<Textarea
74+
className="nowheel nodrag nopan"
75+
value={value}
76+
onChange={onChangeInput}
77+
p={2}
78+
resize="none"
79+
rows={5}
80+
fontSize="sm"
81+
/>
82+
</FormControl>
83+
);
84+
});
85+
GeneratorTextareaWithFileUpload.displayName = 'GeneratorTextareaWithFileUpload';

invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/IntegerGeneratorParseStringSettings.tsx

Lines changed: 5 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { Flex, FormControl, FormLabel, Input, Textarea } from '@invoke-ai/ui-library';
2-
import { LoadTextFromFileIconButton } from 'features/nodes/components/flow/nodes/Invocation/fields/inputs/LoadTextFromFileIconButton';
1+
import { Flex, FormControl, FormLabel, Input } from '@invoke-ai/ui-library';
2+
import { GeneratorTextareaWithFileUpload } from 'features/nodes/components/flow/nodes/Invocation/fields/inputs/GeneratorTextareaWithFileUpload';
33
import type { IntegerGeneratorParseString } from 'features/nodes/types/field';
44
import type { ChangeEvent } from 'react';
55
import { memo, useCallback } from 'react';
@@ -21,15 +21,8 @@ export const IntegerGeneratorParseStringSettings = memo(
2121
);
2222

2323
const onChangeInput = useCallback(
24-
(e: ChangeEvent<HTMLTextAreaElement>) => {
25-
onChange({ ...state, input: e.target.value });
26-
},
27-
[onChange, state]
28-
);
29-
30-
const onLoadFile = useCallback(
31-
(value: string) => {
32-
onChange({ ...state, input: value });
24+
(input: string) => {
25+
onChange({ ...state, input });
3326
},
3427
[onChange, state]
3528
);
@@ -40,19 +33,7 @@ export const IntegerGeneratorParseStringSettings = memo(
4033
<FormLabel>{t('nodes.splitOn')}</FormLabel>
4134
<Input value={state.splitOn} onChange={onChangeSplitOn} />
4235
</FormControl>
43-
<FormControl orientation="vertical" position="relative">
44-
<FormLabel>{t('common.input')}</FormLabel>
45-
<Textarea
46-
className="nowheel nodrag nopan"
47-
value={state.input}
48-
onChange={onChangeInput}
49-
p={2}
50-
resize="none"
51-
rows={5}
52-
fontSize="sm"
53-
/>
54-
<LoadTextFromFileIconButton position="absolute" top={10} right={2} onLoadFile={onLoadFile} />
55-
</FormControl>
36+
<GeneratorTextareaWithFileUpload value={state.input} onChange={onChangeInput} />
5637
</Flex>
5738
);
5839
}

invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/LoadTextFromFileIconButton.tsx

Lines changed: 0 additions & 64 deletions
This file was deleted.

invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/StringGeneratorDynamicPromptsCombinatorialSettings.tsx

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1-
import { CompositeNumberInput, Flex, FormControl, FormLabel, Textarea } from '@invoke-ai/ui-library';
2-
import { LoadTextFromFileIconButton } from 'features/nodes/components/flow/nodes/Invocation/fields/inputs/LoadTextFromFileIconButton';
1+
import { CompositeNumberInput, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
2+
import { GeneratorTextareaWithFileUpload } from 'features/nodes/components/flow/nodes/Invocation/fields/inputs/GeneratorTextareaWithFileUpload';
33
import type { StringGeneratorDynamicPromptsCombinatorial } from 'features/nodes/types/field';
4-
import type { ChangeEvent } from 'react';
54
import { memo, useCallback, useEffect, useMemo } from 'react';
65
import { useTranslation } from 'react-i18next';
76
import { useDynamicPromptsQuery } from 'services/api/endpoints/utilities';
@@ -17,8 +16,8 @@ export const StringGeneratorDynamicPromptsCombinatorialSettings = memo(
1716
const loadingValues = useMemo(() => [`<${t('nodes.generatorLoading')}>`], [t]);
1817

1918
const onChangeInput = useCallback(
20-
(e: ChangeEvent<HTMLTextAreaElement>) => {
21-
onChange({ ...state, input: e.target.value, values: loadingValues });
19+
(input: string) => {
20+
onChange({ ...state, input, values: loadingValues });
2221
},
2322
[onChange, state, loadingValues]
2423
);
@@ -47,32 +46,13 @@ export const StringGeneratorDynamicPromptsCombinatorialSettings = memo(
4746
}
4847
}, [data, isLoading, loadingValues, onChange, state]);
4948

50-
const onLoadFile = useCallback(
51-
(value: string) => {
52-
onChange({ ...state, input: value });
53-
},
54-
[onChange, state]
55-
);
56-
5749
return (
5850
<Flex gap={2} flexDir="column">
5951
<FormControl orientation="vertical">
6052
<FormLabel>{t('dynamicPrompts.maxPrompts')}</FormLabel>
6153
<CompositeNumberInput value={state.maxPrompts} onChange={onChangeMaxPrompts} min={1} max={1000} w="full" />
6254
</FormControl>
63-
<FormControl orientation="vertical" position="relative">
64-
<FormLabel>{t('common.input')}</FormLabel>
65-
<Textarea
66-
className="nowheel nodrag nopan"
67-
value={state.input}
68-
onChange={onChangeInput}
69-
p={2}
70-
resize="none"
71-
rows={5}
72-
fontSize="sm"
73-
/>
74-
<LoadTextFromFileIconButton position="absolute" top={10} right={2} onLoadFile={onLoadFile} />
75-
</FormControl>
55+
<GeneratorTextareaWithFileUpload value={state.input} onChange={onChangeInput} />
7656
</Flex>
7757
);
7858
}

invokeai/frontend/web/src/features/nodes/components/flow/nodes/Invocation/fields/inputs/StringGeneratorDynamicPromptsRandomSettings.tsx

Lines changed: 5 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
import { Checkbox, CompositeNumberInput, Flex, FormControl, FormLabel, Textarea } from '@invoke-ai/ui-library';
2-
import { LoadTextFromFileIconButton } from 'features/nodes/components/flow/nodes/Invocation/fields/inputs/LoadTextFromFileIconButton';
1+
import { Checkbox, CompositeNumberInput, Flex, FormControl, FormLabel } from '@invoke-ai/ui-library';
2+
import { GeneratorTextareaWithFileUpload } from 'features/nodes/components/flow/nodes/Invocation/fields/inputs/GeneratorTextareaWithFileUpload';
33
import type { StringGeneratorDynamicPromptsRandom } from 'features/nodes/types/field';
44
import { isNil, random } from 'lodash-es';
5-
import type { ChangeEvent } from 'react';
65
import { memo, useCallback, useEffect, useMemo } from 'react';
76
import { useTranslation } from 'react-i18next';
87
import { useDynamicPromptsQuery } from 'services/api/endpoints/utilities';
@@ -18,8 +17,8 @@ export const StringGeneratorDynamicPromptsRandomSettings = memo(
1817
const loadingValues = useMemo(() => [`<${t('nodes.generatorLoading')}>`], [t]);
1918

2019
const onChangeInput = useCallback(
21-
(e: ChangeEvent<HTMLTextAreaElement>) => {
22-
onChange({ ...state, input: e.target.value, values: loadingValues });
20+
(input: string) => {
21+
onChange({ ...state, input, values: loadingValues });
2322
},
2423
[onChange, state, loadingValues]
2524
);
@@ -39,13 +38,6 @@ export const StringGeneratorDynamicPromptsRandomSettings = memo(
3938
[onChange, state, loadingValues]
4039
);
4140

42-
const onLoadFile = useCallback(
43-
(value: string) => {
44-
onChange({ ...state, input: value });
45-
},
46-
[onChange, state]
47-
);
48-
4941
const arg = useMemo(() => {
5042
const { input, count, seed } = state;
5143
return { prompt: input, max_prompts: count, combinatorial: false, seed: seed ?? random() };
@@ -87,19 +79,7 @@ export const StringGeneratorDynamicPromptsRandomSettings = memo(
8779
<CompositeNumberInput value={state.count} onChange={onChangeCount} min={1} max={1000} />
8880
</FormControl>
8981
</Flex>
90-
<FormControl orientation="vertical" position="relative">
91-
<FormLabel>{t('common.input')}</FormLabel>
92-
<Textarea
93-
className="nowheel nodrag nopan"
94-
value={state.input}
95-
onChange={onChangeInput}
96-
p={2}
97-
resize="none"
98-
rows={5}
99-
fontSize="sm"
100-
/>
101-
<LoadTextFromFileIconButton position="absolute" top={10} right={2} onLoadFile={onLoadFile} />
102-
</FormControl>
82+
<GeneratorTextareaWithFileUpload value={state.input} onChange={onChangeInput} />
10383
</Flex>
10484
);
10585
}

0 commit comments

Comments
 (0)