wwf
3 天以前 a430284aa21e3ae1f0d5654e55b2ad2852519cc2
app/components/app/overview/settings/index.tsx
@@ -162,20 +162,9 @@
      return check
    }
    const validatePrivacyPolicy = (privacyPolicy: string | null) => {
      if (privacyPolicy === null || privacyPolicy?.length === 0)
        return true
      return privacyPolicy.startsWith('http://') || privacyPolicy.startsWith('https://')
    }
    if (inputInfo !== null) {
      if (!validateColorHex(inputInfo.chatColorTheme)) {
        notify({ type: 'error', message: t(`${prefixSettings}.invalidHexMessage`) })
        return
      }
      if (!validatePrivacyPolicy(inputInfo.privacyPolicy)) {
        notify({ type: 'error', message: t(`${prefixSettings}.invalidPrivacyPolicy`) })
        return
      }
    }
@@ -232,24 +221,24 @@
        className='max-w-[520px] p-0'
      >
        {/* header */}
        <div className='pb-3 pl-6 pr-5 pt-5'>
        <div className='pl-6 pt-5 pr-5 pb-3'>
          <div className='flex items-center gap-1'>
            <div className='title-2xl-semi-bold grow text-text-primary'>{t(`${prefixSettings}.title`)}</div>
            <div className='grow text-text-primary title-2xl-semi-bold'>{t(`${prefixSettings}.title`)}</div>
            <ActionButton className='shrink-0' onClick={onHide}>
              <RiCloseLine className='h-4 w-4' />
              <RiCloseLine className='w-4 h-4' />
            </ActionButton>
          </div>
          <div className='system-xs-regular mt-0.5 text-text-tertiary'>
          <div className='mt-0.5 text-text-tertiary system-xs-regular'>
            <span>{t(`${prefixSettings}.modalTip`)}</span>
            <Link href={`${locale === LanguagesSupported[1] ? 'https://docs.dify.ai/zh-hans/guides/application-publishing/launch-your-webapp-quickly#she-zhi-ni-de-ai-zhan-dian' : 'https://docs.dify.ai/en/guides/application-publishing/launch-your-webapp-quickly/README'}`} target='_blank' rel='noopener noreferrer' className='text-text-accent'>{t('common.operation.learnMore')}</Link>
            <Link href={`${locale === LanguagesSupported[1] ? 'https://docs.dify.ai/zh-hans/guides/application-publishing/launch-your-webapp-quickly#she-zhi-ni-de-ai-zhan-dian' : 'https://docs.dify.ai/guides/application-publishing/launch-your-webapp-quickly#setting-up-your-ai-site'}`} target='_blank' rel='noopener noreferrer' className='text-text-accent'>{t('common.operation.learnMore')}</Link>
          </div>
        </div>
        {/* form body */}
        <div className='space-y-5 px-6 py-3'>
        <div className='px-6 py-3 space-y-5'>
          {/* name & icon */}
          <div className='flex gap-4'>
            <div className='grow'>
              <div className={cn('system-sm-semibold mb-1 py-1 text-text-secondary')}>{t(`${prefixSettings}.webName`)}</div>
              <div className={cn('mb-1 py-1 text-text-secondary system-sm-semibold')}>{t(`${prefixSettings}.webName`)}</div>
              <Input
                className='w-full'
                value={inputInfo.title}
