From f355c8d595a010a4fb0d3f512e6b4fd0a271aeb0 Mon Sep 17 00:00:00 2001
From: Stephen Zhou <38493346+hyoban@users.noreply.github.com>
Date: Tue, 10 Feb 2026 17:55:11 +0800
Subject: [PATCH] refactor: type safe env, update to zod v4 (#32035)
---
.../workflow-parallel-limit.test.tsx | 261 ------------------
.../field/input-type-select/types.tsx | 2 +-
.../base/form/form-scenarios/base/utils.ts | 2 +-
.../base/form/form-scenarios/demo/types.ts | 6 +-
.../form/form-scenarios/input-field/utils.ts | 2 +-
.../components/base/param-item/top-k-item.tsx | 8 +-
.../base/with-input-validation/index.spec.tsx | 2 +-
.../with-input-validation/index.stories.tsx | 8 +-
.../create/step-two/components/inputs.tsx | 3 +-
.../step-two/hooks/use-segmentation-state.ts | 6 +-
.../process-documents/components.spec.tsx | 4 +-
.../header/account-dropdown/index.tsx | 3 +-
web/app/components/provider/serwist.tsx | 3 +-
.../panel/input-field/editor/form/schema.ts | 2 +-
web/app/components/sentry-initializer.tsx | 3 +-
.../top-k-and-score-threshold.tsx | 8 +-
.../components/workflow/nodes/llm/utils.ts | 2 +-
.../workflow/variable-inspect/utils.tsx | 4 +-
.../forgot-password/ForgotPasswordForm.tsx | 10 +-
web/app/install/installForm.tsx | 18 +-
web/app/layout.tsx | 37 +--
web/app/serwist/[path]/route.ts | 3 +-
web/config/index.ts | 169 +++---------
web/context/app-context.tsx | 3 +-
web/env.ts | 235 ++++++++++++++++
web/eslint-suppressions.json | 13 -
web/next.config.ts | 20 +-
web/package.json | 6 +-
web/pnpm-lock.yaml | 178 +++++-------
web/proxy.ts | 7 +-
web/service/client.spec.ts | 2 +-
web/types/feature.ts | 34 ---
web/utils/var.ts | 3 +-
web/utils/zod.spec.ts | 173 ------------
34 files changed, 401 insertions(+), 839 deletions(-)
delete mode 100644 web/__tests__/workflow-parallel-limit.test.tsx
create mode 100644 web/env.ts
delete mode 100644 web/utils/zod.spec.ts
diff --git a/web/__tests__/workflow-parallel-limit.test.tsx b/web/__tests__/workflow-parallel-limit.test.tsx
deleted file mode 100644
index ba3840ac3e..0000000000
--- a/web/__tests__/workflow-parallel-limit.test.tsx
+++ /dev/null
@@ -1,261 +0,0 @@
-/**
- * MAX_PARALLEL_LIMIT Configuration Bug Test
- *
- * This test reproduces and verifies the fix for issue #23083:
- * MAX_PARALLEL_LIMIT environment variable does not take effect in iteration panel
- */
-
-import { render, screen } from '@testing-library/react'
-import * as React from 'react'
-
-// Mock environment variables before importing constants
-const originalEnv = process.env.NEXT_PUBLIC_MAX_PARALLEL_LIMIT
-
-// Test with different environment values
-function setupEnvironment(value?: string) {
- if (value)
- process.env.NEXT_PUBLIC_MAX_PARALLEL_LIMIT = value
- else
- delete process.env.NEXT_PUBLIC_MAX_PARALLEL_LIMIT
-
- // Clear module cache to force re-evaluation
- vi.resetModules()
-}
-
-function restoreEnvironment() {
- if (originalEnv)
- process.env.NEXT_PUBLIC_MAX_PARALLEL_LIMIT = originalEnv
- else
- delete process.env.NEXT_PUBLIC_MAX_PARALLEL_LIMIT
-
- vi.resetModules()
-}
-
-// Mock i18next with proper implementation
-vi.mock('react-i18next', () => ({
- useTranslation: () => ({
- t: (key: string) => {
- if (key.includes('MaxParallelismTitle'))
- return 'Max Parallelism'
- if (key.includes('MaxParallelismDesc'))
- return 'Maximum number of parallel executions'
- if (key.includes('parallelMode'))
- return 'Parallel Mode'
- if (key.includes('parallelPanelDesc'))
- return 'Enable parallel execution'
- if (key.includes('errorResponseMethod'))
- return 'Error Response Method'
- return key
- },
- }),
- initReactI18next: {
- type: '3rdParty',
- init: vi.fn(),
- },
-}))
-
-// Mock i18next module completely to prevent initialization issues
-vi.mock('i18next', () => ({
- use: vi.fn().mockReturnThis(),
- init: vi.fn().mockReturnThis(),
- t: vi.fn(key => key),
- isInitialized: true,
-}))
-
-// Mock the useConfig hook
-vi.mock('@/app/components/workflow/nodes/iteration/use-config', () => ({
- default: () => ({
- inputs: {
- is_parallel: true,
- parallel_nums: 5,
- error_handle_mode: 'terminated',
- },
- changeParallel: vi.fn(),
- changeParallelNums: vi.fn(),
- changeErrorHandleMode: vi.fn(),
- }),
-}))
-
-// Mock other components
-vi.mock('@/app/components/workflow/nodes/_base/components/variable/var-reference-picker', () => ({
- default: function MockVarReferencePicker() {
- return
Usage Example
- {`import { z } from 'zod'
+ {`import * as z from 'zod'
import withValidation from './withValidation'
// Define your component
diff --git a/web/app/components/datasets/create/step-two/components/inputs.tsx b/web/app/components/datasets/create/step-two/components/inputs.tsx
index 4568431356..349796858e 100644
--- a/web/app/components/datasets/create/step-two/components/inputs.tsx
+++ b/web/app/components/datasets/create/step-two/components/inputs.tsx
@@ -5,6 +5,7 @@ import { useTranslation } from 'react-i18next'
import Input from '@/app/components/base/input'
import { InputNumber } from '@/app/components/base/input-number'
import Tooltip from '@/app/components/base/tooltip'
+import { env } from '@/env'
const TextLabel: FC = (props) => {
return
@@ -46,7 +47,7 @@ export const DelimiterInput: FC = (props) =>
}
export const MaxLengthInput: FC = (props) => {
- const maxValue = Number.parseInt(globalThis.document?.body?.getAttribute('data-public-indexing-max-segmentation-tokens-length') || '4000', 10)
+ const maxValue = env.NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH
const { t } = useTranslation()
return (
diff --git a/web/app/components/datasets/create/step-two/hooks/use-segmentation-state.ts b/web/app/components/datasets/create/step-two/hooks/use-segmentation-state.ts
index 503704276e..abef8a98cb 100644
--- a/web/app/components/datasets/create/step-two/hooks/use-segmentation-state.ts
+++ b/web/app/components/datasets/create/step-two/hooks/use-segmentation-state.ts
@@ -1,5 +1,6 @@
import type { ParentMode, PreProcessingRule, ProcessRule, Rules, SummaryIndexSetting as SummaryIndexSettingType } from '@/models/datasets'
import { useCallback, useRef, useState } from 'react'
+import { env } from '@/env'
import { ChunkingMode, ProcessMode } from '@/models/datasets'
import escape from './escape'
import unescape from './unescape'
@@ -8,10 +9,7 @@ import unescape from './unescape'
export const DEFAULT_SEGMENT_IDENTIFIER = '\\n\\n'
export const DEFAULT_MAXIMUM_CHUNK_LENGTH = 1024
export const DEFAULT_OVERLAP = 50
-export const MAXIMUM_CHUNK_TOKEN_LENGTH = Number.parseInt(
- globalThis.document?.body?.getAttribute('data-public-indexing-max-segmentation-tokens-length') || '4000',
- 10,
-)
+export const MAXIMUM_CHUNK_TOKEN_LENGTH = env.NEXT_PUBLIC_INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH
export type ParentChildConfig = {
chunkForContext: ParentMode
diff --git a/web/app/components/datasets/documents/create-from-pipeline/process-documents/components.spec.tsx b/web/app/components/datasets/documents/create-from-pipeline/process-documents/components.spec.tsx
index 322e6edd49..6f47575b27 100644
--- a/web/app/components/datasets/documents/create-from-pipeline/process-documents/components.spec.tsx
+++ b/web/app/components/datasets/documents/create-from-pipeline/process-documents/components.spec.tsx
@@ -1,7 +1,7 @@
import type { BaseConfiguration } from '@/app/components/base/form/form-scenarios/base/types'
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import * as React from 'react'
-import { z } from 'zod'
+import * as z from 'zod'
import { BaseFieldType } from '@/app/components/base/form/form-scenarios/base/types'
import Toast from '@/app/components/base/toast'
import Actions from './actions'
@@ -53,7 +53,7 @@ const createFailingSchema = () => {
issues: [{ path: ['field1'], message: 'is required' }],
},
}),
- } as unknown as z.ZodSchema
+ } as unknown as z.ZodType
}
// ==========================================
diff --git a/web/app/components/header/account-dropdown/index.tsx b/web/app/components/header/account-dropdown/index.tsx
index 07dd0fca3d..983f9e434d 100644
--- a/web/app/components/header/account-dropdown/index.tsx
+++ b/web/app/components/header/account-dropdown/index.tsx
@@ -28,6 +28,7 @@ import { useGlobalPublicStore } from '@/context/global-public-context'
import { useDocLink } from '@/context/i18n'
import { useModalContext } from '@/context/modal-context'
import { useProviderContext } from '@/context/provider-context'
+import { env } from '@/env'
import { useLogout } from '@/service/use-common'
import { cn } from '@/utils/classnames'
import AccountAbout from '../account-about'
@@ -178,7 +179,7 @@ export default function AppSelector() {
{
- document?.body?.getAttribute('data-public-site-about') !== 'hide' && (
+ env.NEXT_PUBLIC_SITE_ABOUT !== 'hide' && (