Compare commits

..

4 Commits

Author SHA1 Message Date
yyh
510f952e18 Merge branch 'main' into provider-search-clear-btn 2026-02-27 19:33:45 +08:00
yyh
0b0d236225 refactor(web): use SearchInput for provider search 2026-02-27 19:33:18 +08:00
-LAN-
a11ebbe742 fix(web): resolve web style lint failures 2026-02-27 18:24:28 +08:00
-LAN-
579342d777 feat: add a clear btn in provider's search field
Signed-off-by: -LAN- <laipz8200@outlook.com>
2026-02-27 17:25:46 +08:00
10 changed files with 736 additions and 801 deletions

View File

@@ -77,7 +77,7 @@ def _restx_mask_defaults(app: Flask):
def test_code_based_extension_get_returns_service_data(app: Flask, monkeypatch: pytest.MonkeyPatch):
service_result = [{"entrypoint": "main:agent"}]
service_result = {"entrypoint": "main:agent"}
service_mock = MagicMock(return_value=service_result)
monkeypatch.setattr(
"controllers.console.extension.CodeBasedExtensionService.get_code_based_extension",

View File

@@ -33,7 +33,7 @@ Then, configure the environment variables. Create a file named `.env.local` in t
cp .env.example .env.local
```
```txt
```
# For production release, change this to PRODUCTION
NEXT_PUBLIC_DEPLOY_ENV=DEVELOPMENT
# The deployment edition, SELF_HOSTED

View File

@@ -61,7 +61,8 @@ const ParamsConfig = ({
if (tempDataSetConfigs.retrieval_model === RETRIEVE_TYPE.multiWay) {
if (tempDataSetConfigs.reranking_enable
&& tempDataSetConfigs.reranking_mode === RerankingModeEnum.RerankingModel
&& !isCurrentRerankModelValid) {
&& !isCurrentRerankModelValid
) {
errMsg = t('datasetConfig.rerankModelRequired', { ns: 'appDebug' })
}
}

View File

@@ -1,6 +1,5 @@
import type { VariantProps } from 'class-variance-authority'
import type { ChangeEventHandler, CSSProperties, FocusEventHandler } from 'react'
import { RiCloseCircleFill, RiErrorWarningLine, RiSearchLine } from '@remixicon/react'
import { cva } from 'class-variance-authority'
import { noop } from 'es-toolkit/function'
import * as React from 'react'
@@ -13,8 +12,8 @@ export const inputVariants = cva(
{
variants: {
size: {
regular: 'px-3 radius-md system-sm-regular',
large: 'px-4 radius-lg system-md-regular',
regular: 'px-3 system-sm-regular radius-md',
large: 'px-4 system-md-regular radius-lg',
},
},
defaultVariants: {
@@ -83,7 +82,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({
}
return (
<div className={cn('relative w-full', wrapperClassName)}>
{showLeftIcon && <RiSearchLine className={cn('absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-components-input-text-placeholder')} />}
{showLeftIcon && <span className={cn('i-ri-search-line absolute left-2 top-1/2 h-4 w-4 -translate-y-1/2 text-components-input-text-placeholder')} />}
<input
ref={ref}
style={styleCss}
@@ -115,11 +114,11 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({
onClick={onClear}
data-testid="input-clear"
>
<RiCloseCircleFill className="h-3.5 w-3.5 cursor-pointer text-text-quaternary group-hover:text-text-tertiary" />
<span className="i-ri-close-circle-fill h-3.5 w-3.5 cursor-pointer text-text-quaternary group-hover:text-text-tertiary" />
</div>
)}
{destructive && (
<RiErrorWarningLine className="absolute right-2 top-1/2 h-4 w-4 -translate-y-1/2 text-text-destructive-secondary" />
<span className="i-ri-error-warning-line absolute right-2 top-1/2 h-4 w-4 -translate-y-1/2 text-text-destructive-secondary" />
)}
{showCopyIcon && (
<div className={cn('group absolute right-0 top-1/2 -translate-y-1/2 cursor-pointer')}>
@@ -131,7 +130,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({
)}
{
unit && (
<div className="system-sm-regular absolute right-2 top-1/2 -translate-y-1/2 text-text-tertiary">
<div className="absolute right-2 top-1/2 -translate-y-1/2 text-text-tertiary system-sm-regular">
{unit}
</div>
)

View File

@@ -1,24 +1,8 @@
'use client'
import type { AccountSettingTab } from '@/app/components/header/account-setting/constants'
import {
RiBrain2Fill,
RiBrain2Line,
RiCloseLine,
RiColorFilterFill,
RiColorFilterLine,
RiDatabase2Fill,
RiDatabase2Line,
RiGroup2Fill,
RiGroup2Line,
RiMoneyDollarCircleFill,
RiMoneyDollarCircleLine,
RiPuzzle2Fill,
RiPuzzle2Line,
RiTranslate2,
} from '@remixicon/react'
import { useEffect, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import Input from '@/app/components/base/input'
import SearchInput from '@/app/components/base/search-input'
import BillingPage from '@/app/components/billing/billing-page'
import CustomPage from '@/app/components/custom/custom-page'
import {
@@ -76,14 +60,14 @@ export default function AccountSetting({
{
key: ACCOUNT_SETTING_TAB.PROVIDER,
name: t('settings.provider', { ns: 'common' }),
icon: <RiBrain2Line className={iconClassName} />,
activeIcon: <RiBrain2Fill className={iconClassName} />,
icon: <span className={cn('i-ri-brain-2-line', iconClassName)} />,
activeIcon: <span className={cn('i-ri-brain-2-fill', iconClassName)} />,
},
{
key: ACCOUNT_SETTING_TAB.MEMBERS,
name: t('settings.members', { ns: 'common' }),
icon: <RiGroup2Line className={iconClassName} />,
activeIcon: <RiGroup2Fill className={iconClassName} />,
icon: <span className={cn('i-ri-group-2-line', iconClassName)} />,
activeIcon: <span className={cn('i-ri-group-2-fill', iconClassName)} />,
},
]
@@ -92,8 +76,8 @@ export default function AccountSetting({
key: ACCOUNT_SETTING_TAB.BILLING,
name: t('settings.billing', { ns: 'common' }),
description: t('plansCommon.receiptInfo', { ns: 'billing' }),
icon: <RiMoneyDollarCircleLine className={iconClassName} />,
activeIcon: <RiMoneyDollarCircleFill className={iconClassName} />,
icon: <span className={cn('i-ri-money-dollar-circle-line', iconClassName)} />,
activeIcon: <span className={cn('i-ri-money-dollar-circle-fill', iconClassName)} />,
})
}
@@ -101,14 +85,14 @@ export default function AccountSetting({
{
key: ACCOUNT_SETTING_TAB.DATA_SOURCE,
name: t('settings.dataSource', { ns: 'common' }),
icon: <RiDatabase2Line className={iconClassName} />,
activeIcon: <RiDatabase2Fill className={iconClassName} />,
icon: <span className={cn('i-ri-database-2-line', iconClassName)} />,
activeIcon: <span className={cn('i-ri-database-2-fill', iconClassName)} />,
},
{
key: ACCOUNT_SETTING_TAB.API_BASED_EXTENSION,
name: t('settings.apiBasedExtension', { ns: 'common' }),
icon: <RiPuzzle2Line className={iconClassName} />,
activeIcon: <RiPuzzle2Fill className={iconClassName} />,
icon: <span className={cn('i-ri-puzzle-2-line', iconClassName)} />,
activeIcon: <span className={cn('i-ri-puzzle-2-fill', iconClassName)} />,
},
)
@@ -116,8 +100,8 @@ export default function AccountSetting({
items.push({
key: ACCOUNT_SETTING_TAB.CUSTOM,
name: t('custom', { ns: 'custom' }),
icon: <RiColorFilterLine className={iconClassName} />,
activeIcon: <RiColorFilterFill className={iconClassName} />,
icon: <span className={cn('i-ri-color-filter-line', iconClassName)} />,
activeIcon: <span className={cn('i-ri-color-filter-fill', iconClassName)} />,
})
}
@@ -140,8 +124,8 @@ export default function AccountSetting({
{
key: ACCOUNT_SETTING_TAB.LANGUAGE,
name: t('settings.language', { ns: 'common' }),
icon: <RiTranslate2 className={iconClassName} />,
activeIcon: <RiTranslate2 className={iconClassName} />,
icon: <span className={cn('i-ri-translate-2', iconClassName)} />,
activeIcon: <span className={cn('i-ri-translate-2', iconClassName)} />,
},
],
},
@@ -171,13 +155,13 @@ export default function AccountSetting({
>
<div className="mx-auto flex h-[100vh] max-w-[1048px]">
<div className="flex w-[44px] flex-col border-r border-divider-burn pl-4 pr-6 sm:w-[224px]">
<div className="title-2xl-semi-bold mb-8 mt-6 px-3 py-2 text-text-primary">{t('userProfile.settings', { ns: 'common' })}</div>
<div className="mb-8 mt-6 px-3 py-2 text-text-primary title-2xl-semi-bold">{t('userProfile.settings', { ns: 'common' })}</div>
<div className="w-full">
{
menuItems.map(menuItem => (
<div key={menuItem.key} className="mb-2">
{!isCurrentWorkspaceDatasetOperator && (
<div className="system-xs-medium-uppercase mb-0.5 py-2 pb-1 pl-3 text-text-tertiary">{menuItem.name}</div>
<div className="mb-0.5 py-2 pb-1 pl-3 text-text-tertiary system-xs-medium-uppercase">{menuItem.name}</div>
)}
<div>
{
@@ -186,7 +170,7 @@ export default function AccountSetting({
key={item.key}
className={cn(
'mb-0.5 flex h-[37px] cursor-pointer items-center rounded-lg p-1 pl-3 text-sm',
activeMenu === item.key ? 'system-sm-semibold bg-state-base-active text-components-menu-item-text-active' : 'system-sm-medium text-components-menu-item-text',
activeMenu === item.key ? 'bg-state-base-active text-components-menu-item-text-active system-sm-semibold' : 'text-components-menu-item-text system-sm-medium',
)}
title={item.name}
onClick={() => {
@@ -213,25 +197,23 @@ export default function AccountSetting({
className="px-2"
onClick={onCancel}
>
<RiCloseLine className="h-5 w-5" />
<span className="i-ri-close-line h-5 w-5" />
</Button>
<div className="system-2xs-medium-uppercase mt-1 text-text-tertiary">ESC</div>
<div className="mt-1 text-text-tertiary system-2xs-medium-uppercase">ESC</div>
</div>
<div ref={scrollRef} className="w-full overflow-y-auto bg-components-panel-bg pb-4">
<div className={cn('sticky top-0 z-20 mx-8 mb-[18px] flex items-center bg-components-panel-bg pb-2 pt-[27px]', scrolled && 'border-b border-divider-regular')}>
<div className="title-2xl-semi-bold shrink-0 text-text-primary">
<div className="shrink-0 text-text-primary title-2xl-semi-bold">
{activeItem?.name}
{activeItem?.description && (
<div className="system-sm-regular mt-1 text-text-tertiary">{activeItem?.description}</div>
<div className="mt-1 text-text-tertiary system-sm-regular">{activeItem?.description}</div>
)}
</div>
{activeItem?.key === 'provider' && (
<div className="flex grow justify-end">
<Input
showLeftIcon
wrapperClassName="!w-[200px]"
className="!h-8 !text-[13px]"
onChange={e => setSearchValue(e.target.value)}
<SearchInput
className="w-[200px]"
onChange={setSearchValue}
value={searchValue}
/>
</div>

View File

@@ -46,7 +46,8 @@ const nodeDefault: NodeDefault<HttpNodeType> = {
if (!errorMessages
&& payload.body.type === BodyType.binary
&& ((!(payload.body.data as BodyPayload)[0]?.file) || (payload.body.data as BodyPayload)[0]?.file?.length === 0)) {
&& ((!(payload.body.data as BodyPayload)[0]?.file) || (payload.body.data as BodyPayload)[0]?.file?.length === 0)
) {
errorMessages = t('errorMsg.fieldRequired', { ns: 'workflow', field: t('nodes.http.binaryFileVariable', { ns: 'workflow' }) })
}

View File

@@ -2052,9 +2052,6 @@
"app/components/base/input/index.tsx": {
"react-refresh/only-export-components": {
"count": 1
},
"tailwindcss/enforce-consistent-class-order": {
"count": 3
}
},
"app/components/base/linked-apps-panel/index.tsx": {
@@ -3994,9 +3991,6 @@
"app/components/header/account-setting/index.tsx": {
"react-hooks-extra/no-direct-set-state-in-use-effect": {
"count": 1
},
"tailwindcss/enforce-consistent-class-order": {
"count": 7
}
},
"app/components/header/account-setting/key-validator/declarations.ts": {
@@ -8169,6 +8163,11 @@
"count": 3
}
},
"i18n-config/README.md": {
"no-irregular-whitespace": {
"count": 1
}
},
"i18n/de-DE/billing.json": {
"no-irregular-whitespace": {
"count": 1

View File

@@ -6,7 +6,7 @@ This directory contains i18n tooling and configuration. Translation files live u
## File Structure
```txt
```
web/i18n
├── en-US
│ ├── app.json
@@ -36,7 +36,7 @@ By default we will use `LanguagesSupported` to determine which languages are sup
1. Create a new folder for the new language.
```txt
```
cd web/i18n
cp -r en-US id-ID
```
@@ -98,7 +98,7 @@ export const languages = [
{
value: 'ru-RU',
name: 'Русский(Россия)',
example: 'Привет, Dify!',
example: ' Привет, Dify!',
supported: false,
},
{

View File

@@ -3,7 +3,7 @@
"type": "module",
"version": "1.13.0",
"private": true,
"packageManager": "pnpm@10.27.0",
"packageManager": "pnpm@10.27.0+sha512.72d699da16b1179c14ba9e64dc71c9a40988cbdc65c264cb0e489db7de917f20dcf4d64d8723625f2969ba52d4b7e2a1170682d9ac2a5dcaeaab732b7e16f04a",
"imports": {
"#i18n": {
"react-server": "./i18n-config/lib.server.ts",
@@ -165,10 +165,10 @@
"zustand": "5.0.9"
},
"devDependencies": {
"@antfu/eslint-config": "7.6.1",
"@antfu/eslint-config": "7.2.0",
"@chromatic-com/storybook": "5.0.0",
"@egoist/tailwindcss-icons": "1.9.2",
"@eslint-react/eslint-plugin": "2.13.0",
"@eslint-react/eslint-plugin": "2.9.4",
"@iconify-json/heroicons": "1.2.3",
"@iconify-json/ri": "1.2.9",
"@mdx-js/loader": "3.1.1",
@@ -208,7 +208,7 @@
"@types/semver": "7.7.1",
"@types/sortablejs": "1.15.8",
"@types/uuid": "10.0.0",
"@typescript-eslint/parser": "8.56.1",
"@typescript-eslint/parser": "8.54.0",
"@typescript/native-preview": "7.0.0-dev.20251209.1",
"@vitejs/plugin-react": "5.1.2",
"@vitest/coverage-v8": "4.0.17",
@@ -216,13 +216,13 @@
"code-inspector-plugin": "1.3.6",
"cross-env": "10.1.0",
"esbuild": "0.27.2",
"eslint": "10.0.2",
"eslint-plugin-better-tailwindcss": "4.3.1",
"eslint-plugin-hyoban": "0.11.2",
"eslint": "9.39.2",
"eslint-plugin-better-tailwindcss": "https://pkg.pr.new/hyoban/eslint-plugin-better-tailwindcss@c0161c7",
"eslint-plugin-hyoban": "0.11.1",
"eslint-plugin-react-hooks": "7.0.1",
"eslint-plugin-react-refresh": "0.5.2",
"eslint-plugin-sonarjs": "4.0.0",
"eslint-plugin-storybook": "10.2.13",
"eslint-plugin-react-refresh": "0.5.0",
"eslint-plugin-sonarjs": "3.0.6",
"eslint-plugin-storybook": "10.2.6",
"husky": "9.1.7",
"iconify-import-svg": "0.1.1",
"jsdom": "27.3.0",
@@ -249,7 +249,6 @@
"overrides": {
"@monaco-editor/loader": "1.5.0",
"@nolyfill/safe-buffer": "npm:safe-buffer@^5.2.1",
"@stylistic/eslint-plugin": "https://pkg.pr.new/@stylistic/eslint-plugin@258f9d8",
"array-includes": "npm:@nolyfill/array-includes@^1",
"array.prototype.findlast": "npm:@nolyfill/array.prototype.findlast@^1",
"array.prototype.findlastindex": "npm:@nolyfill/array.prototype.findlastindex@^1",

1408
web/pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff