fix: not configure default model tip not align

This commit is contained in:
Joel
2026-05-15 14:30:58 +08:00
committed by Jingyi-Dify
parent b2e2e7b60b
commit 05e8a94bb5
5 changed files with 70 additions and 22 deletions

View File

@ -47,12 +47,24 @@ const mockQuotaConfig = {
}
const renderModelProviderPage = (
props: { searchText?: string, enableMarketplace?: boolean, stickyToolbar?: boolean } = {},
props: {
enableMarketplace?: boolean
fixedWarningAlignment?: 'viewport' | 'content-frame'
searchText?: string
stickyToolbar?: boolean
} = {},
) => {
const { searchText = '', enableMarketplace = true, stickyToolbar = true } = props
return renderWithSystemFeatures(<ModelProviderPage searchText={searchText} stickyToolbar={stickyToolbar} />, {
const { fixedWarningAlignment, searchText = '', enableMarketplace = true, stickyToolbar = true } = props
return renderWithSystemFeatures((
<ModelProviderPage
fixedWarningAlignment={fixedWarningAlignment}
searchText={searchText}
stickyToolbar={stickyToolbar}
/>
), {
systemFeatures: { enable_marketplace: enableMarketplace },
})
},
)
}
const mockProviders = [
@ -316,6 +328,17 @@ describe('ModelProviderPage', () => {
expect(screen.getByText('common.modelProvider.noneConfigured')).toBeInTheDocument()
})
it('should align the fixed warning to the content frame when requested', () => {
const { container } = renderModelProviderPage({ fixedWarningAlignment: 'content-frame' })
const warning = screen.getByText('common.modelProvider.noneConfigured')
const warningContainer = warning.closest('.fixed')
expect(warningContainer).not.toHaveClass('right-2')
expect(warningContainer).toHaveClass('right-0', 'left-[var(--model-provider-warning-left,0px)]')
expect(warning.closest('.mx-auto')).toHaveClass('max-w-[1600px]', 'justify-end', 'px-6')
expect(container.firstElementChild).toHaveClass('relative')
})
it('should not show warning when some default models are set', () => {
mockDefaultModels.llm = {
data: { model: 'gpt-4', model_type: 'llm', provider: { provider: 'openai', icon_small: { en_US: '' } } },

View File

@ -32,6 +32,7 @@ import { providerToPluginId } from './utils'
type SystemModelConfigStatus = 'no-provider' | 'none-configured' | 'partially-configured' | 'fully-configured'
type Props = {
fixedWarningAlignment?: 'viewport' | 'content-frame'
onSearchTextChange?: (value: string) => void
searchText: string
stickyToolbar?: boolean
@ -40,6 +41,7 @@ type Props = {
const FixedModelProvider = ['langgenius/openai/openai', 'langgenius/anthropic/anthropic']
const ModelProviderPage = ({
fixedWarningAlignment = 'viewport',
onSearchTextChange,
searchText,
stickyToolbar,
@ -176,20 +178,28 @@ const ModelProviderPage = ({
</div>
</div>
{showWarning && !warningDismissed && (
<div className="fixed top-2 right-2 z-50 p-2">
<div className="flex items-center gap-2 rounded-lg border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-3 py-2 shadow-xs backdrop-blur-[5px]">
<span aria-hidden className="i-ri-alert-fill size-4 shrink-0 text-text-warning-secondary" />
<span className="shrink-0 system-xs-medium whitespace-nowrap text-text-primary" title={t(warningTextKey, { ns: 'common' })}>
{t(warningTextKey, { ns: 'common' })}
</span>
<button
type="button"
className="flex size-4 shrink-0 items-center justify-center text-text-tertiary hover:text-text-secondary"
aria-label={t('operation.close', { ns: 'common' })}
onClick={() => setWarningDismissed(true)}
>
<span aria-hidden className="i-ri-close-line size-4" />
</button>
<div className={fixedWarningAlignment === 'content-frame'
? 'pointer-events-none fixed top-2 right-0 left-[var(--model-provider-warning-left,0px)] z-50'
: 'fixed top-2 right-2 z-50 p-2'}
>
<div className={fixedWarningAlignment === 'content-frame'
? 'mx-auto box-border flex w-full max-w-[1600px] justify-end px-6 py-2'
: undefined}
>
<div className="pointer-events-auto flex items-center gap-2 rounded-lg border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-3 py-2 shadow-xs backdrop-blur-[5px]">
<span aria-hidden className="i-ri-alert-fill size-4 shrink-0 text-text-warning-secondary" />
<span className="shrink-0 system-xs-medium whitespace-nowrap text-text-primary" title={t(warningTextKey, { ns: 'common' })}>
{t(warningTextKey, { ns: 'common' })}
</span>
<button
type="button"
className="flex size-4 shrink-0 items-center justify-center text-text-tertiary hover:text-text-secondary"
aria-label={t('operation.close', { ns: 'common' })}
onClick={() => setWarningDismissed(true)}
>
<span aria-hidden className="i-ri-close-line size-4" />
</button>
</div>
</div>
</div>
)}

View File

@ -88,13 +88,15 @@ vi.mock('@/app/components/plugins/plugin-page/install-plugin-dropdown', () => ({
vi.mock('@/app/components/header/account-setting/model-provider-page', () => ({
__esModule: true,
default: ({
fixedWarningAlignment,
onSearchTextChange,
searchText,
}: {
fixedWarningAlignment?: string
onSearchTextChange?: (value: string) => void
searchText: string
}) => (
<div data-testid="model-provider-page">
<div data-testid="model-provider-page" data-fixed-warning-alignment={fixedWarningAlignment}>
<input
aria-label="search"
value={searchText}
@ -170,6 +172,7 @@ describe('IntegrationsPage', () => {
expect(screen.getByTestId('model-provider-page')).toBeInTheDocument()
expect(screen.getByTestId('model-provider-page').parentElement).toHaveClass('max-w-[1600px]', 'px-6', 'pt-2')
expect(screen.getByTestId('model-provider-page')).toHaveAttribute('data-fixed-warning-alignment', 'content-frame')
expect(screen.getAllByText('common.settings.provider')).toHaveLength(2)
expect(screen.getByRole('textbox', { name: 'search' })).toBeInTheDocument()
})
@ -398,10 +401,17 @@ describe('IntegrationsPage', () => {
})
it('collapses and expands the integrations sidebar', () => {
renderIntegrationsPage({ section: 'provider' })
const { container } = renderIntegrationsPage({ section: 'provider' })
expect(container.firstElementChild).toHaveStyle({
'--model-provider-warning-left': 'calc(240px + 200px)',
})
fireEvent.click(screen.getByRole('button', { name: 'common.settings.collapse' }))
expect(container.firstElementChild).toHaveStyle({
'--model-provider-warning-left': 'calc(240px + 56px)',
})
expect(screen.queryByText('common.settings.integrations')).not.toBeInTheDocument()
expect(screen.queryByText('common.settings.swaggerAPIAsTool')).not.toBeInTheDocument()
expect(screen.getByRole('link', { name: 'MCP' })).toBeInTheDocument()

View File

@ -28,6 +28,7 @@ const IntegrationSectionRenderer = ({
return (
<div className={`${toolsContentFrameClassNames.compact} ${toolsContentInsetClassNames.compact} pt-2`}>
<ModelProviderPage
fixedWarningAlignment="content-frame"
searchText={providerSearchText}
stickyToolbar
onSearchTextChange={onProviderSearchTextChange}

View File

@ -1,6 +1,6 @@
'use client'
import type { ComponentType } from 'react'
import type { ComponentType, CSSProperties } from 'react'
import type { Permissions, ReferenceSetting } from '@/app/components/plugins/types'
import type { IntegrationSection } from '@/app/components/tools/integration-routes'
import { Button } from '@langgenius/dify-ui/button'
@ -280,6 +280,10 @@ export default function IntegrationsPage({
toolsContentInsetClassNames.compact,
toolsUnifiedContentFrameClassName,
)
const sidebarWidthStyle = {
'--integrations-sidebar-width': sidebarCollapsed ? '56px' : '200px',
'--model-provider-warning-left': `calc(240px + ${sidebarCollapsed ? '56px' : '200px'})`,
} as CSSProperties & Record<'--integrations-sidebar-width' | '--model-provider-warning-left', string>
const integrationHeader = useMemo(() => {
switch (section) {
case 'builtin':
@ -355,7 +359,7 @@ export default function IntegrationsPage({
: undefined
return (
<div className="flex h-full min-h-0 bg-components-panel-bg">
<div className="flex h-full min-h-0 bg-components-panel-bg" style={sidebarWidthStyle}>
<aside className={cn(
'flex shrink-0 flex-col border-r border-divider-burn bg-components-panel-bg px-2 py-2 transition-[width]',
sidebarCollapsed ? 'w-14 items-center' : 'w-[200px] items-end',