mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 01:48:04 +08:00
Merge remote-tracking branch 'origin/main' into feat/model-provider-refactor
This commit is contained in:
@ -70,6 +70,7 @@ const { mockConfig, mockEnv } = vi.hoisted(() => ({
|
||||
mockConfig: {
|
||||
IS_CLOUD_EDITION: false,
|
||||
ZENDESK_WIDGET_KEY: '',
|
||||
SUPPORT_EMAIL_ADDRESS: '',
|
||||
},
|
||||
mockEnv: {
|
||||
env: {
|
||||
@ -80,6 +81,7 @@ const { mockConfig, mockEnv } = vi.hoisted(() => ({
|
||||
vi.mock('@/config', () => ({
|
||||
get IS_CLOUD_EDITION() { return mockConfig.IS_CLOUD_EDITION },
|
||||
get ZENDESK_WIDGET_KEY() { return mockConfig.ZENDESK_WIDGET_KEY },
|
||||
get SUPPORT_EMAIL_ADDRESS() { return mockConfig.SUPPORT_EMAIL_ADDRESS },
|
||||
IS_DEV: false,
|
||||
IS_CE_EDITION: false,
|
||||
}))
|
||||
|
||||
@ -11,6 +11,10 @@ const { mockZendeskKey } = vi.hoisted(() => ({
|
||||
mockZendeskKey: { value: 'test-key' },
|
||||
}))
|
||||
|
||||
const { mockSupportEmailKey } = vi.hoisted(() => ({
|
||||
mockSupportEmailKey: { value: '' },
|
||||
}))
|
||||
|
||||
vi.mock('@/context/app-context', async (importOriginal) => {
|
||||
const actual = await importOriginal<typeof import('@/context/app-context')>()
|
||||
return {
|
||||
@ -33,6 +37,7 @@ vi.mock('@/config', async (importOriginal) => {
|
||||
...actual,
|
||||
IS_CE_EDITION: false,
|
||||
get ZENDESK_WIDGET_KEY() { return mockZendeskKey.value },
|
||||
get SUPPORT_EMAIL_ADDRESS() { return mockSupportEmailKey.value },
|
||||
}
|
||||
})
|
||||
|
||||
@ -84,6 +89,7 @@ describe('Support', () => {
|
||||
vi.clearAllMocks()
|
||||
window.zE = vi.fn()
|
||||
mockZendeskKey.value = 'test-key'
|
||||
mockSupportEmailKey.value = ''
|
||||
vi.mocked(useAppContext).mockReturnValue(baseAppContextValue)
|
||||
vi.mocked(useProviderContext).mockReturnValue({
|
||||
...baseProviderContextValue,
|
||||
@ -96,7 +102,7 @@ describe('Support', () => {
|
||||
|
||||
const renderSupport = () => {
|
||||
return render(
|
||||
<DropdownMenu open={true} onOpenChange={() => {}}>
|
||||
<DropdownMenu open={true} onOpenChange={() => { }}>
|
||||
<DropdownMenuTrigger>open</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<Support closeAccountDropdown={mockCloseAccountDropdown} />
|
||||
@ -125,7 +131,7 @@ describe('Support', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('Plan-based Channels', () => {
|
||||
describe('Dedicated Channels', () => {
|
||||
it('should show "Contact Us" when ZENDESK_WIDGET_KEY is present', () => {
|
||||
// Act
|
||||
renderSupport()
|
||||
@ -166,6 +172,27 @@ describe('Support', () => {
|
||||
expect(screen.getByText('common.userProfile.emailSupport')).toBeInTheDocument()
|
||||
expect(screen.queryByText('common.userProfile.contactUs')).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it('should show email support if specified in the config', () => {
|
||||
// Arrange
|
||||
mockZendeskKey.value = ''
|
||||
mockSupportEmailKey.value = 'support@example.com'
|
||||
vi.mocked(useProviderContext).mockReturnValue({
|
||||
...baseProviderContextValue,
|
||||
plan: {
|
||||
...baseProviderContextValue.plan,
|
||||
type: Plan.sandbox,
|
||||
},
|
||||
})
|
||||
|
||||
// Act
|
||||
renderSupport()
|
||||
fireEvent.click(screen.getByText('common.userProfile.support'))
|
||||
|
||||
// Assert
|
||||
expect(screen.queryByText('common.userProfile.emailSupport')).toBeInTheDocument()
|
||||
expect(screen.getByText('common.userProfile.emailSupport')?.closest('a')?.getAttribute('href')).toMatch(new RegExp(`^mailto:${mockSupportEmailKey.value}`))
|
||||
})
|
||||
})
|
||||
|
||||
describe('Interactions and Links', () => {
|
||||
|
||||
@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { DropdownMenuGroup, DropdownMenuItem, DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger } from '@/app/components/base/ui/dropdown-menu'
|
||||
import { toggleZendeskWindow } from '@/app/components/base/zendesk/utils'
|
||||
import { Plan } from '@/app/components/billing/type'
|
||||
import { ZENDESK_WIDGET_KEY } from '@/config'
|
||||
import { SUPPORT_EMAIL_ADDRESS, ZENDESK_WIDGET_KEY } from '@/config'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { useProviderContext } from '@/context/provider-context'
|
||||
import { mailToSupport } from '../utils/util'
|
||||
@ -17,8 +17,8 @@ export default function Support({ closeAccountDropdown }: SupportProps) {
|
||||
const { t } = useTranslation()
|
||||
const { plan } = useProviderContext()
|
||||
const { userProfile, langGeniusVersionInfo } = useAppContext()
|
||||
const hasDedicatedChannel = plan.type !== Plan.sandbox
|
||||
const hasZendeskWidget = !!ZENDESK_WIDGET_KEY?.trim()
|
||||
const hasDedicatedChannel = plan.type !== Plan.sandbox || Boolean(SUPPORT_EMAIL_ADDRESS.trim())
|
||||
const hasZendeskWidget = Boolean(ZENDESK_WIDGET_KEY.trim())
|
||||
|
||||
return (
|
||||
<DropdownMenuSub>
|
||||
@ -49,7 +49,7 @@ export default function Support({ closeAccountDropdown }: SupportProps) {
|
||||
{hasDedicatedChannel && !hasZendeskWidget && (
|
||||
<DropdownMenuItem
|
||||
className="justify-between"
|
||||
render={<a href={mailToSupport(userProfile.email, plan.type, langGeniusVersionInfo?.current_version)} rel="noopener noreferrer" target="_blank" />}
|
||||
render={<a href={mailToSupport(userProfile.email, plan.type, langGeniusVersionInfo?.current_version, SUPPORT_EMAIL_ADDRESS)} rel="noopener noreferrer" target="_blank" />}
|
||||
>
|
||||
<MenuItemContent
|
||||
iconClassName="i-ri-mail-send-line"
|
||||
|
||||
@ -10,7 +10,7 @@ export const generateMailToLink = (email: string, subject?: string, body?: strin
|
||||
return mailtoLink
|
||||
}
|
||||
|
||||
export const mailToSupport = (account: string, plan: string, version: string) => {
|
||||
export const mailToSupport = (account: string, plan: string, version: string, supportEmailAddress?: string) => {
|
||||
const subject = `Technical Support Request ${plan} ${account}`
|
||||
const body = `
|
||||
Please do not remove the following information:
|
||||
@ -21,5 +21,5 @@ export const mailToSupport = (account: string, plan: string, version: string) =>
|
||||
Platform:
|
||||
Problem Description:
|
||||
`
|
||||
return generateMailToLink('support@dify.ai', subject, body)
|
||||
return generateMailToLink(supportEmailAddress || 'support@dify.ai', subject, body)
|
||||
}
|
||||
|
||||
@ -342,6 +342,12 @@ export const ZENDESK_FIELD_IDS = {
|
||||
'',
|
||||
),
|
||||
}
|
||||
|
||||
export const SUPPORT_EMAIL_ADDRESS = getStringConfig(
|
||||
env.NEXT_PUBLIC_SUPPORT_EMAIL_ADDRESS,
|
||||
'',
|
||||
)
|
||||
|
||||
export const APP_VERSION = pkg.version
|
||||
|
||||
export const IS_MARKETPLACE = env.NEXT_PUBLIC_IS_MARKETPLACE
|
||||
|
||||
@ -115,6 +115,7 @@ const clientSchema = {
|
||||
*/
|
||||
NEXT_PUBLIC_SENTRY_DSN: z.string().optional(),
|
||||
NEXT_PUBLIC_SITE_ABOUT: z.string().optional(),
|
||||
NEXT_PUBLIC_SUPPORT_EMAIL_ADDRESS: z.email().optional(),
|
||||
NEXT_PUBLIC_SUPPORT_MAIL_LOGIN: coercedBoolean.default(false),
|
||||
/**
|
||||
* The timeout for the text generation in millisecond
|
||||
@ -184,6 +185,7 @@ export const env = createEnv({
|
||||
NEXT_PUBLIC_PUBLIC_API_PREFIX: isServer ? process.env.NEXT_PUBLIC_PUBLIC_API_PREFIX : getRuntimeEnvFromBody('publicApiPrefix'),
|
||||
NEXT_PUBLIC_SENTRY_DSN: isServer ? process.env.NEXT_PUBLIC_SENTRY_DSN : getRuntimeEnvFromBody('sentryDsn'),
|
||||
NEXT_PUBLIC_SITE_ABOUT: isServer ? process.env.NEXT_PUBLIC_SITE_ABOUT : getRuntimeEnvFromBody('siteAbout'),
|
||||
NEXT_PUBLIC_SUPPORT_EMAIL_ADDRESS: isServer ? process.env.NEXT_PUBLIC_SUPPORT_EMAIL_ADDRESS : getRuntimeEnvFromBody('supportEmailAddress'),
|
||||
NEXT_PUBLIC_SUPPORT_MAIL_LOGIN: isServer ? process.env.NEXT_PUBLIC_SUPPORT_MAIL_LOGIN : getRuntimeEnvFromBody('supportMailLogin'),
|
||||
NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS: isServer ? process.env.NEXT_PUBLIC_TEXT_GENERATION_TIMEOUT_MS : getRuntimeEnvFromBody('textGenerationTimeoutMs'),
|
||||
NEXT_PUBLIC_TOP_K_MAX_VALUE: isServer ? process.env.NEXT_PUBLIC_TOP_K_MAX_VALUE : getRuntimeEnvFromBody('topKMaxValue'),
|
||||
|
||||
@ -124,7 +124,7 @@
|
||||
"metadata.datasetMetadata.deleteContent": "Êtes-vous sûr de vouloir supprimer les métadonnées \"{{name}}\" ?",
|
||||
"metadata.datasetMetadata.deleteTitle": "Confirmer la suppression",
|
||||
"metadata.datasetMetadata.description": "Vous pouvez gérer toutes les métadonnées dans cette connaissance ici. Les modifications seront synchronisées avec chaque document.",
|
||||
"metadata.datasetMetadata.disabled": "handicapés",
|
||||
"metadata.datasetMetadata.disabled": "Désactivé",
|
||||
"metadata.datasetMetadata.name": "Nom",
|
||||
"metadata.datasetMetadata.namePlaceholder": "Nom de métadonnées",
|
||||
"metadata.datasetMetadata.rename": "Renommer",
|
||||
|
||||
@ -95,7 +95,7 @@
|
||||
"detailPanel.deprecation.reason.businessAdjustments": "ajustements commerciaux",
|
||||
"detailPanel.deprecation.reason.noMaintainer": "aucun mainteneur",
|
||||
"detailPanel.deprecation.reason.ownershipTransferred": "propriété transférée",
|
||||
"detailPanel.disabled": "Handicapé",
|
||||
"detailPanel.disabled": "Désactivé",
|
||||
"detailPanel.endpointDeleteContent": "Souhaitez-vous supprimer {{name}} ?",
|
||||
"detailPanel.endpointDeleteTip": "Supprimer le point de terminaison",
|
||||
"detailPanel.endpointDisableContent": "Souhaitez-vous désactiver {{name}} ?",
|
||||
|
||||
@ -687,7 +687,7 @@
|
||||
"nodes.knowledgeRetrieval.metadata.options.automatic.subTitle": "Générer automatiquement des conditions de filtrage des métadonnées en fonction de la requête de l'utilisateur",
|
||||
"nodes.knowledgeRetrieval.metadata.options.automatic.title": "Automatique",
|
||||
"nodes.knowledgeRetrieval.metadata.options.disabled.subTitle": "Ne pas activer le filtrage des métadonnées",
|
||||
"nodes.knowledgeRetrieval.metadata.options.disabled.title": "Handicapé",
|
||||
"nodes.knowledgeRetrieval.metadata.options.disabled.title": "Désactivé",
|
||||
"nodes.knowledgeRetrieval.metadata.options.manual.subTitle": "Ajouter manuellement des conditions de filtrage des métadonnées",
|
||||
"nodes.knowledgeRetrieval.metadata.options.manual.title": "Manuel",
|
||||
"nodes.knowledgeRetrieval.metadata.panel.add": "Ajouter une condition",
|
||||
|
||||
@ -99,7 +99,7 @@
|
||||
"cron-parser": "5.4.0",
|
||||
"dayjs": "1.11.19",
|
||||
"decimal.js": "10.6.0",
|
||||
"dompurify": "3.3.0",
|
||||
"dompurify": "3.3.2",
|
||||
"echarts": "5.6.0",
|
||||
"echarts-for-react": "3.0.5",
|
||||
"elkjs": "0.9.3",
|
||||
|
||||
47
web/pnpm-lock.yaml
generated
47
web/pnpm-lock.yaml
generated
@ -169,8 +169,8 @@ importers:
|
||||
specifier: 10.6.0
|
||||
version: 10.6.0
|
||||
dompurify:
|
||||
specifier: 3.3.0
|
||||
version: 3.3.0
|
||||
specifier: 3.3.2
|
||||
version: 3.3.2
|
||||
echarts:
|
||||
specifier: 5.6.0
|
||||
version: 5.6.0
|
||||
@ -4492,8 +4492,9 @@ packages:
|
||||
dompurify@3.2.7:
|
||||
resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==}
|
||||
|
||||
dompurify@3.3.0:
|
||||
resolution: {integrity: sha512-r+f6MYR1gGN1eJv0TVQbhA7if/U7P87cdPl3HN5rikqaBSBxLiCb/b9O+2eG0cxz0ghyU+mU1QkbsOwERMYlWQ==}
|
||||
dompurify@3.3.2:
|
||||
resolution: {integrity: sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==}
|
||||
engines: {node: '>=20'}
|
||||
|
||||
domutils@3.2.2:
|
||||
resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==}
|
||||
@ -4657,7 +4658,7 @@ packages:
|
||||
eslint: '*'
|
||||
|
||||
eslint-plugin-better-tailwindcss@https://pkg.pr.new/hyoban/eslint-plugin-better-tailwindcss@a520d15:
|
||||
resolution: {integrity: sha512-hbxpqInIW0Q5UIwXEuQxSBjrMd5bYttXeSPU6dfK2zpECKNIzGR+KXZZEdZaPagEMDJosSyQ9RKievmBcCAxfA==, tarball: https://pkg.pr.new/hyoban/eslint-plugin-better-tailwindcss@a520d15}
|
||||
resolution: {tarball: https://pkg.pr.new/hyoban/eslint-plugin-better-tailwindcss@a520d15}
|
||||
version: 4.3.1
|
||||
engines: {node: ^20.19.0 || ^22.12.0 || >=23.0.0}
|
||||
peerDependencies:
|
||||
@ -6548,9 +6549,6 @@ packages:
|
||||
resolution: {integrity: sha512-h36JMxKRqrAxVD8201FrCpyeNuUY9Y5zZwujr20fFO77tpUtGa6EZzfKw/3WaiBX95fq7+MpsuMLNdSnORAwSA==}
|
||||
engines: {node: '>=14.18.0'}
|
||||
|
||||
randombytes@2.1.0:
|
||||
resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==}
|
||||
|
||||
rc@1.2.8:
|
||||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
||||
hasBin: true
|
||||
@ -6946,9 +6944,6 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
serialize-javascript@6.0.2:
|
||||
resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==}
|
||||
|
||||
seroval-plugins@1.5.0:
|
||||
resolution: {integrity: sha512-EAHqADIQondwRZIdeW2I636zgsODzoBDwb3PT/+7TLDWyw1Dy/Xv7iGUIEXXav7usHDE9HVhOU61irI3EnyyHA==}
|
||||
engines: {node: '>=10'}
|
||||
@ -7223,8 +7218,8 @@ packages:
|
||||
engines: {node: '>=18'}
|
||||
deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me
|
||||
|
||||
terser-webpack-plugin@5.3.16:
|
||||
resolution: {integrity: sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==}
|
||||
terser-webpack-plugin@5.3.17:
|
||||
resolution: {integrity: sha512-YR7PtUp6GMU91BgSJmlaX/rS2lGDbAF7D+Wtq7hRO+MiljNmodYvqslzCFiYVAgW+Qoaaia/QUIP4lGXufjdZw==}
|
||||
engines: {node: '>= 10.13.0'}
|
||||
peerDependencies:
|
||||
'@swc/core': '*'
|
||||
@ -7567,7 +7562,7 @@ packages:
|
||||
resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==}
|
||||
|
||||
vinext@https://pkg.pr.new/hyoban/vinext@556a6d6:
|
||||
resolution: {integrity: sha512-Sz8RkTDsY6cnGrevlQi4nXgahu8okEGsdKY5m31d/L9tXo35bNETMHfVee5gaI2UKZS9LMcffWaTOxxINUgogQ==, tarball: https://pkg.pr.new/hyoban/vinext@556a6d6}
|
||||
resolution: {tarball: https://pkg.pr.new/hyoban/vinext@556a6d6}
|
||||
version: 0.0.5
|
||||
engines: {node: '>=22'}
|
||||
hasBin: true
|
||||
@ -12198,7 +12193,7 @@ snapshots:
|
||||
optionalDependencies:
|
||||
'@types/trusted-types': 2.0.7
|
||||
|
||||
dompurify@3.3.0:
|
||||
dompurify@3.3.2:
|
||||
optionalDependencies:
|
||||
'@types/trusted-types': 2.0.7
|
||||
|
||||
@ -13978,7 +13973,7 @@ snapshots:
|
||||
d3-sankey: 0.12.3
|
||||
dagre-d3-es: 7.0.11
|
||||
dayjs: 1.11.19
|
||||
dompurify: 3.3.0
|
||||
dompurify: 3.3.2
|
||||
katex: 0.16.25
|
||||
khroma: 2.1.0
|
||||
lodash-es: 4.17.23
|
||||
@ -14124,8 +14119,8 @@ snapshots:
|
||||
|
||||
micromark-extension-mdxjs@3.0.0:
|
||||
dependencies:
|
||||
acorn: 8.16.0
|
||||
acorn-jsx: 5.3.2(acorn@8.16.0)
|
||||
acorn: 8.15.0
|
||||
acorn-jsx: 5.3.2(acorn@8.15.0)
|
||||
micromark-extension-mdx-expression: 3.0.1
|
||||
micromark-extension-mdx-jsx: 3.0.2
|
||||
micromark-extension-mdx-md: 2.0.0
|
||||
@ -14776,10 +14771,6 @@ snapshots:
|
||||
|
||||
radash@12.1.1: {}
|
||||
|
||||
randombytes@2.1.0:
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
rc@1.2.8:
|
||||
dependencies:
|
||||
deep-extend: 0.6.0
|
||||
@ -15284,7 +15275,8 @@ snapshots:
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
safe-buffer@5.2.1: {}
|
||||
safe-buffer@5.2.1:
|
||||
optional: true
|
||||
|
||||
sass@1.93.2:
|
||||
dependencies:
|
||||
@ -15335,10 +15327,6 @@ snapshots:
|
||||
|
||||
semver@7.7.4: {}
|
||||
|
||||
serialize-javascript@6.0.2:
|
||||
dependencies:
|
||||
randombytes: 2.1.0
|
||||
|
||||
seroval-plugins@1.5.0(seroval@1.5.0):
|
||||
dependencies:
|
||||
seroval: 1.5.0
|
||||
@ -15681,12 +15669,11 @@ snapshots:
|
||||
minizlib: 3.1.0
|
||||
yallist: 5.0.0
|
||||
|
||||
terser-webpack-plugin@5.3.16(esbuild@0.27.2)(uglify-js@3.19.3)(webpack@5.104.1(esbuild@0.27.2)(uglify-js@3.19.3)):
|
||||
terser-webpack-plugin@5.3.17(esbuild@0.27.2)(uglify-js@3.19.3)(webpack@5.104.1(esbuild@0.27.2)(uglify-js@3.19.3)):
|
||||
dependencies:
|
||||
'@jridgewell/trace-mapping': 0.3.31
|
||||
jest-worker: 27.5.1
|
||||
schema-utils: 4.3.3
|
||||
serialize-javascript: 6.0.2
|
||||
terser: 5.46.0
|
||||
webpack: 5.104.1(esbuild@0.27.2)(uglify-js@3.19.3)
|
||||
optionalDependencies:
|
||||
@ -16249,7 +16236,7 @@ snapshots:
|
||||
neo-async: 2.6.2
|
||||
schema-utils: 4.3.3
|
||||
tapable: 2.3.0
|
||||
terser-webpack-plugin: 5.3.16(esbuild@0.27.2)(uglify-js@3.19.3)(webpack@5.104.1(esbuild@0.27.2)(uglify-js@3.19.3))
|
||||
terser-webpack-plugin: 5.3.17(esbuild@0.27.2)(uglify-js@3.19.3)(webpack@5.104.1(esbuild@0.27.2)(uglify-js@3.19.3))
|
||||
watchpack: 2.5.1
|
||||
webpack-sources: 3.3.4
|
||||
transitivePeerDependencies:
|
||||
|
||||
Reference in New Issue
Block a user