How to save user entered data in a form for personalizations? #4517

Closed
opened 2026-02-21 18:06:50 -05:00 by yindo · 2 comments
Owner

Originally created by @lheng18 on GitHub (Jul 9, 2024).

Self Checks

  • I have searched for existing issues search for existing issues, including closed ones.
  • I confirm that I am using English to submit this report (我已阅读并同意 Language Policy).
  • 请务必使用英文提交 Issue,否则会被关闭。谢谢!:)
  • Please do not modify this template :) and fill in all the required fields.

1. Is this request related to a challenge you're experiencing? Tell me about your story.

Need to create a web site that allow users register and enter their own data through forms. How to integrate a regular database to the tool? Thanks!

2. Additional context or comments

No response

3. Can you help us with this feature?

  • I am interested in contributing to this feature.
Originally created by @lheng18 on GitHub (Jul 9, 2024). ### Self Checks - [X] I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones. - [X] I confirm that I am using English to submit this report (我已阅读并同意 [Language Policy](https://github.com/langgenius/dify/issues/1542)). - [X] 请务必使用英文提交 Issue,否则会被关闭。谢谢!:) - [X] Please do not modify this template :) and fill in all the required fields. ### 1. Is this request related to a challenge you're experiencing? Tell me about your story. Need to create a web site that allow users register and enter their own data through forms. How to integrate a regular database to the tool? Thanks! ### 2. Additional context or comments _No response_ ### 3. Can you help us with this feature? - [ ] I am interested in contributing to this feature.
yindo added the 🙋‍♂️ question label 2026-02-21 18:06:50 -05:00
yindo closed this issue 2026-02-21 18:06:50 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Jul 9, 2024):

@lheng18 Hello there! I'm a bot here to help you with bugs, questions, and becoming a contributor. While you wait for a human maintainer, feel free to ask me anything.

To save user-entered data in a form for personalizations in Dify, you can follow these steps:

  1. Define the Form Schema: Use a schema validation library like zod to define the structure and validation rules for your form data.
  2. Create the Form Component: Use a form handling library like react-hook-form to create the form component.
  3. Handle Form Submission: Implement a function to handle form submission, which will send the form data to the backend service.
  4. Link to Database: Ensure that the backend service is configured to store the form data in the database.

Here is an example based on the provided code:

Step 1: Define the Form Schema

const accountFormSchema = z.object({
  email: z
    .string()
    .min(1, { message: 'login.error.emailInValid' })
    .email('login.error.emailInValid'),
  name: z.string().min(1, { message: 'login.error.nameEmpty' }),
  password: z.string().min(8, {
    message: 'login.error.passwordLengthInValid',
  }).regex(validPassword, 'login.error.passwordInvalid'),
});

Step 2: Create the Form Component

const InstallForm = () => {
  const { t } = useTranslation();
  const router = useRouter();
  const [showPassword, setShowPassword] = React.useState(false);
  const [loading, setLoading] = React.useState(true);
  const {
    register,
    handleSubmit,
    formState: { errors },
  } = useForm<AccountFormValues>({
    resolver: zodResolver(accountFormSchema),
    defaultValues: {
      name: '',
      password: '',
      email: '',
    },
  });

  const onSubmit: SubmitHandler<AccountFormValues> = async (data) => {
    await setup({
      body: {
        ...data,
      },
    });
    router.push('/signin');
  };

  const handleSetting = async () => {
    handleSubmit(onSubmit)();
  };

  useEffect(() => {
    fetchSetupStatus().then((res: SetupStatusResponse) => {
      if (res.step === 'finished') {
        window.location.href = '/signin';
      } else {
        fetchInitValidateStatus().then((res: InitValidateStatusResponse) => {
          if (res.status === 'not_started')
            window.location.href = '/init';
        });
      }
      setLoading(false);
    });
  }, []);

  return (
    loading
      ? <Loading />
      : <>
        <div className="sm:mx-auto sm:w-full sm:max-w-md">
          <h2 className="text-[32px] font-bold text-gray-900">{t('login.setAdminAccount')}</h2>
          <p className='mt-1 text-sm text-gray-600'>{t('login.setAdminAccountDesc')}</p>
        </div>
        <div className="grow mt-8 sm:mx-auto sm:w-full sm:max-w-md">
          <div className="bg-white">
            <form onSubmit={handleSubmit(onSubmit)}>
              <div className='mb-5'>
                <label htmlFor="email" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900">
                  {t('login.email')}
                </label>
                <div className="mt-1">
                  <input
                    {...register('email')}
                    placeholder={t('login.emailPlaceholder') || ''}
                    className={'appearance-none block w-full rounded-lg pl-[14px] px-3 py-2 border border-gray-200 hover:border-gray-300 hover:shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 placeholder-gray-400 caret-primary-600 sm:text-sm'}
                  />
                  {errors.email && <span className='text-red-400 text-sm'>{t(`${errors.email?.message}`)}</span>}
                </div>
              </div>
              <div className='mb-5'>
                <label htmlFor="name" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900">
                  {t('login.name')}
                </label>
                <div className="mt-1 relative rounded-md shadow-sm">
                  <input
                    {...register('name')}
                    placeholder={t('login.namePlaceholder') || ''}
                    className={'appearance-none block w-full rounded-lg pl-[14px] px-3 py-2 border border-gray-200 hover:border-gray-300 hover:shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 placeholder-gray-400 caret-primary-600 sm:text-sm pr-10'}
                  />
                </div>
                {errors.name && <span className='text-red-400 text-sm'>{t(`${errors.name.message}`)}</span>}
              </div>
              <div className='mb-5'>
                <label htmlFor="password" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900">
                  {t('login.password')}
                </label>
                <div className="mt-1 relative rounded-md shadow-sm">
                  <input
                    {...register('password')}
                    type={showPassword ? 'text' : 'password'}
                    placeholder={t('login.passwordPlaceholder') || ''}
                    className={'appearance-none block w-full rounded-lg pl-[14px] px-3 py-2 border border-gray-200 hover:border-gray-300 hover:shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 placeholder-gray-400 caret-primary-600 sm:text-sm pr-10'}
                  />
                  <div className="absolute inset-y-0 right-0 flex items-center pr-3">
                    <button
                      type="button"
                      onClick={() => setShowPassword(!showPassword)}
                      className="text-gray-400 hover:text-gray-500 focus:outline-none focus:text-gray-500"
                    >
                      {showPassword ? '👀' : '😝'}
                    </button>
                  </div>
                </div>
                <div className={classNames('mt-1 text-xs text-gray-500', {
                  'text-red-400 !text-sm': errors.password,
                })}>{t('login.error.passwordInvalid')}</div>
              </div>
              <div>
                <Button variant='primary' className='w-full' onClick={handleSetting}>
                  {t('login.installBtn')}
                </Button>
              </div>
            </form>
            <div className="block w-hull mt-2 text-xs text-gray-600">
              {t('login.license.tip')}
              &nbsp;
              <Link
                className='text-primary-600'
                target='_blank' rel='noopener noreferrer'
                href={'https://docs.dify.ai/user-agreement/open-source'}
              >{t('login.license.link')}</Link>
            </div>
          </div>
        </div>
      </>
  );
};

export default InstallForm;

Step 3: Handle Form Submission

The onSubmit function handles the form submission and sends the data to the backend service using the setup function.

Step 4: Link to Database

Ensure that the setup function in your backend service is configured to store the form data in the database. This function should handle the necessary database operations to save the user data.

const onSubmit: SubmitHandler<AccountFormValues> = async (data) => {
  await setup({
    body: {
      ...data,
    },
  });
  router.push('/signin');
};

This code snippet demonstrates how to create a custom user registration form in Dify and link it to the database for storing user data [1].

To continue talking to Dosu, mention @dosu.