@@ -269,46 +258,45 @@
          </div>
          {/* description */}
          <div className='relative'>
            <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.webDesc`)}</div>
            <div className={cn('py-1 text-text-secondary system-sm-semibold')}>{t(`${prefixSettings}.webDesc`)}</div>
            <Textarea
              className='mt-1'
              value={inputInfo.desc}
              onChange={e => onDesChange(e.target.value)}
              placeholder={t(`${prefixSettings}.webDescPlaceholder`) as string}
            />
            <p className={cn('body-xs-regular pb-0.5 text-text-tertiary')}>{t(`${prefixSettings}.webDescTip`)}</p>
            <p className={cn('pb-0.5 text-text-tertiary body-xs-regular')}>{t(`${prefixSettings}.webDescTip`)}</p>
          </div>
          <Divider className="my-0 h-px" />
          <Divider className="h-px my-0" />
          {/* answer icon */}
          {isChat && (
            <div className='w-full'>
              <div className='flex items-center justify-between'>
                <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t('app.answerIcon.title')}</div>
              <div className='flex justify-between items-center'>
                <div className={cn('py-1 text-text-secondary system-sm-semibold')}>{t('app.answerIcon.title')}</div>
                <Switch
                  defaultValue={inputInfo.use_icon_as_answer_icon}
                  onChange={v => setInputInfo({ ...inputInfo, use_icon_as_answer_icon: v })}
                />
              </div>
              <p className='body-xs-regular pb-0.5 text-text-tertiary'>{t('app.answerIcon.description')}</p>
              <p className='pb-0.5 text-text-tertiary body-xs-regular'>{t('app.answerIcon.description')}</p>
            </div>
          )}
          {/* language */}
          <div className='flex items-center'>
            <div className={cn('system-sm-semibold grow py-1 text-text-secondary')}>{t(`${prefixSettings}.language`)}</div>
            <div className={cn('grow py-1 text-text-secondary system-sm-semibold')}>{t(`${prefixSettings}.language`)}</div>
            <SimpleSelect
              wrapperClassName='w-[200px]'
              items={languages.filter(item => item.supported)}
              defaultValue={language}
              onSelect={item => setLanguage(item.value as Language)}
              notClearable
            />
          </div>
          {/* theme color */}
          {isChat && (
            <div className='flex items-center'>
              <div className='grow'>
                <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.chatColorTheme`)}</div>
                <div className='body-xs-regular pb-0.5 text-text-tertiary'>{t(`${prefixSettings}.chatColorThemeDesc`)}</div>
                <div className={cn('py-1 text-text-secondary system-sm-semibold')}>{t(`${prefixSettings}.chatColorTheme`)}</div>
                <div className='pb-0.5 body-xs-regular text-text-tertiary'>{t(`${prefixSettings}.chatColorThemeDesc`)}</div>
              </div>
              <div className='shrink-0'>
                <Input
@@ -317,7 +305,7 @@
                  onChange={onChange('chatColorTheme')}
                  placeholder='E.g #A020F0'
                />
                <div className='flex items-center justify-between'>
                <div className='flex justify-between items-center'>
                  <p className={cn('body-xs-regular text-text-tertiary')}>{t(`${prefixSettings}.chatColorThemeInverted`)}</p>
                  <Switch defaultValue={inputInfo.chatColorThemeInverted} onChange={v => setInputInfo({ ...inputInfo, chatColorThemeInverted: v })}></Switch>
                </div>
@@ -326,24 +314,24 @@
          )}
          {/* workflow detail */}
          <div className='w-full'>
            <div className='flex items-center justify-between'>
              <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.workflow.subTitle`)}</div>
            <div className='flex justify-between items-center'>
              <div className={cn('py-1 text-text-secondary system-sm-semibold')}>{t(`${prefixSettings}.workflow.subTitle`)}</div>
              <Switch
                disabled={!(appInfo.mode === 'workflow' || appInfo.mode === 'advanced-chat')}
                defaultValue={inputInfo.show_workflow_steps}
                onChange={v => setInputInfo({ ...inputInfo, show_workflow_steps: v })}
              />
            </div>
            <p className='body-xs-regular pb-0.5 text-text-tertiary'>{t(`${prefixSettings}.workflow.showDesc`)}</p>
            <p className='pb-0.5 text-text-tertiary body-xs-regular'>{t(`${prefixSettings}.workflow.showDesc`)}</p>
          </div>
          {/* SSO */}
          {systemFeatures.enable_web_sso_switch_component && (
            <>
              <Divider className="my-0 h-px" />
              <Divider className="h-px my-0" />
              <div className='w-full'>
                <p className='system-xs-medium-uppercase mb-1 text-text-tertiary'>{t(`${prefixSettings}.sso.label`)}</p>
                <div className='flex items-center justify-between'>
                  <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.sso.title`)}</div>
                <p className='mb-1 system-xs-medium-uppercase text-text-tertiary'>{t(`${prefixSettings}.sso.label`)}</p>
                <div className='flex justify-between items-center'>
                  <div className={cn('py-1 text-text-secondary system-sm-semibold')}>{t(`${prefixSettings}.sso.title`)}</div>
                  <Tooltip
                    disabled={systemFeatures.sso_enforced_for_web}
                    popupContent={
@@ -354,19 +342,19 @@
                    <Switch disabled={!systemFeatures.sso_enforced_for_web || !isCurrentWorkspaceEditor} defaultValue={systemFeatures.sso_enforced_for_web && inputInfo.enable_sso} onChange={v => setInputInfo({ ...inputInfo, enable_sso: v })}></Switch>
                  </Tooltip>
                </div>
                <p className='body-xs-regular pb-0.5 text-text-tertiary'>{t(`${prefixSettings}.sso.description`)}</p>
                <p className='pb-0.5 body-xs-regular text-text-tertiary'>{t(`${prefixSettings}.sso.description`)}</p>
              </div>
            </>
          )}
          {/* more settings switch */}
          <Divider className="my-0 h-px" />
          <Divider className="h-px my-0" />
          {!isShowMore && (
            <div className='flex cursor-pointer items-center' onClick={() => setIsShowMore(true)}>
            <div className='flex items-center cursor-pointer' onClick={() => setIsShowMore(true)}>
              <div className='grow'>
                <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.more.entry`)}</div>
                <p className={cn('body-xs-regular pb-0.5 text-text-tertiary')}>{t(`${prefixSettings}.more.copyRightPlaceholder`)} & {t(`${prefixSettings}.more.privacyPolicyPlaceholder`)}</p>
                <div className={cn('py-1 text-text-secondary system-sm-semibold')}>{t(`${prefixSettings}.more.entry`)}</div>
                <p className={cn('pb-0.5 text-text-tertiary body-xs-regular')}>{t(`${prefixSettings}.more.copyRightPlaceholder`)} & {t(`${prefixSettings}.more.privacyPolicyPlaceholder`)}</p>
              </div>
              <RiArrowRightSLine className='ml-1 h-4 w-4 shrink-0 text-text-secondary' />
              <RiArrowRightSLine className='shrink-0 ml-1 w-4 h-4 text-text-secondary'/>
            </div>
          )}
          {/* more settings */}
@@ -375,13 +363,13 @@
              {/* copyright */}
              <div className='w-full'>
                <div className='flex items-center'>
                  <div className='flex grow items-center'>
                    <div className={cn('system-sm-semibold mr-1 py-1 text-text-secondary')}>{t(`${prefixSettings}.more.copyright`)}</div>
                  <div className='grow flex items-center'>
                    <div className={cn('mr-1 py-1 text-text-secondary system-sm-semibold')}>{t(`${prefixSettings}.more.copyright`)}</div>
                    {/* upgrade button */}
                    {enableBilling && isFreePlan && (
                      <div className='h-[18px] select-none'>
                      <div className='select-none h-[18px]'>
                        <PremiumBadge size='s' color='blue' allowHover={true} onClick={handlePlanClick}>
                          <SparklesSoft className='flex h-3.5 w-3.5 items-center py-[1px] pl-[3px] text-components-premium-badge-indigo-text-stop-0' />
                          <SparklesSoft className='flex items-center py-[1px] pl-[3px] w-3.5 h-3.5 text-components-premium-badge-indigo-text-stop-0' />
                          <div className='system-xs-medium'>
                            <span className='p-1'>
                              {t('billing.upgradeBtn.encourageShort')}
@@ -405,7 +393,7 @@
                    />
                  </Tooltip>
                </div>
                <p className='body-xs-regular pb-0.5 text-text-tertiary'>{t(`${prefixSettings}.more.copyrightTip`)}</p>
                <p className='pb-0.5 text-text-tertiary body-xs-regular'>{t(`${prefixSettings}.more.copyrightTip`)}</p>
                {inputInfo.copyrightSwitchValue && (
                  <Input
                    className='mt-2 h-10'
@@ -417,11 +405,11 @@
              </div>
              {/* privacy policy */}
              <div className='w-full'>
                <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.more.privacyPolicy`)}</div>
                <p className={cn('body-xs-regular pb-0.5 text-text-tertiary')}>
                <div className={cn('py-1 text-text-secondary system-sm-semibold')}>{t(`${prefixSettings}.more.privacyPolicy`)}</div>
                <p className={cn('pb-0.5 body-xs-regular text-text-tertiary')}>
                  <Trans
                    i18nKey={`${prefixSettings}.more.privacyPolicyTip`}
                    components={{ privacyPolicyLink: <Link href={'https://dify.ai/privacy'} target='_blank' rel='noopener noreferrer' className='text-text-accent' /> }}
                    components={{ privacyPolicyLink: <Link href={'https://docs.dify.ai/user-agreement/privacy-policy'} target='_blank' rel='noopener noreferrer' className='text-text-accent' /> }}
                  />
                </p>
                <Input
