mirror of
https://github.com/langgenius/dify.git
synced 2026-06-16 22:11:09 +08:00
fix: fix human input form logo replace (#37452)
This commit is contained in:
parent
0c5b3fd0f2
commit
3eaa534e99
@ -16,7 +16,7 @@ class EnterpriseFeatureConfig(BaseSettings):
|
||||
|
||||
CAN_REPLACE_LOGO: bool = Field(
|
||||
description="Allow customization of the enterprise logo.",
|
||||
default=False,
|
||||
default=True,
|
||||
)
|
||||
|
||||
ENTERPRISE_REQUEST_TIMEOUT: int = Field(
|
||||
|
||||
@ -354,4 +354,49 @@ describe('Human input share form', () => {
|
||||
await user.click(screen.getByRole('button', { name: 'share-update-summary' }))
|
||||
expect(approveButton).toBeEnabled()
|
||||
})
|
||||
|
||||
it('should hide branding when remove_webapp_brand is enabled', () => {
|
||||
mockUseGetHumanInputForm.mockReturnValue({
|
||||
data: {
|
||||
...formData,
|
||||
site: {
|
||||
...formData.site,
|
||||
custom_config: {
|
||||
remove_webapp_brand: true,
|
||||
replace_webapp_logo: null,
|
||||
},
|
||||
},
|
||||
},
|
||||
isLoading: false,
|
||||
error: null,
|
||||
})
|
||||
|
||||
render(<FormContent />)
|
||||
|
||||
expect(screen.queryByText('share.chat.poweredBy')).not.toBeInTheDocument()
|
||||
expect(screen.queryByText('dify-logo')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should render the custom branding logo when replace_webapp_logo is provided', () => {
|
||||
mockUseGetHumanInputForm.mockReturnValue({
|
||||
data: {
|
||||
...formData,
|
||||
site: {
|
||||
...formData.site,
|
||||
custom_config: {
|
||||
remove_webapp_brand: false,
|
||||
replace_webapp_logo: 'https://example.com/custom-logo.png',
|
||||
},
|
||||
},
|
||||
},
|
||||
isLoading: false,
|
||||
error: null,
|
||||
})
|
||||
|
||||
render(<FormContent />)
|
||||
|
||||
expect(screen.getByText('share.chat.poweredBy')).toBeInTheDocument()
|
||||
expect(screen.getByRole('img', { name: 'logo' })).toHaveAttribute('src', 'https://example.com/custom-logo.png')
|
||||
expect(screen.queryByText('dify-logo')).not.toBeInTheDocument()
|
||||
})
|
||||
})
|
||||
|
||||
30
web/app/(humanInputLayout)/form/[token]/branding-footer.tsx
Normal file
30
web/app/(humanInputLayout)/form/[token]/branding-footer.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import DifyLogo from '@/app/components/base/logo/dify-logo'
|
||||
|
||||
type BrandingFooterProps = {
|
||||
removeWebappBrand?: boolean
|
||||
replaceWebappLogo?: string | null
|
||||
}
|
||||
|
||||
const BrandingFooter = ({
|
||||
removeWebappBrand,
|
||||
replaceWebappLogo,
|
||||
}: BrandingFooterProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
if (removeWebappBrand)
|
||||
return null
|
||||
|
||||
return (
|
||||
<div className="flex flex-row-reverse px-2 py-3">
|
||||
<div className="flex shrink-0 items-center gap-1.5 px-1">
|
||||
<div className="system-2xs-medium-uppercase text-text-tertiary">{t('chat.poweredBy', { ns: 'share' })}</div>
|
||||
{replaceWebappLogo
|
||||
? <img src={replaceWebappLogo} alt="logo" className="block h-5 w-auto" />
|
||||
: <DifyLogo size="small" />}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default BrandingFooter
|
||||
@ -1,7 +1,7 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import DifyLogo from '@/app/components/base/logo/dify-logo'
|
||||
import BrandingFooter from './branding-footer'
|
||||
|
||||
type FormStatusCardProps = {
|
||||
iconClassName: string
|
||||
@ -9,6 +9,7 @@ type FormStatusCardProps = {
|
||||
subtitle?: ReactNode
|
||||
submissionID?: string
|
||||
removeWebappBrand?: boolean
|
||||
replaceWebappLogo?: string | null
|
||||
}
|
||||
|
||||
const FormStatusCard = ({
|
||||
@ -17,6 +18,7 @@ const FormStatusCard = ({
|
||||
subtitle,
|
||||
submissionID,
|
||||
removeWebappBrand,
|
||||
replaceWebappLogo,
|
||||
}: FormStatusCardProps) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
@ -39,14 +41,10 @@ const FormStatusCard = ({
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{!removeWebappBrand && (
|
||||
<div className="flex flex-row-reverse px-2 py-3">
|
||||
<div className="flex shrink-0 items-center gap-1.5 px-1">
|
||||
<div className="system-2xs-medium-uppercase text-text-tertiary">{t('chat.poweredBy', { ns: 'share' })}</div>
|
||||
<DifyLogo size="small" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<BrandingFooter
|
||||
removeWebappBrand={removeWebappBrand}
|
||||
replaceWebappLogo={replaceWebappLogo}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -35,6 +35,9 @@ const FormContent = () => {
|
||||
const { isSubmitting, submit, success } = useFormSubmit(token)
|
||||
|
||||
const removeWebappBrand = formData?.site?.custom_config?.remove_webapp_brand === true
|
||||
const replaceWebappLogo = typeof formData?.site?.custom_config?.replace_webapp_logo === 'string'
|
||||
? formData.site.custom_config.replace_webapp_logo
|
||||
: null
|
||||
|
||||
const expired = (error as HumanInputFormError | null)?.code === 'human_input_form_expired'
|
||||
const submitted = (error as HumanInputFormError | null)?.code === 'human_input_form_submitted'
|
||||
@ -54,6 +57,7 @@ const FormContent = () => {
|
||||
subtitle={t('humanInput.recorded', { ns: 'share' })}
|
||||
submissionID={token}
|
||||
removeWebappBrand={removeWebappBrand}
|
||||
replaceWebappLogo={replaceWebappLogo}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@ -105,6 +109,7 @@ const FormContent = () => {
|
||||
isSubmitting={isSubmitting}
|
||||
onSubmit={submit}
|
||||
removeWebappBrand={removeWebappBrand}
|
||||
replaceWebappLogo={replaceWebappLogo}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@ -6,18 +6,18 @@ import { Button } from '@langgenius/dify-ui/button'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { produce } from 'immer'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
import ContentItem from '@/app/components/base/chat/chat/answer/human-input-content/content-item'
|
||||
import ExpirationTime from '@/app/components/base/chat/chat/answer/human-input-content/expiration-time'
|
||||
import { getButtonStyle, getRenderedFormInputs, hasInvalidRequiredHumanInput, initializeInputs, splitByOutputVar } from '@/app/components/base/chat/chat/answer/human-input-content/utils'
|
||||
import DifyLogo from '@/app/components/base/logo/dify-logo'
|
||||
import BrandingFooter from './branding-footer'
|
||||
|
||||
type LoadedFormContentProps = {
|
||||
formData: FormData
|
||||
isSubmitting: boolean
|
||||
onSubmit: (inputs: Record<string, HumanInputFieldValue>, actionID: string, formInputs: FormData['inputs']) => void
|
||||
removeWebappBrand?: boolean
|
||||
replaceWebappLogo?: string | null
|
||||
}
|
||||
|
||||
const LoadedFormContent = ({
|
||||
@ -25,15 +25,25 @@ const LoadedFormContent = ({
|
||||
isSubmitting,
|
||||
onSubmit,
|
||||
removeWebappBrand,
|
||||
replaceWebappLogo,
|
||||
}: LoadedFormContentProps) => {
|
||||
const { t } = useTranslation()
|
||||
const renderedFormInputs = getRenderedFormInputs(formData.inputs, formData.form_content)
|
||||
const [inputs, setInputs] = useState<Record<string, HumanInputFieldValue>>(() =>
|
||||
initializeInputs(renderedFormInputs, formData.resolved_default_values),
|
||||
)
|
||||
|
||||
const contentList = useMemo(() => {
|
||||
return splitByOutputVar(formData.form_content)
|
||||
const contentCounts = new Map<string, number>()
|
||||
|
||||
return splitByOutputVar(formData.form_content).map((content) => {
|
||||
const occurrence = (contentCounts.get(content) || 0) + 1
|
||||
contentCounts.set(content, occurrence)
|
||||
|
||||
return {
|
||||
key: `${content}-${occurrence}`,
|
||||
content,
|
||||
}
|
||||
})
|
||||
}, [formData.form_content])
|
||||
|
||||
const handleInputsChange = (name: string, value: HumanInputFieldValue) => {
|
||||
@ -63,9 +73,9 @@ const LoadedFormContent = ({
|
||||
</div>
|
||||
<div className="h-0 w-full grow overflow-y-auto">
|
||||
<div className="rounded-[20px] border border-divider-subtle bg-chat-bubble-bg p-4 shadow-lg backdrop-blur-xs">
|
||||
{contentList.map((content, index) => (
|
||||
{contentList.map(({ key, content }) => (
|
||||
<ContentItem
|
||||
key={index}
|
||||
key={key}
|
||||
content={content}
|
||||
formInputFields={formData.inputs}
|
||||
inputs={inputs}
|
||||
@ -86,14 +96,10 @@ const LoadedFormContent = ({
|
||||
</div>
|
||||
<ExpirationTime expirationTime={formData.expiration_time * 1000} />
|
||||
</div>
|
||||
{!removeWebappBrand && (
|
||||
<div className="flex flex-row-reverse px-2 py-3">
|
||||
<div className="flex shrink-0 items-center gap-1.5 px-1">
|
||||
<div className="system-2xs-medium-uppercase text-text-tertiary">{t('chat.poweredBy', { ns: 'share' })}</div>
|
||||
<DifyLogo size="small" />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<BrandingFooter
|
||||
removeWebappBrand={removeWebappBrand}
|
||||
replaceWebappLogo={replaceWebappLogo}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user