mirror of https://github.com/buster-so/buster.git
add success messages
This commit is contained in:
parent
0d2132f021
commit
f06e675e21
|
@ -32,7 +32,7 @@ const DataSourceFormHeader: React.FC<{ dataSource: DataSource }> = ({ dataSource
|
|||
<div className="flex justify-between space-x-2">
|
||||
<div className="flex items-center space-x-4">
|
||||
<div className="text-icon-color text-4xl">
|
||||
<AppDataSourceIcon size={55} type={dataSource.type} />
|
||||
<AppDataSourceIcon size={32} type={dataSource.type} />
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col space-y-1">
|
||||
|
|
|
@ -4,16 +4,51 @@ import React from 'react';
|
|||
import { WhiteListBlock } from './WhiteListBlock';
|
||||
import { FormApi } from '@tanstack/react-form';
|
||||
import { Button } from '@/components/ui/buttons';
|
||||
import { SubscribeButton } from '@/components/ui/form/FormBase';
|
||||
|
||||
// Common field interface properties
|
||||
interface FieldComponentProps {
|
||||
label: string | null;
|
||||
labelClassName?: string;
|
||||
className?: string;
|
||||
placeholder?: string;
|
||||
}
|
||||
|
||||
// Define a more specific but limited interface for our form
|
||||
// This avoids the deep type recursion while maintaining safety
|
||||
export interface BusterFormApi {
|
||||
handleSubmit: () => void;
|
||||
reset: () => void;
|
||||
state: {
|
||||
canSubmit: boolean;
|
||||
isSubmitting: boolean;
|
||||
isDirty: boolean;
|
||||
};
|
||||
AppForm: React.ComponentType<{ children?: React.ReactNode }>;
|
||||
AppField: any; // Using any for AppField to avoid type complexity
|
||||
SubscribeButton: React.ComponentType<{
|
||||
submitLabel: string;
|
||||
disableIfNotChanged?: boolean;
|
||||
useResetButton?: boolean;
|
||||
}>;
|
||||
}
|
||||
|
||||
// Field interface representing what's available inside the field prop
|
||||
interface FieldInterface {
|
||||
TextField: React.FC<FieldComponentProps>;
|
||||
NumberField: React.FC<FieldComponentProps>;
|
||||
PasswordField: React.FC<FieldComponentProps>;
|
||||
name: string;
|
||||
}
|
||||
|
||||
// Use a typed approach for the form
|
||||
export interface FormWrapperProps {
|
||||
children: React.ReactNode;
|
||||
flow: 'create' | 'update';
|
||||
form: FormApi<any, any, any, any, any, any, any, any, any, any>;
|
||||
form: BusterFormApi;
|
||||
}
|
||||
|
||||
export function FormWrapper({ form, children, flow }: FormWrapperProps) {
|
||||
console.log(form);
|
||||
|
||||
return (
|
||||
<form
|
||||
className="[&_.label-wrapper]:border-b-border flex flex-col space-y-4 [&_.label-wrapper]:border-b [&_.label-wrapper]:pb-4"
|
||||
|
@ -25,18 +60,12 @@ export function FormWrapper({ form, children, flow }: FormWrapperProps) {
|
|||
|
||||
<WhiteListBlock />
|
||||
|
||||
<div className="flex w-full justify-end space-x-2">
|
||||
<Button variant="ghost" type="reset" onClick={() => form.reset()}>
|
||||
Reset
|
||||
</Button>
|
||||
<Button
|
||||
variant="black"
|
||||
type="submit"
|
||||
disabled={!form.state.canSubmit}
|
||||
loading={form.state.isSubmitting}>
|
||||
{flow === 'create' ? 'Create' : 'Update'}
|
||||
</Button>
|
||||
</div>
|
||||
<form.AppForm>
|
||||
<form.SubscribeButton
|
||||
submitLabel={flow === 'create' ? 'Create' : 'Update'}
|
||||
disableIfNotChanged={flow === 'update'}
|
||||
/>
|
||||
</form.AppForm>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -8,32 +8,50 @@ import {
|
|||
} from '@/api/buster_rest/data_source';
|
||||
import { useAppForm } from '@/components/ui/form/useFormBaseHooks';
|
||||
import { MultipleInlineFields } from '@/components/ui/form/FormBase';
|
||||
import { useBusterNotifications } from '@/context/BusterNotifications';
|
||||
import { useRouter } from 'next/router';
|
||||
import { BusterRoutes, createBusterRoute } from '@/routes/busterRoutes';
|
||||
import { useConfetti } from '@/hooks/useConfetti';
|
||||
|
||||
export const PostgresForm: React.FC<{
|
||||
dataSource?: DataSource;
|
||||
}> = ({ dataSource }) => {
|
||||
const { fireConfetti } = useConfetti();
|
||||
const { openSuccessMessage, openConfirmModal } = useBusterNotifications();
|
||||
const router = useRouter();
|
||||
const { mutateAsync: createDataSource } = useCreatePostgresDataSource();
|
||||
const { mutateAsync: updateDataSource } = useUpdatePostgresDataSource();
|
||||
const credentials = dataSource?.credentials as PostgresCredentials;
|
||||
const credentials = dataSource?.credentials as PostgresCredentials | undefined;
|
||||
|
||||
const flow = dataSource?.id ? 'update' : 'create';
|
||||
|
||||
const form = useAppForm({
|
||||
defaultValues: {
|
||||
host: credentials.host || '',
|
||||
port: credentials.port || 5432,
|
||||
username: credentials.username || '',
|
||||
password: credentials.password || '',
|
||||
default_database: credentials.default_database || '',
|
||||
default_schema: credentials.default_schema || '',
|
||||
host: credentials?.host || '',
|
||||
port: credentials?.port || 5432,
|
||||
username: credentials?.username || '',
|
||||
password: credentials?.password || '',
|
||||
default_database: credentials?.default_database || '',
|
||||
default_schema: credentials?.default_schema || '',
|
||||
type: 'postgres' as const,
|
||||
name: dataSource?.name || credentials.name || ''
|
||||
name: dataSource?.name || credentials?.name || ''
|
||||
} satisfies Parameters<typeof createPostgresDataSource>[0],
|
||||
onSubmit: async ({ value }) => {
|
||||
if (flow === 'update' && dataSource?.id) {
|
||||
await updateDataSource({ id: dataSource.id, ...value });
|
||||
openSuccessMessage('Datasource updated');
|
||||
} else {
|
||||
await createDataSource(value);
|
||||
fireConfetti(9999);
|
||||
openConfirmModal({
|
||||
title: 'Datasource created',
|
||||
description: 'Datasource created successfully',
|
||||
content:
|
||||
'Hooray! Your datasource has been created. You can now use it in your projects. You will need to create datasets to use with it.',
|
||||
onOk: () => {
|
||||
router.push(createBusterRoute({ route: BusterRoutes.APP_DATASETS }));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -41,7 +59,7 @@ export const PostgresForm: React.FC<{
|
|||
const labelClassName = 'min-w-[175px]';
|
||||
|
||||
return (
|
||||
<FormWrapper form={form} flow={dataSource?.id ? 'update' : 'create'}>
|
||||
<FormWrapper form={form} flow={flow}>
|
||||
<form.AppField
|
||||
name="name"
|
||||
children={(field) => (
|
||||
|
|
|
@ -35,7 +35,7 @@ const workspaceItems: ISidebarGroup = {
|
|||
id: createBusterRoute({ route: BusterRoutes.SETTINGS_API_KEYS })
|
||||
},
|
||||
{
|
||||
label: 'Datasources',
|
||||
label: 'Data Sources',
|
||||
route: createBusterRoute({ route: BusterRoutes.SETTINGS_DATASOURCES }),
|
||||
id: createBusterRoute({ route: BusterRoutes.SETTINGS_DATASOURCES })
|
||||
}
|
||||
|
|
|
@ -154,15 +154,17 @@ export function MultipleInlineFields({
|
|||
|
||||
export function SubscribeButton({
|
||||
submitLabel,
|
||||
useResetButton = true
|
||||
useResetButton = true,
|
||||
disableIfNotChanged = false
|
||||
}: {
|
||||
submitLabel: string;
|
||||
useResetButton?: boolean;
|
||||
disableIfNotChanged?: boolean;
|
||||
}) {
|
||||
const form = useFormContext();
|
||||
|
||||
return (
|
||||
<form.Subscribe selector={(state) => [state.canSubmit, state.isSubmitting]}>
|
||||
<form.Subscribe selector={(state) => [state.canSubmit, state.isSubmitting, state.isDirty]}>
|
||||
{([canSubmit, isSubmitting]) => (
|
||||
<div className="flex w-full justify-end space-x-2">
|
||||
{useResetButton && (
|
||||
|
@ -170,7 +172,11 @@ export function SubscribeButton({
|
|||
Reset
|
||||
</Button>
|
||||
)}
|
||||
<Button variant="black" type="submit" disabled={!canSubmit} loading={isSubmitting}>
|
||||
<Button
|
||||
variant="black"
|
||||
type="submit"
|
||||
disabled={!canSubmit || (disableIfNotChanged && !form.state.isDirty)}
|
||||
loading={isSubmitting}>
|
||||
{submitLabel}
|
||||
</Button>
|
||||
</div>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { createFormHookContexts, createFormHook } from '@tanstack/react-form';
|
||||
import { createFormHook } from '@tanstack/react-form';
|
||||
import {
|
||||
NumberField,
|
||||
PasswordField,
|
||||
|
|
Loading…
Reference in New Issue