@@ -433,8 +421,8 @@
              </div>
              {/* custom disclaimer */}
              <div className='w-full'>
                <div className={cn('system-sm-semibold py-1 text-text-secondary')}>{t(`${prefixSettings}.more.customDisclaimer`)}</div>
                <p className={cn('body-xs-regular pb-0.5 text-text-tertiary')}>{t(`${prefixSettings}.more.customDisclaimerTip`)}</p>
                <div className={cn('py-1 text-text-secondary system-sm-semibold')}>{t(`${prefixSettings}.more.customDisclaimer`)}</div>
                <p className={cn('pb-0.5 body-xs-regular text-text-tertiary')}>{t(`${prefixSettings}.more.customDisclaimerTip`)}</p>
                <Textarea
                  className='mt-1'
                  value={inputInfo.customDisclaimer}
@@ -446,29 +434,27 @@
          )}
        </div>
        {/* footer */}
        <div className='flex justify-end p-6 pt-5'>
        <div className='p-6 pt-5 flex justify-end'>
          <Button className='mr-2' onClick={onHide}>{t('common.operation.cancel')}</Button>
          <Button variant='primary' onClick={onClickSave} loading={saveLoading}>{t('common.operation.save')}</Button>
        </div>
        {showAppIconPicker && (
          <div onClick={e => e.stopPropagation()}>
            <AppIconPicker
              onSelect={(payload) => {
                setAppIcon(payload)
                setShowAppIconPicker(false)
              }}
              onClose={() => {
                setAppIcon(icon_type === 'image'
                  ? { type: 'image', url: icon_url!, fileId: icon }
                  : { type: 'emoji', icon, background: icon_background! })
                setShowAppIconPicker(false)
              }}
            />
          </div>
        )}
      </Modal>
      </Modal >
      {showAppIconPicker && (
        <AppIconPicker
          onSelect={(payload) => {
            setAppIcon(payload)
            setShowAppIconPicker(false)
          }}
          onClose={() => {
            setAppIcon(icon_type === 'image'
              ? { type: 'image', url: icon_url!, fileId: icon }
              : { type: 'emoji', icon, background: icon_background! })
            setShowAppIconPicker(false)
          }}
        />
      )}
    </>
  )
}
export default React.memo(SettingsModal)