From d67f04f63edbdacaa67cdfe6dc058233cbe0ffed Mon Sep 17 00:00:00 2001 From: zyssyz123 <916125788@qq.com> Date: Wed, 11 Mar 2026 10:56:33 +0800 Subject: [PATCH 01/10] feat: source for plugin tasks (#33244) Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- api/core/plugin/entities/plugin_daemon.py | 1 + 1 file changed, 1 insertion(+) diff --git a/api/core/plugin/entities/plugin_daemon.py b/api/core/plugin/entities/plugin_daemon.py index 2dc540e6a8..416e0f6b4d 100644 --- a/api/core/plugin/entities/plugin_daemon.py +++ b/api/core/plugin/entities/plugin_daemon.py @@ -157,6 +157,7 @@ class PluginInstallTaskPluginStatus(BaseModel): message: str = Field(description="The message of the install task.") icon: str = Field(description="The icon of the plugin.") labels: I18nObject = Field(description="The labels of the plugin.") + source: str | None = Field(default=None, description="The installation source of the plugin") class PluginInstallTask(BasePluginEntity): From 8fe376848f1c6c5494583c87f01dde6d1ca1b635 Mon Sep 17 00:00:00 2001 From: GuanMu Date: Wed, 11 Mar 2026 11:09:29 +0800 Subject: [PATCH 02/10] fix: PromptEditor leaves a pending blur timer that triggers a Vitest unhandled error (#33253) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .../plugins/on-blur-or-focus-block.tsx | 22 ++++++++++++++----- web/eslint-suppressions.json | 5 ----- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/web/app/components/base/prompt-editor/plugins/on-blur-or-focus-block.tsx b/web/app/components/base/prompt-editor/plugins/on-blur-or-focus-block.tsx index 84eacb01ed..80c3ddba21 100644 --- a/web/app/components/base/prompt-editor/plugins/on-blur-or-focus-block.tsx +++ b/web/app/components/base/prompt-editor/plugins/on-blur-or-focus-block.tsx @@ -20,17 +20,21 @@ const OnBlurBlock: FC = ({ }) => { const [editor] = useLexicalComposerContext() - const ref = useRef(null) + const ref = useRef | null>(null) useEffect(() => { - return mergeRegister( + const clearHideMenuTimeout = () => { + if (ref.current) { + clearTimeout(ref.current) + ref.current = null + } + } + + const unregister = mergeRegister( editor.registerCommand( CLEAR_HIDE_MENU_TIMEOUT, () => { - if (ref.current) { - clearTimeout(ref.current) - ref.current = null - } + clearHideMenuTimeout() return true }, COMMAND_PRIORITY_EDITOR, @@ -41,6 +45,7 @@ const OnBlurBlock: FC = ({ // Check if the clicked target element is var-search-input const target = event?.relatedTarget as HTMLElement if (!target?.classList?.contains('var-search-input')) { + clearHideMenuTimeout() ref.current = setTimeout(() => { editor.dispatchCommand(KEY_ESCAPE_COMMAND, new KeyboardEvent('keydown', { key: 'Escape' })) }, 200) @@ -61,6 +66,11 @@ const OnBlurBlock: FC = ({ COMMAND_PRIORITY_EDITOR, ), ) + + return () => { + clearHideMenuTimeout() + unregister() + } }, [editor, onBlur, onFocus]) return null diff --git a/web/eslint-suppressions.json b/web/eslint-suppressions.json index 1c9e9d43f6..b7f18c3d3c 100644 --- a/web/eslint-suppressions.json +++ b/web/eslint-suppressions.json @@ -3624,11 +3624,6 @@ "count": 2 } }, - "app/components/base/prompt-editor/plugins/on-blur-or-focus-block.tsx": { - "ts/no-explicit-any": { - "count": 1 - } - }, "app/components/base/prompt-editor/plugins/query-block/index.tsx": { "react-refresh/only-export-components": { "count": 2 From 904289bb1d363427b6c55c50b023cdeb98fa8305 Mon Sep 17 00:00:00 2001 From: Stephen Zhou Date: Wed, 11 Mar 2026 11:36:09 +0800 Subject: [PATCH 03/10] chore: remove optimize standalone script (#33256) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- web/eslint-suppressions.json | 8 -- web/eslint.config.mjs | 3 + web/package.json | 39 ++++--- web/scripts/README.md | 38 ------- web/scripts/optimize-standalone.js | 163 ----------------------------- 5 files changed, 21 insertions(+), 230 deletions(-) delete mode 100644 web/scripts/README.md delete mode 100644 web/scripts/optimize-standalone.js diff --git a/web/eslint-suppressions.json b/web/eslint-suppressions.json index b7f18c3d3c..937ac6a0ed 100644 --- a/web/eslint-suppressions.json +++ b/web/eslint-suppressions.json @@ -12898,14 +12898,6 @@ "count": 2 } }, - "scripts/optimize-standalone.js": { - "e18e/prefer-static-regex": { - "count": 1 - }, - "unused-imports/no-unused-vars": { - "count": 2 - } - }, "scripts/refactor-component.js": { "e18e/prefer-static-regex": { "count": 14 diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs index 145df1484e..de78e90548 100644 --- a/web/eslint.config.mjs +++ b/web/eslint.config.mjs @@ -218,3 +218,6 @@ export default antfu( }, }, ) + .disableRulesFix([ + 'e18e/prefer-array-at', + ]) diff --git a/web/package.json b/web/package.json index dcb060e6bd..30434e8707 100644 --- a/web/package.json +++ b/web/package.json @@ -26,39 +26,36 @@ "node": "^22.22.1" }, "scripts": { + "analyze": "next experimental-analyze", + "analyze-component": "node ./scripts/analyze-component.js", + "build": "next build", + "build:vinext": "vinext build", "dev": "next dev", "dev:inspect": "next dev --inspect", "dev:vinext": "vinext dev", - "build": "next build", - "build:docker": "next build && node scripts/optimize-standalone.js", - "build:vinext": "vinext build", - "start": "node ./scripts/copy-and-start.mjs", - "start:vinext": "vinext start", + "gen-doc-paths": "tsx ./scripts/gen-doc-paths.ts", + "gen-icons": "node ./scripts/gen-icons.mjs && eslint --fix app/components/base/icons/src/", + "i18n:check": "tsx ./scripts/check-i18n.js", + "knip": "knip", "lint": "eslint --cache --concurrency=auto", "lint:ci": "eslint --cache --concurrency 2", "lint:fix": "pnpm lint --fix", "lint:quiet": "pnpm lint --quiet", - "lint:complexity": "pnpm lint --rule 'complexity: [error, {max: 15}]' --quiet", - "lint:report": "pnpm lint --output-file eslint_report.json --format json", "lint:tss": "tsslint --project tsconfig.json", - "type-check": "tsc --noEmit", - "type-check:tsgo": "tsgo --noEmit", + "preinstall": "npx only-allow pnpm", "prepare": "cd ../ && node -e \"if (process.env.NODE_ENV !== 'production'){process.exit(1)} \" || husky ./web/.husky", - "gen-icons": "node ./scripts/gen-icons.mjs && eslint --fix app/components/base/icons/src/", - "gen-doc-paths": "tsx ./scripts/gen-doc-paths.ts", - "uglify-embed": "node ./bin/uglify-embed", - "i18n:check": "tsx ./scripts/check-i18n.js", - "test": "vitest run", - "test:coverage": "vitest run --coverage", - "test:ci": "vitest run --coverage --silent=passed-only", - "test:watch": "vitest --watch", - "analyze-component": "node ./scripts/analyze-component.js", "refactor-component": "node ./scripts/refactor-component.js", + "start": "node ./scripts/copy-and-start.mjs", + "start:vinext": "vinext start", "storybook": "storybook dev -p 6006", "storybook:build": "storybook build", - "preinstall": "npx only-allow pnpm", - "analyze": "next experimental-analyze", - "knip": "knip" + "test": "vitest run", + "test:ci": "vitest run --coverage --silent=passed-only", + "test:coverage": "vitest run --coverage", + "test:watch": "vitest --watch", + "type-check": "tsc --noEmit", + "type-check:tsgo": "tsgo --noEmit", + "uglify-embed": "node ./bin/uglify-embed" }, "dependencies": { "@amplitude/analytics-browser": "2.36.3", diff --git a/web/scripts/README.md b/web/scripts/README.md deleted file mode 100644 index 2c575a244c..0000000000 --- a/web/scripts/README.md +++ /dev/null @@ -1,38 +0,0 @@ -# Production Build Optimization Scripts - -## optimize-standalone.js - -This script removes unnecessary development dependencies from the Next.js standalone build output to reduce the production Docker image size. - -### What it does - -The script specifically targets and removes `jest-worker` packages that are bundled with Next.js but not needed in production. These packages are included because: - -1. Next.js includes jest-worker in its compiled dependencies -1. terser-webpack-plugin (used by Next.js for minification) depends on jest-worker -1. pnpm's dependency resolution creates symlinks to jest-worker in various locations - -### Usage - -The script is automatically run during Docker builds via the `build:docker` npm script: - -```bash -# Docker build (removes jest-worker after build) -pnpm build:docker -``` - -To run the optimization manually: - -```bash -node scripts/optimize-standalone.js -``` - -### What gets removed - -- `node_modules/.pnpm/next@*/node_modules/next/dist/compiled/jest-worker` -- `node_modules/.pnpm/terser-webpack-plugin@*/node_modules/jest-worker` (symlinks) -- `node_modules/.pnpm/jest-worker@*` (actual packages) - -### Impact - -Removing jest-worker saves approximately 36KB per instance from the production image. While this may seem small, it helps ensure production images only contain necessary runtime dependencies. diff --git a/web/scripts/optimize-standalone.js b/web/scripts/optimize-standalone.js deleted file mode 100644 index b73667eac6..0000000000 --- a/web/scripts/optimize-standalone.js +++ /dev/null @@ -1,163 +0,0 @@ -/** - * Script to optimize Next.js standalone output for production - * Removes unnecessary files like jest-worker that are bundled with Next.js - */ - -import fs from 'node:fs' -import path from 'node:path' -import { fileURLToPath } from 'node:url' - -const __filename = fileURLToPath(import.meta.url) -const __dirname = path.dirname(__filename) - -console.log('🔧 Optimizing standalone output...') - -const standaloneDir = path.join(__dirname, '..', '.next', 'standalone') - -// Check if standalone directory exists -if (!fs.existsSync(standaloneDir)) { - console.error('❌ Standalone directory not found. Please run "next build" first.') - process.exit(1) -} - -// List of paths to remove (relative to standalone directory) -const pathsToRemove = [ - // Remove jest-worker from Next.js compiled dependencies - 'node_modules/.pnpm/next@*/node_modules/next/dist/compiled/jest-worker', - // Remove jest-worker symlinks from terser-webpack-plugin - 'node_modules/.pnpm/terser-webpack-plugin@*/node_modules/jest-worker', - // Remove actual jest-worker packages (directories only, not symlinks) - 'node_modules/.pnpm/jest-worker@*', -] - -// Function to safely remove a path -function removePath(basePath, relativePath) { - const fullPath = path.join(basePath, relativePath) - - // Handle wildcard patterns - if (relativePath.includes('*')) { - const parts = relativePath.split('/') - let currentPath = basePath - - for (let i = 0; i < parts.length; i++) { - const part = parts[i] - if (part.includes('*')) { - // Find matching directories - if (fs.existsSync(currentPath)) { - const entries = fs.readdirSync(currentPath) - - // replace '*' with '.*' - const regexPattern = part.replace(/\*/g, '.*') - - const regex = new RegExp(`^${regexPattern}$`) - - for (const entry of entries) { - if (regex.test(entry)) { - const remainingPath = parts.slice(i + 1).join('/') - const matchedPath = path.join(currentPath, entry, remainingPath) - - try { - // Use lstatSync to check if path exists (works for both files and symlinks) - const stats = fs.lstatSync(matchedPath) - - if (stats.isSymbolicLink()) { - // Remove symlink - fs.unlinkSync(matchedPath) - console.log(`✅ Removed symlink: ${path.relative(basePath, matchedPath)}`) - } - else { - // Remove directory/file - fs.rmSync(matchedPath, { recursive: true, force: true }) - console.log(`✅ Removed: ${path.relative(basePath, matchedPath)}`) - } - } - catch (error) { - // Silently ignore ENOENT (path not found) errors - if (error.code !== 'ENOENT') { - console.error(`❌ Failed to remove ${matchedPath}: ${error.message}`) - } - } - } - } - } - return - } - else { - currentPath = path.join(currentPath, part) - } - } - } - else { - // Direct path removal - if (fs.existsSync(fullPath)) { - try { - fs.rmSync(fullPath, { recursive: true, force: true }) - console.log(`✅ Removed: ${relativePath}`) - } - catch (error) { - console.error(`❌ Failed to remove ${fullPath}: ${error.message}`) - } - } - } -} - -// Remove unnecessary paths -console.log('🗑️ Removing unnecessary files...') -for (const pathToRemove of pathsToRemove) { - removePath(standaloneDir, pathToRemove) -} - -// Calculate size reduction -console.log('\n📊 Optimization complete!') - -// Optional: Display the size of remaining jest-related files (if any) -const checkForJest = (dir) => { - const jestFiles = [] - - function walk(currentPath) { - if (!fs.existsSync(currentPath)) - return - - try { - const entries = fs.readdirSync(currentPath) - for (const entry of entries) { - const fullPath = path.join(currentPath, entry) - - try { - const stat = fs.lstatSync(fullPath) // Use lstatSync to handle symlinks - - if (stat.isDirectory() && !stat.isSymbolicLink()) { - // Skip node_modules subdirectories to avoid deep traversal - if (entry === 'node_modules' && currentPath !== standaloneDir) { - continue - } - walk(fullPath) - } - else if (stat.isFile() && entry.includes('jest')) { - jestFiles.push(path.relative(standaloneDir, fullPath)) - } - } - catch (err) { - // Skip files that can't be accessed - continue - } - } - } - catch (err) { - // Skip directories that can't be read - - } - } - - walk(dir) - return jestFiles -} - -const remainingJestFiles = checkForJest(standaloneDir) -if (remainingJestFiles.length > 0) { - console.log('\n⚠️ Warning: Some jest-related files still remain:') - remainingJestFiles.forEach(file => console.log(` - ${file}`)) -} -else { - console.log('\n✨ No jest-related files found in standalone output!') -} From 0fad13370c9c073191c4a739854b37d37f5881fc Mon Sep 17 00:00:00 2001 From: Stephen Zhou Date: Wed, 11 Mar 2026 11:42:19 +0800 Subject: [PATCH 04/10] chore: update script for build docker (#33261) --- web/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/Dockerfile b/web/Dockerfile index 9b24f9ea0a..b54bae706c 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -35,7 +35,7 @@ COPY --from=packages /app/web/ . COPY . . ENV NODE_OPTIONS="--max-old-space-size=4096" -RUN pnpm build:docker +RUN pnpm build # production stage From 8b12389e19e5d9e630b931ffc22d59b18fa37335 Mon Sep 17 00:00:00 2001 From: Stephen Zhou Date: Wed, 11 Mar 2026 12:42:18 +0800 Subject: [PATCH 05/10] chore: disable some auto fix, disable e18e rules (#33265) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- web/eslint-suppressions.json | 3321 ---------------------------------- web/eslint.config.mjs | 15 +- 2 files changed, 11 insertions(+), 3325 deletions(-) diff --git a/web/eslint-suppressions.json b/web/eslint-suppressions.json index 937ac6a0ed..abd403a6f6 100644 --- a/web/eslint-suppressions.json +++ b/web/eslint-suppressions.json @@ -1,44 +1,5 @@ { - "__tests__/apps/app-card-operations-flow.test.tsx": { - "e18e/prefer-spread-syntax": { - "count": 5 - } - }, - "__tests__/billing/billing-integration.test.tsx": { - "e18e/prefer-static-regex": { - "count": 72 - } - }, - "__tests__/billing/cloud-plan-payment-flow.test.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - } - }, - "__tests__/billing/education-verification-flow.test.tsx": { - "e18e/prefer-static-regex": { - "count": 18 - } - }, - "__tests__/billing/pricing-modal-flow.test.tsx": { - "e18e/prefer-static-regex": { - "count": 28 - } - }, - "__tests__/billing/self-hosted-plan-flow.test.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, "__tests__/check-i18n.test.ts": { - "e18e/prefer-array-to-sorted": { - "count": 1 - }, - "e18e/prefer-regex-test": { - "count": 2 - }, - "e18e/prefer-static-regex": { - "count": 6 - }, "regexp/no-unused-capturing-group": { "count": 1 }, @@ -46,36 +7,17 @@ "count": 2 } }, - "__tests__/datasets/document-management.test.tsx": { - "e18e/prefer-array-at": { - "count": 2 - } - }, - "__tests__/datasets/metadata-management-flow.test.tsx": { - "e18e/prefer-array-fill": { - "count": 2 - } - }, "__tests__/document-detail-navigation-fix.test.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - }, "no-console": { "count": 10 } }, "__tests__/document-list-sorting.test.tsx": { - "e18e/prefer-array-to-sorted": { - "count": 1 - }, "ts/no-explicit-any": { "count": 3 } }, "__tests__/embedded-user-id-auth.test.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "ts/no-explicit-any": { "count": 8 } @@ -85,20 +27,12 @@ "count": 3 } }, - "__tests__/explore/installed-app-flow.test.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, "__tests__/goto-anything/command-selector.test.tsx": { "ts/no-explicit-any": { "count": 2 } }, "__tests__/i18n-upload-features.test.ts": { - "e18e/prefer-static-regex": { - "count": 19 - }, "no-console": { "count": 3 } @@ -113,15 +47,7 @@ "count": 2 } }, - "__tests__/plugins/plugin-install-flow.test.ts": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "__tests__/real-browser-flicker.test.tsx": { - "e18e/prefer-array-at": { - "count": 3 - }, "no-console": { "count": 16 }, @@ -198,9 +124,6 @@ } }, "app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/panel.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 2 } @@ -232,9 +155,6 @@ } }, "app/(humanInputLayout)/form/[token]/form.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 }, @@ -256,9 +176,6 @@ } }, "app/(shareLayout)/webapp-reset-password/check-code/page.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 4 } @@ -282,9 +199,6 @@ } }, "app/(shareLayout)/webapp-signin/check-code/page.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 4 } @@ -326,9 +240,6 @@ } }, "app/account/(commonLayout)/account-page/email-change-modal.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -395,27 +306,11 @@ } }, "app/account/oauth/authorize/page.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "ts/no-explicit-any": { "count": 1 } }, - "app/components/app-sidebar/app-info/__tests__/app-operations.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 2 - } - }, - "app/components/app-sidebar/app-info/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/app-sidebar/app-info/app-operations.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -485,20 +380,11 @@ } }, "app/components/app/annotation/batch-add-annotation-modal/csv-uploader.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 1 } }, "app/components/app/annotation/batch-add-annotation-modal/index.tsx": { - "e18e/prefer-timer-args": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -520,11 +406,6 @@ "count": 1 } }, - "app/components/app/annotation/edit-annotation-modal/edit-item/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - } - }, "app/components/app/annotation/edit-annotation-modal/edit-item/index.tsx": { "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 @@ -537,9 +418,6 @@ } }, "app/components/app/annotation/edit-annotation-modal/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - }, "test/prefer-hooks-in-order": { "count": 1 } @@ -624,9 +502,6 @@ } }, "app/components/app/app-access-control/add-member-or-group-pop.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -687,22 +562,11 @@ } }, "app/components/app/configuration/base/var-highlight/index.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - }, "react-refresh/only-export-components": { "count": 1 } }, - "app/components/app/configuration/base/warning-mask/formatting-changed.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/app/configuration/config-prompt/advanced-prompt-input.tsx": { - "e18e/prefer-array-some": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -728,20 +592,12 @@ "count": 1 } }, - "app/components/app/configuration/config-prompt/index.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/app/configuration/config-prompt/message-type-selector.tsx": { "tailwindcss/no-unnecessary-whitespace": { "count": 1 } }, "app/components/app/configuration/config-prompt/simple-prompt-input.tsx": { - "e18e/prefer-array-some": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -811,17 +667,11 @@ } }, "app/components/app/configuration/config-vision/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, "ts/no-explicit-any": { "count": 1 } }, "app/components/app/configuration/config-vision/index.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -864,9 +714,6 @@ } }, "app/components/app/configuration/config/agent/agent-tools/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - }, "ts/no-explicit-any": { "count": 5 } @@ -909,11 +756,6 @@ "count": 1 } }, - "app/components/app/configuration/config/assistant-type-picker/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 115 - } - }, "app/components/app/configuration/config/assistant-type-picker/index.tsx": { "no-restricted-imports": { "count": 1 @@ -947,11 +789,6 @@ "count": 1 } }, - "app/components/app/configuration/config/automatic/instruction-editor-in-workflow.tsx": { - "e18e/prefer-array-some": { - "count": 1 - } - }, "app/components/app/configuration/config/automatic/instruction-editor.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 4 @@ -1004,9 +841,6 @@ } }, "app/components/app/configuration/config/config-audio.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -1020,9 +854,6 @@ } }, "app/components/app/configuration/config/config-document.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -1045,11 +876,6 @@ "count": 1 } }, - "app/components/app/configuration/dataset-config/context-var/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 2 - } - }, "app/components/app/configuration/dataset-config/context-var/index.tsx": { "no-restricted-imports": { "count": 1 @@ -1067,9 +893,6 @@ } }, "app/components/app/configuration/dataset-config/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "ts/no-explicit-any": { "count": 37 } @@ -1151,12 +974,6 @@ } }, "app/components/app/configuration/debug/debug-with-multiple-model/index.spec.tsx": { - "e18e/prefer-array-fill": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 7 - }, "ts/no-explicit-any": { "count": 5 } @@ -1195,9 +1012,6 @@ } }, "app/components/app/configuration/debug/index.tsx": { - "e18e/prefer-array-some": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -1216,18 +1030,7 @@ "count": 1 } }, - "app/components/app/configuration/hooks/use-advanced-prompt-config.ts": { - "e18e/prefer-array-some": { - "count": 2 - } - }, "app/components/app/configuration/index.tsx": { - "e18e/prefer-array-some": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -1261,17 +1064,11 @@ } }, "app/components/app/configuration/prompt-value-panel/utils.ts": { - "e18e/prefer-static-regex": { - "count": 1 - }, "ts/no-explicit-any": { "count": 1 } }, "app/components/app/configuration/tools/external-data-tool-modal.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "no-restricted-imports": { "count": 2 }, @@ -1288,9 +1085,6 @@ } }, "app/components/app/create-app-dialog/app-card/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - }, "ts/no-explicit-any": { "count": 1 } @@ -1321,11 +1115,6 @@ "count": 2 } }, - "app/components/app/create-app-modal/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/app/create-app-modal/index.tsx": { "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 @@ -1360,9 +1149,6 @@ } }, "app/components/app/create-from-dsl-modal/uploader.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, "tailwindcss/no-unnecessary-whitespace": { "count": 1 } @@ -1394,9 +1180,6 @@ } }, "app/components/app/log/list.tsx": { - "e18e/prefer-array-at": { - "count": 2 - }, "no-restricted-imports": { "count": 1 }, @@ -1457,18 +1240,10 @@ } }, "app/components/app/overview/app-chart.tsx": { - "e18e/prefer-array-fill": { - "count": 2 - }, "ts/no-explicit-any": { "count": 13 } }, - "app/components/app/overview/customize/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 16 - } - }, "app/components/app/overview/customize/index.tsx": { "no-restricted-imports": { "count": 1 @@ -1492,9 +1267,6 @@ } }, "app/components/app/overview/settings/index.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "no-restricted-imports": { "count": 3 }, @@ -1525,9 +1297,6 @@ } }, "app/components/app/text-generate/item/index.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 3 }, @@ -1597,9 +1366,6 @@ } }, "app/components/app/workflow-log/list.tsx": { - "e18e/prefer-array-to-sorted": { - "count": 1 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 2 }, @@ -1615,19 +1381,6 @@ "count": 1 } }, - "app/components/apps/__tests__/app-card.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, - "app/components/apps/__tests__/list.spec.tsx": { - "e18e/prefer-array-at": { - "count": 3 - }, - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/apps/app-card.tsx": { "no-restricted-imports": { "count": 3 @@ -1652,71 +1405,16 @@ "count": 1 } }, - "app/components/apps/hooks/__tests__/use-apps-query-state.spec.tsx": { - "e18e/prefer-array-at": { - "count": 6 - } - }, - "app/components/apps/hooks/use-dsl-drag-drop.ts": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, "app/components/apps/new-app-card.tsx": { "ts/no-explicit-any": { "count": 1 } }, - "app/components/base/__tests__/app-unavailable.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, - "app/components/base/__tests__/badge.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, - "app/components/base/__tests__/theme-selector.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, "app/components/base/action-button/index.tsx": { "react-refresh/only-export-components": { "count": 1 } }, - "app/components/base/agent-log-modal/__tests__/detail.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 12 - } - }, - "app/components/base/agent-log-modal/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/agent-log-modal/__tests__/iteration.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, - "app/components/base/agent-log-modal/__tests__/result.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/base/agent-log-modal/__tests__/tool-call.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/agent-log-modal/__tests__/tracing.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/agent-log-modal/detail.tsx": { "ts/no-explicit-any": { "count": 1 @@ -1746,9 +1444,6 @@ } }, "app/components/base/amplitude/AmplitudeProvider.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "react-refresh/only-export-components": { "count": 1 } @@ -1763,16 +1458,6 @@ "count": 1 } }, - "app/components/base/app-icon-picker/__tests__/ImageInput.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 9 - } - }, - "app/components/base/app-icon-picker/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 23 - } - }, "app/components/base/app-icon-picker/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -1783,11 +1468,6 @@ "count": 15 } }, - "app/components/base/audio-btn/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/base/audio-btn/audio.ts": { "node/prefer-global/buffer": { "count": 1 @@ -1797,26 +1477,15 @@ } }, "app/components/base/audio-btn/index.tsx": { - "e18e/prefer-timer-args": { - "count": 2 - }, "no-restricted-imports": { "count": 1 } }, "app/components/base/audio-gallery/AudioPlayer.tsx": { - "e18e/prefer-timer-args": { - "count": 1 - }, "ts/no-explicit-any": { "count": 2 } }, - "app/components/base/audio-gallery/__tests__/AudioPlayer.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, "app/components/base/auto-height-textarea/index.stories.tsx": { "no-console": { "count": 2 @@ -1826,9 +1495,6 @@ } }, "app/components/base/auto-height-textarea/index.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "tailwindcss/no-unnecessary-whitespace": { "count": 1 } @@ -1838,11 +1504,6 @@ "count": 1 } }, - "app/components/base/block-input/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/base/block-input/index.stories.tsx": { "no-console": { "count": 2 @@ -1852,9 +1513,6 @@ } }, "app/components/base/block-input/index.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 }, @@ -1885,29 +1543,11 @@ "count": 1 } }, - "app/components/base/carousel/__tests__/index.spec.tsx": { - "e18e/prefer-array-fill": { - "count": 1 - } - }, "app/components/base/carousel/index.tsx": { "react-refresh/only-export-components": { "count": 1 } }, - "app/components/base/chat/chat-with-history/__tests__/chat-wrapper.spec.tsx": { - "e18e/prefer-array-at": { - "count": 8 - }, - "e18e/prefer-static-regex": { - "count": 5 - } - }, - "app/components/base/chat/chat-with-history/__tests__/header-in-mobile.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 34 - } - }, "app/components/base/chat/chat-with-history/chat-wrapper.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -1929,11 +1569,6 @@ "count": 2 } }, - "app/components/base/chat/chat-with-history/header/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/base/chat/chat-with-history/header/index.tsx": { "no-restricted-imports": { "count": 2 @@ -1966,11 +1601,6 @@ "count": 1 } }, - "app/components/base/chat/chat-with-history/inputs-form/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/base/chat/chat-with-history/inputs-form/content.tsx": { "no-restricted-imports": { "count": 1 @@ -2023,54 +1653,6 @@ "count": 1 } }, - "app/components/base/chat/chat/__tests__/content-switch.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, - "app/components/base/chat/chat/__tests__/context.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/chat/chat/__tests__/hooks.spec.tsx": { - "e18e/prefer-array-at": { - "count": 6 - } - }, - "app/components/base/chat/chat/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, - "app/components/base/chat/chat/__tests__/question.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, - "app/components/base/chat/chat/__tests__/try-to-ask.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/base/chat/chat/answer/__tests__/more.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, - "app/components/base/chat/chat/answer/__tests__/operation.spec.tsx": { - "e18e/prefer-array-at": { - "count": 6 - }, - "e18e/prefer-static-regex": { - "count": 5 - } - }, - "app/components/base/chat/chat/answer/__tests__/workflow-process.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/chat/chat/answer/agent-content.tsx": { "style/multiline-ternary": { "count": 2 @@ -2079,20 +1661,7 @@ "count": 1 } }, - "app/components/base/chat/chat/answer/basic-content.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/chat/chat/answer/human-input-content/content-item.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/chat/chat/answer/human-input-content/utils.ts": { - "e18e/prefer-static-regex": { - "count": 1 - }, "ts/no-explicit-any": { "count": 1 } @@ -2116,22 +1685,11 @@ } }, "app/components/base/chat/chat/answer/workflow-process.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 } }, - "app/components/base/chat/chat/chat-input-area/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/chat/chat/chat-input-area/index.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "ts/no-explicit-any": { "count": 3 } @@ -2141,31 +1699,11 @@ "count": 1 } }, - "app/components/base/chat/chat/citation/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/base/chat/chat/citation/__tests__/popup.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/base/chat/chat/citation/__tests__/progress-tooltip.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/chat/chat/citation/index.tsx": { "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 } }, - "app/components/base/chat/chat/citation/popup.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/base/chat/chat/hooks.ts": { "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 2 @@ -2182,16 +1720,6 @@ "count": 3 } }, - "app/components/base/chat/chat/loading-anim/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, - "app/components/base/chat/chat/thought/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 20 - } - }, "app/components/base/chat/chat/try-to-ask.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -2203,9 +1731,6 @@ } }, "app/components/base/chat/chat/utils.ts": { - "e18e/prefer-static-regex": { - "count": 1 - }, "ts/no-explicit-any": { "count": 3 } @@ -2231,28 +1756,10 @@ } }, "app/components/base/chat/embedded-chatbot/index.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 1 } }, - "app/components/base/chat/embedded-chatbot/inputs-form/__tests__/content.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 12 - } - }, - "app/components/base/chat/embedded-chatbot/inputs-form/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/chat/embedded-chatbot/inputs-form/__tests__/view-form-dropdown.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/base/chat/embedded-chatbot/inputs-form/content.tsx": { "no-restricted-imports": { "count": 1 @@ -2262,12 +1769,6 @@ } }, "app/components/base/chat/utils.ts": { - "e18e/prefer-array-to-reversed": { - "count": 1 - }, - "e18e/prefer-spread-syntax": { - "count": 5 - }, "ts/no-explicit-any": { "count": 10 } @@ -2280,11 +1781,6 @@ "count": 1 } }, - "app/components/base/chip/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 8 - } - }, "app/components/base/chip/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -2302,9 +1798,6 @@ } }, "app/components/base/confirm/index.tsx": { - "e18e/prefer-timer-args": { - "count": 1 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 2 }, @@ -2317,11 +1810,6 @@ "count": 1 } }, - "app/components/base/copy-feedback/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/copy-feedback/index.tsx": { "no-restricted-imports": { "count": 1 @@ -2332,16 +1820,6 @@ "count": 1 } }, - "app/components/base/date-and-time-picker/calendar/__tests__/days-of-week.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/base/date-and-time-picker/calendar/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/date-and-time-picker/calendar/days-of-week.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -2357,24 +1835,6 @@ "count": 1 } }, - "app/components/base/date-and-time-picker/date-picker/__tests__/footer.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, - "app/components/base/date-and-time-picker/date-picker/__tests__/header.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/base/date-and-time-picker/date-picker/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 2 - }, - "e18e/prefer-static-regex": { - "count": 33 - } - }, "app/components/base/date-and-time-picker/date-picker/footer.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -2390,21 +1850,6 @@ "count": 4 } }, - "app/components/base/date-and-time-picker/time-picker/__tests__/footer.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, - "app/components/base/date-and-time-picker/time-picker/__tests__/header.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/date-and-time-picker/time-picker/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 22 - } - }, "app/components/base/date-and-time-picker/time-picker/header.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -2420,31 +1865,6 @@ "count": 3 } }, - "app/components/base/date-and-time-picker/utils/__tests__/dayjs.spec.ts": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/date-and-time-picker/utils/dayjs.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/base/date-and-time-picker/year-and-month-picker/__tests__/footer.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, - "app/components/base/date-and-time-picker/year-and-month-picker/__tests__/header.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/base/date-and-time-picker/year-and-month-picker/__tests__/options.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/base/date-and-time-picker/year-and-month-picker/header.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -2465,11 +1885,6 @@ "count": 1 } }, - "app/components/base/drawer-plus/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/base/drawer-plus/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -2480,36 +1895,16 @@ "count": 1 } }, - "app/components/base/emoji-picker/__tests__/Inner.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/base/emoji-picker/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, "app/components/base/emoji-picker/index.tsx": { "no-restricted-imports": { "count": 1 } }, - "app/components/base/encrypted-bottom/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/encrypted-bottom/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 } }, - "app/components/base/error-boundary/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/base/error-boundary/index.tsx": { "react-refresh/only-export-components": { "count": 3 @@ -2523,56 +1918,6 @@ "count": 1 } }, - "app/components/base/features/new-feature-panel/__tests__/citation.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/features/new-feature-panel/__tests__/feature-bar.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 16 - } - }, - "app/components/base/features/new-feature-panel/__tests__/feature-card.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, - "app/components/base/features/new-feature-panel/__tests__/follow-up.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/features/new-feature-panel/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 23 - } - }, - "app/components/base/features/new-feature-panel/__tests__/more-like-this.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/base/features/new-feature-panel/__tests__/speech-to-text.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/features/new-feature-panel/annotation-reply/__tests__/config-param-modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, - "app/components/base/features/new-feature-panel/annotation-reply/__tests__/config-param.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/features/new-feature-panel/annotation-reply/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 18 - } - }, "app/components/base/features/new-feature-panel/annotation-reply/annotation-ctrl-button.tsx": { "no-restricted-imports": { "count": 1 @@ -2595,9 +1940,6 @@ } }, "app/components/base/features/new-feature-panel/annotation-reply/index.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 5 }, @@ -2605,11 +1947,6 @@ "count": 3 } }, - "app/components/base/features/new-feature-panel/annotation-reply/score-slider/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/features/new-feature-panel/annotation-reply/score-slider/base-slider/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -2628,16 +1965,6 @@ "count": 2 } }, - "app/components/base/features/new-feature-panel/conversation-opener/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 17 - } - }, - "app/components/base/features/new-feature-panel/conversation-opener/__tests__/modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 18 - } - }, "app/components/base/features/new-feature-panel/conversation-opener/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -2670,21 +1997,6 @@ "count": 5 } }, - "app/components/base/features/new-feature-panel/file-upload/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 19 - } - }, - "app/components/base/features/new-feature-panel/file-upload/__tests__/setting-content.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, - "app/components/base/features/new-feature-panel/file-upload/__tests__/setting-modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, "app/components/base/features/new-feature-panel/file-upload/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 5 @@ -2695,11 +2007,6 @@ "count": 1 } }, - "app/components/base/features/new-feature-panel/image-upload/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 19 - } - }, "app/components/base/features/new-feature-panel/image-upload/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 5 @@ -2710,26 +2017,6 @@ "count": 3 } }, - "app/components/base/features/new-feature-panel/moderation/__tests__/form-generation.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/base/features/new-feature-panel/moderation/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 25 - } - }, - "app/components/base/features/new-feature-panel/moderation/__tests__/moderation-content.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/base/features/new-feature-panel/moderation/__tests__/moderation-setting-modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 37 - } - }, "app/components/base/features/new-feature-panel/moderation/form-generation.tsx": { "no-restricted-imports": { "count": 1 @@ -2744,9 +2031,6 @@ } }, "app/components/base/features/new-feature-panel/moderation/moderation-setting-modal.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -2754,30 +2038,12 @@ "count": 2 } }, - "app/components/base/features/new-feature-panel/text-to-speech/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, - "app/components/base/features/new-feature-panel/text-to-speech/__tests__/param-config-content.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - } - }, - "app/components/base/features/new-feature-panel/text-to-speech/__tests__/voice-settings.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/features/new-feature-panel/text-to-speech/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 7 } }, "app/components/base/features/new-feature-panel/text-to-speech/param-config-content.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "no-restricted-imports": { "count": 2 } @@ -2797,26 +2063,11 @@ "count": 1 } }, - "app/components/base/file-uploader/__tests__/file-list-in-log.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, - "app/components/base/file-uploader/__tests__/pdf-preview.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/file-uploader/dynamic-pdf-preview.tsx": { "ts/no-explicit-any": { "count": 1 } }, - "app/components/base/file-uploader/file-from-link-or-local/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 17 - } - }, "app/components/base/file-uploader/file-from-link-or-local/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 @@ -2836,36 +2087,11 @@ "count": 1 } }, - "app/components/base/file-uploader/file-uploader-in-attachment/__tests__/file-item.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - } - }, - "app/components/base/file-uploader/file-uploader-in-attachment/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, "app/components/base/file-uploader/file-uploader-in-attachment/file-item.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 } }, - "app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/file-image-item.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 5 - } - }, - "app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/file-item.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 12 - } - }, - "app/components/base/file-uploader/file-uploader-in-chat-input/__tests__/file-list.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, "app/components/base/file-uploader/file-uploader-in-chat-input/file-image-item.tsx": { "tailwindcss/no-unnecessary-whitespace": { "count": 1 @@ -2887,22 +2113,11 @@ } }, "app/components/base/file-uploader/utils.ts": { - "e18e/prefer-array-at": { - "count": 1 - }, "ts/no-explicit-any": { "count": 3 } }, - "app/components/base/form/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/base/form/components/base/base-field.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, "no-restricted-imports": { "count": 2 }, @@ -2954,11 +2169,6 @@ "count": 3 } }, - "app/components/base/form/form-scenarios/base/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/base/form/form-scenarios/base/field.tsx": { "ts/no-explicit-any": { "count": 1 @@ -2969,16 +2179,6 @@ "count": 3 } }, - "app/components/base/form/form-scenarios/demo/__tests__/contact-fields.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, - "app/components/base/form/form-scenarios/demo/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 14 - } - }, "app/components/base/form/form-scenarios/demo/contact-fields.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -3030,44 +2230,15 @@ } }, "app/components/base/ga/index.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "react-refresh/only-export-components": { "count": 1 } }, - "app/components/base/icons/icon-gallery.stories.tsx": { - "e18e/prefer-array-to-sorted": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/icons/utils.ts": { - "e18e/prefer-static-regex": { - "count": 3 - }, "ts/no-explicit-any": { "count": 3 } }, - "app/components/base/image-uploader/__tests__/chat-image-uploader.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/image-uploader/__tests__/image-list.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/base/image-uploader/__tests__/image-preview.spec.tsx": { - "e18e/prefer-object-has-own": { - "count": 1 - } - }, "app/components/base/image-uploader/hooks.ts": { "ts/no-explicit-any": { "count": 4 @@ -3106,11 +2277,6 @@ "count": 1 } }, - "app/components/base/input-number/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 28 - } - }, "app/components/base/input-number/index.stories.tsx": { "no-console": { "count": 2 @@ -3124,15 +2290,7 @@ "count": 1 } }, - "app/components/base/input/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, "app/components/base/input/index.stories.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "no-console": { "count": 2 }, @@ -3141,9 +2299,6 @@ } }, "app/components/base/input/index.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "react-refresh/only-export-components": { "count": 1 } @@ -3161,46 +2316,11 @@ "count": 1 } }, - "app/components/base/logo/__tests__/dify-logo.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, - "app/components/base/logo/__tests__/logo-embedded-chat-avatar.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/base/logo/__tests__/logo-embedded-chat-header.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/logo/__tests__/logo-site.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/logo/dify-logo.tsx": { "react-refresh/only-export-components": { "count": 2 } }, - "app/components/base/markdown-blocks/__tests__/code-block.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 12 - } - }, - "app/components/base/markdown-blocks/__tests__/music.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/markdown-blocks/__tests__/think-block.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 13 - } - }, "app/components/base/markdown-blocks/audio-block.tsx": { "ts/no-explicit-any": { "count": 5 @@ -3212,9 +2332,6 @@ } }, "app/components/base/markdown-blocks/code-block.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 7 }, @@ -3223,9 +2340,6 @@ } }, "app/components/base/markdown-blocks/link.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "ts/no-explicit-any": { "count": 1 } @@ -3253,48 +2367,22 @@ "count": 4 } }, - "app/components/base/markdown-blocks/utils.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/base/markdown-blocks/video-block.tsx": { "ts/no-explicit-any": { "count": 5 } }, - "app/components/base/markdown/__tests__/error-boundary.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/base/markdown/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, - "app/components/base/markdown/__tests__/markdown-utils.spec.ts": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/markdown/error-boundary.tsx": { "ts/no-explicit-any": { "count": 3 } }, "app/components/base/markdown/markdown-utils.ts": { - "e18e/prefer-static-regex": { - "count": 11 - }, "regexp/no-unused-capturing-group": { "count": 1 } }, "app/components/base/mermaid/index.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 7 }, @@ -3306,9 +2394,6 @@ } }, "app/components/base/mermaid/utils.ts": { - "e18e/prefer-static-regex": { - "count": 26 - }, "regexp/no-unused-capturing-group": { "count": 1 }, @@ -3316,11 +2401,6 @@ "count": 4 } }, - "app/components/base/message-log-modal/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/base/message-log-modal/index.stories.tsx": { "no-console": { "count": 1 @@ -3342,11 +2422,6 @@ "count": 3 } }, - "app/components/base/modal/__tests__/modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, "app/components/base/modal/index.stories.tsx": { "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 @@ -3360,15 +2435,7 @@ "count": 1 } }, - "app/components/base/new-audio-button/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/base/new-audio-button/index.tsx": { - "e18e/prefer-timer-args": { - "count": 2 - }, "no-restricted-imports": { "count": 1 }, @@ -3381,11 +2448,6 @@ "count": 1 } }, - "app/components/base/notion-connector/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/notion-connector/index.stories.tsx": { "no-console": { "count": 1 @@ -3397,39 +2459,15 @@ } }, "app/components/base/notion-page-selector/base.tsx": { - "e18e/prefer-spread-syntax": { - "count": 3 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 2 } }, "app/components/base/notion-page-selector/page-selector/index.tsx": { - "e18e/prefer-spread-syntax": { - "count": 2 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 } }, - "app/components/base/pagination/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 3 - }, - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/base/pagination/__tests__/pagination.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 16 - } - }, - "app/components/base/pagination/hook.ts": { - "e18e/prefer-array-at": { - "count": 3 - } - }, "app/components/base/pagination/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 8 @@ -3443,21 +2481,6 @@ "count": 1 } }, - "app/components/base/param-item/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/base/param-item/__tests__/score-threshold-item.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/param-item/__tests__/top-k-item.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/param-item/index.tsx": { "no-restricted-imports": { "count": 1 @@ -3474,16 +2497,6 @@ "count": 1 } }, - "app/components/base/progress-bar/__tests__/progress-circle.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/prompt-editor/constants.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/prompt-editor/index.stories.tsx": { "no-console": { "count": 1 @@ -3497,19 +2510,6 @@ "count": 4 } }, - "app/components/base/prompt-editor/plugins/component-picker-block/__tests__/hooks.spec.tsx": { - "e18e/prefer-array-at": { - "count": 5 - } - }, - "app/components/base/prompt-editor/plugins/component-picker-block/__tests__/index.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/base/prompt-editor/plugins/component-picker-block/index.tsx": { "ts/no-explicit-any": { "count": 1 @@ -3520,11 +2520,6 @@ "count": 2 } }, - "app/components/base/prompt-editor/plugins/context-block/__tests__/component.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/base/prompt-editor/plugins/context-block/component.tsx": { "ts/no-explicit-any": { "count": 1 @@ -3570,15 +2565,7 @@ "count": 2 } }, - "app/components/base/prompt-editor/plugins/hitl-input-block/__tests__/input-field.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, "app/components/base/prompt-editor/plugins/hitl-input-block/hitl-input-block-replacement-block.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "ts/no-explicit-any": { "count": 1 } @@ -3589,9 +2576,6 @@ } }, "app/components/base/prompt-editor/plugins/hitl-input-block/input-field.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 7 }, @@ -3640,9 +2624,6 @@ } }, "app/components/base/prompt-editor/plugins/shortcuts-popup-plugin/index.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, "ts/no-explicit-any": { "count": 2 } @@ -3707,11 +2688,6 @@ "count": 2 } }, - "app/components/base/radio/component/radio/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/base/radio/context/index.ts": { "ts/no-explicit-any": { "count": 1 @@ -3722,11 +2698,6 @@ "count": 1 } }, - "app/components/base/search-input/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/search-input/index.stories.tsx": { "no-console": { "count": 3 @@ -3745,31 +2716,6 @@ "count": 1 } }, - "app/components/base/select/__tests__/custom.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, - "app/components/base/select/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, - "app/components/base/select/__tests__/locale-signin.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, - "app/components/base/select/__tests__/locale.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, - "app/components/base/select/__tests__/pure.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, "app/components/base/select/custom.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -3817,11 +2763,6 @@ "count": 1 } }, - "app/components/base/sort/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/base/sort/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 @@ -3830,21 +2771,11 @@ "count": 2 } }, - "app/components/base/svg-gallery/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/base/svg-gallery/index.tsx": { "node/prefer-global/buffer": { "count": 1 } }, - "app/components/base/svg/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/switch/index.stories.tsx": { "no-console": { "count": 1 @@ -3866,31 +2797,6 @@ "count": 1 } }, - "app/components/base/tag-input/index.tsx": { - "e18e/prefer-array-some": { - "count": 1 - } - }, - "app/components/base/tag-management/__tests__/filter.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/base/tag-management/__tests__/panel.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/base/tag-management/__tests__/selector.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/tag-management/__tests__/trigger.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/base/tag-management/index.tsx": { "no-restricted-imports": { "count": 1 @@ -3916,16 +2822,6 @@ "count": 1 } }, - "app/components/base/tag/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/base/text-generation/__tests__/hooks.spec.ts": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/base/text-generation/hooks.ts": { "ts/no-explicit-any": { "count": 1 @@ -3944,29 +2840,11 @@ "count": 1 } }, - "app/components/base/timezone-label/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/base/ui/select/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, "app/components/base/video-gallery/VideoPlayer.tsx": { - "e18e/prefer-timer-args": { - "count": 1 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 } }, - "app/components/base/voice-input/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/base/voice-input/index.stories.tsx": { "no-console": { "count": 2 @@ -3995,11 +2873,6 @@ "count": 4 } }, - "app/components/billing/__tests__/config.spec.ts": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/billing/annotation-full/modal.tsx": { "no-restricted-imports": { "count": 1 @@ -4010,11 +2883,6 @@ "count": 5 } }, - "app/components/billing/billing-page/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, "app/components/billing/billing-page/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 @@ -4028,39 +2896,6 @@ "count": 1 } }, - "app/components/billing/plan/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, - "app/components/billing/plan/assets/__tests__/enterprise.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/billing/plan/assets/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/billing/plan/assets/__tests__/professional.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, - "app/components/billing/plan/assets/__tests__/sandbox.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, - "app/components/billing/plan/assets/__tests__/team.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, "app/components/billing/plan/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -4069,11 +2904,6 @@ "count": 2 } }, - "app/components/billing/pricing/assets/__tests__/index.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 4 - } - }, "app/components/billing/pricing/header.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -4084,11 +2914,6 @@ "count": 1 } }, - "app/components/billing/pricing/plan-switcher/__tests__/plan-range-switcher.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/billing/pricing/plan-switcher/plan-range-switcher.tsx": { "react-refresh/only-export-components": { "count": 1 @@ -4099,16 +2924,6 @@ "count": 1 } }, - "app/components/billing/pricing/plans/cloud-plan-item/__tests__/button.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/billing/pricing/plans/cloud-plan-item/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/billing/pricing/plans/cloud-plan-item/button.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -4129,11 +2944,6 @@ "count": 1 } }, - "app/components/billing/pricing/plans/self-hosted-plan-item/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/billing/pricing/plans/self-hosted-plan-item/button.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -4165,26 +2975,11 @@ "count": 1 } }, - "app/components/billing/upgrade-btn/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 34 - } - }, "app/components/billing/upgrade-btn/index.tsx": { "ts/no-explicit-any": { "count": 3 } }, - "app/components/billing/usage-info/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/billing/usage-info/__tests__/vector-space-info.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, "app/components/billing/usage-info/index.tsx": { "no-restricted-imports": { "count": 1 @@ -4193,11 +2988,6 @@ "count": 8 } }, - "app/components/billing/utils/index.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/custom/custom-page/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -4208,36 +2998,11 @@ "count": 2 } }, - "app/components/datasets/__tests__/chunk.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/datasets/chunk.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 } }, - "app/components/datasets/common/__tests__/chunking-mode-label.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, - "app/components/datasets/common/__tests__/credential-icon.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, - "app/components/datasets/common/document-picker/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, - "app/components/datasets/common/document-picker/__tests__/preview-document-picker.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/datasets/common/document-picker/index.tsx": { "no-restricted-imports": { "count": 1 @@ -4254,34 +3019,11 @@ "count": 2 } }, - "app/components/datasets/common/document-status-with-action/__tests__/auto-disabled-document.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, - "app/components/datasets/common/document-status-with-action/__tests__/index-failed.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 12 - } - }, - "app/components/datasets/common/image-list/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, "app/components/datasets/common/image-list/more.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 } }, - "app/components/datasets/common/image-previewer/__tests__/index.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 9 - }, - "e18e/prefer-static-regex": { - "count": 4 - } - }, "app/components/datasets/common/image-previewer/index.tsx": { "no-irregular-whitespace": { "count": 1 @@ -4291,18 +3033,10 @@ } }, "app/components/datasets/common/image-uploader/hooks/use-upload.ts": { - "e18e/prefer-spread-syntax": { - "count": 2 - }, "ts/no-explicit-any": { "count": 3 } }, - "app/components/datasets/common/image-uploader/image-uploader-in-chunk/__tests__/image-input.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/datasets/common/image-uploader/image-uploader-in-chunk/image-input.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -4321,11 +3055,6 @@ "count": 4 } }, - "app/components/datasets/common/image-uploader/utils.ts": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/datasets/common/retrieval-method-info/index.tsx": { "react-refresh/only-export-components": { "count": 1 @@ -4339,41 +3068,6 @@ "count": 3 } }, - "app/components/datasets/create-from-pipeline/__tests__/footer.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 9 - } - }, - "app/components/datasets/create-from-pipeline/__tests__/header.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/datasets/create-from-pipeline/__tests__/index.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, - "app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/__tests__/dsl-confirm-modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 16 - } - }, - "app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/__tests__/header.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, - "app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/__tests__/uploader.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, "app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/dsl-confirm-modal.tsx": { "no-restricted-imports": { "count": 1 @@ -4395,11 +3089,6 @@ "count": 1 } }, - "app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/tab/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, "app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/tab/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -4410,11 +3099,6 @@ "count": 1 } }, - "app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/uploader.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, "app/components/datasets/create-from-pipeline/footer.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -4428,21 +3112,6 @@ "count": 1 } }, - "app/components/datasets/create-from-pipeline/list/__tests__/create-card.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 9 - } - }, - "app/components/datasets/create-from-pipeline/list/__tests__/customized-list.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/create-from-pipeline/list/__tests__/index.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, "app/components/datasets/create-from-pipeline/list/create-card.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -4453,26 +3122,6 @@ "count": 1 } }, - "app/components/datasets/create-from-pipeline/list/template-card/__tests__/actions.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, - "app/components/datasets/create-from-pipeline/list/template-card/__tests__/content.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, - "app/components/datasets/create-from-pipeline/list/template-card/__tests__/edit-pipeline-info.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 21 - } - }, - "app/components/datasets/create-from-pipeline/list/template-card/__tests__/operations.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 13 - } - }, "app/components/datasets/create-from-pipeline/list/template-card/actions.tsx": { "no-restricted-imports": { "count": 1 @@ -4483,11 +3132,6 @@ "count": 3 } }, - "app/components/datasets/create-from-pipeline/list/template-card/details/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 9 - } - }, "app/components/datasets/create-from-pipeline/list/template-card/details/chunk-structure-card.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -4516,16 +3160,6 @@ "count": 3 } }, - "app/components/datasets/create/embedding-process/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 28 - } - }, - "app/components/datasets/create/embedding-process/__tests__/indexing-progress-item.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/datasets/create/embedding-process/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -4544,57 +3178,16 @@ "count": 1 } }, - "app/components/datasets/create/file-preview/__tests__/index.spec.tsx": { - "e18e/prefer-timer-args": { - "count": 2 - } - }, "app/components/datasets/create/file-preview/index.tsx": { "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 } }, - "app/components/datasets/create/file-uploader/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 4 - } - }, - "app/components/datasets/create/file-uploader/components/__tests__/upload-dropzone.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/datasets/create/file-uploader/hooks/use-file-upload.ts": { - "e18e/prefer-array-from-map": { - "count": 1 - }, - "e18e/prefer-spread-syntax": { - "count": 2 - } - }, - "app/components/datasets/create/notion-page-preview/__tests__/index.spec.tsx": { - "e18e/prefer-timer-args": { - "count": 2 - } - }, "app/components/datasets/create/notion-page-preview/index.tsx": { "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 } }, - "app/components/datasets/create/step-one/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 13 - } - }, - "app/components/datasets/create/step-one/__tests__/upgrade-card.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, "app/components/datasets/create/step-one/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -4608,21 +3201,11 @@ "count": 1 } }, - "app/components/datasets/create/step-three/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/datasets/create/step-three/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 7 } }, - "app/components/datasets/create/step-two/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 39 - } - }, "app/components/datasets/create/step-two/components/general-chunking-options.tsx": { "no-restricted-imports": { "count": 1 @@ -4667,11 +3250,6 @@ "count": 1 } }, - "app/components/datasets/create/step-two/language-select/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/datasets/create/step-two/language-select/index.tsx": { "no-restricted-imports": { "count": 1 @@ -4680,14 +3258,6 @@ "count": 2 } }, - "app/components/datasets/create/step-two/preview-item/__tests__/index.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 2 - }, - "e18e/prefer-static-regex": { - "count": 16 - } - }, "app/components/datasets/create/step-two/preview-item/index.tsx": { "react-refresh/only-export-components": { "count": 1 @@ -4698,11 +3268,6 @@ "count": 2 } }, - "app/components/datasets/create/stop-embedding-modal/__tests__/index.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 2 - } - }, "app/components/datasets/create/stop-embedding-modal/index.tsx": { "no-restricted-imports": { "count": 1 @@ -4713,41 +3278,6 @@ "count": 1 } }, - "app/components/datasets/create/website/__tests__/base.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/create/website/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, - "app/components/datasets/create/website/__tests__/no-data.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 11 - } - }, - "app/components/datasets/create/website/__tests__/preview.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, - "app/components/datasets/create/website/base/__tests__/crawled-result.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/datasets/create/website/base/__tests__/crawling.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/datasets/create/website/base/__tests__/url-input.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 13 - } - }, "app/components/datasets/create/website/base/checkbox-with-label.tsx": { "no-restricted-imports": { "count": 1 @@ -4773,16 +3303,6 @@ "count": 1 } }, - "app/components/datasets/create/website/firecrawl/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 37 - } - }, - "app/components/datasets/create/website/firecrawl/__tests__/options.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 11 - } - }, "app/components/datasets/create/website/firecrawl/index.tsx": { "no-console": { "count": 1 @@ -4807,26 +3327,6 @@ "count": 7 } }, - "app/components/datasets/create/website/jina-reader/__tests__/base.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 11 - } - }, - "app/components/datasets/create/website/jina-reader/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 68 - } - }, - "app/components/datasets/create/website/jina-reader/__tests__/options.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/datasets/create/website/jina-reader/base/__tests__/url-input.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 9 - } - }, "app/components/datasets/create/website/jina-reader/index.tsx": { "no-console": { "count": 1 @@ -4856,16 +3356,6 @@ "count": 2 } }, - "app/components/datasets/create/website/watercrawl/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 63 - } - }, - "app/components/datasets/create/website/watercrawl/__tests__/options.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, "app/components/datasets/create/website/watercrawl/index.tsx": { "no-console": { "count": 1 @@ -4885,36 +3375,6 @@ "count": 1 } }, - "app/components/datasets/documents/components/__tests__/documents-header.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 15 - } - }, - "app/components/datasets/documents/components/__tests__/empty-element.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, - "app/components/datasets/documents/components/__tests__/list.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/documents/components/__tests__/rename-modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - } - }, - "app/components/datasets/documents/components/document-list/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/datasets/documents/components/document-list/components/document-source-icon.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/datasets/documents/components/document-list/components/document-table-row.tsx": { "no-restricted-imports": { "count": 1 @@ -4935,16 +3395,6 @@ "count": 1 } }, - "app/components/datasets/documents/create-from-pipeline/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/datasets/documents/create-from-pipeline/actions/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 11 - } - }, "app/components/datasets/documents/create-from-pipeline/actions/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -4955,11 +3405,6 @@ "count": 1 } }, - "app/components/datasets/documents/create-from-pipeline/data-source/base/credential-selector/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/datasets/documents/create-from-pipeline/data-source/base/credential-selector/index.tsx": { "no-restricted-imports": { "count": 1 @@ -4983,31 +3428,12 @@ "count": 1 } }, - "app/components/datasets/documents/create-from-pipeline/data-source/local-file/components/__tests__/upload-dropzone.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/datasets/documents/create-from-pipeline/data-source/local-file/hooks/__tests__/use-local-file-upload.spec.tsx": { - "e18e/prefer-array-at": { - "count": 2 - }, - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/datasets/documents/create-from-pipeline/data-source/online-documents/index.tsx": { - "e18e/prefer-spread-syntax": { - "count": 2 - }, "ts/no-explicit-any": { "count": 1 } }, "app/components/datasets/documents/create-from-pipeline/data-source/online-documents/page-selector/index.tsx": { - "e18e/prefer-spread-syntax": { - "count": 2 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 } @@ -5017,26 +3443,11 @@ "count": 1 } }, - "app/components/datasets/documents/create-from-pipeline/data-source/online-drive/connect/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, "app/components/datasets/documents/create-from-pipeline/data-source/online-drive/connect/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 } }, - "app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - } - }, "app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/bucket.tsx": { "no-restricted-imports": { "count": 1 @@ -5064,9 +3475,6 @@ } }, "app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/header/breadcrumbs/index.tsx": { - "e18e/prefer-array-at": { - "count": 2 - }, "tailwindcss/enforce-consistent-class-order": { "count": 2 } @@ -5076,11 +3484,6 @@ "count": 3 } }, - "app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/list/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, "app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/list/empty-folder.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -5099,20 +3502,12 @@ "count": 2 } }, - "app/components/datasets/documents/create-from-pipeline/data-source/online-drive/file-list/list/utils.ts": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/datasets/documents/create-from-pipeline/data-source/online-drive/header.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 } }, "app/components/datasets/documents/create-from-pipeline/data-source/online-drive/index.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 5 } @@ -5132,21 +3527,6 @@ "count": 4 } }, - "app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/base/__tests__/crawled-result.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/base/__tests__/crawling.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/base/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 11 - } - }, "app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/base/checkbox-with-label.tsx": { "no-restricted-imports": { "count": 1 @@ -5175,11 +3555,6 @@ "count": 2 } }, - "app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/base/options/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 12 - } - }, "app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/base/options/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -5193,11 +3568,6 @@ "count": 2 } }, - "app/components/datasets/documents/create-from-pipeline/hooks/use-datasource-actions.ts": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, "app/components/datasets/documents/create-from-pipeline/left-header.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 @@ -5206,26 +3576,6 @@ "count": 1 } }, - "app/components/datasets/documents/create-from-pipeline/preview/__tests__/chunk-preview.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, - "app/components/datasets/documents/create-from-pipeline/preview/__tests__/file-preview.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, - "app/components/datasets/documents/create-from-pipeline/preview/__tests__/online-document-preview.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/datasets/documents/create-from-pipeline/preview/__tests__/web-preview.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/datasets/documents/create-from-pipeline/preview/file-preview.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 4 @@ -5244,16 +3594,6 @@ "count": 1 } }, - "app/components/datasets/documents/create-from-pipeline/process-documents/__tests__/components.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 36 - } - }, - "app/components/datasets/documents/create-from-pipeline/process-documents/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 14 - } - }, "app/components/datasets/documents/create-from-pipeline/process-documents/form.tsx": { "ts/no-explicit-any": { "count": 3 @@ -5269,11 +3609,6 @@ "count": 2 } }, - "app/components/datasets/documents/create-from-pipeline/processing/embedding-process/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/datasets/documents/create-from-pipeline/processing/embedding-process/index.tsx": { "no-restricted-imports": { "count": 1 @@ -5287,46 +3622,7 @@ "count": 3 } }, - "app/components/datasets/documents/create-from-pipeline/steps/__tests__/preview-panel.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/documents/create-from-pipeline/steps/__tests__/step-one-content.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, - "app/components/datasets/documents/detail/__tests__/new-segment.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/datasets/documents/detail/batch-modal/__tests__/csv-downloader.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, - "app/components/datasets/documents/detail/batch-modal/__tests__/csv-uploader.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, - "app/components/datasets/documents/detail/batch-modal/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 12 - } - }, "app/components/datasets/documents/detail/batch-modal/csv-uploader.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, - "e18e/prefer-spread-syntax": { - "count": 2 - }, - "e18e/prefer-static-regex": { - "count": 1 - }, "tailwindcss/no-unnecessary-whitespace": { "count": 1 } @@ -5339,26 +3635,6 @@ "count": 1 } }, - "app/components/datasets/documents/detail/completed/__tests__/child-segment-detail.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/datasets/documents/detail/completed/__tests__/child-segment-list.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, - "app/components/datasets/documents/detail/completed/__tests__/new-child-segment.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/documents/detail/completed/__tests__/segment-detail.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/datasets/documents/detail/completed/child-segment-detail.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 @@ -5369,49 +3645,6 @@ "count": 2 } }, - "app/components/datasets/documents/detail/completed/common/__tests__/action-buttons.spec.tsx": { - "e18e/prefer-array-at": { - "count": 2 - }, - "e18e/prefer-static-regex": { - "count": 13 - } - }, - "app/components/datasets/documents/detail/completed/common/__tests__/add-another.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/documents/detail/completed/common/__tests__/batch-action.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 20 - } - }, - "app/components/datasets/documents/detail/completed/common/__tests__/empty.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/documents/detail/completed/common/__tests__/keywords.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/documents/detail/completed/common/__tests__/regeneration-modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 21 - } - }, - "app/components/datasets/documents/detail/completed/common/__tests__/segment-index-tag.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/documents/detail/completed/common/__tests__/summary.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 13 - } - }, "app/components/datasets/documents/detail/completed/common/action-buttons.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -5443,11 +3676,6 @@ "count": 1 } }, - "app/components/datasets/documents/detail/completed/common/drawer.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, "app/components/datasets/documents/detail/completed/common/empty.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -5486,11 +3714,6 @@ "count": 2 } }, - "app/components/datasets/documents/detail/completed/components/__tests__/menu-bar.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/datasets/documents/detail/completed/components/menu-bar.tsx": { "no-restricted-imports": { "count": 2 @@ -5522,11 +3745,6 @@ "count": 1 } }, - "app/components/datasets/documents/detail/completed/segment-card/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 12 - } - }, "app/components/datasets/documents/detail/completed/segment-card/chunk-content.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -5545,11 +3763,6 @@ "count": 2 } }, - "app/components/datasets/documents/detail/completed/segment-list.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/datasets/documents/detail/completed/skeleton/parent-chunk-card-skeleton.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -5565,26 +3778,6 @@ "count": 1 } }, - "app/components/datasets/documents/detail/embedding/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 16 - } - }, - "app/components/datasets/documents/detail/embedding/components/__tests__/rule-detail.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 20 - } - }, - "app/components/datasets/documents/detail/embedding/components/__tests__/segment-progress.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 13 - } - }, - "app/components/datasets/documents/detail/embedding/components/__tests__/status-header.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, "app/components/datasets/documents/detail/embedding/components/segment-progress.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -5595,21 +3788,6 @@ "count": 3 } }, - "app/components/datasets/documents/detail/index.tsx": { - "e18e/prefer-timer-args": { - "count": 1 - } - }, - "app/components/datasets/documents/detail/metadata/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 44 - } - }, - "app/components/datasets/documents/detail/metadata/components/__tests__/doc-type-selector.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 13 - } - }, "app/components/datasets/documents/detail/metadata/components/doc-type-selector.tsx": { "no-restricted-imports": { "count": 1 @@ -5628,11 +3806,6 @@ "count": 1 } }, - "app/components/datasets/documents/detail/segment-add/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 20 - } - }, "app/components/datasets/documents/detail/segment-add/index.tsx": { "no-restricted-imports": { "count": 1 @@ -5644,16 +3817,6 @@ "count": 6 } }, - "app/components/datasets/documents/detail/settings/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, - "app/components/datasets/documents/detail/settings/pipeline-settings/__tests__/left-header.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/datasets/documents/detail/settings/pipeline-settings/index.tsx": { "ts/no-explicit-any": { "count": 6 @@ -5667,26 +3830,11 @@ "count": 1 } }, - "app/components/datasets/documents/detail/settings/pipeline-settings/process-documents/__tests__/actions.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/documents/detail/settings/pipeline-settings/process-documents/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/datasets/documents/detail/settings/pipeline-settings/process-documents/index.tsx": { "ts/no-explicit-any": { "count": 3 } }, - "app/components/datasets/documents/hooks/__tests__/use-document-list-query-state.spec.tsx": { - "e18e/prefer-array-at": { - "count": 18 - } - }, "app/components/datasets/documents/status-item/index.tsx": { "no-restricted-imports": { "count": 1 @@ -5697,19 +3845,6 @@ "count": 2 } }, - "app/components/datasets/external-api/external-api-modal/__tests__/Form.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 14 - } - }, - "app/components/datasets/external-api/external-api-modal/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 26 - } - }, "app/components/datasets/external-api/external-api-modal/index.tsx": { "no-restricted-imports": { "count": 3 @@ -5721,21 +3856,11 @@ "count": 5 } }, - "app/components/datasets/external-api/external-api-panel/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/datasets/external-api/external-api-panel/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 4 } }, - "app/components/datasets/external-api/external-knowledge-api-card/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 11 - } - }, "app/components/datasets/external-api/external-knowledge-api-card/index.tsx": { "no-restricted-imports": { "count": 1 @@ -5775,31 +3900,11 @@ "count": 1 } }, - "app/components/datasets/external-knowledge-base/create/__tests__/InfoPanel.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - } - }, - "app/components/datasets/external-knowledge-base/create/__tests__/KnowledgeBaseInfo.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 11 - } - }, "app/components/datasets/external-knowledge-base/create/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 6 } }, - "app/components/datasets/extra-info/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 28 - } - }, - "app/components/datasets/extra-info/api-access/__tests__/card.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, "app/components/datasets/extra-info/api-access/card.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -5813,19 +3918,6 @@ "count": 1 } }, - "app/components/datasets/extra-info/service-api/__tests__/card.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 11 - } - }, - "app/components/datasets/extra-info/service-api/__tests__/index.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 56 - } - }, "app/components/datasets/extra-info/service-api/card.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 6 @@ -5847,59 +3939,11 @@ "count": 4 } }, - "app/components/datasets/formatted-text/flavours/__tests__/edit-slice.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, - "app/components/datasets/formatted-text/flavours/__tests__/preview-slice.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, "app/components/datasets/formatted-text/flavours/type.ts": { "ts/no-empty-object-type": { "count": 1 } }, - "app/components/datasets/hit-testing/__tests__/index.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 6 - }, - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/hit-testing/components/__tests__/child-chunks-item.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/datasets/hit-testing/components/__tests__/empty-records.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/hit-testing/components/__tests__/result-item-external.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/datasets/hit-testing/components/__tests__/result-item-footer.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/datasets/hit-testing/components/__tests__/result-item-meta.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/datasets/hit-testing/components/__tests__/result-item.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/datasets/hit-testing/components/child-chunks-item.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -5916,11 +3960,6 @@ "count": 3 } }, - "app/components/datasets/hit-testing/components/query-input/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 12 - } - }, "app/components/datasets/hit-testing/components/query-input/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -5935,9 +3974,6 @@ } }, "app/components/datasets/hit-testing/components/records.tsx": { - "e18e/prefer-array-to-sorted": { - "count": 1 - }, "tailwindcss/no-unnecessary-whitespace": { "count": 3 } @@ -5965,46 +4001,6 @@ "count": 1 } }, - "app/components/datasets/list/__tests__/datasets.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/datasets/list/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/datasets/list/dataset-card/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 12 - } - }, - "app/components/datasets/list/dataset-card/__tests__/operations.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 12 - } - }, - "app/components/datasets/list/dataset-card/components/__tests__/corner-labels.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, - "app/components/datasets/list/dataset-card/components/__tests__/dataset-card-footer.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/list/dataset-card/components/__tests__/dataset-card-header.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, - "app/components/datasets/list/dataset-card/components/__tests__/dataset-card-modals.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/datasets/list/dataset-card/components/dataset-card-footer.tsx": { "no-restricted-imports": { "count": 1 @@ -6043,31 +4039,11 @@ "count": 1 } }, - "app/components/datasets/list/dataset-footer/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/list/new-dataset-card/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/datasets/list/new-dataset-card/option.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 } }, - "app/components/datasets/metadata/edit-metadata-batch/__tests__/input-has-set-multiple-value.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/metadata/edit-metadata-batch/__tests__/modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, "app/components/datasets/metadata/edit-metadata-batch/edit-row.tsx": { "tailwindcss/no-unnecessary-whitespace": { "count": 1 @@ -6104,26 +4080,6 @@ "count": 3 } }, - "app/components/datasets/metadata/hooks/__tests__/use-edit-dataset-metadata.spec.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/metadata/hooks/__tests__/use-metadata-document.spec.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/datasets/metadata/hooks/use-batch-edit-document-metadata.ts": { - "e18e/prefer-array-some": { - "count": 2 - } - }, - "app/components/datasets/metadata/hooks/use-check-metadata-name.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/datasets/metadata/hooks/use-edit-dataset-metadata.ts": { "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 @@ -6134,19 +4090,6 @@ "count": 1 } }, - "app/components/datasets/metadata/metadata-dataset/__tests__/dataset-metadata-drawer.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/datasets/metadata/metadata-dataset/__tests__/select-metadata.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, "app/components/datasets/metadata/metadata-dataset/create-content.tsx": { "ts/no-explicit-any": { "count": 1 @@ -6189,11 +4132,6 @@ "count": 2 } }, - "app/components/datasets/metadata/metadata-document/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 16 - } - }, "app/components/datasets/metadata/metadata-document/field.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -6215,11 +4153,6 @@ "count": 1 } }, - "app/components/datasets/preview/__tests__/header.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, "app/components/datasets/preview/header.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -6230,36 +4163,6 @@ "count": 1 } }, - "app/components/datasets/settings/__tests__/option-card.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/datasets/settings/chunk-structure/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/datasets/settings/form/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 27 - } - }, - "app/components/datasets/settings/form/components/__tests__/basic-info-section.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 12 - } - }, - "app/components/datasets/settings/form/components/__tests__/external-knowledge-section.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 9 - } - }, - "app/components/datasets/settings/form/components/__tests__/indexing-section.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 26 - } - }, "app/components/datasets/settings/form/components/basic-info-section.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 @@ -6275,16 +4178,6 @@ "count": 7 } }, - "app/components/datasets/settings/index-method/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 12 - } - }, - "app/components/datasets/settings/index-method/__tests__/keyword-number.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/datasets/settings/index-method/index.tsx": { "no-restricted-imports": { "count": 1 @@ -6303,16 +4196,6 @@ "count": 2 } }, - "app/components/datasets/settings/permission-selector/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 33 - } - }, - "app/components/datasets/settings/permission-selector/__tests__/member-item.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, "app/components/datasets/settings/permission-selector/index.tsx": { "no-restricted-imports": { "count": 1 @@ -6342,23 +4225,7 @@ "count": 11 } }, - "app/components/develop/__tests__/ApiServer.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/develop/__tests__/code.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/develop/code.tsx": { - "e18e/prefer-array-to-sorted": { - "count": 1 - }, - "e18e/prefer-timer-args": { - "count": 1 - }, "ts/no-empty-object-type": { "count": 1 }, @@ -6366,15 +4233,7 @@ "count": 9 } }, - "app/components/develop/hooks/use-doc-toc.ts": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, "app/components/develop/md.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "ts/no-empty-object-type": { "count": 1 }, @@ -6382,11 +4241,6 @@ "count": 2 } }, - "app/components/develop/secret-key/__tests__/secret-key-generate.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, "app/components/develop/secret-key/input-copy.tsx": { "no-restricted-imports": { "count": 1 @@ -6407,11 +4261,6 @@ "count": 2 } }, - "app/components/explore/banner/__tests__/banner-item.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/explore/banner/banner-item.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 4 @@ -6430,11 +4279,6 @@ "count": 1 } }, - "app/components/explore/create-app-modal/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 16 - } - }, "app/components/explore/create-app-modal/index.tsx": { "no-restricted-imports": { "count": 1 @@ -6449,11 +4293,6 @@ "count": 1 } }, - "app/components/explore/installed-app/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 31 - } - }, "app/components/explore/item-operation/index.tsx": { "no-restricted-imports": { "count": 1 @@ -6477,11 +4316,6 @@ "count": 3 } }, - "app/components/explore/try-app/__tests__/index.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, "app/components/explore/try-app/app/chat.tsx": { "no-restricted-imports": { "count": 1 @@ -6519,9 +4353,6 @@ } }, "app/components/goto-anything/actions/commands/registry.ts": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, "ts/no-explicit-any": { "count": 3 } @@ -6539,25 +4370,12 @@ "count": 1 } }, - "app/components/goto-anything/actions/index.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/goto-anything/actions/types.ts": { "ts/no-explicit-any": { "count": 2 } }, - "app/components/goto-anything/components/__tests__/footer.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/goto-anything/context.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 4 }, @@ -6570,26 +4388,11 @@ "count": 1 } }, - "app/components/header/ maintenance-notice.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/header/account-about/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, "app/components/header/account-about/index.tsx": { "no-restricted-imports": { "count": 1 } }, - "app/components/header/account-dropdown/workplace-selector/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/header/account-dropdown/workplace-selector/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 @@ -6603,11 +4406,6 @@ "count": 2 } }, - "app/components/header/account-setting/api-based-extension-page/item.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, "app/components/header/account-setting/api-based-extension-page/item.tsx": { "no-restricted-imports": { "count": 1 @@ -6623,11 +4421,6 @@ "count": 1 } }, - "app/components/header/account-setting/data-source-page-new/card.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 16 - } - }, "app/components/header/account-setting/data-source-page-new/card.tsx": { "no-restricted-imports": { "count": 1 @@ -6639,11 +4432,6 @@ "count": 2 } }, - "app/components/header/account-setting/data-source-page-new/configure.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - } - }, "app/components/header/account-setting/data-source-page-new/configure.tsx": { "no-restricted-imports": { "count": 1 @@ -6653,9 +4441,6 @@ } }, "app/components/header/account-setting/data-source-page-new/hooks/use-marketplace-all-plugins.ts": { - "e18e/prefer-array-some": { - "count": 1 - }, "ts/no-explicit-any": { "count": 1 } @@ -6689,21 +4474,11 @@ "count": 2 } }, - "app/components/header/account-setting/data-source-page/data-source-notion/operate/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/header/account-setting/data-source-page/data-source-notion/operate/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 4 } }, - "app/components/header/account-setting/data-source-page/data-source-website/config-firecrawl-modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - } - }, "app/components/header/account-setting/data-source-page/data-source-website/config-firecrawl-modal.tsx": { "no-restricted-imports": { "count": 1 @@ -6712,11 +4487,6 @@ "count": 1 } }, - "app/components/header/account-setting/data-source-page/data-source-website/config-jina-reader-modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 9 - } - }, "app/components/header/account-setting/data-source-page/data-source-website/config-jina-reader-modal.tsx": { "no-restricted-imports": { "count": 1 @@ -6725,11 +4495,6 @@ "count": 1 } }, - "app/components/header/account-setting/data-source-page/data-source-website/config-watercrawl-modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - } - }, "app/components/header/account-setting/data-source-page/data-source-website/config-watercrawl-modal.tsx": { "no-restricted-imports": { "count": 1 @@ -6738,15 +4503,7 @@ "count": 1 } }, - "app/components/header/account-setting/data-source-page/data-source-website/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, "app/components/header/account-setting/data-source-page/data-source-website/index.tsx": { - "e18e/prefer-array-some": { - "count": 1 - }, "ts/no-explicit-any": { "count": 1 } @@ -6769,11 +4526,6 @@ "count": 1 } }, - "app/components/header/account-setting/key-validator/KeyInput.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/header/account-setting/key-validator/declarations.ts": { "ts/no-explicit-any": { "count": 1 @@ -6784,36 +4536,16 @@ "count": 2 } }, - "app/components/header/account-setting/members-page/edit-workspace-modal/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/header/account-setting/members-page/edit-workspace-modal/index.tsx": { "no-restricted-imports": { "count": 1 } }, - "app/components/header/account-setting/members-page/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 15 - } - }, "app/components/header/account-setting/members-page/index.tsx": { "no-restricted-imports": { "count": 1 } }, - "app/components/header/account-setting/members-page/invite-button.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/header/account-setting/members-page/invite-modal/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 13 - } - }, "app/components/header/account-setting/members-page/invite-modal/index.tsx": { "no-restricted-imports": { "count": 1 @@ -6822,21 +4554,11 @@ "count": 3 } }, - "app/components/header/account-setting/members-page/invite-modal/role-selector.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/header/account-setting/members-page/invite-modal/role-selector.tsx": { "no-restricted-imports": { "count": 1 } }, - "app/components/header/account-setting/members-page/invited-modal/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - } - }, "app/components/header/account-setting/members-page/invited-modal/index.tsx": { "no-restricted-imports": { "count": 2 @@ -6855,25 +4577,12 @@ "count": 5 } }, - "app/components/header/account-setting/members-page/operation/transfer-ownership.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, "app/components/header/account-setting/members-page/operation/transfer-ownership.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 } }, - "app/components/header/account-setting/members-page/transfer-ownership-modal/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, "app/components/header/account-setting/members-page/transfer-ownership-modal/index.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - }, "no-restricted-imports": { "count": 1 }, @@ -6881,11 +4590,6 @@ "count": 3 } }, - "app/components/header/account-setting/members-page/transfer-ownership-modal/member-selector.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/header/account-setting/members-page/transfer-ownership-modal/member-selector.tsx": { "no-restricted-imports": { "count": 1 @@ -6900,12 +4604,6 @@ } }, "app/components/header/account-setting/model-provider-page/hooks.ts": { - "e18e/prefer-array-some": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 1 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 }, @@ -6913,21 +4611,11 @@ "count": 3 } }, - "app/components/header/account-setting/model-provider-page/index.tsx": { - "e18e/prefer-array-some": { - "count": 1 - } - }, "app/components/header/account-setting/model-provider-page/install-from-marketplace.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 } }, - "app/components/header/account-setting/model-provider-page/model-auth/add-credential-in-load-balancing.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/header/account-setting/model-provider-page/model-auth/add-credential-in-load-balancing.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -6936,11 +4624,6 @@ "count": 4 } }, - "app/components/header/account-setting/model-provider-page/model-auth/add-custom-model.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/header/account-setting/model-provider-page/model-auth/add-custom-model.tsx": { "no-restricted-imports": { "count": 2 @@ -6962,11 +4645,6 @@ "count": 1 } }, - "app/components/header/account-setting/model-provider-page/model-auth/authorized/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - } - }, "app/components/header/account-setting/model-provider-page/model-auth/authorized/index.tsx": { "no-restricted-imports": { "count": 3 @@ -6978,31 +4656,16 @@ "count": 2 } }, - "app/components/header/account-setting/model-provider-page/model-auth/config-model.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, "app/components/header/account-setting/model-provider-page/model-auth/config-model.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 } }, - "app/components/header/account-setting/model-provider-page/model-auth/config-provider.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, "app/components/header/account-setting/model-provider-page/model-auth/config-provider.tsx": { "no-restricted-imports": { "count": 1 } }, - "app/components/header/account-setting/model-provider-page/model-auth/credential-selector.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, "app/components/header/account-setting/model-provider-page/model-auth/credential-selector.tsx": { "no-restricted-imports": { "count": 1 @@ -7021,16 +4684,6 @@ "count": 2 } }, - "app/components/header/account-setting/model-provider-page/model-auth/manage-custom-model-credentials.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/header/account-setting/model-provider-page/model-auth/switch-credential-in-load-balancing.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 8 - } - }, "app/components/header/account-setting/model-provider-page/model-auth/switch-credential-in-load-balancing.tsx": { "no-restricted-imports": { "count": 1 @@ -7039,26 +4692,11 @@ "count": 3 } }, - "app/components/header/account-setting/model-provider-page/model-badge/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/header/account-setting/model-provider-page/model-badge/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 } }, - "app/components/header/account-setting/model-provider-page/model-icon/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, - "app/components/header/account-setting/model-provider-page/model-modal/Form.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/header/account-setting/model-provider-page/model-modal/Form.tsx": { "no-restricted-imports": { "count": 2 @@ -7101,11 +4739,6 @@ "count": 2 } }, - "app/components/header/account-setting/model-provider-page/model-parameter-modal/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/header/account-setting/model-provider-page/model-parameter-modal/index.tsx": { "no-restricted-imports": { "count": 1 @@ -7127,11 +4760,6 @@ "count": 2 } }, - "app/components/header/account-setting/model-provider-page/model-parameter-modal/presets-parameter.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, "app/components/header/account-setting/model-provider-page/model-parameter-modal/presets-parameter.tsx": { "no-restricted-imports": { "count": 1 @@ -7182,11 +4810,6 @@ "count": 1 } }, - "app/components/header/account-setting/model-provider-page/model-selector/popup-item.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/header/account-setting/model-provider-page/model-selector/popup-item.tsx": { "no-restricted-imports": { "count": 1 @@ -7213,11 +4836,6 @@ "count": 2 } }, - "app/components/header/account-setting/model-provider-page/provider-added-card/credential-panel.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, "app/components/header/account-setting/model-provider-page/provider-added-card/credential-panel.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -7226,11 +4844,6 @@ "count": 1 } }, - "app/components/header/account-setting/model-provider-page/provider-added-card/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/header/account-setting/model-provider-page/provider-added-card/index.tsx": { "ts/no-explicit-any": { "count": 1 @@ -7244,11 +4857,6 @@ "count": 1 } }, - "app/components/header/account-setting/model-provider-page/provider-added-card/model-list.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/header/account-setting/model-provider-page/provider-added-card/model-list.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -7262,11 +4870,6 @@ "count": 5 } }, - "app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 23 - } - }, "app/components/header/account-setting/model-provider-page/provider-added-card/model-load-balancing-modal.tsx": { "no-restricted-imports": { "count": 2 @@ -7283,11 +4886,6 @@ "count": 1 } }, - "app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, "app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.tsx": { "no-restricted-imports": { "count": 1 @@ -7301,26 +4899,11 @@ "count": 1 } }, - "app/components/header/account-setting/model-provider-page/system-model-selector/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 28 - } - }, "app/components/header/account-setting/model-provider-page/system-model-selector/index.tsx": { "no-restricted-imports": { "count": 2 } }, - "app/components/header/account-setting/plugin-page/SerpapiPlugin.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/header/account-setting/plugin-page/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/header/account-setting/plugin-page/utils.ts": { "ts/no-explicit-any": { "count": 4 @@ -7334,51 +4917,21 @@ "count": 1 } }, - "app/components/header/app-selector/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, - "app/components/header/dataset-nav/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, "app/components/header/header-wrapper.tsx": { "ts/no-explicit-any": { "count": 1 } }, - "app/components/header/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, "app/components/header/index.tsx": { "tailwindcss/no-unnecessary-whitespace": { "count": 1 } }, - "app/components/header/license-env/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, "app/components/header/license-env/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 } }, - "app/components/header/nav/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 11 - } - }, - "app/components/header/nav/nav-selector/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/header/nav/nav-selector/index.tsx": { "tailwindcss/no-unnecessary-whitespace": { "count": 1 @@ -7389,11 +4942,6 @@ "count": 1 } }, - "app/components/plugins/base/__tests__/deprecation-notice.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/plugins/base/badges/icon-with-tooltip.tsx": { "no-restricted-imports": { "count": 1 @@ -7448,11 +4996,6 @@ "count": 1 } }, - "app/components/plugins/install-plugin/__tests__/hooks.spec.ts": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/plugins/install-plugin/base/installed.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -7468,11 +5011,6 @@ "count": 4 } }, - "app/components/plugins/install-plugin/install-bundle/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 11 - } - }, "app/components/plugins/install-plugin/install-bundle/index.tsx": { "no-restricted-imports": { "count": 1 @@ -7489,20 +5027,7 @@ "count": 1 } }, - "app/components/plugins/install-plugin/install-bundle/steps/__tests__/install.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 23 - } - }, - "app/components/plugins/install-plugin/install-bundle/steps/hooks/use-install-multi-state.ts": { - "e18e/prefer-array-some": { - "count": 1 - } - }, "app/components/plugins/install-plugin/install-bundle/steps/install.tsx": { - "e18e/prefer-array-some": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 2 } @@ -7518,16 +5043,6 @@ "count": 3 } }, - "app/components/plugins/install-plugin/install-from-github/steps/__tests__/loaded.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 17 - } - }, - "app/components/plugins/install-plugin/install-from-github/steps/__tests__/selectPackage.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/plugins/install-plugin/install-from-github/steps/loaded.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -7554,16 +5069,6 @@ "count": 1 } }, - "app/components/plugins/install-plugin/install-from-local-package/steps/__tests__/install.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 7 - } - }, - "app/components/plugins/install-plugin/install-from-local-package/steps/__tests__/uploading.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/plugins/install-plugin/install-from-local-package/steps/install.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -7585,31 +5090,11 @@ "count": 1 } }, - "app/components/plugins/install-plugin/install-from-marketplace/steps/__tests__/install.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, "app/components/plugins/install-plugin/install-from-marketplace/steps/install.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 } }, - "app/components/plugins/install-plugin/utils.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/plugins/marketplace/__tests__/hooks-integration.spec.tsx": { - "e18e/prefer-timer-args": { - "count": 1 - } - }, - "app/components/plugins/marketplace/description/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/plugins/marketplace/description/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 9 @@ -7643,11 +5128,6 @@ "count": 1 } }, - "app/components/plugins/marketplace/search-box/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/plugins/marketplace/search-box/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 @@ -7679,16 +5159,6 @@ "count": 3 } }, - "app/components/plugins/plugin-auth/__tests__/plugin-auth-in-agent.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, - "app/components/plugins/plugin-auth/__tests__/plugin-auth-in-datasource-node.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/plugins/plugin-auth/authorize/add-oauth-button.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 @@ -7726,14 +5196,6 @@ "count": 1 } }, - "app/components/plugins/plugin-auth/authorized/__tests__/index.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 24 - }, - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/plugins/plugin-auth/authorized/index.tsx": { "no-restricted-imports": { "count": 3 @@ -7781,11 +5243,6 @@ "count": 2 } }, - "app/components/plugins/plugin-detail-panel/__tests__/detail-header.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/plugins/plugin-detail-panel/action-list.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -7799,14 +5256,6 @@ "count": 1 } }, - "app/components/plugins/plugin-detail-panel/app-selector/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 2 - }, - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/plugins/plugin-detail-panel/app-selector/app-inputs-form.tsx": { "no-restricted-imports": { "count": 1 @@ -7836,11 +5285,6 @@ "count": 2 } }, - "app/components/plugins/plugin-detail-panel/app-selector/hooks/use-app-inputs-form-schema.ts": { - "e18e/prefer-array-from-map": { - "count": 1 - } - }, "app/components/plugins/plugin-detail-panel/app-selector/index.tsx": { "no-restricted-imports": { "count": 1 @@ -7913,11 +5357,6 @@ "count": 1 } }, - "app/components/plugins/plugin-detail-panel/model-selector/__tests__/llm-params-panel.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/plugins/plugin-detail-panel/model-selector/index.tsx": { "no-restricted-imports": { "count": 1 @@ -7946,9 +5385,6 @@ } }, "app/components/plugins/plugin-detail-panel/multiple-tool-selector/index.tsx": { - "e18e/prefer-array-some": { - "count": 2 - }, "no-restricted-imports": { "count": 1 }, @@ -7980,36 +5416,6 @@ "count": 2 } }, - "app/components/plugins/plugin-detail-panel/subscription-list/__tests__/delete-confirm.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, - "app/components/plugins/plugin-detail-panel/subscription-list/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/plugins/plugin-detail-panel/subscription-list/__tests__/list-view.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/plugins/plugin-detail-panel/subscription-list/__tests__/log-viewer.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - } - }, - "app/components/plugins/plugin-detail-panel/subscription-list/__tests__/selector-view.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, - "app/components/plugins/plugin-detail-panel/subscription-list/__tests__/subscription-card.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/plugins/plugin-detail-panel/subscription-list/create/common-modal.tsx": { "no-restricted-imports": { "count": 1 @@ -8044,16 +5450,6 @@ "count": 1 } }, - "app/components/plugins/plugin-detail-panel/subscription-list/edit/__tests__/manual-edit-modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/plugins/plugin-detail-panel/subscription-list/edit/__tests__/oauth-edit-modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/plugins/plugin-detail-panel/subscription-list/edit/apikey-edit-modal.tsx": { "no-restricted-imports": { "count": 1 @@ -8117,11 +5513,6 @@ "count": 3 } }, - "app/components/plugins/plugin-detail-panel/tool-selector/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 19 - } - }, "app/components/plugins/plugin-detail-panel/tool-selector/components/reasoning-config-form.tsx": { "no-restricted-imports": { "count": 2 @@ -8179,11 +5570,6 @@ "count": 3 } }, - "app/components/plugins/plugin-item/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/plugins/plugin-item/action.tsx": { "no-restricted-imports": { "count": 2 @@ -8200,11 +5586,6 @@ "count": 1 } }, - "app/components/plugins/plugin-mutation-model/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 19 - } - }, "app/components/plugins/plugin-mutation-model/index.tsx": { "no-restricted-imports": { "count": 1 @@ -8213,20 +5594,12 @@ "count": 1 } }, - "app/components/plugins/plugin-page/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 12 - } - }, "app/components/plugins/plugin-page/context.ts": { "ts/no-explicit-any": { "count": 1 } }, "app/components/plugins/plugin-page/debug-info.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -8242,19 +5615,6 @@ "count": 1 } }, - "app/components/plugins/plugin-page/filter-management/__tests__/category-filter.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, - "app/components/plugins/plugin-page/filter-management/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/plugins/plugin-page/filter-management/category-filter.tsx": { "no-restricted-imports": { "count": 1 @@ -8292,14 +5652,6 @@ "count": 1 } }, - "app/components/plugins/plugin-page/plugin-tasks/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 4 - } - }, "app/components/plugins/plugin-page/plugin-tasks/components/plugin-task-list.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -8315,26 +5667,11 @@ "count": 1 } }, - "app/components/plugins/plugin-page/use-uploader.ts": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, "app/components/plugins/provider-card.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 } }, - "app/components/plugins/reference-setting-modal/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, - "app/components/plugins/reference-setting-modal/auto-update-setting/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/plugins/reference-setting-modal/auto-update-setting/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 4 @@ -8399,11 +5736,6 @@ "count": 30 } }, - "app/components/plugins/update-plugin/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/plugins/update-plugin/downgrade-warning.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -8425,26 +5757,6 @@ "count": 3 } }, - "app/components/rag-pipeline/components/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 29 - } - }, - "app/components/rag-pipeline/components/__tests__/version-mismatch-modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, - "app/components/rag-pipeline/components/chunk-card-list/__tests__/chunk-card.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/rag-pipeline/components/chunk-card-list/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 34 - } - }, "app/components/rag-pipeline/components/chunk-card-list/chunk-card.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -8463,16 +5775,6 @@ "count": 2 } }, - "app/components/rag-pipeline/components/panel/input-field/editor/form/__tests__/hooks.spec.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/rag-pipeline/components/panel/input-field/editor/form/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 6 - } - }, "app/components/rag-pipeline/components/panel/input-field/editor/form/hidden-fields.tsx": { "ts/no-explicit-any": { "count": 1 @@ -8488,11 +5790,6 @@ "count": 2 } }, - "app/components/rag-pipeline/components/panel/input-field/editor/form/schema.ts": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/rag-pipeline/components/panel/input-field/editor/form/show-all-settings.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -8511,11 +5808,6 @@ "count": 1 } }, - "app/components/rag-pipeline/components/panel/input-field/field-list/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/rag-pipeline/components/panel/input-field/field-list/field-item.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 @@ -8547,11 +5839,6 @@ "count": 1 } }, - "app/components/rag-pipeline/components/panel/input-field/preview/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/rag-pipeline/components/panel/input-field/preview/data-source.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -8562,31 +5849,16 @@ "count": 1 } }, - "app/components/rag-pipeline/components/panel/test-run/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 18 - } - }, "app/components/rag-pipeline/components/panel/test-run/header.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 } }, - "app/components/rag-pipeline/components/panel/test-run/preparation/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 35 - } - }, "app/components/rag-pipeline/components/panel/test-run/preparation/data-source-options/option-card.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 } }, - "app/components/rag-pipeline/components/panel/test-run/preparation/document-processing/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, "app/components/rag-pipeline/components/panel/test-run/preparation/document-processing/index.tsx": { "ts/no-explicit-any": { "count": 1 @@ -8612,11 +5884,6 @@ "count": 1 } }, - "app/components/rag-pipeline/components/panel/test-run/result/result-preview/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, "app/components/rag-pipeline/components/panel/test-run/result/result-preview/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 3 @@ -8656,21 +5923,6 @@ "count": 1 } }, - "app/components/rag-pipeline/components/rag-pipeline-header/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 30 - } - }, - "app/components/rag-pipeline/components/rag-pipeline-header/publisher/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 33 - } - }, - "app/components/rag-pipeline/components/rag-pipeline-header/publisher/__tests__/popup.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, "app/components/rag-pipeline/components/rag-pipeline-header/publisher/index.tsx": { "no-restricted-imports": { "count": 1 @@ -8713,16 +5965,6 @@ "count": 2 } }, - "app/components/rag-pipeline/hooks/__tests__/use-available-nodes-meta-data.spec.ts": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/rag-pipeline/hooks/__tests__/use-rag-pipeline-search.spec.tsx": { - "e18e/prefer-array-to-sorted": { - "count": 1 - } - }, "app/components/rag-pipeline/hooks/use-DSL.ts": { "ts/no-explicit-any": { "count": 1 @@ -8753,16 +5995,6 @@ "count": 1 } }, - "app/components/rag-pipeline/hooks/use-pipeline.tsx": { - "e18e/prefer-array-some": { - "count": 2 - } - }, - "app/components/rag-pipeline/hooks/use-update-dsl-modal.ts": { - "e18e/prefer-timer-args": { - "count": 1 - } - }, "app/components/rag-pipeline/store/index.ts": { "ts/no-explicit-any": { "count": 2 @@ -8773,11 +6005,6 @@ "count": 1 } }, - "app/components/share/text-generation/__tests__/info-modal.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/share/text-generation/index.tsx": { "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 @@ -8830,9 +6057,6 @@ } }, "app/components/share/text-generation/run-batch/csv-reader/index.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 1 }, @@ -8840,11 +6064,6 @@ "count": 2 } }, - "app/components/share/text-generation/run-once/__tests__/index.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/share/text-generation/run-once/index.tsx": { "no-restricted-imports": { "count": 1 @@ -8864,21 +6083,11 @@ "count": 2 } }, - "app/components/signin/__tests__/countdown.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, "app/components/signin/countdown.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 } }, - "app/components/tools/edit-custom-collection-modal/__tests__/test-api.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/tools/edit-custom-collection-modal/config-credentials.tsx": { "no-restricted-imports": { "count": 1 @@ -8939,31 +6148,11 @@ "count": 1 } }, - "app/components/tools/marketplace/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/tools/marketplace/index.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 10 } }, - "app/components/tools/mcp/__tests__/mcp-service-card.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, - "app/components/tools/mcp/__tests__/modal.spec.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, - "app/components/tools/mcp/__tests__/provider-card.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/tools/mcp/create-card.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 2 @@ -8972,11 +6161,6 @@ "count": 1 } }, - "app/components/tools/mcp/detail/__tests__/content.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/tools/mcp/detail/content.tsx": { "no-restricted-imports": { "count": 2 @@ -9009,11 +6193,6 @@ "count": 3 } }, - "app/components/tools/mcp/hooks/use-mcp-modal-form.ts": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/tools/mcp/mcp-server-modal.tsx": { "no-restricted-imports": { "count": 1 @@ -9063,11 +6242,6 @@ "count": 3 } }, - "app/components/tools/mcp/sections/__tests__/authentication-section.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/tools/mcp/sections/authentication-section.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 5 @@ -9088,16 +6262,6 @@ "count": 1 } }, - "app/components/tools/provider/__tests__/custom-create-card.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/tools/provider/__tests__/empty.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/tools/provider/custom-create-card.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -9134,25 +6298,12 @@ "count": 4 } }, - "app/components/tools/utils/to-form-schema.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/tools/workflow-tool/__tests__/configure-button.spec.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/tools/workflow-tool/confirm-modal/index.tsx": { "no-restricted-imports": { "count": 1 } }, "app/components/tools/workflow-tool/index.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -9176,16 +6327,6 @@ "count": 3 } }, - "app/components/workflow-app/components/workflow-header/__tests__/features-trigger.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - } - }, - "app/components/workflow-app/components/workflow-header/__tests__/index.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/workflow-app/components/workflow-main.tsx": { "ts/no-explicit-any": { "count": 2 @@ -9292,9 +6433,6 @@ } }, "app/components/workflow/block-selector/index-bar.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - }, "react-refresh/only-export-components": { "count": 1 } @@ -9417,20 +6555,12 @@ "count": 2 } }, - "app/components/workflow/constants.ts": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/workflow/context.tsx": { "react-refresh/only-export-components": { "count": 1 } }, "app/components/workflow/datasets-detail-store/provider.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, "react-refresh/only-export-components": { "count": 1 } @@ -9527,12 +6657,6 @@ } }, "app/components/workflow/hooks/use-checklist.ts": { - "e18e/prefer-array-some": { - "count": 4 - }, - "e18e/prefer-spread-syntax": { - "count": 1 - }, "ts/no-empty-object-type": { "count": 2 }, @@ -9545,11 +6669,6 @@ "count": 3 } }, - "app/components/workflow/hooks/use-edges-interactions.ts": { - "e18e/prefer-array-some": { - "count": 1 - } - }, "app/components/workflow/hooks/use-helpline.ts": { "ts/no-explicit-any": { "count": 1 @@ -9566,12 +6685,6 @@ } }, "app/components/workflow/hooks/use-nodes-interactions.ts": { - "e18e/prefer-array-at": { - "count": 1 - }, - "e18e/prefer-array-some": { - "count": 4 - }, "ts/no-explicit-any": { "count": 8 } @@ -9611,15 +6724,7 @@ "count": 1 } }, - "app/components/workflow/hooks/use-workflow.ts": { - "e18e/prefer-array-some": { - "count": 3 - } - }, "app/components/workflow/index.tsx": { - "e18e/prefer-timer-args": { - "count": 1 - }, "ts/no-explicit-any": { "count": 2 } @@ -9692,12 +6797,6 @@ } }, "app/components/workflow/nodes/_base/components/editor/code-editor/editor-support-vars.tsx": { - "e18e/prefer-array-some": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 2 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 }, @@ -9832,11 +6931,6 @@ "count": 1 } }, - "app/components/workflow/nodes/_base/components/install-plugin-button.tsx": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, "app/components/workflow/nodes/_base/components/layout/field-title.tsx": { "no-restricted-imports": { "count": 1 @@ -9950,9 +7044,6 @@ } }, "app/components/workflow/nodes/_base/components/readonly-input-with-select-var.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "ts/no-explicit-any": { "count": 1 } @@ -9986,11 +7077,6 @@ "count": 1 } }, - "app/components/workflow/nodes/_base/components/support-var-input/index.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/workflow/nodes/_base/components/switch-plugin-version.tsx": { "no-restricted-imports": { "count": 1 @@ -10038,12 +7124,6 @@ } }, "app/components/workflow/nodes/_base/components/variable/utils.ts": { - "e18e/prefer-array-some": { - "count": 1 - }, - "e18e/prefer-array-to-sorted": { - "count": 1 - }, "ts/no-explicit-any": { "count": 32 } @@ -10056,11 +7136,6 @@ "count": 1 } }, - "app/components/workflow/nodes/_base/components/variable/var-list.tsx": { - "e18e/prefer-array-at": { - "count": 2 - } - }, "app/components/workflow/nodes/_base/components/variable/var-reference-picker.tsx": { "no-restricted-imports": { "count": 2 @@ -10084,9 +7159,6 @@ } }, "app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx": { - "e18e/prefer-array-some": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -10167,9 +7239,6 @@ } }, "app/components/workflow/nodes/_base/hooks/use-one-step-run.ts": { - "e18e/prefer-array-at": { - "count": 1 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 2 }, @@ -10206,9 +7275,6 @@ } }, "app/components/workflow/nodes/agent/components/model-bar.tsx": { - "e18e/prefer-spread-syntax": { - "count": 5 - }, "no-restricted-imports": { "count": 1 }, @@ -10302,11 +7368,6 @@ "count": 1 } }, - "app/components/workflow/nodes/code/code-parser.ts": { - "e18e/prefer-static-regex": { - "count": 4 - } - }, "app/components/workflow/nodes/code/default.ts": { "ts/no-explicit-any": { "count": 1 @@ -10318,9 +7379,6 @@ } }, "app/components/workflow/nodes/code/use-config.ts": { - "e18e/prefer-static-regex": { - "count": 2 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 2 }, @@ -10392,9 +7450,6 @@ } }, "app/components/workflow/nodes/document-extractor/panel.tsx": { - "e18e/prefer-array-from-map": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 1 } @@ -10430,9 +7485,6 @@ } }, "app/components/workflow/nodes/http/components/curl-panel.tsx": { - "e18e/prefer-static-regex": { - "count": 10 - }, "no-restricted-imports": { "count": 1 } @@ -10488,9 +7540,6 @@ } }, "app/components/workflow/nodes/human-input/components/delivery-method/email-configure-modal.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -10523,12 +7572,6 @@ } }, "app/components/workflow/nodes/human-input/components/delivery-method/recipient/email-input.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -10542,9 +7585,6 @@ } }, "app/components/workflow/nodes/human-input/components/delivery-method/recipient/index.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 2 } @@ -10560,12 +7600,6 @@ } }, "app/components/workflow/nodes/human-input/components/delivery-method/test-email-sender.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 4 - }, "no-restricted-imports": { "count": 1 }, @@ -10607,22 +7641,11 @@ } }, "app/components/workflow/nodes/human-input/components/timeout.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 2 } }, - "app/components/workflow/nodes/human-input/components/user-action.tsx": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/workflow/nodes/human-input/components/variable-in-markdown.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "react-refresh/only-export-components": { "count": 2 }, @@ -10630,11 +7653,6 @@ "count": 8 } }, - "app/components/workflow/nodes/human-input/hooks/use-form-content.ts": { - "e18e/prefer-array-some": { - "count": 1 - } - }, "app/components/workflow/nodes/human-input/node.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 4 @@ -10657,9 +7675,6 @@ } }, "app/components/workflow/nodes/if-else/components/condition-files-list-value.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - }, "tailwindcss/enforce-consistent-class-order": { "count": 3 }, @@ -10701,11 +7716,6 @@ "count": 1 } }, - "app/components/workflow/nodes/if-else/components/condition-value.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/workflow/nodes/if-else/components/condition-wrap.tsx": { "no-restricted-imports": { "count": 1 @@ -10761,9 +7771,6 @@ } }, "app/components/workflow/nodes/iteration/use-single-run-form-params.ts": { - "e18e/prefer-array-at": { - "count": 1 - }, "ts/no-explicit-any": { "count": 6 } @@ -10995,12 +8002,6 @@ } }, "app/components/workflow/nodes/llm/components/config-prompt.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, - "e18e/prefer-array-some": { - "count": 1 - }, "ts/no-explicit-any": { "count": 1 } @@ -11090,9 +8091,6 @@ } }, "app/components/workflow/nodes/llm/components/json-schema-config-modal/visual-editor/edit-card/index.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 2 } @@ -11170,9 +8168,6 @@ } }, "app/components/workflow/nodes/loop/components/condition-files-list-value.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - }, "tailwindcss/enforce-consistent-class-order": { "count": 3 }, @@ -11214,11 +8209,6 @@ "count": 1 } }, - "app/components/workflow/nodes/loop/components/condition-value.tsx": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "app/components/workflow/nodes/loop/components/condition-wrap.tsx": { "no-restricted-imports": { "count": 1 @@ -11268,9 +8258,6 @@ } }, "app/components/workflow/nodes/loop/use-single-run-form-params.ts": { - "e18e/prefer-array-at": { - "count": 1 - }, "ts/no-explicit-any": { "count": 4 } @@ -11505,9 +8492,6 @@ } }, "app/components/workflow/nodes/trigger-plugin/use-config.ts": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, "ts/no-explicit-any": { "count": 1 } @@ -11528,9 +8512,6 @@ } }, "app/components/workflow/nodes/trigger-schedule/default.ts": { - "e18e/prefer-static-regex": { - "count": 1 - }, "regexp/no-unused-capturing-group": { "count": 2 }, @@ -11538,20 +8519,7 @@ "count": 10 } }, - "app/components/workflow/nodes/trigger-schedule/utils/cron-parser.ts": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "app/components/workflow/nodes/trigger-schedule/utils/integration.spec.ts": { - "e18e/prefer-static-regex": { - "count": 3 - } - }, "app/components/workflow/nodes/trigger-webhook/components/generic-table.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -11565,9 +8533,6 @@ } }, "app/components/workflow/nodes/trigger-webhook/panel.tsx": { - "e18e/prefer-timer-args": { - "count": 1 - }, "no-restricted-imports": { "count": 2 }, @@ -11575,20 +8540,7 @@ "count": 3 } }, - "app/components/workflow/nodes/trigger-webhook/types.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/workflow/nodes/trigger-webhook/use-config.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/workflow/nodes/trigger-webhook/utils/render-output-vars.tsx": { - "e18e/prefer-array-to-sorted": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 4 } @@ -11603,15 +8555,7 @@ "count": 1 } }, - "app/components/workflow/nodes/variable-assigner/components/node-group-item.tsx": { - "e18e/prefer-array-at": { - "count": 1 - } - }, "app/components/workflow/nodes/variable-assigner/components/node-variable-item.tsx": { - "e18e/prefer-array-at": { - "count": 2 - }, "tailwindcss/enforce-consistent-class-order": { "count": 1 } @@ -11632,11 +8576,6 @@ "count": 2 } }, - "app/components/workflow/nodes/variable-assigner/use-config.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/workflow/nodes/variable-assigner/use-single-run-form-params.ts": { "ts/no-explicit-any": { "count": 5 @@ -11733,9 +8672,6 @@ } }, "app/components/workflow/panel/chat-variable-panel/components/object-value-item.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "react-refresh/only-export-components": { "count": 1 }, @@ -11793,17 +8729,11 @@ } }, "app/components/workflow/panel/chat-variable-panel/index.tsx": { - "e18e/prefer-array-some": { - "count": 2 - }, "tailwindcss/enforce-consistent-class-order": { "count": 11 } }, "app/components/workflow/panel/debug-and-preview/chat-wrapper.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, "ts/no-explicit-any": { "count": 6 } @@ -11838,17 +8768,11 @@ } }, "app/components/workflow/panel/env-panel/index.tsx": { - "e18e/prefer-array-some": { - "count": 2 - }, "tailwindcss/enforce-consistent-class-order": { "count": 2 } }, "app/components/workflow/panel/env-panel/variable-modal.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "no-restricted-imports": { "count": 1 }, @@ -12002,9 +8926,6 @@ } }, "app/components/workflow/run/agent-log/agent-result-panel.tsx": { - "e18e/prefer-array-at": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 1 } @@ -12117,9 +9038,6 @@ } }, "app/components/workflow/run/utils/format-log/agent/index.ts": { - "e18e/prefer-array-some": { - "count": 2 - }, "ts/no-explicit-any": { "count": 11 } @@ -12168,12 +9086,6 @@ } }, "app/components/workflow/selection-contextmenu.tsx": { - "e18e/prefer-array-at": { - "count": 4 - }, - "e18e/prefer-array-to-sorted": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 2 }, @@ -12225,16 +9137,6 @@ "count": 2 } }, - "app/components/workflow/utils/__tests__/common.spec.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "app/components/workflow/utils/__tests__/elk-layout.spec.ts": { - "e18e/prefer-array-at": { - "count": 2 - } - }, "app/components/workflow/utils/data-source.ts": { "ts/no-explicit-any": { "count": 1 @@ -12245,20 +9147,12 @@ "count": 1 } }, - "app/components/workflow/utils/elk-layout.ts": { - "e18e/prefer-array-to-sorted": { - "count": 2 - } - }, "app/components/workflow/utils/node-navigation.ts": { "ts/no-explicit-any": { "count": 2 } }, "app/components/workflow/utils/node.ts": { - "e18e/prefer-static-regex": { - "count": 1 - }, "regexp/no-super-linear-backtracking": { "count": 1 } @@ -12268,26 +9162,12 @@ "count": 2 } }, - "app/components/workflow/utils/variable.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/components/workflow/utils/workflow-init.ts": { - "e18e/prefer-array-at": { - "count": 1 - }, - "e18e/prefer-array-some": { - "count": 1 - }, "ts/no-explicit-any": { "count": 12 } }, "app/components/workflow/utils/workflow.ts": { - "e18e/prefer-array-some": { - "count": 2 - }, "ts/no-explicit-any": { "count": 1 } @@ -12376,9 +9256,6 @@ } }, "app/components/workflow/variable-inspect/value-content.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 5 }, @@ -12479,9 +9356,6 @@ } }, "app/education-apply/verify-state-modal.tsx": { - "e18e/prefer-timer-args": { - "count": 1 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 }, @@ -12490,9 +9364,6 @@ } }, "app/forgot-password/ForgotPasswordForm.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 9 - }, "ts/no-explicit-any": { "count": 5 } @@ -12503,17 +9374,11 @@ } }, "app/install/installForm.spec.tsx": { - "e18e/prefer-static-regex": { - "count": 5 - }, "ts/no-explicit-any": { "count": 7 } }, "app/reset-password/check-code/page.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 4 } @@ -12541,11 +9406,6 @@ "count": 1 } }, - "app/signin/check-code/page.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "app/signin/components/mail-and-code-auth.tsx": { "tailwindcss/enforce-consistent-class-order": { "count": 1 @@ -12581,9 +9441,6 @@ } }, "app/signup/check-code/page.tsx": { - "e18e/prefer-static-regex": { - "count": 1 - }, "tailwindcss/enforce-consistent-class-order": { "count": 4 } @@ -12656,20 +9513,12 @@ "count": 1 } }, - "docs/test.md": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "hooks/use-async-window-open.spec.ts": { "ts/no-explicit-any": { "count": 6 } }, "hooks/use-format-time-from-now.spec.ts": { - "e18e/prefer-static-regex": { - "count": 19 - }, "regexp/no-dupe-disjunctions": { "count": 5 }, @@ -12683,9 +9532,6 @@ } }, "hooks/use-mitt.ts": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, "ts/no-explicit-any": { "count": 2 } @@ -12711,16 +9557,6 @@ "count": 3 } }, - "hooks/use-query-params.spec.tsx": { - "e18e/prefer-array-at": { - "count": 15 - } - }, - "i18n-config/server.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "i18n/de-DE/billing.json": { "no-irregular-whitespace": { "count": 1 @@ -12804,105 +9640,16 @@ "count": 1 } }, - "plugins/eslint/namespaces.js": { - "e18e/prefer-array-to-sorted": { - "count": 1 - } - }, - "plugins/eslint/rules/consistent-placeholders.js": { - "e18e/prefer-object-has-own": { - "count": 1 - }, - "e18e/prefer-spread-syntax": { - "count": 2 - }, - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "plugins/eslint/rules/no-extra-keys.js": { - "e18e/prefer-object-has-own": { - "count": 1 - } - }, - "plugins/eslint/rules/no-legacy-namespace-prefix.js": { - "e18e/prefer-spread-syntax": { - "count": 1 - } - }, - "plugins/eslint/utils.js": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "plugins/vite/code-inspector.ts": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "plugins/vite/utils.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, - "proxy.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "scripts/analyze-component.js": { - "e18e/prefer-static-regex": { - "count": 1 - }, "unused-imports/no-unused-vars": { "count": 1 } }, - "scripts/analyze-i18n-diff.ts": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "scripts/check-i18n.js": { - "e18e/prefer-spread-syntax": { - "count": 2 - }, - "e18e/prefer-static-regex": { - "count": 7 - } - }, "scripts/component-analyzer.js": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 14 - }, "regexp/no-unused-capturing-group": { "count": 6 } }, - "scripts/gen-doc-paths.ts": { - "e18e/prefer-array-to-sorted": { - "count": 1 - }, - "e18e/prefer-spread-syntax": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 6 - } - }, - "scripts/gen-icons.mjs": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, - "scripts/refactor-component.js": { - "e18e/prefer-static-regex": { - "count": 14 - } - }, "service/annotation.ts": { "ts/no-explicit-any": { "count": 4 @@ -12914,24 +9661,10 @@ } }, "service/base.ts": { - "e18e/prefer-array-at": { - "count": 1 - }, - "e18e/prefer-spread-syntax": { - "count": 7 - }, - "e18e/prefer-static-regex": { - "count": 4 - }, "ts/no-explicit-any": { "count": 3 } }, - "service/client.ts": { - "e18e/prefer-url-canparse": { - "count": 1 - } - }, "service/common.ts": { "ts/no-explicit-any": { "count": 29 @@ -12948,9 +9681,6 @@ } }, "service/fetch.ts": { - "e18e/prefer-static-regex": { - "count": 1 - }, "regexp/no-unused-capturing-group": { "count": 1 }, @@ -12958,11 +9688,6 @@ "count": 2 } }, - "service/refresh-token.ts": { - "e18e/prefer-date-now": { - "count": 2 - } - }, "service/share.ts": { "ts/no-explicit-any": { "count": 3 @@ -12986,11 +9711,6 @@ "count": 7 } }, - "service/use-explore.ts": { - "e18e/prefer-array-to-sorted": { - "count": 1 - } - }, "service/use-pipeline.ts": { "ts/no-explicit-any": { "count": 1 @@ -13002,12 +9722,6 @@ } }, "service/use-plugins.ts": { - "e18e/prefer-array-some": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 2 - }, "react-hooks-extra/no-direct-set-state-in-use-effect": { "count": 1 }, @@ -13029,9 +9743,6 @@ } }, "service/utils.spec.ts": { - "e18e/prefer-static-regex": { - "count": 4 - }, "ts/no-explicit-any": { "count": 2 } @@ -13087,9 +9798,6 @@ } }, "utils/error-parser.ts": { - "e18e/prefer-static-regex": { - "count": 1 - }, "no-console": { "count": 1 }, @@ -13097,11 +9805,6 @@ "count": 1 } }, - "utils/format.ts": { - "e18e/prefer-static-regex": { - "count": 2 - } - }, "utils/get-icon.spec.ts": { "ts/no-explicit-any": { "count": 2 @@ -13113,9 +9816,6 @@ } }, "utils/index.spec.ts": { - "e18e/prefer-static-regex": { - "count": 1 - }, "test/no-identical-title": { "count": 2 }, @@ -13148,35 +9848,14 @@ "count": 4 } }, - "utils/time.spec.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "utils/tool-call.spec.ts": { "ts/no-explicit-any": { "count": 1 } }, - "utils/urlValidation.ts": { - "e18e/prefer-static-regex": { - "count": 1 - } - }, "utils/validators.ts": { - "e18e/prefer-spread-syntax": { - "count": 1 - }, "ts/no-explicit-any": { "count": 2 } - }, - "utils/var.ts": { - "e18e/prefer-array-some": { - "count": 1 - }, - "e18e/prefer-static-regex": { - "count": 1 - } } } \ No newline at end of file diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs index de78e90548..bfdf284b03 100644 --- a/web/eslint.config.mjs +++ b/web/eslint.config.mjs @@ -1,5 +1,5 @@ // @ts-check -import antfu, { GLOB_TESTS, GLOB_TS, GLOB_TSX } from '@antfu/eslint-config' +import antfu, { GLOB_TESTS, GLOB_TS, GLOB_TSX, isInEditorEnv, isInGitHooksOrLintStaged } from '@antfu/eslint-config' import pluginQuery from '@tanstack/eslint-plugin-query' import tailwindcss from 'eslint-plugin-better-tailwindcss' import hyoban from 'eslint-plugin-hyoban' @@ -12,6 +12,8 @@ import dify from './plugins/eslint/index.js' // See: tailwind-css-plugin.ts process.env.TAILWIND_MODE ??= 'ESLINT' +const disableRuleAutoFix = !(isInEditorEnv() || isInGitHooksOrLintStaged()) + export default antfu( { react: { @@ -46,6 +48,7 @@ export default antfu( 'antfu/top-level-function': 'off', }, }, + e18e: false, }, { rules: { @@ -218,6 +221,10 @@ export default antfu( }, }, ) - .disableRulesFix([ - 'e18e/prefer-array-at', - ]) + .disableRulesFix(disableRuleAutoFix + ? [ + 'tailwindcss/enforce-consistent-class-order', + 'tailwindcss/no-duplicate-classes', + 'tailwindcss/no-unnecessary-whitespace', + ] + : []) From d6721a1dd31fab8da69fb31bd7581e816138ab33 Mon Sep 17 00:00:00 2001 From: wangxiaolei Date: Wed, 11 Mar 2026 13:37:23 +0800 Subject: [PATCH 06/10] fix: use moderation modified inputs and query (#33180) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Crazywoola <100913391+crazywoola@users.noreply.github.com> --- api/core/app/apps/advanced_chat/app_runner.py | 21 ++- .../test_app_runner_conversation_variables.py | 18 +- .../test_app_runner_input_moderation.py | 170 ++++++++++++++++++ 3 files changed, 198 insertions(+), 11 deletions(-) create mode 100644 api/tests/unit_tests/core/app/apps/advanced_chat/test_app_runner_input_moderation.py diff --git a/api/core/app/apps/advanced_chat/app_runner.py b/api/core/app/apps/advanced_chat/app_runner.py index b38dfdfc1f..66037696af 100644 --- a/api/core/app/apps/advanced_chat/app_runner.py +++ b/api/core/app/apps/advanced_chat/app_runner.py @@ -138,20 +138,25 @@ class AdvancedChatAppRunner(WorkflowBasedAppRunner): query = self.application_generate_entity.query # moderation - if self.handle_input_moderation( + stop, new_inputs, new_query = self.handle_input_moderation( app_record=self._app, app_generate_entity=self.application_generate_entity, inputs=inputs, query=query, message_id=self.message.id, - ): + ) + if stop: return + self.application_generate_entity.inputs = new_inputs + self.application_generate_entity.query = new_query + system_inputs.query = new_query + # annotation reply if self.handle_annotation_reply( app_record=self._app, message=self.message, - query=query, + query=new_query, app_generate_entity=self.application_generate_entity, ): return @@ -163,7 +168,7 @@ class AdvancedChatAppRunner(WorkflowBasedAppRunner): # init variable pool variable_pool = VariablePool( system_variables=system_inputs, - user_inputs=inputs, + user_inputs=new_inputs, environment_variables=self._workflow.environment_variables, # Based on the definition of `Variable`, # `VariableBase` instances can be safely used as `Variable` since they are compatible. @@ -240,10 +245,10 @@ class AdvancedChatAppRunner(WorkflowBasedAppRunner): inputs: Mapping[str, Any], query: str, message_id: str, - ) -> bool: + ) -> tuple[bool, Mapping[str, Any], str]: try: # process sensitive_word_avoidance - _, inputs, query = self.moderation_for_inputs( + _, new_inputs, new_query = self.moderation_for_inputs( app_id=app_record.id, tenant_id=app_generate_entity.app_config.tenant_id, app_generate_entity=app_generate_entity, @@ -253,9 +258,9 @@ class AdvancedChatAppRunner(WorkflowBasedAppRunner): ) except ModerationError as e: self._complete_with_stream_output(text=str(e), stopped_by=QueueStopEvent.StopBy.INPUT_MODERATION) - return True + return True, inputs, query - return False + return False, new_inputs, new_query def handle_annotation_reply( self, app_record: App, message: Message, query: str, app_generate_entity: AdvancedChatAppGenerateEntity diff --git a/api/tests/unit_tests/core/app/apps/advanced_chat/test_app_runner_conversation_variables.py b/api/tests/unit_tests/core/app/apps/advanced_chat/test_app_runner_conversation_variables.py index 12ab587564..15aceef2c7 100644 --- a/api/tests/unit_tests/core/app/apps/advanced_chat/test_app_runner_conversation_variables.py +++ b/api/tests/unit_tests/core/app/apps/advanced_chat/test_app_runner_conversation_variables.py @@ -125,7 +125,11 @@ class TestAdvancedChatAppRunnerConversationVariables: patch("core.app.apps.advanced_chat.app_runner.select") as mock_select, patch("core.app.apps.advanced_chat.app_runner.db") as mock_db, patch.object(runner, "_init_graph") as mock_init_graph, - patch.object(runner, "handle_input_moderation", return_value=False), + patch.object( + runner, + "handle_input_moderation", + return_value=(False, mock_app_generate_entity.inputs, mock_app_generate_entity.query), + ), patch.object(runner, "handle_annotation_reply", return_value=False), patch("core.app.apps.advanced_chat.app_runner.WorkflowEntry") as mock_workflow_entry_class, patch("core.app.apps.advanced_chat.app_runner.GraphRuntimeState") as mock_graph_runtime_state_class, @@ -265,7 +269,11 @@ class TestAdvancedChatAppRunnerConversationVariables: patch("core.app.apps.advanced_chat.app_runner.select") as mock_select, patch("core.app.apps.advanced_chat.app_runner.db") as mock_db, patch.object(runner, "_init_graph") as mock_init_graph, - patch.object(runner, "handle_input_moderation", return_value=False), + patch.object( + runner, + "handle_input_moderation", + return_value=(False, mock_app_generate_entity.inputs, mock_app_generate_entity.query), + ), patch.object(runner, "handle_annotation_reply", return_value=False), patch("core.app.apps.advanced_chat.app_runner.WorkflowEntry") as mock_workflow_entry_class, patch("core.app.apps.advanced_chat.app_runner.GraphRuntimeState") as mock_graph_runtime_state_class, @@ -412,7 +420,11 @@ class TestAdvancedChatAppRunnerConversationVariables: patch("core.app.apps.advanced_chat.app_runner.select") as mock_select, patch("core.app.apps.advanced_chat.app_runner.db") as mock_db, patch.object(runner, "_init_graph") as mock_init_graph, - patch.object(runner, "handle_input_moderation", return_value=False), + patch.object( + runner, + "handle_input_moderation", + return_value=(False, mock_app_generate_entity.inputs, mock_app_generate_entity.query), + ), patch.object(runner, "handle_annotation_reply", return_value=False), patch("core.app.apps.advanced_chat.app_runner.WorkflowEntry") as mock_workflow_entry_class, patch("core.app.apps.advanced_chat.app_runner.GraphRuntimeState") as mock_graph_runtime_state_class, diff --git a/api/tests/unit_tests/core/app/apps/advanced_chat/test_app_runner_input_moderation.py b/api/tests/unit_tests/core/app/apps/advanced_chat/test_app_runner_input_moderation.py new file mode 100644 index 0000000000..5792a2f1e2 --- /dev/null +++ b/api/tests/unit_tests/core/app/apps/advanced_chat/test_app_runner_input_moderation.py @@ -0,0 +1,170 @@ +from unittest.mock import MagicMock, patch +from uuid import uuid4 + +import pytest + +from core.app.apps.advanced_chat.app_runner import AdvancedChatAppRunner +from core.app.entities.app_invoke_entities import AdvancedChatAppGenerateEntity, InvokeFrom +from core.app.entities.queue_entities import QueueStopEvent +from core.moderation.base import ModerationError + + +@pytest.fixture +def build_runner(): + """Construct a minimal AdvancedChatAppRunner with heavy dependencies mocked.""" + app_id = str(uuid4()) + workflow_id = str(uuid4()) + + # Mocks for constructor args + mock_queue_manager = MagicMock() + + mock_conversation = MagicMock() + mock_conversation.id = str(uuid4()) + mock_conversation.app_id = app_id + + mock_message = MagicMock() + mock_message.id = str(uuid4()) + + mock_workflow = MagicMock() + mock_workflow.id = workflow_id + mock_workflow.tenant_id = str(uuid4()) + mock_workflow.app_id = app_id + mock_workflow.type = "chat" + mock_workflow.graph_dict = {} + mock_workflow.environment_variables = [] + + mock_app_config = MagicMock() + mock_app_config.app_id = app_id + mock_app_config.workflow_id = workflow_id + mock_app_config.tenant_id = str(uuid4()) + + gen = MagicMock(spec=AdvancedChatAppGenerateEntity) + gen.app_config = mock_app_config + gen.inputs = {"q": "raw"} + gen.query = "raw-query" + gen.files = [] + gen.user_id = str(uuid4()) + gen.invoke_from = InvokeFrom.SERVICE_API + gen.workflow_run_id = str(uuid4()) + gen.task_id = str(uuid4()) + gen.call_depth = 0 + gen.single_iteration_run = None + gen.single_loop_run = None + gen.trace_manager = None + + runner = AdvancedChatAppRunner( + application_generate_entity=gen, + queue_manager=mock_queue_manager, + conversation=mock_conversation, + message=mock_message, + dialogue_count=1, + variable_loader=MagicMock(), + workflow=mock_workflow, + system_user_id=str(uuid4()), + app=MagicMock(), + workflow_execution_repository=MagicMock(), + workflow_node_execution_repository=MagicMock(), + ) + + return runner + + +def _patch_common_run_deps(runner: AdvancedChatAppRunner): + """Context manager that patches common heavy deps used by run().""" + return patch.multiple( + "core.app.apps.advanced_chat.app_runner", + Session=MagicMock( + return_value=MagicMock( + __enter__=lambda s: s, + __exit__=lambda *a, **k: False, + scalar=lambda *a, **k: MagicMock(), + ), + ), + select=MagicMock(), + db=MagicMock(engine=MagicMock()), + RedisChannel=MagicMock(), + redis_client=MagicMock(), + WorkflowEntry=MagicMock(**{"return_value.run.return_value": iter([])}), + GraphRuntimeState=MagicMock(), + ) + + +def test_handle_input_moderation_stops_on_moderation_error(build_runner): + runner = build_runner + + # moderation_for_inputs raises ModerationError -> should stop and emit stop event + with ( + patch.object(runner, "moderation_for_inputs", side_effect=ModerationError("blocked")), + patch.object(runner, "_complete_with_stream_output") as mock_complete, + ): + stop, new_inputs, new_query = runner.handle_input_moderation( + app_record=MagicMock(), + app_generate_entity=runner.application_generate_entity, + inputs={"k": "v"}, + query="hello", + message_id="mid", + ) + + assert stop is True + # inputs/query should be unchanged on error path + assert new_inputs == {"k": "v"} + assert new_query == "hello" + # ensure stopped_by reason is INPUT_MODERATION + assert mock_complete.called + args, kwargs = mock_complete.call_args + assert kwargs.get("stopped_by") == QueueStopEvent.StopBy.INPUT_MODERATION + + +def test_run_applies_overridden_inputs_and_query_from_moderation(build_runner): + runner = build_runner + + overridden_inputs = {"q": "sanitized"} + overridden_query = "sanitized-query" + + with ( + _patch_common_run_deps(runner), + patch.object( + runner, + "moderation_for_inputs", + return_value=(True, overridden_inputs, overridden_query), + ) as mock_moderate, + patch.object(runner, "handle_annotation_reply", return_value=False) as mock_anno, + patch.object(runner, "_init_graph", return_value=MagicMock()) as mock_init_graph, + ): + runner.run() + + # moderation called with original values + mock_moderate.assert_called_once() + + # application_generate_entity should be updated to overridden values + assert runner.application_generate_entity.inputs == overridden_inputs + assert runner.application_generate_entity.query == overridden_query + + # annotation reply should use the new query + mock_anno.assert_called() + assert mock_anno.call_args.kwargs.get("query") == overridden_query + + # since not stopped, graph initialization should proceed + assert mock_init_graph.called + + +def test_run_returns_early_when_direct_output_via_handle_input_moderation(build_runner): + runner = build_runner + + with ( + _patch_common_run_deps(runner), + # Simulate handle_input_moderation signalling to stop + patch.object( + runner, + "handle_input_moderation", + return_value=(True, runner.application_generate_entity.inputs, runner.application_generate_entity.query), + ) as mock_handle, + patch.object(runner, "_init_graph") as mock_init_graph, + patch.object(runner, "handle_annotation_reply") as mock_anno, + ): + runner.run() + + mock_handle.assert_called_once() + # Ensure no further steps executed + mock_anno.assert_not_called() + mock_init_graph.assert_not_called() From 1f4b6c84e0d50d772822066b92bb01da2f6f3ff4 Mon Sep 17 00:00:00 2001 From: wangxiaolei Date: Wed, 11 Mar 2026 13:46:38 +0800 Subject: [PATCH 07/10] fix: fix mcp tool parameter extract (#33258) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- api/services/tools/tools_transform_service.py | 47 ++++++- .../tools/test_mcp_tools_transform.py | 133 +++++++++++++++++- 2 files changed, 175 insertions(+), 5 deletions(-) diff --git a/api/services/tools/tools_transform_service.py b/api/services/tools/tools_transform_service.py index e323b3cda9..b6e5367023 100644 --- a/api/services/tools/tools_transform_service.py +++ b/api/services/tools/tools_transform_service.py @@ -33,6 +33,8 @@ logger = logging.getLogger(__name__) class ToolTransformService: + _MCP_SCHEMA_TYPE_RESOLUTION_MAX_DEPTH = 10 + @classmethod def get_tool_provider_icon_url( cls, provider_type: str, provider_name: str, icon: str | Mapping[str, str] @@ -435,6 +437,46 @@ class ToolTransformService: :return: list of ToolParameter instances """ + def resolve_property_type(prop: dict[str, Any], depth: int = 0) -> str: + """ + Resolve a JSON schema property type while guarding against cyclic or deeply nested unions. + """ + if depth >= ToolTransformService._MCP_SCHEMA_TYPE_RESOLUTION_MAX_DEPTH: + return "string" + prop_type = prop.get("type") + if isinstance(prop_type, list): + non_null_types = [type_name for type_name in prop_type if type_name != "null"] + if non_null_types: + return non_null_types[0] + if prop_type: + return "string" + elif isinstance(prop_type, str): + if prop_type == "null": + return "string" + return prop_type + + for union_key in ("anyOf", "oneOf"): + union_schemas = prop.get(union_key) + if not isinstance(union_schemas, list): + continue + + for union_schema in union_schemas: + if not isinstance(union_schema, dict): + continue + union_type = resolve_property_type(union_schema, depth + 1) + if union_type != "null": + return union_type + + all_of_schemas = prop.get("allOf") + if isinstance(all_of_schemas, list): + for all_of_schema in all_of_schemas: + if not isinstance(all_of_schema, dict): + continue + all_of_type = resolve_property_type(all_of_schema, depth + 1) + if all_of_type != "null": + return all_of_type + return "string" + def create_parameter( name: str, description: str, param_type: str, required: bool, input_schema: dict[str, Any] | None = None ) -> ToolParameter: @@ -461,10 +503,7 @@ class ToolTransformService: parameters = [] for name, prop in props.items(): current_description = prop.get("description", "") - prop_type = prop.get("type", "string") - - if isinstance(prop_type, list): - prop_type = prop_type[0] + prop_type = resolve_property_type(prop) if prop_type in TYPE_MAPPING: prop_type = TYPE_MAPPING[prop_type] input_schema = prop if prop_type in COMPLEX_TYPES else None diff --git a/api/tests/unit_tests/services/tools/test_mcp_tools_transform.py b/api/tests/unit_tests/services/tools/test_mcp_tools_transform.py index 7511fd6f0c..9537d207f0 100644 --- a/api/tests/unit_tests/services/tools/test_mcp_tools_transform.py +++ b/api/tests/unit_tests/services/tools/test_mcp_tools_transform.py @@ -7,7 +7,7 @@ import pytest from core.mcp.types import Tool as MCPTool from core.tools.entities.api_entities import ToolApiEntity, ToolProviderApiEntity from core.tools.entities.common_entities import I18nObject -from core.tools.entities.tool_entities import ToolProviderType +from core.tools.entities.tool_entities import ToolParameter, ToolProviderType from models.tools import MCPToolProvider from services.tools.tools_transform_service import ToolTransformService @@ -175,6 +175,137 @@ class TestMCPToolTransform: # The actual parameter conversion is handled by convert_mcp_schema_to_parameter # which should be tested separately + def test_convert_mcp_schema_to_parameter_preserves_anyof_object_type(self): + """Nullable object schemas should keep the object parameter type.""" + schema = { + "type": "object", + "properties": { + "retrieval_model": { + "anyOf": [{"type": "object"}, {"type": "null"}], + "description": "检索模型配置", + } + }, + } + + result = ToolTransformService.convert_mcp_schema_to_parameter(schema) + + assert len(result) == 1 + assert result[0].name == "retrieval_model" + assert result[0].type == ToolParameter.ToolParameterType.OBJECT + assert result[0].input_schema == schema["properties"]["retrieval_model"] + + def test_convert_mcp_schema_to_parameter_preserves_oneof_object_type(self): + """Nullable oneOf object schemas should keep the object parameter type.""" + schema = { + "type": "object", + "properties": { + "retrieval_model": { + "oneOf": [{"type": "object"}, {"type": "null"}], + "description": "检索模型配置", + } + }, + } + + result = ToolTransformService.convert_mcp_schema_to_parameter(schema) + + assert len(result) == 1 + assert result[0].name == "retrieval_model" + assert result[0].type == ToolParameter.ToolParameterType.OBJECT + assert result[0].input_schema == schema["properties"]["retrieval_model"] + + def test_convert_mcp_schema_to_parameter_handles_null_type(self): + """Schemas with only a null type should fall back to string.""" + schema = { + "type": "object", + "properties": { + "null_prop_str": {"type": "null"}, + "null_prop_list": {"type": ["null"]}, + }, + } + + result = ToolTransformService.convert_mcp_schema_to_parameter(schema) + + assert len(result) == 2 + param_map = {parameter.name: parameter for parameter in result} + assert "null_prop_str" in param_map + assert param_map["null_prop_str"].type == ToolParameter.ToolParameterType.STRING + assert "null_prop_list" in param_map + assert param_map["null_prop_list"].type == ToolParameter.ToolParameterType.STRING + + def test_convert_mcp_schema_to_parameter_preserves_allof_object_type_with_multiple_object_items(self): + """Property-level allOf with multiple object items should still resolve to object.""" + schema = { + "type": "object", + "properties": { + "config": { + "allOf": [ + { + "type": "object", + "properties": { + "enabled": {"type": "boolean"}, + }, + "required": ["enabled"], + }, + { + "type": "object", + "properties": { + "priority": {"type": "integer", "minimum": 1, "maximum": 10}, + }, + "required": ["priority"], + }, + ], + "description": "Config must match all schemas (allOf)", + } + }, + } + + result = ToolTransformService.convert_mcp_schema_to_parameter(schema) + + assert len(result) == 1 + assert result[0].name == "config" + assert result[0].type == ToolParameter.ToolParameterType.OBJECT + assert result[0].input_schema == schema["properties"]["config"] + + def test_convert_mcp_schema_to_parameter_preserves_allof_object_type(self): + """Composed property schemas should keep the object parameter type.""" + schema = { + "type": "object", + "properties": { + "retrieval_model": { + "allOf": [ + {"type": "object"}, + {"properties": {"top_k": {"type": "integer"}}}, + ], + "description": "检索模型配置", + } + }, + } + + result = ToolTransformService.convert_mcp_schema_to_parameter(schema) + + assert len(result) == 1 + assert result[0].name == "retrieval_model" + assert result[0].type == ToolParameter.ToolParameterType.OBJECT + assert result[0].input_schema == schema["properties"]["retrieval_model"] + + def test_convert_mcp_schema_to_parameter_limits_recursive_schema_depth(self): + """Self-referential composed schemas should stop resolving after the configured max depth.""" + recursive_property: dict[str, object] = {"description": "Recursive schema"} + recursive_property["anyOf"] = [recursive_property] + schema = { + "type": "object", + "properties": { + "recursive_config": recursive_property, + }, + } + + result = ToolTransformService.convert_mcp_schema_to_parameter(schema) + + assert len(result) == 1 + assert result[0].name == "recursive_config" + assert result[0].type == ToolParameter.ToolParameterType.STRING + assert result[0].input_schema is None + def test_mcp_provider_to_user_provider_for_list(self, mock_provider_full): """Test mcp_provider_to_user_provider with for_list=True.""" # Set tools data with null description From 0a320c63a00be0ebcfb8b92efe8ee89ff5836671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9D=9E=E6=B3=95=E6=93=8D=E4=BD=9C?= Date: Wed, 11 Mar 2026 13:55:17 +0800 Subject: [PATCH 08/10] fix: vertically center key-value table headers in HTTP and Webhook (#33260) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .../components/key-value/key-value-edit/index.tsx | 8 ++++---- .../trigger-webhook/components/generic-table.tsx | 13 ++++++++----- web/eslint-suppressions.json | 6 ------ 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/web/app/components/workflow/nodes/http/components/key-value/key-value-edit/index.tsx b/web/app/components/workflow/nodes/http/components/key-value/key-value-edit/index.tsx index b1112a9b5b..55ccee4068 100644 --- a/web/app/components/workflow/nodes/http/components/key-value/key-value-edit/index.tsx +++ b/web/app/components/workflow/nodes/http/components/key-value/key-value-edit/index.tsx @@ -58,10 +58,10 @@ const KeyValueList: FC = ({ return (
-
-
{t(`${i18nPrefix}.key`, { ns: 'workflow' })}
- {isSupportFile &&
{t(`${i18nPrefix}.type`, { ns: 'workflow' })}
} -
{t(`${i18nPrefix}.value`, { ns: 'workflow' })}
+
+
{t(`${i18nPrefix}.key`, { ns: 'workflow' })}
+ {isSupportFile &&
{t(`${i18nPrefix}.type`, { ns: 'workflow' })}
} +
{t(`${i18nPrefix}.value`, { ns: 'workflow' })}
{ list.map((item, index) => ( diff --git a/web/app/components/workflow/nodes/trigger-webhook/components/generic-table.tsx b/web/app/components/workflow/nodes/trigger-webhook/components/generic-table.tsx index d85b622e10..0d31428bd2 100644 --- a/web/app/components/workflow/nodes/trigger-webhook/components/generic-table.tsx +++ b/web/app/components/workflow/nodes/trigger-webhook/components/generic-table.tsx @@ -96,7 +96,10 @@ const GenericTable: FC = ({ }) // If the last configured row has content, append a trailing empty row - const lastHasContent = !isEmptyRow(data[data.length - 1]) + const lastRow = data.at(-1) + if (!lastRow) + return rows + const lastHasContent = !isEmptyRow(lastRow) if (lastHasContent) rows.push({ row: { ...emptyRowData }, dataIndex: null, isVirtual: true }) @@ -163,7 +166,7 @@ const GenericTable: FC = ({ // Ghost/inline style: looks like plain text until focus/hover 'h-6 rounded-none border-0 bg-transparent px-0 py-0 shadow-none', 'hover:border-transparent hover:bg-transparent focus:border-transparent focus:bg-transparent', - 'system-sm-regular text-text-secondary placeholder:text-text-quaternary', + 'text-text-secondary system-sm-regular placeholder:text-text-quaternary', )} /> ) @@ -212,12 +215,12 @@ const GenericTable: FC = ({ return (
{showHeader && ( -
+
{columns.map((column, index) => (
= ({ return (
-

{title}

+

{title}

{showPlaceholder diff --git a/web/eslint-suppressions.json b/web/eslint-suppressions.json index abd403a6f6..40c8a43205 100644 --- a/web/eslint-suppressions.json +++ b/web/eslint-suppressions.json @@ -7490,9 +7490,6 @@ } }, "app/components/workflow/nodes/http/components/key-value/key-value-edit/index.tsx": { - "tailwindcss/enforce-consistent-class-order": { - "count": 1 - }, "ts/no-explicit-any": { "count": 2 } @@ -8522,9 +8519,6 @@ "app/components/workflow/nodes/trigger-webhook/components/generic-table.tsx": { "no-restricted-imports": { "count": 1 - }, - "tailwindcss/enforce-consistent-class-order": { - "count": 3 } }, "app/components/workflow/nodes/trigger-webhook/default.ts": { From a6e8e43883c5ff25c53cd6968c9e098e4f3f2a74 Mon Sep 17 00:00:00 2001 From: Saumya Talwani <68903741+saumyatalwani@users.noreply.github.com> Date: Wed, 11 Mar 2026 11:51:56 +0530 Subject: [PATCH 09/10] test: add tests for some files in services module (#32583) --- .../services/test_api_token_service.py | 466 ++++++++++++++++ .../services/test_app_model_config_service.py | 88 +++ .../services/test_async_workflow_service.py | 507 ++++++++++++++++++ .../services/test_attachment_service.py | 73 +++ .../test_code_based_extension_service.py | 89 +++ .../test_conversation_variable_updater.py | 75 +++ .../services/test_credit_pool_service.py | 157 ++++++ 7 files changed, 1455 insertions(+) create mode 100644 api/tests/unit_tests/services/test_api_token_service.py create mode 100644 api/tests/unit_tests/services/test_app_model_config_service.py create mode 100644 api/tests/unit_tests/services/test_async_workflow_service.py create mode 100644 api/tests/unit_tests/services/test_attachment_service.py create mode 100644 api/tests/unit_tests/services/test_code_based_extension_service.py create mode 100644 api/tests/unit_tests/services/test_conversation_variable_updater.py create mode 100644 api/tests/unit_tests/services/test_credit_pool_service.py diff --git a/api/tests/unit_tests/services/test_api_token_service.py b/api/tests/unit_tests/services/test_api_token_service.py new file mode 100644 index 0000000000..ad4de93b25 --- /dev/null +++ b/api/tests/unit_tests/services/test_api_token_service.py @@ -0,0 +1,466 @@ +from datetime import datetime +from types import SimpleNamespace +from unittest.mock import MagicMock, patch + +import pytest +from werkzeug.exceptions import Unauthorized + +import services.api_token_service as api_token_service_module +from services.api_token_service import ApiTokenCache, CachedApiToken + + +@pytest.fixture +def mock_db_session(): + """Fixture providing common DB session mocking for query_token_from_db tests.""" + fake_engine = MagicMock() + + session = MagicMock() + session_context = MagicMock() + session_context.__enter__.return_value = session + session_context.__exit__.return_value = None + + with ( + patch.object(api_token_service_module, "db", new=SimpleNamespace(engine=fake_engine)), + patch.object(api_token_service_module, "Session", return_value=session_context) as mock_session_class, + patch.object(api_token_service_module.ApiTokenCache, "set") as mock_cache_set, + patch.object(api_token_service_module, "record_token_usage") as mock_record_usage, + ): + yield { + "session": session, + "mock_session_class": mock_session_class, + "mock_cache_set": mock_cache_set, + "mock_record_usage": mock_record_usage, + "fake_engine": fake_engine, + } + + +class TestQueryTokenFromDb: + def test_should_return_api_token_and_cache_when_token_exists(self, mock_db_session): + """Test DB lookup success path caches token and records usage.""" + # Arrange + auth_token = "token-123" + scope = "app" + api_token = MagicMock() + + mock_db_session["session"].scalar.return_value = api_token + + # Act + result = api_token_service_module.query_token_from_db(auth_token, scope) + + # Assert + assert result == api_token + mock_db_session["mock_session_class"].assert_called_once_with( + mock_db_session["fake_engine"], expire_on_commit=False + ) + mock_db_session["mock_cache_set"].assert_called_once_with(auth_token, scope, api_token) + mock_db_session["mock_record_usage"].assert_called_once_with(auth_token, scope) + + def test_should_cache_null_and_raise_unauthorized_when_token_not_found(self, mock_db_session): + """Test DB lookup miss path caches null marker and raises Unauthorized.""" + # Arrange + auth_token = "missing-token" + scope = "app" + + mock_db_session["session"].scalar.return_value = None + + # Act / Assert + with pytest.raises(Unauthorized, match="Access token is invalid"): + api_token_service_module.query_token_from_db(auth_token, scope) + + mock_db_session["mock_cache_set"].assert_called_once_with(auth_token, scope, None) + mock_db_session["mock_record_usage"].assert_not_called() + + +class TestRecordTokenUsage: + def test_should_write_active_key_with_iso_timestamp_and_ttl(self): + """Test record_token_usage writes usage timestamp with one-hour TTL.""" + # Arrange + auth_token = "token-123" + scope = "dataset" + fixed_time = datetime(2026, 2, 24, 12, 0, 0) + expected_key = ApiTokenCache.make_active_key(auth_token, scope) + + with ( + patch.object(api_token_service_module, "naive_utc_now", return_value=fixed_time), + patch.object(api_token_service_module, "redis_client") as mock_redis, + ): + # Act + api_token_service_module.record_token_usage(auth_token, scope) + + # Assert + mock_redis.set.assert_called_once_with(expected_key, fixed_time.isoformat(), ex=3600) + + def test_should_not_raise_when_redis_write_fails(self): + """Test record_token_usage swallows Redis errors.""" + # Arrange + with patch.object(api_token_service_module, "redis_client") as mock_redis: + mock_redis.set.side_effect = Exception("redis unavailable") + + # Act / Assert + api_token_service_module.record_token_usage("token-123", "app") + + +class TestFetchTokenWithSingleFlight: + def test_should_return_cached_token_when_lock_acquired_and_cache_filled(self): + """Test single-flight returns cache when another request already populated it.""" + # Arrange + auth_token = "token-123" + scope = "app" + cached_token = CachedApiToken( + id="id-1", + app_id="app-1", + tenant_id="tenant-1", + type="app", + token=auth_token, + last_used_at=None, + created_at=None, + ) + + lock = MagicMock() + lock.acquire.return_value = True + + with ( + patch.object(api_token_service_module, "redis_client") as mock_redis, + patch.object(api_token_service_module.ApiTokenCache, "get", return_value=cached_token) as mock_cache_get, + patch.object(api_token_service_module, "query_token_from_db") as mock_query_db, + ): + mock_redis.lock.return_value = lock + + # Act + result = api_token_service_module.fetch_token_with_single_flight(auth_token, scope) + + # Assert + assert result == cached_token + mock_redis.lock.assert_called_once_with( + f"api_token_query_lock:{scope}:{auth_token}", + timeout=10, + blocking_timeout=5, + ) + lock.acquire.assert_called_once_with(blocking=True) + lock.release.assert_called_once() + mock_cache_get.assert_called_once_with(auth_token, scope) + mock_query_db.assert_not_called() + + def test_should_query_db_when_lock_acquired_and_cache_missed(self): + """Test single-flight queries DB when cache remains empty after lock acquisition.""" + # Arrange + auth_token = "token-123" + scope = "app" + db_token = MagicMock() + + lock = MagicMock() + lock.acquire.return_value = True + + with ( + patch.object(api_token_service_module, "redis_client") as mock_redis, + patch.object(api_token_service_module.ApiTokenCache, "get", return_value=None), + patch.object(api_token_service_module, "query_token_from_db", return_value=db_token) as mock_query_db, + ): + mock_redis.lock.return_value = lock + + # Act + result = api_token_service_module.fetch_token_with_single_flight(auth_token, scope) + + # Assert + assert result == db_token + mock_query_db.assert_called_once_with(auth_token, scope) + lock.release.assert_called_once() + + def test_should_query_db_directly_when_lock_not_acquired(self): + """Test lock timeout branch falls back to direct DB query.""" + # Arrange + auth_token = "token-123" + scope = "app" + db_token = MagicMock() + + lock = MagicMock() + lock.acquire.return_value = False + + with ( + patch.object(api_token_service_module, "redis_client") as mock_redis, + patch.object(api_token_service_module.ApiTokenCache, "get") as mock_cache_get, + patch.object(api_token_service_module, "query_token_from_db", return_value=db_token) as mock_query_db, + ): + mock_redis.lock.return_value = lock + + # Act + result = api_token_service_module.fetch_token_with_single_flight(auth_token, scope) + + # Assert + assert result == db_token + mock_cache_get.assert_not_called() + mock_query_db.assert_called_once_with(auth_token, scope) + lock.release.assert_not_called() + + def test_should_reraise_unauthorized_from_db_query(self): + """Test Unauthorized from DB query is propagated unchanged.""" + # Arrange + auth_token = "token-123" + scope = "app" + lock = MagicMock() + lock.acquire.return_value = True + + with ( + patch.object(api_token_service_module, "redis_client") as mock_redis, + patch.object(api_token_service_module.ApiTokenCache, "get", return_value=None), + patch.object( + api_token_service_module, + "query_token_from_db", + side_effect=Unauthorized("Access token is invalid"), + ), + ): + mock_redis.lock.return_value = lock + + # Act / Assert + with pytest.raises(Unauthorized, match="Access token is invalid"): + api_token_service_module.fetch_token_with_single_flight(auth_token, scope) + + lock.release.assert_called_once() + + def test_should_fallback_to_db_query_when_lock_raises_exception(self): + """Test Redis lock errors fall back to direct DB query.""" + # Arrange + auth_token = "token-123" + scope = "app" + db_token = MagicMock() + + lock = MagicMock() + lock.acquire.side_effect = RuntimeError("redis lock error") + + with ( + patch.object(api_token_service_module, "redis_client") as mock_redis, + patch.object(api_token_service_module, "query_token_from_db", return_value=db_token) as mock_query_db, + ): + mock_redis.lock.return_value = lock + + # Act + result = api_token_service_module.fetch_token_with_single_flight(auth_token, scope) + + # Assert + assert result == db_token + mock_query_db.assert_called_once_with(auth_token, scope) + + +class TestApiTokenCacheTenantBranches: + @patch("services.api_token_service.redis_client") + def test_delete_with_scope_should_remove_from_tenant_index_when_tenant_found(self, mock_redis): + """Test scoped delete removes cache key and tenant index membership.""" + # Arrange + token = "token-123" + scope = "app" + cache_key = ApiTokenCache._make_cache_key(token, scope) + cached_token = CachedApiToken( + id="id-1", + app_id="app-1", + tenant_id="tenant-1", + type="app", + token=token, + last_used_at=None, + created_at=None, + ) + mock_redis.get.return_value = cached_token.model_dump_json().encode("utf-8") + + with patch.object(ApiTokenCache, "_remove_from_tenant_index") as mock_remove_index: + # Act + result = ApiTokenCache.delete(token, scope) + + # Assert + assert result is True + mock_redis.delete.assert_called_once_with(cache_key) + mock_remove_index.assert_called_once_with("tenant-1", cache_key) + + @patch("services.api_token_service.redis_client") + def test_invalidate_by_tenant_should_delete_all_indexed_cache_keys(self, mock_redis): + """Test tenant invalidation deletes indexed cache entries and index key.""" + # Arrange + tenant_id = "tenant-1" + index_key = ApiTokenCache._make_tenant_index_key(tenant_id) + mock_redis.smembers.return_value = { + b"api_token:app:token-1", + b"api_token:any:token-2", + } + + # Act + result = ApiTokenCache.invalidate_by_tenant(tenant_id) + + # Assert + assert result is True + mock_redis.smembers.assert_called_once_with(index_key) + mock_redis.delete.assert_any_call("api_token:app:token-1") + mock_redis.delete.assert_any_call("api_token:any:token-2") + mock_redis.delete.assert_any_call(index_key) + + +class TestApiTokenCacheCoreBranches: + def test_cached_api_token_repr_should_include_id_and_type(self): + """Test CachedApiToken __repr__ includes key identity fields.""" + token = CachedApiToken( + id="id-123", + app_id="app-123", + tenant_id="tenant-123", + type="app", + token="token-123", + last_used_at=None, + created_at=None, + ) + + assert repr(token) == "" + + def test_serialize_token_should_handle_cached_api_token_instances(self): + """Test serialization path when input is already a CachedApiToken.""" + token = CachedApiToken( + id="id-123", + app_id="app-123", + tenant_id="tenant-123", + type="app", + token="token-123", + last_used_at=None, + created_at=None, + ) + + serialized = ApiTokenCache._serialize_token(token) + + assert isinstance(serialized, bytes) + assert b'"id":"id-123"' in serialized + assert b'"token":"token-123"' in serialized + + def test_deserialize_token_should_return_none_for_null_markers(self): + """Test null cache marker deserializes to None.""" + assert ApiTokenCache._deserialize_token("null") is None + assert ApiTokenCache._deserialize_token(b"null") is None + + def test_deserialize_token_should_return_none_for_invalid_payload(self): + """Test invalid serialized payload returns None.""" + assert ApiTokenCache._deserialize_token("not-json") is None + + @patch("services.api_token_service.redis_client") + def test_get_should_return_none_on_cache_miss(self, mock_redis): + """Test cache miss branch in ApiTokenCache.get.""" + mock_redis.get.return_value = None + + result = ApiTokenCache.get("token-123", "app") + + assert result is None + mock_redis.get.assert_called_once_with("api_token:app:token-123") + + @patch("services.api_token_service.redis_client") + def test_get_should_deserialize_cached_payload_on_cache_hit(self, mock_redis): + """Test cache hit branch in ApiTokenCache.get.""" + token = CachedApiToken( + id="id-123", + app_id="app-123", + tenant_id="tenant-123", + type="app", + token="token-123", + last_used_at=None, + created_at=None, + ) + mock_redis.get.return_value = token.model_dump_json().encode("utf-8") + + result = ApiTokenCache.get("token-123", "app") + + assert isinstance(result, CachedApiToken) + assert result.id == "id-123" + + @patch("services.api_token_service.redis_client") + def test_add_to_tenant_index_should_skip_when_tenant_id_missing(self, mock_redis): + """Test tenant index update exits early for missing tenant id.""" + ApiTokenCache._add_to_tenant_index(None, "api_token:app:token-123") + + mock_redis.sadd.assert_not_called() + mock_redis.expire.assert_not_called() + + @patch("services.api_token_service.redis_client") + def test_add_to_tenant_index_should_swallow_index_update_errors(self, mock_redis): + """Test tenant index update handles Redis write errors gracefully.""" + mock_redis.sadd.side_effect = Exception("redis down") + + ApiTokenCache._add_to_tenant_index("tenant-123", "api_token:app:token-123") + + mock_redis.sadd.assert_called_once() + + @patch("services.api_token_service.redis_client") + def test_remove_from_tenant_index_should_skip_when_tenant_id_missing(self, mock_redis): + """Test tenant index removal exits early for missing tenant id.""" + ApiTokenCache._remove_from_tenant_index(None, "api_token:app:token-123") + + mock_redis.srem.assert_not_called() + + @patch("services.api_token_service.redis_client") + def test_remove_from_tenant_index_should_swallow_redis_errors(self, mock_redis): + """Test tenant index removal handles Redis errors gracefully.""" + mock_redis.srem.side_effect = Exception("redis down") + + ApiTokenCache._remove_from_tenant_index("tenant-123", "api_token:app:token-123") + + mock_redis.srem.assert_called_once() + + @patch("services.api_token_service.redis_client") + def test_set_should_return_false_when_cache_write_raises_exception(self, mock_redis): + """Test set returns False when Redis setex fails.""" + mock_redis.setex.side_effect = Exception("redis write failed") + api_token = MagicMock() + api_token.id = "id-123" + api_token.app_id = "app-123" + api_token.tenant_id = "tenant-123" + api_token.type = "app" + api_token.token = "token-123" + api_token.last_used_at = None + api_token.created_at = None + + result = ApiTokenCache.set("token-123", "app", api_token) + + assert result is False + + @patch("services.api_token_service.redis_client") + def test_delete_without_scope_should_return_false_when_scan_fails(self, mock_redis): + """Test delete(scope=None) returns False when scan_iter raises.""" + mock_redis.scan_iter.side_effect = Exception("scan failed") + + result = ApiTokenCache.delete("token-123", None) + + assert result is False + + @patch("services.api_token_service.redis_client") + def test_delete_with_scope_should_continue_when_tenant_lookup_raises(self, mock_redis): + """Test scoped delete still succeeds when tenant lookup from cache fails.""" + token = "token-123" + scope = "app" + cache_key = ApiTokenCache._make_cache_key(token, scope) + mock_redis.get.side_effect = Exception("get failed") + + result = ApiTokenCache.delete(token, scope) + + assert result is True + mock_redis.delete.assert_called_once_with(cache_key) + + @patch("services.api_token_service.redis_client") + def test_delete_with_scope_should_return_false_when_delete_raises(self, mock_redis): + """Test scoped delete returns False when delete operation fails.""" + token = "token-123" + scope = "app" + mock_redis.get.return_value = None + mock_redis.delete.side_effect = Exception("delete failed") + + result = ApiTokenCache.delete(token, scope) + + assert result is False + + @patch("services.api_token_service.redis_client") + def test_invalidate_by_tenant_should_return_true_when_index_not_found(self, mock_redis): + """Test tenant invalidation returns True when tenant index is empty.""" + mock_redis.smembers.return_value = set() + + result = ApiTokenCache.invalidate_by_tenant("tenant-123") + + assert result is True + mock_redis.delete.assert_not_called() + + @patch("services.api_token_service.redis_client") + def test_invalidate_by_tenant_should_return_false_when_redis_raises(self, mock_redis): + """Test tenant invalidation returns False when Redis operation fails.""" + mock_redis.smembers.side_effect = Exception("redis failed") + + result = ApiTokenCache.invalidate_by_tenant("tenant-123") + + assert result is False diff --git a/api/tests/unit_tests/services/test_app_model_config_service.py b/api/tests/unit_tests/services/test_app_model_config_service.py new file mode 100644 index 0000000000..d4b4bf14a3 --- /dev/null +++ b/api/tests/unit_tests/services/test_app_model_config_service.py @@ -0,0 +1,88 @@ +from unittest.mock import patch + +import pytest + +from models.model import AppMode +from services.app_model_config_service import AppModelConfigService + + +@pytest.fixture +def mock_config_managers(): + """Fixture that patches all app config manager validate methods. + + Returns a dictionary containing the mocked config_validate methods for each manager. + """ + with ( + patch("services.app_model_config_service.ChatAppConfigManager.config_validate") as mock_chat_validate, + patch("services.app_model_config_service.AgentChatAppConfigManager.config_validate") as mock_agent_validate, + patch( + "services.app_model_config_service.CompletionAppConfigManager.config_validate" + ) as mock_completion_validate, + ): + mock_chat_validate.return_value = {"manager": "chat"} + mock_agent_validate.return_value = {"manager": "agent"} + mock_completion_validate.return_value = {"manager": "completion"} + + yield { + "chat": mock_chat_validate, + "agent": mock_agent_validate, + "completion": mock_completion_validate, + } + + +class TestAppModelConfigService: + @pytest.mark.parametrize( + ("app_mode", "selected_manager"), + [ + (AppMode.CHAT, "chat"), + (AppMode.AGENT_CHAT, "agent"), + (AppMode.COMPLETION, "completion"), + ], + ) + def test_should_route_validation_to_correct_manager_based_on_app_mode( + self, app_mode, selected_manager, mock_config_managers + ): + """Test configuration validation is delegated to the expected manager for each supported app mode.""" + tenant_id = "tenant-123" + config = {"temperature": 0.5} + + mock_chat_validate = mock_config_managers["chat"] + mock_agent_validate = mock_config_managers["agent"] + mock_completion_validate = mock_config_managers["completion"] + + result = AppModelConfigService.validate_configuration(tenant_id=tenant_id, config=config, app_mode=app_mode) + + assert result == {"manager": selected_manager} + + if selected_manager == "chat": + mock_chat_validate.assert_called_once_with(tenant_id, config) + mock_agent_validate.assert_not_called() + mock_completion_validate.assert_not_called() + elif selected_manager == "agent": + mock_agent_validate.assert_called_once_with(tenant_id, config) + mock_chat_validate.assert_not_called() + mock_completion_validate.assert_not_called() + else: + mock_completion_validate.assert_called_once_with(tenant_id, config) + mock_chat_validate.assert_not_called() + mock_agent_validate.assert_not_called() + + def test_should_raise_value_error_when_app_mode_is_not_supported(self, mock_config_managers): + """Test unsupported app modes raise ValueError with the invalid mode in the message.""" + tenant_id = "tenant-123" + config = {"temperature": 0.5} + + mock_chat_validate = mock_config_managers["chat"] + mock_agent_validate = mock_config_managers["agent"] + mock_completion_validate = mock_config_managers["completion"] + + with pytest.raises(ValueError, match=f"Invalid app mode: {AppMode.WORKFLOW}"): + AppModelConfigService.validate_configuration( + tenant_id=tenant_id, + config=config, + app_mode=AppMode.WORKFLOW, + ) + + mock_chat_validate.assert_not_called() + mock_agent_validate.assert_not_called() + mock_completion_validate.assert_not_called() diff --git a/api/tests/unit_tests/services/test_async_workflow_service.py b/api/tests/unit_tests/services/test_async_workflow_service.py new file mode 100644 index 0000000000..639e091041 --- /dev/null +++ b/api/tests/unit_tests/services/test_async_workflow_service.py @@ -0,0 +1,507 @@ +import json +from types import SimpleNamespace +from unittest.mock import MagicMock, patch + +import pytest + +import services.async_workflow_service as async_workflow_service_module +from models.enums import AppTriggerType, CreatorUserRole, WorkflowRunTriggeredFrom, WorkflowTriggerStatus +from services.async_workflow_service import AsyncWorkflowService +from services.errors.app import QuotaExceededError, WorkflowNotFoundError, WorkflowQuotaLimitError +from services.workflow.entities import AsyncTriggerResponse, TriggerData +from services.workflow.queue_dispatcher import QueuePriority + + +class AsyncWorkflowServiceTestDataFactory: + """Factory helpers for async workflow service unit tests.""" + + @staticmethod + def create_trigger_data( + app_id: str = "app-123", + tenant_id: str = "tenant-123", + workflow_id: str | None = "workflow-123", + root_node_id: str = "root-node-123", + ) -> TriggerData: + """Create valid trigger data for async workflow execution tests.""" + return TriggerData( + app_id=app_id, + tenant_id=tenant_id, + workflow_id=workflow_id, + root_node_id=root_node_id, + inputs={"name": "dify"}, + files=[], + trigger_type=AppTriggerType.UNKNOWN, + trigger_from=WorkflowRunTriggeredFrom.APP_RUN, + trigger_metadata=None, + ) + + @staticmethod + def create_trigger_log_with_data(trigger_data: TriggerData, retry_count: int = 0) -> MagicMock: + """Create a mock trigger log with serialized trigger data.""" + trigger_log = MagicMock() + trigger_log.id = "trigger-log-123" + trigger_log.trigger_data = trigger_data.model_dump_json() + trigger_log.retry_count = retry_count + trigger_log.error = "previous-error" + trigger_log.status = WorkflowTriggerStatus.FAILED + trigger_log.to_dict.return_value = {"id": trigger_log.id} + return trigger_log + + +class TestAsyncWorkflowService: + @pytest.fixture + def async_workflow_trigger_mocks(self): + """Shared fixture for async workflow trigger tests. + + Yields mocks for: + - repo: SQLAlchemyWorkflowTriggerLogRepository + - dispatcher_manager_class: QueueDispatcherManager class + - dispatcher: dispatcher instance + - quota_workflow: QuotaType.WORKFLOW + - get_workflow: AsyncWorkflowService._get_workflow method + - professional_task: execute_workflow_professional + - team_task: execute_workflow_team + - sandbox_task: execute_workflow_sandbox + """ + mock_repo = MagicMock() + + def _create_side_effect(new_log): + new_log.id = "trigger-log-123" + return new_log + + mock_repo.create.side_effect = _create_side_effect + + mock_dispatcher = MagicMock() + quota_workflow = MagicMock() + mock_get_workflow = MagicMock() + + mock_professional_task = MagicMock() + mock_team_task = MagicMock() + mock_sandbox_task = MagicMock() + + with ( + patch.object( + async_workflow_service_module, + "SQLAlchemyWorkflowTriggerLogRepository", + return_value=mock_repo, + ), + patch.object(async_workflow_service_module, "QueueDispatcherManager") as mock_dispatcher_manager_class, + patch.object(async_workflow_service_module, "WorkflowService"), + patch.object( + async_workflow_service_module.AsyncWorkflowService, + "_get_workflow", + ) as mock_get_workflow, + patch.object( + async_workflow_service_module, + "QuotaType", + new=SimpleNamespace(WORKFLOW=quota_workflow), + ), + patch.object(async_workflow_service_module, "execute_workflow_professional") as mock_professional_task, + patch.object(async_workflow_service_module, "execute_workflow_team") as mock_team_task, + patch.object(async_workflow_service_module, "execute_workflow_sandbox") as mock_sandbox_task, + ): + # Configure dispatcher_manager to return our mock_dispatcher + mock_dispatcher_manager_class.return_value.get_dispatcher.return_value = mock_dispatcher + + yield { + "repo": mock_repo, + "dispatcher_manager_class": mock_dispatcher_manager_class, + "dispatcher": mock_dispatcher, + "quota_workflow": quota_workflow, + "get_workflow": mock_get_workflow, + "professional_task": mock_professional_task, + "team_task": mock_team_task, + "sandbox_task": mock_sandbox_task, + } + + @pytest.mark.parametrize( + ("queue_name", "selected_task_attr"), + [ + (QueuePriority.PROFESSIONAL, "execute_workflow_professional"), + (QueuePriority.TEAM, "execute_workflow_team"), + (QueuePriority.SANDBOX, "execute_workflow_sandbox"), + ], + ) + def test_should_dispatch_to_matching_celery_task_when_triggering_workflow( + self, queue_name, selected_task_attr, async_workflow_trigger_mocks + ): + """Test queue-based task routing and successful async trigger response.""" + # Arrange + session = MagicMock() + session.commit = MagicMock() + app_model = MagicMock() + app_model.id = "app-123" + session.scalar.return_value = app_model + trigger_data = AsyncWorkflowServiceTestDataFactory.create_trigger_data() + workflow = MagicMock() + workflow.id = "workflow-123" + + mocks = async_workflow_trigger_mocks + mocks["dispatcher"].get_queue_name.return_value = queue_name + mocks["get_workflow"].return_value = workflow + + task_result = MagicMock() + task_result.id = "task-123" + mocks["professional_task"].delay.return_value = task_result + mocks["team_task"].delay.return_value = task_result + mocks["sandbox_task"].delay.return_value = task_result + + class DummyAccount: + def __init__(self, user_id: str): + self.id = user_id + + with patch.object(async_workflow_service_module, "Account", DummyAccount): + user = DummyAccount("account-123") + + # Act + result = AsyncWorkflowService.trigger_workflow_async(session=session, user=user, trigger_data=trigger_data) + + # Assert + assert isinstance(result, AsyncTriggerResponse) + assert result.workflow_trigger_log_id == "trigger-log-123" + assert result.task_id == "task-123" + assert result.status == "queued" + assert result.queue == queue_name + + mocks["quota_workflow"].consume.assert_called_once_with("tenant-123") + assert session.commit.call_count == 2 + + created_log = mocks["repo"].create.call_args[0][0] + assert created_log.status == WorkflowTriggerStatus.QUEUED + assert created_log.queue_name == queue_name + assert created_log.created_by_role == CreatorUserRole.ACCOUNT + assert created_log.created_by == "account-123" + assert created_log.trigger_data == trigger_data.model_dump_json() + assert created_log.inputs == json.dumps(dict(trigger_data.inputs)) + assert created_log.celery_task_id == "task-123" + + task_mocks = { + "execute_workflow_professional": mocks["professional_task"], + "execute_workflow_team": mocks["team_task"], + "execute_workflow_sandbox": mocks["sandbox_task"], + } + for task_attr, task_mock in task_mocks.items(): + if task_attr == selected_task_attr: + task_mock.delay.assert_called_once_with({"workflow_trigger_log_id": "trigger-log-123"}) + else: + task_mock.delay.assert_not_called() + + def test_should_set_end_user_role_when_triggered_by_end_user(self, async_workflow_trigger_mocks): + """Test that non-account users are tracked as END_USER in trigger logs.""" + # Arrange + session = MagicMock() + session.commit = MagicMock() + app_model = MagicMock() + app_model.id = "app-123" + session.scalar.return_value = app_model + trigger_data = AsyncWorkflowServiceTestDataFactory.create_trigger_data() + workflow = MagicMock() + workflow.id = "workflow-123" + + mocks = async_workflow_trigger_mocks + mocks["dispatcher"].get_queue_name.return_value = QueuePriority.SANDBOX + mocks["get_workflow"].return_value = workflow + + task_result = MagicMock(id="task-123") + mocks["sandbox_task"].delay.return_value = task_result + + user = SimpleNamespace(id="end-user-123") + + # Act + AsyncWorkflowService.trigger_workflow_async(session=session, user=user, trigger_data=trigger_data) + + # Assert + created_log = mocks["repo"].create.call_args[0][0] + assert created_log.created_by_role == CreatorUserRole.END_USER + assert created_log.created_by == "end-user-123" + + def test_should_raise_workflow_not_found_when_app_does_not_exist(self): + """Test trigger failure when app lookup returns no result.""" + # Arrange + session = MagicMock() + session.scalar.return_value = None + trigger_data = AsyncWorkflowServiceTestDataFactory.create_trigger_data(app_id="missing-app") + + with ( + patch.object(async_workflow_service_module, "SQLAlchemyWorkflowTriggerLogRepository"), + patch.object(async_workflow_service_module, "QueueDispatcherManager"), + patch.object(async_workflow_service_module, "WorkflowService"), + ): + # Act / Assert + with pytest.raises(WorkflowNotFoundError, match="App not found: missing-app"): + AsyncWorkflowService.trigger_workflow_async( + session=session, + user=SimpleNamespace(id="user-123"), + trigger_data=trigger_data, + ) + + def test_should_mark_log_rate_limited_and_raise_when_quota_exceeded(self, async_workflow_trigger_mocks): + """Test quota-exceeded path updates trigger log and raises WorkflowQuotaLimitError.""" + # Arrange + session = MagicMock() + session.commit = MagicMock() + app_model = MagicMock() + app_model.id = "app-123" + session.scalar.return_value = app_model + trigger_data = AsyncWorkflowServiceTestDataFactory.create_trigger_data() + workflow = MagicMock() + workflow.id = "workflow-123" + + mocks = async_workflow_trigger_mocks + mocks["dispatcher"].get_queue_name.return_value = QueuePriority.TEAM + mocks["get_workflow"].return_value = workflow + mocks["quota_workflow"].consume.side_effect = QuotaExceededError( + feature="workflow", + tenant_id="tenant-123", + required=1, + ) + + # Act / Assert + with pytest.raises( + WorkflowQuotaLimitError, + match="Workflow execution quota limit reached for tenant tenant-123", + ): + AsyncWorkflowService.trigger_workflow_async( + session=session, + user=SimpleNamespace(id="user-123"), + trigger_data=trigger_data, + ) + + assert session.commit.call_count == 2 + updated_log = mocks["repo"].update.call_args[0][0] + assert updated_log.status == WorkflowTriggerStatus.RATE_LIMITED + assert "Quota limit reached" in updated_log.error + mocks["professional_task"].delay.assert_not_called() + mocks["team_task"].delay.assert_not_called() + mocks["sandbox_task"].delay.assert_not_called() + + def test_should_raise_when_reinvoke_target_log_does_not_exist(self): + """Test reinvoke_trigger error path when original trigger log is missing.""" + # Arrange + session = MagicMock() + repo = MagicMock() + repo.get_by_id.return_value = None + + with patch.object(async_workflow_service_module, "SQLAlchemyWorkflowTriggerLogRepository", return_value=repo): + # Act / Assert + with pytest.raises(ValueError, match="Trigger log not found: missing-log"): + AsyncWorkflowService.reinvoke_trigger( + session=session, + user=SimpleNamespace(id="user-123"), + workflow_trigger_log_id="missing-log", + ) + + def test_should_update_original_log_and_requeue_when_reinvoking(self): + """Test reinvoke flow updates original log state and triggers a new async run.""" + # Arrange + session = MagicMock() + trigger_data = AsyncWorkflowServiceTestDataFactory.create_trigger_data() + trigger_log = AsyncWorkflowServiceTestDataFactory.create_trigger_log_with_data(trigger_data, retry_count=1) + repo = MagicMock() + repo.get_by_id.return_value = trigger_log + + expected_response = AsyncTriggerResponse( + workflow_trigger_log_id="new-trigger-log-456", + task_id="task-456", + status="queued", + queue=QueuePriority.TEAM, + ) + + with ( + patch.object(async_workflow_service_module, "SQLAlchemyWorkflowTriggerLogRepository", return_value=repo), + patch.object( + async_workflow_service_module.AsyncWorkflowService, + "trigger_workflow_async", + return_value=expected_response, + ) as mock_trigger_workflow_async, + ): + user = SimpleNamespace(id="user-123") + + # Act + response = AsyncWorkflowService.reinvoke_trigger( + session=session, + user=user, + workflow_trigger_log_id="trigger-log-123", + ) + + # Assert + assert response == expected_response + assert trigger_log.status == WorkflowTriggerStatus.RETRYING + assert trigger_log.retry_count == 2 + assert trigger_log.error is None + assert trigger_log.triggered_at is not None + repo.update.assert_called_once_with(trigger_log) + session.commit.assert_called_once() + called_trigger_data = mock_trigger_workflow_async.call_args[0][2] + assert isinstance(called_trigger_data, TriggerData) + assert called_trigger_data.app_id == "app-123" + + @pytest.mark.parametrize( + ("repo_result", "expected"), + [ + (None, None), + (MagicMock(), {"id": "trigger-log-123"}), + ], + ) + def test_should_return_trigger_log_dict_or_none(self, repo_result, expected): + """Test get_trigger_log returns serialized log data or None.""" + # Arrange + mock_session = MagicMock() + mock_repo = MagicMock() + fake_engine = MagicMock() + mock_repo.get_by_id.return_value = repo_result + if repo_result: + repo_result.to_dict.return_value = expected + + mock_session_context = MagicMock() + mock_session_context.__enter__.return_value = mock_session + mock_session_context.__exit__.return_value = None + + with ( + patch.object(async_workflow_service_module, "db", new=SimpleNamespace(engine=fake_engine)), + patch.object( + async_workflow_service_module, "Session", return_value=mock_session_context + ) as mock_session_class, + patch.object( + async_workflow_service_module, + "SQLAlchemyWorkflowTriggerLogRepository", + return_value=mock_repo, + ), + ): + # Act + result = AsyncWorkflowService.get_trigger_log("trigger-log-123", tenant_id="tenant-123") + + # Assert + assert result == expected + mock_session_class.assert_called_once_with(fake_engine) + mock_repo.get_by_id.assert_called_once_with("trigger-log-123", "tenant-123") + + def test_should_return_recent_logs_as_dict_list(self): + """Test get_recent_logs converts repository models into dictionaries.""" + # Arrange + mock_session = MagicMock() + mock_repo = MagicMock() + log1 = MagicMock() + log1.to_dict.return_value = {"id": "log-1"} + log2 = MagicMock() + log2.to_dict.return_value = {"id": "log-2"} + mock_repo.get_recent_logs.return_value = [log1, log2] + + mock_session_context = MagicMock() + mock_session_context.__enter__.return_value = mock_session + mock_session_context.__exit__.return_value = None + + with ( + patch.object(async_workflow_service_module, "db", new=SimpleNamespace(engine=MagicMock())), + patch.object(async_workflow_service_module, "Session", return_value=mock_session_context), + patch.object( + async_workflow_service_module, + "SQLAlchemyWorkflowTriggerLogRepository", + return_value=mock_repo, + ), + ): + # Act + result = AsyncWorkflowService.get_recent_logs( + tenant_id="tenant-123", + app_id="app-123", + hours=12, + limit=50, + offset=10, + ) + + # Assert + assert result == [{"id": "log-1"}, {"id": "log-2"}] + mock_repo.get_recent_logs.assert_called_once_with( + tenant_id="tenant-123", + app_id="app-123", + hours=12, + limit=50, + offset=10, + ) + + def test_should_return_failed_logs_for_retry_as_dict_list(self): + """Test get_failed_logs_for_retry serializes repository logs into dicts.""" + # Arrange + mock_session = MagicMock() + mock_repo = MagicMock() + log = MagicMock() + log.to_dict.return_value = {"id": "failed-log-1"} + mock_repo.get_failed_for_retry.return_value = [log] + + mock_session_context = MagicMock() + mock_session_context.__enter__.return_value = mock_session + mock_session_context.__exit__.return_value = None + + with ( + patch.object(async_workflow_service_module, "db", new=SimpleNamespace(engine=MagicMock())), + patch.object(async_workflow_service_module, "Session", return_value=mock_session_context), + patch.object( + async_workflow_service_module, + "SQLAlchemyWorkflowTriggerLogRepository", + return_value=mock_repo, + ), + ): + # Act + result = AsyncWorkflowService.get_failed_logs_for_retry(tenant_id="tenant-123", max_retry_count=4, limit=20) + + # Assert + assert result == [{"id": "failed-log-1"}] + mock_repo.get_failed_for_retry.assert_called_once_with(tenant_id="tenant-123", max_retry_count=4, limit=20) + + +class TestAsyncWorkflowServiceGetWorkflow: + def test_should_return_specific_workflow_when_workflow_id_exists(self): + """Test _get_workflow returns published workflow by id when provided.""" + # Arrange + workflow_service = MagicMock() + app_model = MagicMock() + workflow = MagicMock() + workflow_service.get_published_workflow_by_id.return_value = workflow + + # Act + result = AsyncWorkflowService._get_workflow(workflow_service, app_model, workflow_id="workflow-123") + + # Assert + assert result == workflow + workflow_service.get_published_workflow_by_id.assert_called_once_with(app_model, "workflow-123") + workflow_service.get_published_workflow.assert_not_called() + + def test_should_raise_when_specific_workflow_id_not_found(self): + """Test _get_workflow raises WorkflowNotFoundError for unknown workflow id.""" + # Arrange + workflow_service = MagicMock() + app_model = MagicMock() + workflow_service.get_published_workflow_by_id.return_value = None + + # Act / Assert + with pytest.raises(WorkflowNotFoundError, match="Published workflow not found: workflow-404"): + AsyncWorkflowService._get_workflow(workflow_service, app_model, workflow_id="workflow-404") + + def test_should_return_default_published_workflow_when_workflow_id_not_provided(self): + """Test _get_workflow returns default published workflow when no id is provided.""" + # Arrange + workflow_service = MagicMock() + app_model = MagicMock() + app_model.id = "app-123" + workflow = MagicMock() + workflow_service.get_published_workflow.return_value = workflow + + # Act + result = AsyncWorkflowService._get_workflow(workflow_service, app_model) + + # Assert + assert result == workflow + workflow_service.get_published_workflow.assert_called_once_with(app_model) + workflow_service.get_published_workflow_by_id.assert_not_called() + + def test_should_raise_when_default_published_workflow_not_found(self): + """Test _get_workflow raises WorkflowNotFoundError when app has no published workflow.""" + # Arrange + workflow_service = MagicMock() + app_model = MagicMock() + app_model.id = "app-123" + workflow_service.get_published_workflow.return_value = None + + # Act / Assert + with pytest.raises(WorkflowNotFoundError, match="No published workflow found for app: app-123"): + AsyncWorkflowService._get_workflow(workflow_service, app_model) diff --git a/api/tests/unit_tests/services/test_attachment_service.py b/api/tests/unit_tests/services/test_attachment_service.py new file mode 100644 index 0000000000..88be20bc41 --- /dev/null +++ b/api/tests/unit_tests/services/test_attachment_service.py @@ -0,0 +1,73 @@ +import base64 +from unittest.mock import MagicMock, patch + +import pytest +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from werkzeug.exceptions import NotFound + +import services.attachment_service as attachment_service_module +from models.model import UploadFile +from services.attachment_service import AttachmentService + + +class TestAttachmentService: + def test_should_initialize_with_sessionmaker_when_sessionmaker_is_provided(self): + """Test that AttachmentService keeps the provided sessionmaker instance.""" + session_factory = sessionmaker() + + service = AttachmentService(session_factory=session_factory) + + assert service._session_maker is session_factory + + def test_should_initialize_with_bound_sessionmaker_when_engine_is_provided(self): + """Test that AttachmentService builds a sessionmaker bound to the provided engine.""" + engine = create_engine("sqlite:///:memory:") + + service = AttachmentService(session_factory=engine) + session = service._session_maker() + try: + assert session.bind == engine + finally: + session.close() + engine.dispose() + + @pytest.mark.parametrize("invalid_session_factory", [None, "not-a-session-factory", 1]) + def test_should_raise_assertion_error_when_session_factory_type_is_invalid(self, invalid_session_factory): + """Test that invalid session_factory types are rejected.""" + with pytest.raises(AssertionError, match="must be a sessionmaker or an Engine."): + AttachmentService(session_factory=invalid_session_factory) + + def test_should_return_base64_encoded_blob_when_file_exists(self): + """Test that existing files are loaded from storage and returned as base64.""" + service = AttachmentService(session_factory=sessionmaker()) + upload_file = MagicMock(spec=UploadFile) + upload_file.key = "upload-file-key" + + session = MagicMock() + session.query.return_value.where.return_value.first.return_value = upload_file + service._session_maker = MagicMock(return_value=session) + + with patch.object(attachment_service_module.storage, "load_once", return_value=b"binary-content") as mock_load: + result = service.get_file_base64("file-123") + + assert result == base64.b64encode(b"binary-content").decode() + service._session_maker.assert_called_once_with(expire_on_commit=False) + session.query.assert_called_once_with(UploadFile) + mock_load.assert_called_once_with("upload-file-key") + + def test_should_raise_not_found_when_file_does_not_exist(self): + """Test that missing files raise NotFound and never call storage.""" + service = AttachmentService(session_factory=sessionmaker()) + + session = MagicMock() + session.query.return_value.where.return_value.first.return_value = None + service._session_maker = MagicMock(return_value=session) + + with patch.object(attachment_service_module.storage, "load_once") as mock_load: + with pytest.raises(NotFound, match="File not found"): + service.get_file_base64("missing-file") + + service._session_maker.assert_called_once_with(expire_on_commit=False) + session.query.assert_called_once_with(UploadFile) + mock_load.assert_not_called() diff --git a/api/tests/unit_tests/services/test_code_based_extension_service.py b/api/tests/unit_tests/services/test_code_based_extension_service.py new file mode 100644 index 0000000000..f6538a140a --- /dev/null +++ b/api/tests/unit_tests/services/test_code_based_extension_service.py @@ -0,0 +1,89 @@ +from types import SimpleNamespace +from unittest.mock import MagicMock + +import pytest + +from services.code_based_extension_service import CodeBasedExtensionService + + +class TestCodeBasedExtensionService: + def test_should_return_only_non_builtin_extensions_with_public_fields(self, monkeypatch: pytest.MonkeyPatch): + """Test service returns only non-builtin extensions with name/label/form_schema fields.""" + moderation_extension = SimpleNamespace( + name="custom-moderation", + label={"en-US": "Custom Moderation"}, + form_schema=[{"variable": "api_key"}], + builtin=False, + extension_class=object, + position=20, + ) + builtin_extension = SimpleNamespace( + name="builtin-moderation", + label={"en-US": "Builtin Moderation"}, + form_schema=[{"variable": "token"}], + builtin=True, + extension_class=object, + position=1, + ) + retrieval_extension = SimpleNamespace( + name="custom-retrieval", + label={"en-US": "Custom Retrieval"}, + form_schema=None, + builtin=False, + extension_class=object, + position=30, + ) + module_extensions_mock = MagicMock(return_value=[moderation_extension, builtin_extension, retrieval_extension]) + monkeypatch.setattr( + "services.code_based_extension_service.code_based_extension.module_extensions", + module_extensions_mock, + ) + + result = CodeBasedExtensionService.get_code_based_extension("external_data_tool") + + assert result == [ + { + "name": "custom-moderation", + "label": {"en-US": "Custom Moderation"}, + "form_schema": [{"variable": "api_key"}], + }, + { + "name": "custom-retrieval", + "label": {"en-US": "Custom Retrieval"}, + "form_schema": None, + }, + ] + assert set(result[0].keys()) == {"name", "label", "form_schema"} + module_extensions_mock.assert_called_once_with("external_data_tool") + + def test_should_return_empty_list_when_all_extensions_are_builtin(self, monkeypatch: pytest.MonkeyPatch): + """Test builtin extensions are filtered out completely.""" + builtin_extension = SimpleNamespace( + name="builtin-moderation", + label={"en-US": "Builtin Moderation"}, + form_schema=[{"variable": "token"}], + builtin=True, + ) + module_extensions_mock = MagicMock(return_value=[builtin_extension]) + monkeypatch.setattr( + "services.code_based_extension_service.code_based_extension.module_extensions", + module_extensions_mock, + ) + + result = CodeBasedExtensionService.get_code_based_extension("moderation") + + assert result == [] + module_extensions_mock.assert_called_once_with("moderation") + + def test_should_propagate_error_when_module_extensions_lookup_fails(self, monkeypatch: pytest.MonkeyPatch): + """Test ValueError from extension lookup bubbles up unchanged.""" + module_extensions_mock = MagicMock(side_effect=ValueError("Extension Module invalid-module not found")) + monkeypatch.setattr( + "services.code_based_extension_service.code_based_extension.module_extensions", + module_extensions_mock, + ) + + with pytest.raises(ValueError, match="Extension Module invalid-module not found"): + CodeBasedExtensionService.get_code_based_extension("invalid-module") + + module_extensions_mock.assert_called_once_with("invalid-module") diff --git a/api/tests/unit_tests/services/test_conversation_variable_updater.py b/api/tests/unit_tests/services/test_conversation_variable_updater.py new file mode 100644 index 0000000000..157424a2a7 --- /dev/null +++ b/api/tests/unit_tests/services/test_conversation_variable_updater.py @@ -0,0 +1,75 @@ +from types import SimpleNamespace +from unittest.mock import MagicMock + +import pytest + +from core.variables.variables import StringVariable +from services.conversation_variable_updater import ConversationVariableNotFoundError, ConversationVariableUpdater + + +class TestConversationVariableUpdater: + def test_should_update_conversation_variable_data_and_commit(self): + """Test update persists serialized variable data when the row exists.""" + conversation_id = "conv-123" + variable = StringVariable( + id="var-123", + name="topic", + value="new value", + ) + expected_json = variable.model_dump_json() + + row = SimpleNamespace(data="old value") + session = MagicMock() + session.scalar.return_value = row + + session_context = MagicMock() + session_context.__enter__.return_value = session + session_context.__exit__.return_value = None + + session_maker = MagicMock(return_value=session_context) + updater = ConversationVariableUpdater(session_maker) + + updater.update(conversation_id=conversation_id, variable=variable) + + session_maker.assert_called_once_with() + session.scalar.assert_called_once() + stmt = session.scalar.call_args.args[0] + compiled_params = stmt.compile().params + assert variable.id in compiled_params.values() + assert conversation_id in compiled_params.values() + assert row.data == expected_json + session.commit.assert_called_once() + + def test_should_raise_not_found_error_when_conversation_variable_missing(self): + """Test update raises ConversationVariableNotFoundError when no matching row exists.""" + conversation_id = "conv-404" + variable = StringVariable( + id="var-404", + name="topic", + value="value", + ) + + session = MagicMock() + session.scalar.return_value = None + + session_context = MagicMock() + session_context.__enter__.return_value = session + session_context.__exit__.return_value = None + + session_maker = MagicMock(return_value=session_context) + updater = ConversationVariableUpdater(session_maker) + + with pytest.raises(ConversationVariableNotFoundError, match="conversation variable not found in the database"): + updater.update(conversation_id=conversation_id, variable=variable) + + session.commit.assert_not_called() + + def test_should_do_nothing_when_flush_is_called(self): + """Test flush currently behaves as a no-op and returns None.""" + session_maker = MagicMock() + updater = ConversationVariableUpdater(session_maker) + + result = updater.flush() + + assert result is None + session_maker.assert_not_called() diff --git a/api/tests/unit_tests/services/test_credit_pool_service.py b/api/tests/unit_tests/services/test_credit_pool_service.py new file mode 100644 index 0000000000..9ef314cb9e --- /dev/null +++ b/api/tests/unit_tests/services/test_credit_pool_service.py @@ -0,0 +1,157 @@ +from types import SimpleNamespace +from unittest.mock import MagicMock, patch + +import pytest + +import services.credit_pool_service as credit_pool_service_module +from core.errors.error import QuotaExceededError +from models import TenantCreditPool +from services.credit_pool_service import CreditPoolService + + +@pytest.fixture +def mock_credit_deduction_setup(): + """Fixture providing common setup for credit deduction tests.""" + pool = SimpleNamespace(remaining_credits=50) + fake_engine = MagicMock() + session = MagicMock() + session_context = MagicMock() + session_context.__enter__.return_value = session + session_context.__exit__.return_value = None + + mock_get_pool = patch.object(CreditPoolService, "get_pool", return_value=pool) + mock_db = patch.object(credit_pool_service_module, "db", new=SimpleNamespace(engine=fake_engine)) + mock_session = patch.object(credit_pool_service_module, "Session", return_value=session_context) + + return { + "pool": pool, + "fake_engine": fake_engine, + "session": session, + "session_context": session_context, + "patches": (mock_get_pool, mock_db, mock_session), + } + + +class TestCreditPoolService: + def test_should_create_default_pool_with_trial_type_and_configured_quota(self): + """Test create_default_pool persists a trial pool using configured hosted credits.""" + tenant_id = "tenant-123" + hosted_pool_credits = 5000 + + with ( + patch.object(credit_pool_service_module.dify_config, "HOSTED_POOL_CREDITS", hosted_pool_credits), + patch.object(credit_pool_service_module, "db") as mock_db, + ): + pool = CreditPoolService.create_default_pool(tenant_id) + + assert isinstance(pool, TenantCreditPool) + assert pool.tenant_id == tenant_id + assert pool.pool_type == "trial" + assert pool.quota_limit == hosted_pool_credits + assert pool.quota_used == 0 + mock_db.session.add.assert_called_once_with(pool) + mock_db.session.commit.assert_called_once() + + def test_should_return_first_pool_from_query_when_get_pool_called(self): + """Test get_pool queries by tenant and pool_type and returns first result.""" + tenant_id = "tenant-123" + pool_type = "enterprise" + expected_pool = MagicMock(spec=TenantCreditPool) + + with patch.object(credit_pool_service_module, "db") as mock_db: + query = mock_db.session.query.return_value + filtered_query = query.filter_by.return_value + filtered_query.first.return_value = expected_pool + + result = CreditPoolService.get_pool(tenant_id=tenant_id, pool_type=pool_type) + + assert result == expected_pool + mock_db.session.query.assert_called_once_with(TenantCreditPool) + query.filter_by.assert_called_once_with(tenant_id=tenant_id, pool_type=pool_type) + filtered_query.first.assert_called_once() + + def test_should_return_false_when_pool_not_found_in_check_credits_available(self): + """Test check_credits_available returns False when tenant has no pool.""" + with patch.object(CreditPoolService, "get_pool", return_value=None) as mock_get_pool: + result = CreditPoolService.check_credits_available(tenant_id="tenant-123", credits_required=10) + + assert result is False + mock_get_pool.assert_called_once_with("tenant-123", "trial") + + def test_should_return_true_when_remaining_credits_cover_required_amount(self): + """Test check_credits_available returns True when remaining credits are sufficient.""" + pool = SimpleNamespace(remaining_credits=100) + + with patch.object(CreditPoolService, "get_pool", return_value=pool) as mock_get_pool: + result = CreditPoolService.check_credits_available(tenant_id="tenant-123", credits_required=60) + + assert result is True + mock_get_pool.assert_called_once_with("tenant-123", "trial") + + def test_should_return_false_when_remaining_credits_are_insufficient(self): + """Test check_credits_available returns False when required credits exceed remaining credits.""" + pool = SimpleNamespace(remaining_credits=30) + + with patch.object(CreditPoolService, "get_pool", return_value=pool): + result = CreditPoolService.check_credits_available(tenant_id="tenant-123", credits_required=60) + + assert result is False + + def test_should_raise_quota_exceeded_when_pool_not_found_in_check_and_deduct(self): + """Test check_and_deduct_credits raises when tenant credit pool does not exist.""" + with patch.object(CreditPoolService, "get_pool", return_value=None): + with pytest.raises(QuotaExceededError, match="Credit pool not found"): + CreditPoolService.check_and_deduct_credits(tenant_id="tenant-123", credits_required=10) + + def test_should_raise_quota_exceeded_when_pool_has_no_remaining_credits(self): + """Test check_and_deduct_credits raises when remaining credits are zero or negative.""" + pool = SimpleNamespace(remaining_credits=0) + + with patch.object(CreditPoolService, "get_pool", return_value=pool): + with pytest.raises(QuotaExceededError, match="No credits remaining"): + CreditPoolService.check_and_deduct_credits(tenant_id="tenant-123", credits_required=10) + + def test_should_deduct_minimum_of_required_and_remaining_credits(self, mock_credit_deduction_setup): + """Test check_and_deduct_credits updates quota_used by the actual deducted amount.""" + tenant_id = "tenant-123" + pool_type = "trial" + credits_required = 200 + remaining_credits = 120 + expected_deducted_credits = 120 + + mock_credit_deduction_setup["pool"].remaining_credits = remaining_credits + patches = mock_credit_deduction_setup["patches"] + session = mock_credit_deduction_setup["session"] + + with patches[0], patches[1], patches[2]: + result = CreditPoolService.check_and_deduct_credits( + tenant_id=tenant_id, + credits_required=credits_required, + pool_type=pool_type, + ) + + assert result == expected_deducted_credits + session.execute.assert_called_once() + session.commit.assert_called_once() + + stmt = session.execute.call_args.args[0] + compiled_params = stmt.compile().params + assert tenant_id in compiled_params.values() + assert pool_type in compiled_params.values() + assert expected_deducted_credits in compiled_params.values() + + def test_should_raise_quota_exceeded_when_deduction_update_fails(self, mock_credit_deduction_setup): + """Test check_and_deduct_credits translates DB update failures to QuotaExceededError.""" + mock_credit_deduction_setup["pool"].remaining_credits = 50 + mock_credit_deduction_setup["session"].execute.side_effect = Exception("db failure") + session = mock_credit_deduction_setup["session"] + + patches = mock_credit_deduction_setup["patches"] + mock_logger = patch.object(credit_pool_service_module, "logger") + + with patches[0], patches[1], patches[2], mock_logger as mock_logger_obj: + with pytest.raises(QuotaExceededError, match="Failed to deduct credits"): + CreditPoolService.check_and_deduct_credits(tenant_id="tenant-123", credits_required=10) + + session.commit.assert_not_called() + mock_logger_obj.exception.assert_called_once() From 5d0c3d58ace3bdeddb434b013498f1088739a5bf Mon Sep 17 00:00:00 2001 From: yyh <92089059+lyzno1@users.noreply.github.com> Date: Wed, 11 Mar 2026 14:26:04 +0800 Subject: [PATCH 10/10] refactor(avatar): migrate to Base UI primitives with Record size variants (#33268) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .../account-page/AvatarWithEdit.tsx | 4 +- .../(commonLayout)/account-page/index.tsx | 13 +- web/app/account/(commonLayout)/avatar.tsx | 16 +- web/app/account/oauth/authorize/page.tsx | 10 +- .../add-member-or-group-pop.tsx | 4 +- .../specific-groups-or-members.tsx | 4 +- .../chat-item.spec.tsx | 2 +- .../debug-with-multiple-model/chat-item.tsx | 4 +- .../debug/debug-with-single-model/index.tsx | 4 +- .../base/avatar/__tests__/index.spec.tsx | 318 ++++-------------- .../components/base/avatar/index.stories.tsx | 36 +- web/app/components/base/avatar/index.tsx | 86 ++--- .../chat/chat-with-history/chat-wrapper.tsx | 4 +- .../chat/embedded-chatbot/chat-wrapper.tsx | 4 +- .../settings/permission-selector/index.tsx | 16 +- .../header/account-dropdown/index.tsx | 6 +- .../account-setting/members-page/index.tsx | 4 +- .../member-selector.tsx | 6 +- .../delivery-method/recipient/email-item.tsx | 4 +- .../delivery-method/recipient/member-list.tsx | 4 +- web/app/education-apply/user-info.tsx | 4 +- web/eslint-suppressions.json | 5 - web/eslint.config.mjs | 2 +- 23 files changed, 185 insertions(+), 375 deletions(-) diff --git a/web/app/account/(commonLayout)/account-page/AvatarWithEdit.tsx b/web/app/account/(commonLayout)/account-page/AvatarWithEdit.tsx index 0a17822187..9bd32d2576 100644 --- a/web/app/account/(commonLayout)/account-page/AvatarWithEdit.tsx +++ b/web/app/account/(commonLayout)/account-page/AvatarWithEdit.tsx @@ -11,7 +11,7 @@ import { useTranslation } from 'react-i18next' import { useContext } from 'use-context-selector' import ImageInput from '@/app/components/base/app-icon-picker/ImageInput' import getCroppedImg from '@/app/components/base/app-icon-picker/utils' -import Avatar from '@/app/components/base/avatar' +import { Avatar } from '@/app/components/base/avatar' import Button from '@/app/components/base/button' import Divider from '@/app/components/base/divider' import { useLocalFileUploader } from '@/app/components/base/image-uploader/hooks' @@ -103,7 +103,7 @@ const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => { <>
- setOnAvatarError(x)} /> + setOnAvatarError(status === 'error')} />
{ diff --git a/web/app/account/(commonLayout)/account-page/index.tsx b/web/app/account/(commonLayout)/account-page/index.tsx index 908ef9c2e8..58331e3a77 100644 --- a/web/app/account/(commonLayout)/account-page/index.tsx +++ b/web/app/account/(commonLayout)/account-page/index.tsx @@ -4,6 +4,7 @@ import type { App } from '@/types/app' import { RiGraduationCapFill, } from '@remixicon/react' +import { useQueryClient } from '@tanstack/react-query' import { useState } from 'react' import { useTranslation } from 'react-i18next' import { useContext } from 'use-context-selector' @@ -15,11 +16,11 @@ import PremiumBadge from '@/app/components/base/premium-badge' import { ToastContext } from '@/app/components/base/toast/context' import Collapse from '@/app/components/header/account-setting/collapse' import { IS_CE_EDITION, validPassword } from '@/config' -import { useAppContext } from '@/context/app-context' import { useGlobalPublicStore } from '@/context/global-public-context' import { useProviderContext } from '@/context/provider-context' import { updateUserProfile } from '@/service/common' import { useAppList } from '@/service/use-apps' +import { commonQueryKeys, useUserProfile } from '@/service/use-common' import DeleteAccount from '../delete-account' import AvatarWithEdit from './AvatarWithEdit' @@ -37,7 +38,10 @@ export default function AccountPage() { const { systemFeatures } = useGlobalPublicStore() const { data: appList } = useAppList({ page: 1, limit: 100, name: '' }) const apps = appList?.data || [] - const { mutateUserProfile, userProfile } = useAppContext() + const queryClient = useQueryClient() + const { data: userProfileResp } = useUserProfile() + const userProfile = userProfileResp?.profile + const mutateUserProfile = () => queryClient.invalidateQueries({ queryKey: commonQueryKeys.userProfile }) const { isEducationAccount } = useProviderContext() const { notify } = useContext(ToastContext) const [editNameModalVisible, setEditNameModalVisible] = useState(false) @@ -53,6 +57,9 @@ export default function AccountPage() { const [showConfirmPassword, setShowConfirmPassword] = useState(false) const [showUpdateEmail, setShowUpdateEmail] = useState(false) + if (!userProfile) + return null + const handleEditName = () => { setEditNameModalVisible(true) setEditName(userProfile.name) @@ -149,7 +156,7 @@ export default function AccountPage() {

{t('account.myAccount', { ns: 'common' })}

- +

{userProfile.name} diff --git a/web/app/account/(commonLayout)/avatar.tsx b/web/app/account/(commonLayout)/avatar.tsx index 8ea29e8e45..07b685b8c5 100644 --- a/web/app/account/(commonLayout)/avatar.tsx +++ b/web/app/account/(commonLayout)/avatar.tsx @@ -7,12 +7,11 @@ import { useRouter } from 'next/navigation' import { Fragment } from 'react' import { useTranslation } from 'react-i18next' import { resetUser } from '@/app/components/base/amplitude/utils' -import Avatar from '@/app/components/base/avatar' +import { Avatar } from '@/app/components/base/avatar' import { LogOut01 } from '@/app/components/base/icons/src/vender/line/general' import PremiumBadge from '@/app/components/base/premium-badge' -import { useAppContext } from '@/context/app-context' import { useProviderContext } from '@/context/provider-context' -import { useLogout } from '@/service/use-common' +import { useLogout, useUserProfile } from '@/service/use-common' export type IAppSelector = { isMobile: boolean @@ -21,10 +20,15 @@ export type IAppSelector = { export default function AppSelector() { const router = useRouter() const { t } = useTranslation() - const { userProfile } = useAppContext() + const { data: userProfileResp } = useUserProfile() + const userProfile = userProfileResp?.profile const { isEducationAccount } = useProviderContext() const { mutateAsync: logout } = useLogout() + + if (!userProfile) + return null + const handleLogout = async () => { await logout() @@ -50,7 +54,7 @@ export default function AppSelector() { ${open && 'bg-components-panel-bg-blur'} `} > - +

{userProfile.email}
- +
diff --git a/web/app/account/oauth/authorize/page.tsx b/web/app/account/oauth/authorize/page.tsx index d718e0941d..835a1e702e 100644 --- a/web/app/account/oauth/authorize/page.tsx +++ b/web/app/account/oauth/authorize/page.tsx @@ -11,14 +11,13 @@ import { useRouter, useSearchParams } from 'next/navigation' import * as React from 'react' import { useEffect, useRef } from 'react' import { useTranslation } from 'react-i18next' -import Avatar from '@/app/components/base/avatar' +import { Avatar } from '@/app/components/base/avatar' import Button from '@/app/components/base/button' import Loading from '@/app/components/base/loading' import Toast from '@/app/components/base/toast' import { useLanguage } from '@/app/components/header/account-setting/model-provider-page/hooks' import { setPostLoginRedirect } from '@/app/signin/utils/post-login-redirect' -import { useAppContext } from '@/context/app-context' -import { useIsLogin } from '@/service/use-common' +import { useIsLogin, useUserProfile } from '@/service/use-common' import { useAuthorizeOAuthApp, useOAuthAppInfo } from '@/service/use-oauth' function buildReturnUrl(pathname: string, search: string) { @@ -62,7 +61,8 @@ export default function OAuthAuthorize() { const searchParams = useSearchParams() const client_id = decodeURIComponent(searchParams.get('client_id') || '') const redirect_uri = decodeURIComponent(searchParams.get('redirect_uri') || '') - const { userProfile } = useAppContext() + const { data: userProfileResp } = useUserProfile() + const userProfile = userProfileResp?.profile const { data: authAppInfo, isLoading: isOAuthLoading, isError } = useOAuthAppInfo(client_id, redirect_uri) const { mutateAsync: authorize, isPending: authorizing } = useAuthorizeOAuthApp() const hasNotifiedRef = useRef(false) @@ -138,7 +138,7 @@ export default function OAuthAuthorize() { {isLoggedIn && userProfile && (
- +
{userProfile.name}
{userProfile.email}
diff --git a/web/app/components/app/app-access-control/add-member-or-group-pop.tsx b/web/app/components/app/app-access-control/add-member-or-group-pop.tsx index 5c803a91f0..90cbac13a4 100644 --- a/web/app/components/app/app-access-control/add-member-or-group-pop.tsx +++ b/web/app/components/app/app-access-control/add-member-or-group-pop.tsx @@ -10,7 +10,7 @@ import { SubjectType } from '@/models/access-control' import { useSearchForWhiteListCandidates } from '@/service/access-control' import { cn } from '@/utils/classnames' import useAccessControlStore from '../../../../context/access-control-store' -import Avatar from '../../base/avatar' +import { Avatar } from '../../base/avatar' import Button from '../../base/button' import Checkbox from '../../base/checkbox' import Input from '../../base/input' @@ -203,7 +203,7 @@ function MemberItem({ member }: MemberItemProps) {
- +

{member.name}

diff --git a/web/app/components/app/app-access-control/specific-groups-or-members.tsx b/web/app/components/app/app-access-control/specific-groups-or-members.tsx index 8ca817c872..2c0e4b2694 100644 --- a/web/app/components/app/app-access-control/specific-groups-or-members.tsx +++ b/web/app/components/app/app-access-control/specific-groups-or-members.tsx @@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next' import { AccessMode } from '@/models/access-control' import { useAppWhiteListSubjects } from '@/service/access-control' import useAccessControlStore from '../../../../context/access-control-store' -import Avatar from '../../base/avatar' +import { Avatar } from '../../base/avatar' import Loading from '../../base/loading' import Tooltip from '../../base/tooltip' import AddMemberOrGroupDialog from './add-member-or-group-pop' @@ -106,7 +106,7 @@ function MemberItem({ member }: MemberItemProps) { }, [member, setSpecificMembers, specificMembers]) return ( } + icon={} onRemove={handleRemoveMember} >

{member.name}

diff --git a/web/app/components/app/configuration/debug/debug-with-multiple-model/chat-item.spec.tsx b/web/app/components/app/configuration/debug/debug-with-multiple-model/chat-item.spec.tsx index d621bb3941..350ede8c96 100644 --- a/web/app/components/app/configuration/debug/debug-with-multiple-model/chat-item.spec.tsx +++ b/web/app/components/app/configuration/debug/debug-with-multiple-model/chat-item.spec.tsx @@ -91,7 +91,7 @@ vi.mock('@/app/components/base/chat/chat', () => ({ })) vi.mock('@/app/components/base/avatar', () => ({ - default: ({ name }: { name: string }) =>
{name}
, + Avatar: ({ name }: { name: string }) =>
{name}
, })) const createModelAndParameter = (overrides: Partial = {}): ModelAndParameter => ({ diff --git a/web/app/components/app/configuration/debug/debug-with-multiple-model/chat-item.tsx b/web/app/components/app/configuration/debug/debug-with-multiple-model/chat-item.tsx index b7a7e90fca..e957fc24c4 100644 --- a/web/app/components/app/configuration/debug/debug-with-multiple-model/chat-item.tsx +++ b/web/app/components/app/configuration/debug/debug-with-multiple-model/chat-item.tsx @@ -7,7 +7,7 @@ import { useCallback, useMemo, } from 'react' -import Avatar from '@/app/components/base/avatar' +import { Avatar } from '@/app/components/base/avatar' import Chat from '@/app/components/base/chat/chat' import { useChat } from '@/app/components/base/chat/chat/hooks' import { getLastAnswer } from '@/app/components/base/chat/utils' @@ -149,7 +149,7 @@ const ChatItem: FC = ({ suggestedQuestions={suggestedQuestions} onSend={doSend} showPromptLog - questionIcon={} + questionIcon={} allToolIcons={allToolIcons} hideLogModal noSpacing diff --git a/web/app/components/app/configuration/debug/debug-with-single-model/index.tsx b/web/app/components/app/configuration/debug/debug-with-single-model/index.tsx index addeb92297..84ff8b5ede 100644 --- a/web/app/components/app/configuration/debug/debug-with-single-model/index.tsx +++ b/web/app/components/app/configuration/debug/debug-with-single-model/index.tsx @@ -3,7 +3,7 @@ import type { ChatConfig, ChatItem, OnSend } from '@/app/components/base/chat/ty import type { FileEntity } from '@/app/components/base/file-uploader/types' import { memo, useCallback, useImperativeHandle, useMemo } from 'react' import { useStore as useAppStore } from '@/app/components/app/store' -import Avatar from '@/app/components/base/avatar' +import { Avatar } from '@/app/components/base/avatar' import Chat from '@/app/components/base/chat/chat' import { useChat } from '@/app/components/base/chat/chat/hooks' import { getLastAnswer, isValidGeneratedAnswer } from '@/app/components/base/chat/utils' @@ -168,7 +168,7 @@ const DebugWithSingleModel = ( switchSibling={siblingMessageId => setTargetMessageId(siblingMessageId)} onStopResponding={handleStop} showPromptLog - questionIcon={} + questionIcon={} allToolIcons={allToolIcons} onAnnotationEdited={handleAnnotationEdited} onAnnotationAdded={handleAnnotationAdded} diff --git a/web/app/components/base/avatar/__tests__/index.spec.tsx b/web/app/components/base/avatar/__tests__/index.spec.tsx index 5fad1d0a90..f7fae7105d 100644 --- a/web/app/components/base/avatar/__tests__/index.spec.tsx +++ b/web/app/components/base/avatar/__tests__/index.spec.tsx @@ -1,308 +1,114 @@ -import { fireEvent, render, screen, waitFor } from '@testing-library/react' -import Avatar from '../index' +import { render, screen } from '@testing-library/react' +import { Avatar } from '../index' describe('Avatar', () => { - beforeEach(() => { - vi.clearAllMocks() - }) - - // Rendering tests - verify component renders correctly in different states describe('Rendering', () => { - it('should render img element with correct alt and src when avatar URL is provided', () => { - const avatarUrl = 'https://example.com/avatar.jpg' - const props = { name: 'John Doe', avatar: avatarUrl } - - render() + it('should render img element when avatar URL is provided', () => { + render() const img = screen.getByRole('img', { name: 'John Doe' }) expect(img).toBeInTheDocument() - expect(img).toHaveAttribute('src', avatarUrl) + expect(img).toHaveAttribute('src', 'https://example.com/avatar.jpg') }) - it('should render fallback div with uppercase initial when avatar is null', () => { - const props = { name: 'alice', avatar: null } - - render() + it('should render fallback with uppercase initial when avatar is null', () => { + render() expect(screen.queryByRole('img')).not.toBeInTheDocument() expect(screen.getByText('A')).toBeInTheDocument() }) - }) - // Props tests - verify all props are applied correctly - describe('Props', () => { - describe('size prop', () => { - it.each([ - { size: undefined, expected: '30px', label: 'default (30px)' }, - { size: 50, expected: '50px', label: 'custom (50px)' }, - ])('should apply $label size to img element', ({ size, expected }) => { - const props = { name: 'Test', avatar: 'https://example.com/avatar.jpg', size } + it('should render both image and fallback when avatar is provided', () => { + render() - render() - - expect(screen.getByRole('img')).toHaveStyle({ - width: expected, - height: expected, - fontSize: expected, - lineHeight: expected, - }) - }) - - it('should apply size to fallback div when avatar is null', () => { - const props = { name: 'Test', avatar: null, size: 40 } - - render() - - const textElement = screen.getByText('T') - const outerDiv = textElement.parentElement as HTMLElement - expect(outerDiv).toHaveStyle({ width: '40px', height: '40px' }) - }) - }) - - describe('className prop', () => { - it('should merge className with default avatar classes on img', () => { - const props = { - name: 'Test', - avatar: 'https://example.com/avatar.jpg', - className: 'custom-class', - } - - render() - - const img = screen.getByRole('img') - expect(img).toHaveClass('custom-class') - expect(img).toHaveClass('shrink-0', 'flex', 'items-center', 'rounded-full', 'bg-primary-600') - }) - - it('should merge className with default avatar classes on fallback div', () => { - const props = { - name: 'Test', - avatar: null, - className: 'my-custom-class', - } - - render() - - const textElement = screen.getByText('T') - const outerDiv = textElement.parentElement as HTMLElement - expect(outerDiv).toHaveClass('my-custom-class') - expect(outerDiv).toHaveClass('shrink-0', 'flex', 'items-center', 'rounded-full', 'bg-primary-600') - }) - }) - - describe('textClassName prop', () => { - it('should apply textClassName to the initial text element', () => { - const props = { - name: 'Test', - avatar: null, - textClassName: 'custom-text-class', - } - - render() - - const textElement = screen.getByText('T') - expect(textElement).toHaveClass('custom-text-class') - expect(textElement).toHaveClass('scale-[0.4]', 'text-center', 'text-white') - }) - }) - }) - - // State Management tests - verify useState and useEffect behavior - describe('State Management', () => { - it('should switch to fallback when image fails to load', async () => { - const props = { name: 'John', avatar: 'https://example.com/broken.jpg' } - render() - const img = screen.getByRole('img') - - fireEvent.error(img) - - await waitFor(() => { - expect(screen.queryByRole('img')).not.toBeInTheDocument() - }) - expect(screen.getByText('J')).toBeInTheDocument() - }) - - it('should reset error state when avatar URL changes', async () => { - const initialProps = { name: 'John', avatar: 'https://example.com/broken.jpg' } - const { rerender } = render() - const img = screen.getByRole('img') - - // First, trigger error - fireEvent.error(img) - await waitFor(() => { - expect(screen.queryByRole('img')).not.toBeInTheDocument() - }) - expect(screen.getByText('J')).toBeInTheDocument() - - rerender() - - await waitFor(() => { - expect(screen.getByRole('img')).toBeInTheDocument() - }) - expect(screen.queryByText('J')).not.toBeInTheDocument() - }) - - it('should not reset error state if avatar becomes null', async () => { - const initialProps = { name: 'John', avatar: 'https://example.com/broken.jpg' } - const { rerender } = render() - - // Trigger error - fireEvent.error(screen.getByRole('img')) - await waitFor(() => { - expect(screen.getByText('J')).toBeInTheDocument() - }) - - rerender() - - await waitFor(() => { - expect(screen.queryByRole('img')).not.toBeInTheDocument() - }) + expect(screen.getByRole('img')).toBeInTheDocument() expect(screen.getByText('J')).toBeInTheDocument() }) }) - // Event Handlers tests - verify onError callback behavior - describe('Event Handlers', () => { - it('should call onError with true when image fails to load', () => { - const onErrorMock = vi.fn() - const props = { - name: 'John', - avatar: 'https://example.com/broken.jpg', - onError: onErrorMock, - } - render() + describe('Size variants', () => { + it.each([ + { size: 'xxs' as const, expectedClass: 'size-4' }, + { size: 'xs' as const, expectedClass: 'size-5' }, + { size: 'sm' as const, expectedClass: 'size-6' }, + { size: 'md' as const, expectedClass: 'size-8' }, + { size: 'lg' as const, expectedClass: 'size-9' }, + { size: 'xl' as const, expectedClass: 'size-10' }, + { size: '2xl' as const, expectedClass: 'size-12' }, + { size: '3xl' as const, expectedClass: 'size-16' }, + ])('should apply $expectedClass for size="$size"', ({ size, expectedClass }) => { + const { container } = render() - fireEvent.error(screen.getByRole('img')) - - expect(onErrorMock).toHaveBeenCalledTimes(1) - expect(onErrorMock).toHaveBeenCalledWith(true) + const root = container.firstElementChild as HTMLElement + expect(root).toHaveClass(expectedClass) }) - it('should call onError with false when image loads successfully', () => { - const onErrorMock = vi.fn() - const props = { - name: 'John', - avatar: 'https://example.com/avatar.jpg', - onError: onErrorMock, - } - render() + it('should default to md size when size is not specified', () => { + const { container } = render() - fireEvent.load(screen.getByRole('img')) - - expect(onErrorMock).toHaveBeenCalledTimes(1) - expect(onErrorMock).toHaveBeenCalledWith(false) - }) - - it('should not throw when onError is not provided', async () => { - const props = { name: 'John', avatar: 'https://example.com/broken.jpg' } - render() - - expect(() => fireEvent.error(screen.getByRole('img'))).not.toThrow() - await waitFor(() => { - expect(screen.getByText('J')).toBeInTheDocument() - }) + const root = container.firstElementChild as HTMLElement + expect(root).toHaveClass('size-8') + }) + }) + + describe('className prop', () => { + it('should merge className with avatar variant classes on root', () => { + const { container } = render( + , + ) + + const root = container.firstElementChild as HTMLElement + expect(root).toHaveClass('custom-class') + expect(root).toHaveClass('rounded-full', 'bg-primary-600') }) }) - // Edge Cases tests - verify handling of unusual inputs describe('Edge Cases', () => { it('should handle empty string name gracefully', () => { - const props = { name: '', avatar: null } + const { container } = render() - const { container } = render() - - // Note: Using querySelector here because empty name produces no visible text, - // making semantic queries (getByRole, getByText) impossible - const textElement = container.querySelector('.text-white') as HTMLElement - expect(textElement).toBeInTheDocument() - expect(textElement.textContent).toBe('') + const fallback = container.querySelector('.text-white') as HTMLElement + expect(fallback).toBeInTheDocument() + expect(fallback.textContent).toBe('') }) it.each([ { name: '中文名', expected: '中', label: 'Chinese characters' }, { name: '123User', expected: '1', label: 'number' }, ])('should display first character when name starts with $label', ({ name, expected }) => { - const props = { name, avatar: null } - - render() + render() expect(screen.getByText(expected)).toBeInTheDocument() }) it('should handle empty string avatar as falsy value', () => { - const props = { name: 'Test', avatar: '' as string | null } - - render() + render() expect(screen.queryByRole('img')).not.toBeInTheDocument() expect(screen.getByText('T')).toBeInTheDocument() }) - - it('should handle undefined className and textClassName', () => { - const props = { name: 'Test', avatar: null } - - render() - - const textElement = screen.getByText('T') - const outerDiv = textElement.parentElement as HTMLElement - expect(outerDiv).toHaveClass('shrink-0', 'flex', 'items-center', 'rounded-full', 'bg-primary-600') - }) - - it.each([ - { size: 0, expected: '0px', label: 'zero' }, - { size: 1000, expected: '1000px', label: 'very large' }, - ])('should handle $label size value', ({ size, expected }) => { - const props = { name: 'Test', avatar: null, size } - - render() - - const textElement = screen.getByText('T') - const outerDiv = textElement.parentElement as HTMLElement - expect(outerDiv).toHaveStyle({ width: expected, height: expected }) - }) }) - // Combined props tests - verify props work together correctly - describe('Combined Props', () => { - it('should apply all props correctly when used together', () => { - const onErrorMock = vi.fn() - const props = { - name: 'Test User', - avatar: 'https://example.com/avatar.jpg', - size: 64, - className: 'custom-avatar', - onError: onErrorMock, - } + describe('onLoadingStatusChange', () => { + it('should render image when avatar and onLoadingStatusChange are provided', () => { + render( + , + ) - render() - - const img = screen.getByRole('img') - expect(img).toHaveAttribute('alt', 'Test User') - expect(img).toHaveAttribute('src', 'https://example.com/avatar.jpg') - expect(img).toHaveStyle({ width: '64px', height: '64px' }) - expect(img).toHaveClass('custom-avatar') - - // Trigger load to verify onError callback - fireEvent.load(img) - expect(onErrorMock).toHaveBeenCalledWith(false) + expect(screen.getByRole('img')).toBeInTheDocument() }) - it('should apply all fallback props correctly when used together', () => { - const props = { - name: 'Fallback User', - avatar: null, - size: 48, - className: 'fallback-custom', - textClassName: 'custom-text-style', - } + it('should not render image when avatar is null even with onLoadingStatusChange', () => { + const onStatusChange = vi.fn() + render( + , + ) - render() - - const textElement = screen.getByText('F') - const outerDiv = textElement.parentElement as HTMLElement - expect(outerDiv).toHaveClass('fallback-custom') - expect(outerDiv).toHaveStyle({ width: '48px', height: '48px' }) - expect(textElement).toHaveClass('custom-text-style') + expect(screen.queryByRole('img')).not.toBeInTheDocument() }) }) }) diff --git a/web/app/components/base/avatar/index.stories.tsx b/web/app/components/base/avatar/index.stories.tsx index 5e392640ca..bf4da697db 100644 --- a/web/app/components/base/avatar/index.stories.tsx +++ b/web/app/components/base/avatar/index.stories.tsx @@ -1,5 +1,5 @@ import type { Meta, StoryObj } from '@storybook/nextjs-vite' -import Avatar from '.' +import { Avatar } from '.' const meta = { title: 'Base/Data Display/Avatar', @@ -7,12 +7,12 @@ const meta = { parameters: { docs: { description: { - component: 'Initials or image-based avatar used across contacts and member lists. Falls back to the first letter when the image fails to load.', + component: 'Initials or image-based avatar built on Base UI. Falls back to the first letter when the image fails to load.', }, source: { language: 'tsx', code: ` - + `.trim(), }, }, @@ -20,8 +20,8 @@ const meta = { tags: ['autodocs'], args: { name: 'Alex Doe', - avatar: 'https://cloud.dify.ai/logo/logo.svg', - size: 40, + avatar: 'https://i.pravatar.cc/96?u=avatar-default', + size: 'xl', }, } satisfies Meta @@ -40,23 +40,20 @@ export const WithFallback: Story = { source: { language: 'tsx', code: ` - + `.trim(), }, }, }, } -export const CustomSizes: Story = { +export const AllSizes: Story = { render: args => (
- {[24, 32, 48, 64].map(size => ( + {(['xxs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'] as const).map(size => (
- - {size} - px - + {size}
))}
@@ -66,7 +63,7 @@ export const CustomSizes: Story = { source: { language: 'tsx', code: ` -{[24, 32, 48, 64].map(size => ( +{(['xxs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'] as const).map(size => ( ))} `.trim(), @@ -74,3 +71,16 @@ export const CustomSizes: Story = { }, }, } + +export const AllFallbackSizes: Story = { + render: args => ( +
+ {(['xxs', 'xs', 'sm', 'md', 'lg', 'xl', '2xl', '3xl'] as const).map(size => ( +
+ + {size} +
+ ))} +
+ ), +} diff --git a/web/app/components/base/avatar/index.tsx b/web/app/components/base/avatar/index.tsx index bf7fa060ef..2d55ec2720 100644 --- a/web/app/components/base/avatar/index.tsx +++ b/web/app/components/base/avatar/index.tsx @@ -1,64 +1,52 @@ -'use client' -import { useEffect, useState } from 'react' +import type { ImageLoadingStatus } from '@base-ui/react/avatar' +import { Avatar as BaseAvatar } from '@base-ui/react/avatar' import { cn } from '@/utils/classnames' +const SIZES = { + 'xxs': { root: 'size-4', text: 'text-[7px]' }, + 'xs': { root: 'size-5', text: 'text-[8px]' }, + 'sm': { root: 'size-6', text: 'text-[10px]' }, + 'md': { root: 'size-8', text: 'text-xs' }, + 'lg': { root: 'size-9', text: 'text-sm' }, + 'xl': { root: 'size-10', text: 'text-base' }, + '2xl': { root: 'size-12', text: 'text-xl' }, + '3xl': { root: 'size-16', text: 'text-2xl' }, +} as const + +export type AvatarSize = keyof typeof SIZES + export type AvatarProps = { name: string avatar: string | null - size?: number + size?: AvatarSize className?: string - textClassName?: string - onError?: (x: boolean) => void + onLoadingStatusChange?: (status: ImageLoadingStatus) => void } -const Avatar = ({ + +const BASE_CLASS = 'relative inline-flex shrink-0 select-none items-center justify-center overflow-hidden rounded-full bg-primary-600' + +export const Avatar = ({ name, avatar, - size = 30, + size = 'md', className, - textClassName, - onError, + onLoadingStatusChange, }: AvatarProps) => { - const avatarClassName = 'shrink-0 flex items-center rounded-full bg-primary-600' - const style = { width: `${size}px`, height: `${size}px`, fontSize: `${size}px`, lineHeight: `${size}px` } - const [imgError, setImgError] = useState(false) - - const handleError = () => { - setImgError(true) - onError?.(true) - } - - // after uploaded, api would first return error imgs url: '.../files//file-preview/...'. Then return the right url, Which caused not show the avatar - useEffect(() => { - if (avatar && imgError) - setImgError(false) - }, [avatar]) - - if (avatar && !imgError) { - return ( - {name} onError?.(false)} - /> - ) - } + const sizeConfig = SIZES[size] return ( -
-
- {name && name[0].toLocaleUpperCase()} -
-
+ + {avatar && ( + + )} + + {name?.[0]?.toLocaleUpperCase()} + + ) } - -export default Avatar diff --git a/web/app/components/base/chat/chat-with-history/chat-wrapper.tsx b/web/app/components/base/chat/chat-with-history/chat-wrapper.tsx index 304425b9a7..e56cd194db 100644 --- a/web/app/components/base/chat/chat-with-history/chat-wrapper.tsx +++ b/web/app/components/base/chat/chat-with-history/chat-wrapper.tsx @@ -23,7 +23,7 @@ import { submitHumanInputForm as submitHumanInputFormService } from '@/service/w import { TransferMethod } from '@/types/app' import { cn } from '@/utils/classnames' import { formatBooleanInputs } from '@/utils/model-config' -import Avatar from '../../avatar' +import { Avatar } from '../../avatar' import Chat from '../chat' import { useChat } from '../chat/hooks' import { getLastAnswer, isValidGeneratedAnswer } from '../utils' @@ -351,7 +351,7 @@ const ChatWrapper = () => { ) : undefined diff --git a/web/app/components/base/chat/embedded-chatbot/chat-wrapper.tsx b/web/app/components/base/chat/embedded-chatbot/chat-wrapper.tsx index 2e8f15d636..2f8d4fddb7 100644 --- a/web/app/components/base/chat/embedded-chatbot/chat-wrapper.tsx +++ b/web/app/components/base/chat/embedded-chatbot/chat-wrapper.tsx @@ -23,7 +23,7 @@ import { import { submitHumanInputForm as submitHumanInputFormService } from '@/service/workflow' import { TransferMethod } from '@/types/app' import { cn } from '@/utils/classnames' -import Avatar from '../../avatar' +import { Avatar } from '../../avatar' import Chat from '../chat' import { useChat } from '../chat/hooks' import { getLastAnswer, isValidGeneratedAnswer } from '../utils' @@ -337,7 +337,7 @@ const ChatWrapper = () => { ) : undefined diff --git a/web/app/components/datasets/settings/permission-selector/index.tsx b/web/app/components/datasets/settings/permission-selector/index.tsx index d28deb5b35..8becd7936c 100644 --- a/web/app/components/datasets/settings/permission-selector/index.tsx +++ b/web/app/components/datasets/settings/permission-selector/index.tsx @@ -4,7 +4,7 @@ import { useDebounceFn } from 'ahooks' import * as React from 'react' import { useCallback, useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' -import Avatar from '@/app/components/base/avatar' +import { Avatar } from '@/app/components/base/avatar' import Input from '@/app/components/base/input' import { PortalToFollowElem, @@ -106,7 +106,7 @@ const PermissionSelector = ({ isOnlyMe && ( <>
- +
{t('form.permissionsOnlyMe', { ns: 'datasetSettings' })} @@ -135,7 +135,7 @@ const PermissionSelector = ({ ) } @@ -146,13 +146,13 @@ const PermissionSelector = ({ avatar={selectedMembers[0].avatar_url} name={selectedMembers[0].name} className="absolute left-0 top-0 z-0" - size={16} + size="xxs" /> ) @@ -182,7 +182,7 @@ const PermissionSelector = ({ {/* Only me */} + } text={t('form.permissionsOnlyMe', { ns: 'datasetSettings' })} onClick={onSelectOnlyMe} @@ -226,7 +226,7 @@ const PermissionSelector = ({ {showMe && ( + } name={userProfile.name} email={userProfile.email} @@ -237,7 +237,7 @@ const PermissionSelector = ({ {filteredMemberList.map(member => ( + } name={member.name} email={member.email} diff --git a/web/app/components/header/account-dropdown/index.tsx b/web/app/components/header/account-dropdown/index.tsx index 87b286f319..0a5779839e 100644 --- a/web/app/components/header/account-dropdown/index.tsx +++ b/web/app/components/header/account-dropdown/index.tsx @@ -6,7 +6,7 @@ import { useRouter } from 'next/navigation' import { useState } from 'react' import { useTranslation } from 'react-i18next' import { resetUser } from '@/app/components/base/amplitude/utils' -import Avatar from '@/app/components/base/avatar' +import { Avatar } from '@/app/components/base/avatar' import PremiumBadge from '@/app/components/base/premium-badge' import ThemeSwitcher from '@/app/components/base/theme-switcher' import { DropdownMenu, DropdownMenuContent, DropdownMenuGroup, DropdownMenuItem, DropdownMenuLinkItem, DropdownMenuSeparator, DropdownMenuTrigger } from '@/app/components/base/ui/dropdown-menu' @@ -140,7 +140,7 @@ export default function AppSelector() { aria-label={t('account.account', { ns: 'common' })} className={cn('inline-flex items-center rounded-[20px] p-0.5 hover:bg-background-default-dodge', isAccountMenuOpen && 'bg-background-default-dodge')} > - +
{userProfile.email}
- +
{ accounts.map(account => (
- +
{account.name} diff --git a/web/app/components/header/account-setting/members-page/transfer-ownership-modal/member-selector.tsx b/web/app/components/header/account-setting/members-page/transfer-ownership-modal/member-selector.tsx index d2b1150c9c..a302b37f80 100644 --- a/web/app/components/header/account-setting/members-page/transfer-ownership-modal/member-selector.tsx +++ b/web/app/components/header/account-setting/members-page/transfer-ownership-modal/member-selector.tsx @@ -3,7 +3,7 @@ import type { FC } from 'react' import * as React from 'react' import { useMemo, useState } from 'react' import { useTranslation } from 'react-i18next' -import Avatar from '@/app/components/base/avatar' +import { Avatar } from '@/app/components/base/avatar' import Input from '@/app/components/base/input' import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '@/app/components/base/portal-to-follow-elem' import { useMembers } from '@/service/use-common' @@ -69,7 +69,7 @@ const MemberSelector: FC = ({ )} {currentValue && ( <> - +
{currentValue.name}
{currentValue.email}
@@ -98,7 +98,7 @@ const MemberSelector: FC = ({ setOpen(false) }} > - +
{account.name}
{account.email}
diff --git a/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/email-item.tsx b/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/email-item.tsx index be26c9bece..a655ccd6bb 100644 --- a/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/email-item.tsx +++ b/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/email-item.tsx @@ -3,7 +3,7 @@ import type { Member } from '@/models/common' import { RiCloseCircleFill, RiErrorWarningFill } from '@remixicon/react' import * as React from 'react' import { useTranslation } from 'react-i18next' -import Avatar from '@/app/components/base/avatar' +import { Avatar } from '@/app/components/base/avatar' import { cn } from '@/utils/classnames' type Props = { @@ -34,7 +34,7 @@ const EmailItem = ({ {isError && ( )} - {!isError && } + {!isError && }
{email === data.email ? data.name : data.email} {email === data.email && {t('members.you', { ns: 'common' })}} diff --git a/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/member-list.tsx b/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/member-list.tsx index eca07fd6ce..90f451474a 100644 --- a/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/member-list.tsx +++ b/web/app/components/workflow/nodes/human-input/components/delivery-method/recipient/member-list.tsx @@ -4,7 +4,7 @@ import type { Recipient } from '@/app/components/workflow/nodes/human-input/type import type { Member } from '@/models/common' import { useMemo } from 'react' import { useTranslation } from 'react-i18next' -import Avatar from '@/app/components/base/avatar' +import { Avatar } from '@/app/components/base/avatar' import Input from '@/app/components/base/input' import { cn } from '@/utils/classnames' @@ -65,7 +65,7 @@ const MemberList: FC = ({ searchValue, list, value, onSearchChange, onSel onSelect(account.id) }} > - item.user_id === account.id) && 'opacity-50')} avatar={account.avatar_url} size={24} name={account.name} /> + item.user_id === account.id) && 'opacity-50')} avatar={account.avatar_url} size="sm" name={account.name} />
item.user_id === account.id) && 'opacity-50')}>
{account.name} diff --git a/web/app/education-apply/user-info.tsx b/web/app/education-apply/user-info.tsx index cc7f0bb63e..6481194870 100644 --- a/web/app/education-apply/user-info.tsx +++ b/web/app/education-apply/user-info.tsx @@ -1,6 +1,6 @@ import { useRouter } from 'next/navigation' import { useTranslation } from 'react-i18next' -import Avatar from '@/app/components/base/avatar' +import { Avatar } from '@/app/components/base/avatar' import Button from '@/app/components/base/button' import { Triangle } from '@/app/components/base/icons/src/public/education' import { useAppContext } from '@/context/app-context' @@ -34,7 +34,7 @@ const UserInfo = () => { className="mr-4" avatar={userProfile.avatar_url} name={userProfile.name} - size={48} + size="2xl" />
diff --git a/web/eslint-suppressions.json b/web/eslint-suppressions.json index 40c8a43205..4cbf40ea0a 100644 --- a/web/eslint-suppressions.json +++ b/web/eslint-suppressions.json @@ -1499,11 +1499,6 @@ "count": 1 } }, - "app/components/base/avatar/index.tsx": { - "react-hooks-extra/no-direct-set-state-in-use-effect": { - "count": 1 - } - }, "app/components/base/block-input/index.stories.tsx": { "no-console": { "count": 2 diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs index bfdf284b03..2f06800696 100644 --- a/web/eslint.config.mjs +++ b/web/eslint.config.mjs @@ -151,7 +151,7 @@ export default antfu( }, { name: 'dify/base-ui-primitives', - files: ['app/components/base/ui/**/*.tsx'], + files: ['app/components/base/ui/**/*.tsx', 'app/components/base/avatar/**/*.tsx'], rules: { 'react-refresh/only-export-components': 'off', },