Skip to content

Commit 6fe67ca

Browse files
author
Roman Snapko
committed
Update connections page
1 parent a159a69 commit 6fe67ca

3 files changed

Lines changed: 137 additions & 412 deletions

File tree

packages/react-ui/src/app/features/ai/ai-settings-form.tsx

Lines changed: 48 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,157 +1,92 @@
1-
import {
2-
aiFormSchemaResolver,
3-
AiSettingsFormSchema,
4-
} from '@/app/features/ai/lib/ai-form-utils';
51
import { ConnectionSelect } from '@/app/features/builder/step-settings/block-settings/connection-select';
62
import {
73
BlockMetadataModel,
84
BlockMetadataModelSummary,
95
} from '@openops/blocks-framework';
10-
import {
11-
Button,
12-
Form,
13-
FormField,
14-
FormItem,
15-
Label,
16-
Switch,
17-
} from '@openops/components/ui';
18-
import { AiConfig } from '@openops/shared';
6+
import { Form } from '@openops/components/ui';
7+
import { removeConnectionBrackets } from '@openops/shared';
198
import equal from 'fast-deep-equal';
20-
import { t } from 'i18next';
21-
import { CircleCheck } from 'lucide-react';
22-
import React, { useEffect, useMemo, useState } from 'react';
9+
import debounce from 'lodash.debounce';
10+
import React, { useEffect, useMemo, useRef, useState } from 'react';
2311
import { useForm } from 'react-hook-form';
2412

2513
type AiSettingsFormProps = {
2614
block: BlockMetadataModelSummary | BlockMetadataModel;
27-
savedSettings?: AiConfig;
28-
onSave: (settings: AiSettingsFormSchema) => void;
29-
isSaving: boolean;
15+
providerKey: string;
16+
initialConnection?: string;
17+
onSave: (connectionName: string) => void;
18+
displayName?: string;
19+
disabled?: boolean;
3020
};
3121

32-
export const EMPTY_FORM_VALUE: AiSettingsFormSchema = {
33-
enabled: false,
22+
type LocalForm = { connection: string };
23+
24+
export const EMPTY_FORM_VALUE: LocalForm = {
3425
connection: '',
3526
};
3627

3728
const AiSettingsForm = ({
3829
block,
39-
savedSettings,
30+
providerKey,
31+
initialConnection,
4032
onSave,
41-
isSaving,
33+
displayName,
34+
disabled = false,
4235
}: AiSettingsFormProps) => {
43-
const form = useForm<AiSettingsFormSchema>({
44-
resolver: aiFormSchemaResolver,
36+
const form = useForm<LocalForm>({
4537
defaultValues: EMPTY_FORM_VALUE,
4638
mode: 'onChange',
4739
});
4840
const [initialFormValue, setInitialFormValue] =
49-
useState<AiSettingsFormSchema>(EMPTY_FORM_VALUE);
41+
useState<LocalForm>(EMPTY_FORM_VALUE);
5042

5143
useEffect(() => {
52-
const formValue: AiSettingsFormSchema = {
53-
enabled: savedSettings?.enabled ?? false,
54-
connection: savedSettings?.connection ?? '',
44+
const formValue: LocalForm = {
45+
connection: initialConnection ?? '',
5546
};
5647
setInitialFormValue(formValue);
5748
form.reset(formValue);
58-
}, [savedSettings, form]);
49+
}, [initialConnection, form]);
5950

6051
const currentFormValue = form.watch();
52+
const watchedConnection = form.watch('connection');
6153

6254
const isFormUnchanged = useMemo(() => {
6355
return equal(currentFormValue, initialFormValue);
6456
}, [currentFormValue, initialFormValue]);
6557

66-
const isValidConnection = useMemo(() => {
67-
const omit = (obj?: AiSettingsFormSchema) => {
68-
const { enabled, ...rest } = obj ?? EMPTY_FORM_VALUE;
69-
return rest;
70-
};
71-
72-
return equal(omit(currentFormValue), omit(initialFormValue));
73-
}, [currentFormValue, initialFormValue]);
74-
75-
const resetForm = () => {
76-
form.reset();
77-
};
58+
const debouncedSave = useMemo(
59+
() =>
60+
debounce((connection: string, unchanged: boolean) => {
61+
if (!unchanged) {
62+
onSave(connection);
63+
setInitialFormValue({ connection });
64+
}
65+
}, 300),
66+
[onSave],
67+
);
7868

79-
const onSaveClick = () => {
80-
const formValue = form.getValues();
81-
onSave({
82-
...savedSettings,
83-
...formValue,
84-
});
85-
};
69+
useEffect(() => {
70+
debouncedSave(watchedConnection ?? '', isFormUnchanged);
71+
}, [debouncedSave, watchedConnection, isFormUnchanged]);
8672

87-
const descriptionText = t(
88-
'Enables OpenOps Assistant and other AI-powered features such as the CLI command generation.',
89-
);
73+
useEffect(() => {
74+
return () => {
75+
debouncedSave.cancel();
76+
};
77+
}, [debouncedSave]);
9078

9179
return (
9280
<Form {...form}>
93-
<form className="flex-1 flex flex-col gap-4">
94-
<FormField
95-
control={form.control}
96-
name="enabled"
97-
render={({ field }) => (
98-
<FormItem className="flex flex-col">
99-
<div className="flex items-center gap-[6px]">
100-
<Switch
101-
id="enabled"
102-
checked={field.value}
103-
onCheckedChange={field.onChange}
104-
/>
105-
<Label
106-
className="text-lg font-bold leading-6"
107-
htmlFor="enabled"
108-
>
109-
{t('Enable OpenOps AI')}
110-
</Label>
111-
</div>
112-
<p className="mt-8 text-base font-normal leading-6 text-primary-900">
113-
{descriptionText}
114-
</p>
115-
</FormItem>
116-
)}
81+
<form className="max-w-[516px]">
82+
<ConnectionSelect
83+
disabled={disabled}
84+
allowDynamicValues={false}
85+
block={block}
86+
providerKey={providerKey}
87+
name={'connection'}
88+
displayName={displayName}
11789
/>
118-
<div className="max-w-[516px]">
119-
<ConnectionSelect
120-
disabled={!currentFormValue.enabled}
121-
allowDynamicValues={false}
122-
block={block}
123-
providerKey={'AI'}
124-
name={'connection'}
125-
/>
126-
</div>
127-
128-
<div className="flex items-center justify-between max-w-[516px]">
129-
<div className="flex gap-2">
130-
<Button
131-
variant="outline"
132-
type="button"
133-
onClick={resetForm}
134-
disabled={isSaving || isFormUnchanged}
135-
>
136-
{t('Cancel')}
137-
</Button>
138-
<Button
139-
className="w-[95px]"
140-
type="button"
141-
disabled={!form.formState.isValid || isFormUnchanged}
142-
onClick={onSaveClick}
143-
loading={isSaving}
144-
>
145-
{t('Save')}
146-
</Button>
147-
</div>
148-
{savedSettings?.id && isValidConnection && (
149-
<div className="flex items-center gap-2">
150-
<CircleCheck size={24} className="text-success-300" />
151-
<span>{t('Valid Connection')}</span>
152-
</div>
153-
)}
154-
</div>
15590
</form>
15691
</Form>
15792
);

0 commit comments

Comments
 (0)