connected
diff --git a/web/app/components/header/account-setting/key-validator/Operate.tsx b/web/app/components/header/account-setting/key-validator/Operate.tsx
index 7f09f32f64..984f572a0d 100644
--- a/web/app/components/header/account-setting/key-validator/Operate.tsx
+++ b/web/app/components/header/account-setting/key-validator/Operate.tsx
@@ -1,6 +1,6 @@
import type { Status } from './declarations'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { useTranslation } from 'react-i18next'
-import Indicator from '../../indicator'
type OperateProps = {
isOpen: boolean
@@ -71,13 +71,13 @@ const Operate = ({
status === 'fail' && (
{t('provider.invalidApiKey', { ns: 'common' })}
-
+
)
}
{
status === 'success' && (
-
+
)
}
({
}))
// Mock Indicator
-vi.mock('@/app/components/header/indicator', () => ({
- default: ({ color }: { color: string }) =>
,
+vi.mock('@langgenius/dify-ui/status-dot', () => ({
+ StatusDot: ({ status }: { status: string }) =>
,
}))
describe('ConfigModel', () => {
@@ -19,7 +19,7 @@ describe('ConfigModel', () => {
expect(screen.getByText(/modelProvider.auth.authorizationError/)).toBeInTheDocument()
expect(screen.getByTestId('scales-icon')).toBeInTheDocument()
- expect(screen.getByTestId('indicator-orange')).toBeInTheDocument()
+ expect(screen.getByTestId('indicator-warning')).toBeInTheDocument()
fireEvent.click(screen.getByText(/modelProvider.auth.authorizationError/))
expect(onClick).toHaveBeenCalled()
@@ -29,7 +29,7 @@ describe('ConfigModel', () => {
render(
)
expect(screen.getByText(/modelProvider.auth.credentialRemoved/)).toBeInTheDocument()
- expect(screen.getByTestId('indicator-red')).toBeInTheDocument()
+ expect(screen.getByTestId('indicator-error')).toBeInTheDocument()
})
it('should render standard config message when no flags enabled', () => {
diff --git a/web/app/components/header/account-setting/model-provider-page/model-auth/__tests__/credential-selector.spec.tsx b/web/app/components/header/account-setting/model-provider-page/model-auth/__tests__/credential-selector.spec.tsx
index 720bdc2ff3..408465fbb2 100644
--- a/web/app/components/header/account-setting/model-provider-page/model-auth/__tests__/credential-selector.spec.tsx
+++ b/web/app/components/header/account-setting/model-provider-page/model-auth/__tests__/credential-selector.spec.tsx
@@ -10,8 +10,8 @@ vi.mock('../authorized/credential-item', () => ({
),
}))
-vi.mock('@/app/components/header/indicator', () => ({
- default: () =>
,
+vi.mock('@langgenius/dify-ui/status-dot', () => ({
+ StatusDot: () =>
,
}))
vi.mock('@remixicon/react', () => ({
diff --git a/web/app/components/header/account-setting/model-provider-page/model-auth/__tests__/switch-credential-in-load-balancing.spec.tsx b/web/app/components/header/account-setting/model-provider-page/model-auth/__tests__/switch-credential-in-load-balancing.spec.tsx
index 73aa8f9bfc..e135c23764 100644
--- a/web/app/components/header/account-setting/model-provider-page/model-auth/__tests__/switch-credential-in-load-balancing.spec.tsx
+++ b/web/app/components/header/account-setting/model-provider-page/model-auth/__tests__/switch-credential-in-load-balancing.spec.tsx
@@ -15,8 +15,8 @@ vi.mock('../authorized', () => ({
),
}))
-vi.mock('@/app/components/header/indicator', () => ({
- default: ({ color }: { color: string }) =>
,
+vi.mock('@langgenius/dify-ui/status-dot', () => ({
+ StatusDot: ({ status }: { status: string }) =>
,
}))
vi.mock('@remixicon/react', () => ({
@@ -58,7 +58,7 @@ describe('SwitchCredentialInLoadBalancing', () => {
)
expect(screen.getByText('Key 1'))!.toBeInTheDocument()
- expect(screen.getByTestId('indicator-green'))!.toBeInTheDocument()
+ expect(screen.getByTestId('indicator-success'))!.toBeInTheDocument()
})
it('should render auth removed status when selected credential is not in list', () => {
@@ -73,7 +73,7 @@ describe('SwitchCredentialInLoadBalancing', () => {
)
expect(screen.getByText(/modelProvider.auth.authRemoved/))!.toBeInTheDocument()
- expect(screen.getByTestId('indicator-red'))!.toBeInTheDocument()
+ expect(screen.getByTestId('indicator-error'))!.toBeInTheDocument()
})
it('should render unavailable status when credentials list is empty', () => {
@@ -156,7 +156,7 @@ describe('SwitchCredentialInLoadBalancing', () => {
/>,
)
- expect(screen.getByTestId('indicator-red'))!.toBeInTheDocument()
+ expect(screen.getByTestId('indicator-error'))!.toBeInTheDocument()
expect(screen.getByText(/auth.credentialUnavailableInButton/))!.toBeInTheDocument()
})
@@ -244,9 +244,9 @@ describe('SwitchCredentialInLoadBalancing', () => {
/>,
)
- // indicator-green shown (not authRemoved, not unavailable, not empty)
- // indicator-green shown (not authRemoved, not unavailable, not empty)
- expect(screen.getByTestId('indicator-green'))!.toBeInTheDocument()
+ // indicator-success shown (not authRemoved, not unavailable, not empty)
+ // indicator-success shown (not authRemoved, not unavailable, not empty)
+ expect(screen.getByTestId('indicator-success'))!.toBeInTheDocument()
// credential_name is empty so nothing printed for name
// credential_name is empty so nothing printed for name
// credential_name is empty so nothing printed for name
diff --git a/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/__tests__/credential-item.spec.tsx b/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/__tests__/credential-item.spec.tsx
index c5ef0028fb..0b96f03c7d 100644
--- a/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/__tests__/credential-item.spec.tsx
+++ b/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/__tests__/credential-item.spec.tsx
@@ -2,8 +2,8 @@ import type { Credential } from '../../../declarations'
import { fireEvent, render, screen } from '@testing-library/react'
import CredentialItem from '../credential-item'
-vi.mock('@/app/components/header/indicator', () => ({
- default: () =>
,
+vi.mock('@langgenius/dify-ui/status-dot', () => ({
+ StatusDot: () =>
,
}))
describe('CredentialItem', () => {
diff --git a/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/credential-item.tsx b/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/credential-item.tsx
index 8e315ccd75..610e94890c 100644
--- a/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/credential-item.tsx
+++ b/web/app/components/header/account-setting/model-provider-page/model-auth/authorized/credential-item.tsx
@@ -1,5 +1,6 @@
import type { Credential } from '../../declarations'
import { cn } from '@langgenius/dify-ui/cn'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import {
memo,
@@ -8,7 +9,6 @@ import {
import { useTranslation } from 'react-i18next'
import ActionButton from '@/app/components/base/action-button'
import Badge from '@/app/components/base/badge'
-import Indicator from '@/app/components/header/indicator'
type CredentialItemProps = {
credential: Credential
@@ -71,7 +71,7 @@ const CredentialItem = ({
)
}
-
+
void
@@ -30,7 +30,7 @@ const ConfigModel = ({
>
{t('modelProvider.auth.authorizationError', { ns: 'common' })}
-
+
)
}
@@ -49,7 +49,7 @@ const ConfigModel = ({
credentialRemoved && (
<>
{t('modelProvider.auth.credentialRemoved', { ns: 'common' })}
-
+
>
)
}
diff --git a/web/app/components/header/account-setting/model-provider-page/model-auth/credential-selector.tsx b/web/app/components/header/account-setting/model-provider-page/model-auth/credential-selector.tsx
index 85ff918847..df1287113f 100644
--- a/web/app/components/header/account-setting/model-provider-page/model-auth/credential-selector.tsx
+++ b/web/app/components/header/account-setting/model-provider-page/model-auth/credential-selector.tsx
@@ -4,6 +4,7 @@ import {
PopoverContent,
PopoverTrigger,
} from '@langgenius/dify-ui/popover'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import {
RiAddLine,
RiArrowDownSLine,
@@ -15,7 +16,6 @@ import {
} from 'react'
import { useTranslation } from 'react-i18next'
import Badge from '@/app/components/base/badge'
-import Indicator from '@/app/components/header/indicator'
import CredentialItem from './authorized/credential-item'
type CredentialSelectorProps = {
@@ -60,7 +60,7 @@ const CredentialSelector = ({
selectedCredential && (
{
- !selectedCredential.addNewCredential &&
+ !selectedCredential.addNewCredential &&
}
{selectedCredential.credential_name}
{
diff --git a/web/app/components/header/account-setting/model-provider-page/model-auth/switch-credential-in-load-balancing.tsx b/web/app/components/header/account-setting/model-provider-page/model-auth/switch-credential-in-load-balancing.tsx
index 30bc17d159..aaaa8f5dfa 100644
--- a/web/app/components/header/account-setting/model-provider-page/model-auth/switch-credential-in-load-balancing.tsx
+++ b/web/app/components/header/account-setting/model-provider-page/model-auth/switch-credential-in-load-balancing.tsx
@@ -1,3 +1,4 @@
+import type { StatusDotStatus } from '@langgenius/dify-ui/status-dot'
import type { Dispatch, SetStateAction } from 'react'
import type {
Credential,
@@ -6,6 +7,7 @@ import type {
} from '../declarations'
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import { RiArrowDownSLine } from '@remixicon/react'
import {
@@ -15,7 +17,6 @@ import {
import { useTranslation } from 'react-i18next'
import Badge from '@/app/components/base/badge'
import { ConfigurationMethodEnum, ModelModalModeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
-import Indicator from '@/app/components/header/indicator'
import Authorized from './authorized'
type SwitchCredentialInLoadBalancingProps = {
@@ -49,9 +50,9 @@ const SwitchCredentialInLoadBalancing = ({
const authRemoved = selectedCredentialId && !currentCredential && !empty
const unavailable = currentCredential?.not_allowed_to_use
- let color = 'green'
+ let color: StatusDotStatus = 'success'
if (authRemoved || unavailable)
- color = 'red'
+ color = 'error'
const Item = (
)
diff --git a/web/app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx b/web/app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx
index 0a936d1aa5..24a91f5599 100644
--- a/web/app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx
+++ b/web/app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx
@@ -4,6 +4,7 @@ import { cn } from '@langgenius/dify-ui/cn'
import { ComboboxGroup, ComboboxItem, ComboboxItemIndicator } from '@langgenius/dify-ui/combobox'
import { Popover, PopoverContent, PopoverTrigger } from '@langgenius/dify-ui/popover'
import { PreviewCardTrigger } from '@langgenius/dify-ui/preview-card'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { CreditsCoin } from '@/app/components/base/icons/src/vender/line/financeAndECommerce'
@@ -122,13 +123,13 @@ function PopupItem({
: credentialName
? (
<>
-
+
{credentialName}
>
)
: (
<>
-
+
{t('modelProvider.selector.configureRequired', { ns: 'common' })}
>
)}
diff --git a/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/credential-panel.spec.tsx b/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/credential-panel.spec.tsx
index 9d158a019e..257b0128ab 100644
--- a/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/credential-panel.spec.tsx
+++ b/web/app/components/header/account-setting/model-provider-page/provider-added-card/__tests__/credential-panel.spec.tsx
@@ -85,8 +85,8 @@ vi.mock('../model-auth-dropdown', () => ({
),
}))
-vi.mock('@/app/components/header/indicator', () => ({
- default: ({ color }: { color: string }) =>
,
+vi.mock('@langgenius/dify-ui/status-dot', () => ({
+ StatusDot: ({ status }: { status: string }) =>
,
}))
vi.mock('@/app/components/base/icons/src/vender/line/alertsAndFeedback/Warning', () => ({
@@ -192,7 +192,7 @@ describe('CredentialPanel', () => {
it('should show green indicator and credential name for api-fallback (exhausted + authorized key)', () => {
mockTrialCredits.isExhausted = true
renderWithQueryClient(createProvider())
- expect(screen.getByTestId('indicator')).toHaveAttribute('data-color', 'green')
+ expect(screen.getByTestId('indicator')).toHaveAttribute('data-status', 'success')
expect(screen.getByText('test-credential')).toBeInTheDocument()
})
@@ -206,7 +206,7 @@ describe('CredentialPanel', () => {
renderWithQueryClient(createProvider({
preferred_provider_type: PreferredProviderTypeEnum.custom,
}))
- expect(screen.getByTestId('indicator')).toHaveAttribute('data-color', 'green')
+ expect(screen.getByTestId('indicator')).toHaveAttribute('data-status', 'success')
expect(screen.getByText('test-credential')).toBeInTheDocument()
})
@@ -228,7 +228,7 @@ describe('CredentialPanel', () => {
available_credentials: [{ credential_id: 'cred-1', credential_name: 'Bad Key' }],
},
}))
- expect(screen.getByTestId('indicator')).toHaveAttribute('data-color', 'red')
+ expect(screen.getByTestId('indicator')).toHaveAttribute('data-status', 'error')
expect(screen.getByText('Bad Key')).toBeInTheDocument()
})
})
diff --git a/web/app/components/header/account-setting/model-provider-page/provider-added-card/credential-panel.tsx b/web/app/components/header/account-setting/model-provider-page/provider-added-card/credential-panel.tsx
index 190b05209f..25234a582f 100644
--- a/web/app/components/header/account-setting/model-provider-page/provider-added-card/credential-panel.tsx
+++ b/web/app/components/header/account-setting/model-provider-page/provider-added-card/credential-panel.tsx
@@ -1,9 +1,9 @@
import type { ModelProvider } from '../declarations'
import type { CardVariant } from './use-credential-panel-state'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { memo } from 'react'
import { useTranslation } from 'react-i18next'
import Warning from '@/app/components/base/icons/src/vender/line/alertsAndFeedback/Warning'
-import Indicator from '@/app/components/header/indicator'
import ModelAuthDropdown from './model-auth-dropdown'
import SystemQuotaCard from './system-quota-card'
import { useChangeProviderPriority } from './use-change-provider-priority'
@@ -38,7 +38,7 @@ const CredentialPanel = ({
{isTextLabel
?
- : }
+ : }
-
+
+
)}
/>
diff --git a/web/app/components/header/indicator/__tests__/index.spec.tsx b/web/app/components/header/indicator/__tests__/index.spec.tsx
deleted file mode 100644
index ffb2ade8d3..0000000000
--- a/web/app/components/header/indicator/__tests__/index.spec.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import { render, screen } from '@testing-library/react'
-import Indicator from '../index'
-
-describe('Indicator', () => {
- it('should render with default props', () => {
- render()
- const indicator = screen.getByTestId('status-indicator')
- expect(indicator).toBeInTheDocument()
- expect(indicator).toHaveClass(
- 'bg-components-badge-status-light-success-bg',
- )
- expect(indicator).toHaveClass(
- 'border-components-badge-status-light-success-border-inner',
- )
- expect(indicator).toHaveClass('shadow-status-indicator-green-shadow')
- })
-
- it('should render with orange color', () => {
- render()
- const indicator = screen.getByTestId('status-indicator')
- expect(indicator).toHaveClass(
- 'bg-components-badge-status-light-warning-bg',
- )
- expect(indicator).toHaveClass(
- 'border-components-badge-status-light-warning-border-inner',
- )
- expect(indicator).toHaveClass('shadow-status-indicator-warning-shadow')
- })
-
- it('should render with red color', () => {
- render()
- const indicator = screen.getByTestId('status-indicator')
- expect(indicator).toHaveClass('bg-components-badge-status-light-error-bg')
- expect(indicator).toHaveClass(
- 'border-components-badge-status-light-error-border-inner',
- )
- expect(indicator).toHaveClass('shadow-status-indicator-red-shadow')
- })
-
- it('should render with blue color', () => {
- render()
- const indicator = screen.getByTestId('status-indicator')
- expect(indicator).toHaveClass('bg-components-badge-status-light-normal-bg')
- expect(indicator).toHaveClass(
- 'border-components-badge-status-light-normal-border-inner',
- )
- expect(indicator).toHaveClass('shadow-status-indicator-blue-shadow')
- })
-
- it('should render with yellow color', () => {
- render()
- const indicator = screen.getByTestId('status-indicator')
- expect(indicator).toHaveClass(
- 'bg-components-badge-status-light-warning-bg',
- )
- expect(indicator).toHaveClass(
- 'border-components-badge-status-light-warning-border-inner',
- )
- expect(indicator).toHaveClass('shadow-status-indicator-warning-shadow')
- })
-
- it('should render with gray color', () => {
- render()
- const indicator = screen.getByTestId('status-indicator')
- expect(indicator).toHaveClass(
- 'bg-components-badge-status-light-disabled-bg',
- )
- expect(indicator).toHaveClass(
- 'border-components-badge-status-light-disabled-border-inner',
- )
- expect(indicator).toHaveClass('shadow-status-indicator-gray-shadow')
- })
-
- it('should apply custom className', () => {
- render()
- const indicator = screen.getByTestId('status-indicator')
- expect(indicator).toHaveClass('custom-class')
- })
-})
diff --git a/web/app/components/header/indicator/index.tsx b/web/app/components/header/indicator/index.tsx
deleted file mode 100644
index c60ebcb7bd..0000000000
--- a/web/app/components/header/indicator/index.tsx
+++ /dev/null
@@ -1,54 +0,0 @@
-'use client'
-
-import { cn } from '@langgenius/dify-ui/cn'
-
-export type IndicatorProps = {
- color?: 'green' | 'orange' | 'red' | 'blue' | 'yellow' | 'gray'
- className?: string
-}
-
-export type ColorMap = {
- green: string
- orange: string
- red: string
- blue: string
- yellow: string
- gray: string
-}
-
-const BACKGROUND_MAP: ColorMap = {
- green: 'bg-components-badge-status-light-success-bg',
- orange: 'bg-components-badge-status-light-warning-bg',
- red: 'bg-components-badge-status-light-error-bg',
- blue: 'bg-components-badge-status-light-normal-bg',
- yellow: 'bg-components-badge-status-light-warning-bg',
- gray: 'bg-components-badge-status-light-disabled-bg',
-}
-const BORDER_MAP: ColorMap = {
- green: 'border-components-badge-status-light-success-border-inner',
- orange: 'border-components-badge-status-light-warning-border-inner',
- red: 'border-components-badge-status-light-error-border-inner',
- blue: 'border-components-badge-status-light-normal-border-inner',
- yellow: 'border-components-badge-status-light-warning-border-inner',
- gray: 'border-components-badge-status-light-disabled-border-inner',
-}
-const SHADOW_MAP: ColorMap = {
- green: 'shadow-status-indicator-green-shadow',
- orange: 'shadow-status-indicator-warning-shadow',
- red: 'shadow-status-indicator-red-shadow',
- blue: 'shadow-status-indicator-blue-shadow',
- yellow: 'shadow-status-indicator-warning-shadow',
- gray: 'shadow-status-indicator-gray-shadow',
-}
-
-export default function Indicator({
- color = 'green',
- className = '',
-}: IndicatorProps) {
- return (
-
- )
-}
diff --git a/web/app/components/header/plugins-nav/__tests__/index.spec.tsx b/web/app/components/header/plugins-nav/__tests__/index.spec.tsx
index ab55225641..ff32260811 100644
--- a/web/app/components/header/plugins-nav/__tests__/index.spec.tsx
+++ b/web/app/components/header/plugins-nav/__tests__/index.spec.tsx
@@ -5,6 +5,9 @@ import { useSelectedLayoutSegment } from '@/next/navigation'
import PluginsNav from '../index'
+const queryErrorStatusDot = (container: HTMLElement) =>
+ container.querySelector('.shadow-status-indicator-red-shadow')
+
vi.mock('@/next/navigation', () => ({
useSelectedLayoutSegment: vi.fn(),
}))
@@ -38,7 +41,7 @@ describe('PluginsNav', () => {
const svg = linkElement.querySelector('svg')
expect(svg).toBeInTheDocument()
- expect(screen.queryByTestId('status-indicator')).not.toBeInTheDocument()
+ expect(queryErrorStatusDot(linkElement)).not.toBeInTheDocument()
})
describe('Active State', () => {
@@ -70,7 +73,7 @@ describe('PluginsNav', () => {
expect(svgs.length).toBe(1)
expect(svgs[0]).toHaveClass('install-icon')
- expect(screen.queryByTestId('status-indicator')).not.toBeInTheDocument()
+ expect(queryErrorStatusDot(container)).not.toBeInTheDocument()
})
it('renders Installing With Error state (Inactive)', () => {
@@ -81,7 +84,7 @@ describe('PluginsNav', () => {
const downloadingIcon = container.querySelector('.install-icon')
expect(downloadingIcon).toBeInTheDocument()
- expect(screen.getByTestId('status-indicator')).toBeInTheDocument()
+ expect(queryErrorStatusDot(container)).toBeInTheDocument()
})
it('renders Failed state (Inactive)', () => {
@@ -93,7 +96,7 @@ describe('PluginsNav', () => {
expect(svg).toBeInTheDocument()
expect(svg).not.toHaveClass('install-icon')
- expect(screen.getByTestId('status-indicator')).toBeInTheDocument()
+ expect(queryErrorStatusDot(container)).toBeInTheDocument()
})
it('renders Default icon when Active even if installing', () => {
diff --git a/web/app/components/header/plugins-nav/index.tsx b/web/app/components/header/plugins-nav/index.tsx
index ca3ebdbbb6..8e5ef258b2 100644
--- a/web/app/components/header/plugins-nav/index.tsx
+++ b/web/app/components/header/plugins-nav/index.tsx
@@ -1,9 +1,9 @@
'use client'
import { cn } from '@langgenius/dify-ui/cn'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { useTranslation } from 'react-i18next'
import { Group } from '@/app/components/base/icons/src/vender/other'
-import Indicator from '@/app/components/header/indicator'
import { usePluginTaskStatus } from '@/app/components/plugins/plugin-page/plugin-tasks/hooks'
import Link from '@/next/link'
import { useSelectedLayoutSegment } from '@/next/navigation'
@@ -37,8 +37,8 @@ const PluginsNav = ({
>
{
(isFailed || isInstallingWithError) && !activated && (
-
)
diff --git a/web/app/components/plugins/plugin-auth/__tests__/authorized-in-data-source-node.spec.tsx b/web/app/components/plugins/plugin-auth/__tests__/authorized-in-data-source-node.spec.tsx
index d5cea7a495..76adaf5721 100644
--- a/web/app/components/plugins/plugin-auth/__tests__/authorized-in-data-source-node.spec.tsx
+++ b/web/app/components/plugins/plugin-auth/__tests__/authorized-in-data-source-node.spec.tsx
@@ -2,8 +2,8 @@ import { cleanup, fireEvent, render, screen } from '@testing-library/react'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import AuthorizedInDataSourceNode from '../authorized-in-data-source-node'
-vi.mock('@/app/components/header/indicator', () => ({
- default: ({ color }: { color: string }) => ,
+vi.mock('@langgenius/dify-ui/status-dot', () => ({
+ StatusDot: ({ status }: { status: string }) => ,
}))
describe('AuthorizedInDataSourceNode', () => {
@@ -19,7 +19,7 @@ describe('AuthorizedInDataSourceNode', () => {
it('renders with green indicator', () => {
render()
- expect(screen.getByTestId('indicator')).toHaveAttribute('data-color', 'green')
+ expect(screen.getByTestId('indicator')).toHaveAttribute('data-status', 'success')
})
it('renders singular text for 1 authorization', () => {
diff --git a/web/app/components/plugins/plugin-auth/authorized-in-data-source-node.tsx b/web/app/components/plugins/plugin-auth/authorized-in-data-source-node.tsx
index d8b1245c16..c8dda200bc 100644
--- a/web/app/components/plugins/plugin-auth/authorized-in-data-source-node.tsx
+++ b/web/app/components/plugins/plugin-auth/authorized-in-data-source-node.tsx
@@ -1,11 +1,11 @@
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { RiEqualizer2Line } from '@remixicon/react'
import {
memo,
} from 'react'
import { useTranslation } from 'react-i18next'
-import Indicator from '@/app/components/header/indicator'
type AuthorizedInDataSourceNodeProps = {
authorizationsNum: number
@@ -22,9 +22,9 @@ const AuthorizedInDataSourceNode = ({
size="small"
onClick={onJumpToDataSourcePage}
>
-
{
authorizationsNum > 1
diff --git a/web/app/components/plugins/plugin-auth/authorized-in-node.tsx b/web/app/components/plugins/plugin-auth/authorized-in-node.tsx
index 12a84b56e3..0831fe9a15 100644
--- a/web/app/components/plugins/plugin-auth/authorized-in-node.tsx
+++ b/web/app/components/plugins/plugin-auth/authorized-in-node.tsx
@@ -1,9 +1,11 @@
+import type { StatusDotStatus } from '@langgenius/dify-ui/status-dot'
import type {
Credential,
PluginPayload,
} from './types'
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { RiArrowDownSLine } from '@remixicon/react'
import {
memo,
@@ -11,7 +13,6 @@ import {
useState,
} from 'react'
import { useTranslation } from 'react-i18next'
-import Indicator from '@/app/components/header/indicator'
import {
Authorized,
usePluginAuth,
@@ -41,7 +42,7 @@ const AuthorizedInNode = ({
let label = ''
let removed = false
let unavailable = false
- let color = 'green'
+ let color: StatusDotStatus = 'success'
let defaultUnavailable = false
if (!credentialId) {
label = t('auth.workspaceDefault', { ns: 'plugin' })
@@ -49,7 +50,7 @@ const AuthorizedInNode = ({
const defaultCredential = credentials.find(c => c.is_default)
if (defaultCredential?.not_allowed_to_use) {
- color = 'gray'
+ color = 'disabled'
defaultUnavailable = true
}
}
@@ -60,9 +61,9 @@ const AuthorizedInNode = ({
unavailable = !!credential?.not_allowed_to_use && !credential?.from_enterprise
if (removed)
- color = 'red'
+ color = 'error'
else if (unavailable)
- color = 'gray'
+ color = 'disabled'
}
return (
-
{label}
{
diff --git a/web/app/components/plugins/plugin-detail-panel/__tests__/endpoint-card.spec.tsx b/web/app/components/plugins/plugin-detail-panel/__tests__/endpoint-card.spec.tsx
index 1dab8bdf84..d2ac595c87 100644
--- a/web/app/components/plugins/plugin-detail-panel/__tests__/endpoint-card.spec.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/__tests__/endpoint-card.spec.tsx
@@ -72,8 +72,8 @@ vi.mock('@/service/use-endpoints', () => ({
}),
}))
-vi.mock('@/app/components/header/indicator', () => ({
- default: ({ color }: { color: string }) =>
,
+vi.mock('@langgenius/dify-ui/status-dot', () => ({
+ StatusDot: ({ status }: { status: string }) =>
,
}))
vi.mock('@/app/components/tools/utils/to-form-schema', () => ({
@@ -176,7 +176,7 @@ describe('EndpointCard', () => {
render(
)
expect(screen.getByText('plugin.detailPanel.serviceOk'))!.toBeInTheDocument()
- expect(screen.getByTestId('indicator'))!.toHaveAttribute('data-color', 'green')
+ expect(screen.getByTestId('indicator'))!.toHaveAttribute('data-status', 'success')
})
it('should show disabled status when not enabled', () => {
@@ -184,7 +184,7 @@ describe('EndpointCard', () => {
render(
)
expect(screen.getByText('plugin.detailPanel.disabled'))!.toBeInTheDocument()
- expect(screen.getByTestId('indicator'))!.toHaveAttribute('data-color', 'gray')
+ expect(screen.getByTestId('indicator'))!.toHaveAttribute('data-status', 'disabled')
})
})
diff --git a/web/app/components/plugins/plugin-detail-panel/datasource-action-list.tsx b/web/app/components/plugins/plugin-detail-panel/datasource-action-list.tsx
index 5bba7b823b..b8768b16a1 100644
--- a/web/app/components/plugins/plugin-detail-panel/datasource-action-list.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/datasource-action-list.tsx
@@ -1,6 +1,6 @@
// import { useAppContext } from '@/context/app-context'
// import { Button } from '@langgenius/dify-ui/button'
-// import Indicator from '@/app/components/header/indicator'
+// import { StatusDot } from '@langgenius/dify-ui/status-dot'
// import ToolItem from '@/app/components/tools/provider/tool-item'
// import ConfigCredential from '@/app/components/tools/setting/build-in/config-credentials'
import type { PluginDetail } from '@/app/components/plugins/types'
@@ -60,7 +60,7 @@ const ActionList = ({
onClick={() => setShowSettingAuth(true)}
disabled={!isCurrentWorkspaceManager}
>
-
+
{t('tools.auth.authorized')}
)} */}
diff --git a/web/app/components/plugins/plugin-detail-panel/endpoint-card.tsx b/web/app/components/plugins/plugin-detail-panel/endpoint-card.tsx
index 9cea1defbc..8fff7c7da5 100644
--- a/web/app/components/plugins/plugin-detail-panel/endpoint-card.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/endpoint-card.tsx
@@ -8,6 +8,7 @@ import {
AlertDialogContent,
AlertDialogTitle,
} from '@langgenius/dify-ui/alert-dialog'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { Switch } from '@langgenius/dify-ui/switch'
import { toast } from '@langgenius/dify-ui/toast'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
@@ -18,7 +19,6 @@ import { useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import ActionButton from '@/app/components/base/action-button'
import { CopyCheck } from '@/app/components/base/icons/src/vender/line/files'
-import Indicator from '@/app/components/header/indicator'
import { addDefaultValue, toolCredentialToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
import {
useDeleteEndpoint,
@@ -199,13 +199,13 @@ const EndpointCard = ({
{active && (
-
+
{t('detailPanel.serviceOk', { ns: 'plugin' })}
)}
{!active && (
-
+
{t('detailPanel.disabled', { ns: 'plugin' })}
)}
diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/components/tool-item.tsx b/web/app/components/plugins/plugin-detail-panel/tool-selector/components/tool-item.tsx
index 2bb690777c..06735865f7 100644
--- a/web/app/components/plugins/plugin-detail-panel/tool-selector/components/tool-item.tsx
+++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/components/tool-item.tsx
@@ -2,6 +2,7 @@
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
import { Popover, PopoverContent, PopoverTrigger } from '@langgenius/dify-ui/popover'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { Switch } from '@langgenius/dify-ui/switch'
import {
RiDeleteBinLine,
@@ -14,7 +15,6 @@ import { useTranslation } from 'react-i18next'
import ActionButton from '@/app/components/base/action-button'
import AppIcon from '@/app/components/base/app-icon'
import { Group } from '@/app/components/base/icons/src/vender/other'
-import Indicator from '@/app/components/header/indicator'
import { InstallPluginButton } from '@/app/components/workflow/nodes/_base/components/install-plugin-button'
import { useMCPToolAvailability } from '@/app/components/workflow/nodes/_base/components/mcp-tool-availability'
import McpToolNotSupportTooltip from '@/app/components/workflow/nodes/_base/components/mcp-tool-not-support-tooltip'
@@ -128,13 +128,13 @@ const ToolItem = ({
{!isError && !uninstalled && !versionMismatch && noAuth && (
)}
{!isError && !uninstalled && !versionMismatch && authRemoved && (
)}
{!isError && !uninstalled && versionMismatch && installInfo && (
diff --git a/web/app/components/plugins/plugin-page/plugin-tasks/components/__tests__/task-status-indicator.spec.tsx b/web/app/components/plugins/plugin-page/plugin-tasks/components/__tests__/task-status-indicator.spec.tsx
index addae49d98..8311a54f44 100644
--- a/web/app/components/plugins/plugin-page/plugin-tasks/components/__tests__/task-status-indicator.spec.tsx
+++ b/web/app/components/plugins/plugin-page/plugin-tasks/components/__tests__/task-status-indicator.spec.tsx
@@ -1,9 +1,9 @@
import { fireEvent, render, screen } from '@testing-library/react'
import TaskStatusIndicator from '../task-status-indicator'
-vi.mock('@/app/components/base/progress-bar/progress-circle', () => ({
- default: ({ percentage }: { percentage: number }) => (
-
+vi.mock('@langgenius/dify-ui/progress', () => ({
+ ProgressCircle: ({ value }: { value: number }) => (
+
),
}))
@@ -68,7 +68,7 @@ describe('TaskStatusIndicator', () => {
/>,
)
const progress = screen.getByTestId('progress-circle')
- expect(progress).toHaveAttribute('data-percentage', '40')
+ expect(progress).toHaveAttribute('data-value', '40')
})
it('should show progress circle when isInstallingWithSuccess', () => {
@@ -81,7 +81,7 @@ describe('TaskStatusIndicator', () => {
/>,
)
const progress = screen.getByTestId('progress-circle')
- expect(progress).toHaveAttribute('data-percentage', '75')
+ expect(progress).toHaveAttribute('data-value', '75')
})
it('should show error progress circle when isInstallingWithError', () => {
@@ -106,7 +106,7 @@ describe('TaskStatusIndicator', () => {
/>,
)
const progress = screen.getByTestId('progress-circle')
- expect(progress).toHaveAttribute('data-percentage', '0')
+ expect(progress).toHaveAttribute('data-value', '0')
})
})
diff --git a/web/app/components/plugins/plugin-page/plugin-tasks/components/task-status-indicator.tsx b/web/app/components/plugins/plugin-page/plugin-tasks/components/task-status-indicator.tsx
index ae75566aae..dfab072746 100644
--- a/web/app/components/plugins/plugin-page/plugin-tasks/components/task-status-indicator.tsx
+++ b/web/app/components/plugins/plugin-page/plugin-tasks/components/task-status-indicator.tsx
@@ -1,8 +1,8 @@
import type { FC } from 'react'
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
+import { ProgressCircle } from '@langgenius/dify-ui/progress'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
-import ProgressCircle from '@/app/components/base/progress-bar/progress-circle'
import DownloadingIcon from '@/app/components/header/plugins-nav/downloading-icon'
type TaskStatusIndicatorProps = {
@@ -67,16 +67,15 @@ const TaskStatusIndicator: FC
= ({
{(isInstalling || isInstallingWithSuccess) && (
0 ? successPluginsLength / totalPluginsLength : 0) * 100}
- circleFillColor="fill-components-progress-brand-bg"
+ value={(totalPluginsLength > 0 ? successPluginsLength / totalPluginsLength : 0) * 100}
+ aria-label={tip}
/>
)}
{isInstallingWithError && (
0 ? runningPluginsLength / totalPluginsLength : 0) * 100}
- circleFillColor="fill-components-progress-brand-bg"
- sectorFillColor="fill-components-progress-error-border"
- circleStrokeColor="stroke-components-progress-error-border"
+ value={(totalPluginsLength > 0 ? runningPluginsLength / totalPluginsLength : 0) * 100}
+ color="error"
+ aria-label={tip}
/>
)}
{showSuccessIcon && !isInstalling && !isInstallingWithSuccess && !isInstallingWithError && (
diff --git a/web/app/components/tools/mcp/detail/content.tsx b/web/app/components/tools/mcp/detail/content.tsx
index b83fb847b1..e78d88b783 100644
--- a/web/app/components/tools/mcp/detail/content.tsx
+++ b/web/app/components/tools/mcp/detail/content.tsx
@@ -12,6 +12,7 @@ import {
} from '@langgenius/dify-ui/alert-dialog'
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import { useBoolean } from 'ahooks'
import copy from 'copy-to-clipboard'
@@ -19,7 +20,6 @@ import * as React from 'react'
import { useCallback, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import ActionButton from '@/app/components/base/action-button'
-import Indicator from '@/app/components/header/indicator'
import Icon from '@/app/components/plugins/card/base/card-icon'
import { useAppContext } from '@/context/app-context'
import { openOAuthPopup } from '@/hooks/use-oauth'
@@ -231,7 +231,7 @@ const MCPDetailContent: FC = ({
onClick={handleAuthorize}
disabled={!isCurrentWorkspaceManager}
>
-
+
{t('auth.authorized', { ns: 'tools' })}
)}
diff --git a/web/app/components/tools/mcp/mcp-service-card.tsx b/web/app/components/tools/mcp/mcp-service-card.tsx
index 38c757f841..a897d39dbd 100644
--- a/web/app/components/tools/mcp/mcp-service-card.tsx
+++ b/web/app/components/tools/mcp/mcp-service-card.tsx
@@ -16,6 +16,7 @@ import {
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
import { Popover, PopoverContent, PopoverTrigger } from '@langgenius/dify-ui/popover'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { Switch } from '@langgenius/dify-ui/switch'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import { RiEditLine, RiLoopLeftLine } from '@remixicon/react'
@@ -24,7 +25,6 @@ import { useTranslation } from 'react-i18next'
import CopyFeedback from '@/app/components/base/copy-feedback'
import Divider from '@/app/components/base/divider'
import { Mcp } from '@/app/components/base/icons/src/vender/other'
-import Indicator from '@/app/components/header/indicator'
import MCPServerModal from '@/app/components/tools/mcp/mcp-server-modal'
import { collaborationManager } from '@/app/components/workflow/collaboration/core/collaboration-manager'
import { useDocLink } from '@/context/i18n'
@@ -40,7 +40,7 @@ const StatusIndicator: FC = ({ serverActivated }) => {
const { t } = useTranslation()
return (
-
+
{serverActivated
? t('overview.status.running', { ns: 'appOverview' })
diff --git a/web/app/components/tools/mcp/provider-card.tsx b/web/app/components/tools/mcp/provider-card.tsx
index 45e5a24f68..4536d96cad 100644
--- a/web/app/components/tools/mcp/provider-card.tsx
+++ b/web/app/components/tools/mcp/provider-card.tsx
@@ -9,11 +9,11 @@ import {
AlertDialogTitle,
} from '@langgenius/dify-ui/alert-dialog'
import { cn } from '@langgenius/dify-ui/cn'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { RiHammerFill } from '@remixicon/react'
import { useBoolean } from 'ahooks'
import { useCallback, useState } from 'react'
import { useTranslation } from 'react-i18next'
-import Indicator from '@/app/components/header/indicator'
import Icon from '@/app/components/plugins/card/base/card-icon'
import { useAppContext } from '@/context/app-context'
import { useFormatTimeFromNow } from '@/hooks/use-format-time-from-now'
@@ -112,11 +112,11 @@ const MCPCard = ({
/
{`${t('mcp.updateTime', { ns: 'tools' })} ${formatTimeFromNow(data.updated_at! * 1000)}`}
- {data.is_team_authorization && data.tools.length > 0 &&
}
+ {data.is_team_authorization && data.tools.length > 0 &&
}
{(!data.is_team_authorization || !data.tools.length) && (
{t('mcp.noConfigured', { ns: 'tools' })}
-
+
)}
diff --git a/web/app/components/tools/provider/__tests__/detail.spec.tsx b/web/app/components/tools/provider/__tests__/detail.spec.tsx
index 5a26589e11..70a35f3ddb 100644
--- a/web/app/components/tools/provider/__tests__/detail.spec.tsx
+++ b/web/app/components/tools/provider/__tests__/detail.spec.tsx
@@ -83,8 +83,8 @@ vi.mock('@langgenius/dify-ui/toast', () => ({
},
}))
-vi.mock('@/app/components/header/indicator', () => ({
- default: () => ,
+vi.mock('@langgenius/dify-ui/status-dot', () => ({
+ StatusDot: () => ,
}))
vi.mock('@/app/components/plugins/card/base/card-icon', () => ({
diff --git a/web/app/components/tools/provider/detail.tsx b/web/app/components/tools/provider/detail.tsx
index bf878a6206..ff64e0044c 100644
--- a/web/app/components/tools/provider/detail.tsx
+++ b/web/app/components/tools/provider/detail.tsx
@@ -20,6 +20,7 @@ import {
DrawerPortal,
DrawerViewport,
} from '@langgenius/dify-ui/drawer'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { toast } from '@langgenius/dify-ui/toast'
import {
RiCloseLine,
@@ -31,7 +32,6 @@ import ActionButton from '@/app/components/base/action-button'
import { LinkExternal02, Settings01 } from '@/app/components/base/icons/src/vender/line/general'
import Loading from '@/app/components/base/loading'
import { ConfigurationMethodEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
-import Indicator from '@/app/components/header/indicator'
import Icon from '@/app/components/plugins/card/base/card-icon'
import Description from '@/app/components/plugins/card/base/description'
import OrgInfo from '@/app/components/plugins/card/base/org-info'
@@ -325,7 +325,7 @@ const ProviderDetail = ({
}}
disabled={!isCurrentWorkspaceManager}
>
-
+
{t('auth.authorized', { ns: 'tools' })}
)}
diff --git a/web/app/components/tools/workflow-tool/configure-button.tsx b/web/app/components/tools/workflow-tool/configure-button.tsx
index 5b83e37d3a..0adc923e48 100644
--- a/web/app/components/tools/workflow-tool/configure-button.tsx
+++ b/web/app/components/tools/workflow-tool/configure-button.tsx
@@ -1,9 +1,9 @@
'use client'
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { useTranslation } from 'react-i18next'
import Loading from '@/app/components/base/loading'
-import Indicator from '@/app/components/header/indicator'
import { useRouter } from '@/next/navigation'
import Divider from '../../base/divider'
@@ -90,7 +90,7 @@ const WorkflowToolConfigureButton = ({
disabled={!isCurrentWorkspaceManager || disabled}
>
{t('common.configure', { ns: 'workflow' })}
- {outdated && }
+ {outdated && }
)}
/>
@@ -83,7 +83,7 @@ export const ModelBar: FC = (props) => {
readonly
deprecatedClassName="opacity-50"
/>
- {showWarn && }
+ {showWarn && }
)
diff --git a/web/app/components/workflow/nodes/agent/components/tool-icon.tsx b/web/app/components/workflow/nodes/agent/components/tool-icon.tsx
index f672730523..d898497e42 100644
--- a/web/app/components/workflow/nodes/agent/components/tool-icon.tsx
+++ b/web/app/components/workflow/nodes/agent/components/tool-icon.tsx
@@ -1,11 +1,11 @@
import type { ReactNode } from 'react'
import { cn } from '@langgenius/dify-ui/cn'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import { memo, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import AppIcon from '@/app/components/base/app-icon'
import { Group } from '@/app/components/base/icons/src/vender/other'
-import Indicator from '@/app/components/header/indicator'
import { useAllBuiltInTools, useAllCustomTools, useAllMCPTools, useAllWorkflowTools } from '@/service/use-tools'
import { getIconFromMarketPlace } from '@/utils/get-icon'
@@ -50,7 +50,7 @@ export const ToolIcon = memo(({ providerName }: ToolIconProps) => {
return 'not-authorized'
return undefined
}, [currentProvider, isDataReady])
- const indicator = status === 'not-installed' ? 'red' : status === 'not-authorized' ? 'yellow' : undefined
+ const indicator = status === 'not-installed' ? 'error' : status === 'not-authorized' ? 'warning' : undefined
const notSuccess = (['not-installed', 'not-authorized'] as Array
).includes(status)
const { t } = useTranslation()
const tooltip = useMemo(() => {
@@ -96,7 +96,7 @@ export const ToolIcon = memo(({ providerName }: ToolIconProps) => {
{iconContent}
- {indicator && }
+ {indicator && }
)
diff --git a/web/app/components/workflow/nodes/human-input/components/delivery-method/method-item.tsx b/web/app/components/workflow/nodes/human-input/components/delivery-method/method-item.tsx
index 5a997d0d15..97a086a38b 100644
--- a/web/app/components/workflow/nodes/human-input/components/delivery-method/method-item.tsx
+++ b/web/app/components/workflow/nodes/human-input/components/delivery-method/method-item.tsx
@@ -6,6 +6,7 @@ import type {
} from '@/app/components/workflow/types'
import { Button } from '@langgenius/dify-ui/button'
import { cn } from '@langgenius/dify-ui/cn'
+import { StatusDot } from '@langgenius/dify-ui/status-dot'
import { Switch } from '@langgenius/dify-ui/switch'
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
import {
@@ -19,7 +20,6 @@ import { useCallback, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import ActionButton, { ActionButtonState } from '@/app/components/base/action-button'
import Badge from '@/app/components/base/badge/index'
-import Indicator from '@/app/components/header/indicator'
import { useSelector as useAppContextWithSelector } from '@/context/app-context'
import { DeliveryMethodType } from '../../types'
import EmailConfigureModal from './email-configure-modal'
@@ -177,7 +177,7 @@ const DeliveryMethodItem: FC