@dosubot[bot] commented on GitHub (Jul 9, 2024): <!-- Greeting --> @lheng18 Hello there! I'm a bot here to help you with bugs, questions, and becoming a contributor. While you wait for a human maintainer, feel free to ask me anything. <!-- Answer --> To save user-entered data in a form for personalizations in Dify, you can follow these steps: 1. **Define the Form Schema**: Use a schema validation library like `zod` to define the structure and validation rules for your form data. 2. **Create the Form Component**: Use a form handling library like `react-hook-form` to create the form component. 3. **Handle Form Submission**: Implement a function to handle form submission, which will send the form data to the backend service. 4. **Link to Database**: Ensure that the backend service is configured to store the form data in the database. Here is an example based on the provided code: ### Step 1: Define the Form Schema ```tsx const accountFormSchema = z.object({ email: z .string() .min(1, { message: 'login.error.emailInValid' }) .email('login.error.emailInValid'), name: z.string().min(1, { message: 'login.error.nameEmpty' }), password: z.string().min(8, { message: 'login.error.passwordLengthInValid', }).regex(validPassword, 'login.error.passwordInvalid'), }); ``` ### Step 2: Create the Form Component ```tsx const InstallForm = () => { const { t } = useTranslation(); const router = useRouter(); const [showPassword, setShowPassword] = React.useState(false); const [loading, setLoading] = React.useState(true); const { register, handleSubmit, formState: { errors }, } = useForm<AccountFormValues>({ resolver: zodResolver(accountFormSchema), defaultValues: { name: '', password: '', email: '', }, }); const onSubmit: SubmitHandler<AccountFormValues> = async (data) => { await setup({ body: { ...data, }, }); router.push('/signin'); }; const handleSetting = async () => { handleSubmit(onSubmit)(); }; useEffect(() => { fetchSetupStatus().then((res: SetupStatusResponse) => { if (res.step === 'finished') { window.location.href = '/signin'; } else { fetchInitValidateStatus().then((res: InitValidateStatusResponse) => { if (res.status === 'not_started') window.location.href = '/init'; }); } setLoading(false); }); }, []); return ( loading ? <Loading /> : <> <div className="sm:mx-auto sm:w-full sm:max-w-md"> <h2 className="text-[32px] font-bold text-gray-900">{t('login.setAdminAccount')}</h2> <p className='mt-1 text-sm text-gray-600'>{t('login.setAdminAccountDesc')}</p> </div> <div className="grow mt-8 sm:mx-auto sm:w-full sm:max-w-md"> <div className="bg-white"> <form onSubmit={handleSubmit(onSubmit)}> <div className='mb-5'> <label htmlFor="email" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900"> {t('login.email')} </label> <div className="mt-1"> <input {...register('email')} placeholder={t('login.emailPlaceholder') || ''} className={'appearance-none block w-full rounded-lg pl-[14px] px-3 py-2 border border-gray-200 hover:border-gray-300 hover:shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 placeholder-gray-400 caret-primary-600 sm:text-sm'} /> {errors.email && <span className='text-red-400 text-sm'>{t(`${errors.email?.message}`)}</span>} </div> </div> <div className='mb-5'> <label htmlFor="name" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900"> {t('login.name')} </label> <div className="mt-1 relative rounded-md shadow-sm"> <input {...register('name')} placeholder={t('login.namePlaceholder') || ''} className={'appearance-none block w-full rounded-lg pl-[14px] px-3 py-2 border border-gray-200 hover:border-gray-300 hover:shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 placeholder-gray-400 caret-primary-600 sm:text-sm pr-10'} /> </div> {errors.name && <span className='text-red-400 text-sm'>{t(`${errors.name.message}`)}</span>} </div> <div className='mb-5'> <label htmlFor="password" className="my-2 flex items-center justify-between text-sm font-medium text-gray-900"> {t('login.password')} </label> <div className="mt-1 relative rounded-md shadow-sm"> <input {...register('password')} type={showPassword ? 'text' : 'password'} placeholder={t('login.passwordPlaceholder') || ''} className={'appearance-none block w-full rounded-lg pl-[14px] px-3 py-2 border border-gray-200 hover:border-gray-300 hover:shadow-sm focus:outline-none focus:ring-primary-500 focus:border-primary-500 placeholder-gray-400 caret-primary-600 sm:text-sm pr-10'} /> <div className="absolute inset-y-0 right-0 flex items-center pr-3"> <button type="button" onClick={() => setShowPassword(!showPassword)} className="text-gray-400 hover:text-gray-500 focus:outline-none focus:text-gray-500" > {showPassword ? '👀' : '😝'} </button> </div> </div> <div className={classNames('mt-1 text-xs text-gray-500', { 'text-red-400 !text-sm': errors.password, })}>{t('login.error.passwordInvalid')}</div> </div> <div> <Button variant='primary' className='w-full' onClick={handleSetting}> {t('login.installBtn')} </Button> </div> </form> <div className="block w-hull mt-2 text-xs text-gray-600"> {t('login.license.tip')} &nbsp; <Link className='text-primary-600' target='_blank' rel='noopener noreferrer' href={'https://docs.dify.ai/user-agreement/open-source'} >{t('login.license.link')}</Link> </div> </div> </div> </> ); }; export default InstallForm; ``` ### Step 3: Handle Form Submission The `onSubmit` function handles the form submission and sends the data to the backend service using the `setup` function. ### Step 4: Link to Database Ensure that the `setup` function in your backend service is configured to store the form data in the database. This function should handle the necessary database operations to save the user data. ```tsx const onSubmit: SubmitHandler<AccountFormValues> = async (data) => { await setup({ body: { ...data, }, }); router.push('/signin'); }; ``` This code snippet demonstrates how to create a custom user registration form in Dify and link it to the database for storing user data <sup>[[1]](https://github.com/langgenius/dify/blob/main/web/app/install/installForm.tsx)</sup>. <!-- Dosu Comment Footer --> *To continue talking to [Dosu](https://dosu.dev), mention @dosu.*
Author
Owner

@crazywoola commented on GitHub (Jul 9, 2024):

See this repo https://github.com/crazywoola/dify-tools-worker. You can create an external service to store user related data.

@crazywoola commented on GitHub (Jul 9, 2024): See this repo https://github.com/crazywoola/dify-tools-worker. You can create an external service to store user related data.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#4517