diff --git a/oxlint-suppressions.json b/oxlint-suppressions.json index 40ad8b0544f..cb02e958c99 100644 --- a/oxlint-suppressions.json +++ b/oxlint-suppressions.json @@ -81,11 +81,6 @@ "count": 1 } }, - "web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/(shareLayout)/webapp-reset-password/layout.tsx": { "typescript/no-explicit-any": { "count": 1 @@ -110,9 +105,6 @@ } }, "web/app/components/app/annotation/add-annotation-modal/edit-item/index.tsx": { - "erasable-syntax-only/enums": { - "count": 1 - }, "jsx-a11y/click-events-have-key-events": { "count": 1 }, @@ -137,9 +129,6 @@ } }, "web/app/components/app/annotation/batch-add-annotation-modal/index.tsx": { - "erasable-syntax-only/enums": { - "count": 1 - }, "eslint-react/set-state-in-effect": { "count": 1 }, @@ -151,9 +140,6 @@ } }, "web/app/components/app/annotation/edit-annotation-modal/edit-item/index.tsx": { - "erasable-syntax-only/enums": { - "count": 1 - }, "eslint-react/set-state-in-effect": { "count": 1 }, @@ -196,15 +182,7 @@ "count": 5 } }, - "web/app/components/app/annotation/type.ts": { - "erasable-syntax-only/enums": { - "count": 2 - } - }, "web/app/components/app/annotation/view-annotation-modal/index.tsx": { - "erasable-syntax-only/enums": { - "count": 1 - }, "eslint-react/set-state-in-effect": { "count": 5 }, @@ -388,11 +366,6 @@ "count": 1 } }, - "web/app/components/app/configuration/config/automatic/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/app/configuration/dataset-config/__tests__/index.spec.tsx": { "typescript/no-explicit-any": { "count": 36 @@ -517,9 +490,6 @@ } }, "web/app/components/app/create-app-dialog/app-list/sidebar.tsx": { - "erasable-syntax-only/enums": { - "count": 1 - }, "react/only-export-components": { "count": 1 } @@ -745,11 +715,6 @@ "count": 1 } }, - "web/app/components/base/badge/index.tsx": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/base/carousel/index.tsx": { "eslint-react/set-state-in-effect": { "count": 3 @@ -930,11 +895,6 @@ "count": 1 } }, - "web/app/components/base/date-and-time-picker/types.ts": { - "erasable-syntax-only/enums": { - "count": 2 - } - }, "web/app/components/base/date-and-time-picker/utils/dayjs.ts": { "no-barrel-files/no-barrel-files": { "count": 1 @@ -971,11 +931,6 @@ "count": 3 } }, - "web/app/components/base/features/new-feature-panel/annotation-reply/type.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/base/features/new-feature-panel/annotation-reply/use-annotation-config.ts": { "typescript/no-explicit-any": { "count": 2 @@ -1029,9 +984,6 @@ } }, "web/app/components/base/features/types.ts": { - "erasable-syntax-only/enums": { - "count": 2 - }, "typescript/no-explicit-any": { "count": 1 } @@ -1087,11 +1039,6 @@ "count": 4 } }, - "web/app/components/base/file-uploader/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/base/file-uploader/utils.ts": { "no-restricted-imports": { "count": 1 @@ -1131,9 +1078,6 @@ } }, "web/app/components/base/form/form-scenarios/base/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - }, "typescript/no-explicit-any": { "count": 1 } @@ -1149,9 +1093,6 @@ } }, "web/app/components/base/form/form-scenarios/input-field/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - }, "typescript/no-explicit-any": { "count": 2 } @@ -1172,9 +1113,6 @@ } }, "web/app/components/base/form/types.ts": { - "erasable-syntax-only/enums": { - "count": 2 - }, "typescript/no-explicit-any": { "count": 15 } @@ -1555,9 +1493,6 @@ } }, "web/app/components/base/node-status/index.tsx": { - "erasable-syntax-only/enums": { - "count": 1 - }, "react/only-export-components": { "count": 1 } @@ -1901,11 +1836,6 @@ "count": 3 } }, - "web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/hooks/use-dsl-import.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/index.tsx": { "no-barrel-files/no-barrel-files": { "count": 1 @@ -1919,11 +1849,6 @@ "count": 1 } }, - "web/app/components/datasets/create-from-pipeline/list/template-card/details/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/datasets/create-from-pipeline/list/template-card/operations.tsx": { "jsx-a11y/click-events-have-key-events": { "count": 3 @@ -2005,9 +1930,6 @@ } }, "web/app/components/datasets/create/step-two/hooks/use-indexing-config.ts": { - "erasable-syntax-only/enums": { - "count": 1 - }, "eslint-react/set-state-in-effect": { "count": 3 } @@ -2200,11 +2122,6 @@ "count": 3 } }, - "web/app/components/datasets/documents/create-from-pipeline/types.tsx": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/datasets/documents/detail/batch-modal/csv-downloader.tsx": { "eslint-react/static-components": { "count": 2 @@ -2409,16 +2326,6 @@ "count": 1 } }, - "web/app/components/datasets/metadata/types.ts": { - "erasable-syntax-only/enums": { - "count": 2 - } - }, - "web/app/components/datasets/settings/chunk-structure/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/datasets/settings/option-card.tsx": { "jsx-a11y/click-events-have-key-events": { "count": 1 @@ -2496,9 +2403,6 @@ } }, "web/app/components/header/account-setting/model-provider-page/declarations.ts": { - "erasable-syntax-only/enums": { - "count": 11 - }, "typescript/no-explicit-any": { "count": 4 } @@ -2641,9 +2545,6 @@ } }, "web/app/components/plugins/install-plugin/install-bundle/index.tsx": { - "erasable-syntax-only/enums": { - "count": 1 - }, "react/only-export-components": { "count": 1 } @@ -2749,9 +2650,6 @@ } }, "web/app/components/plugins/plugin-auth/types.ts": { - "erasable-syntax-only/enums": { - "count": 2 - }, "no-barrel-files/no-barrel-files": { "count": 2 } @@ -2830,11 +2728,6 @@ "count": 2 } }, - "web/app/components/plugins/plugin-detail-panel/subscription-list/create/hooks/use-common-modal-state.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/plugins/plugin-detail-panel/subscription-list/create/index.tsx": { "jsx-a11y/click-events-have-key-events": { "count": 1 @@ -2843,29 +2736,16 @@ "count": 1 } }, - "web/app/components/plugins/plugin-detail-panel/subscription-list/create/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/plugins/plugin-detail-panel/subscription-list/index.tsx": { "no-barrel-files/no-barrel-files": { "count": 2 } }, "web/app/components/plugins/plugin-detail-panel/subscription-list/log-viewer.tsx": { - "erasable-syntax-only/enums": { - "count": 1 - }, "typescript/no-explicit-any": { "count": 2 } }, - "web/app/components/plugins/plugin-detail-panel/subscription-list/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/plugins/plugin-detail-panel/trigger/event-detail-drawer.tsx": { "jsx-a11y/click-events-have-key-events": { "count": 1 @@ -2909,15 +2789,7 @@ "count": 1 } }, - "web/app/components/plugins/reference-setting-modal/auto-update-setting/types.ts": { - "erasable-syntax-only/enums": { - "count": 2 - } - }, "web/app/components/plugins/types.ts": { - "erasable-syntax-only/enums": { - "count": 7 - }, "typescript/no-explicit-any": { "count": 25 } @@ -3139,11 +3011,6 @@ "count": 1 } }, - "web/app/components/share/text-generation/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/snippet-list/__tests__/reflow.browser.spec.tsx": { "@tanstack/query/prefer-query-options": { "count": 2 @@ -3194,9 +3061,6 @@ } }, "web/app/components/tools/types.ts": { - "erasable-syntax-only/enums": { - "count": 3 - }, "typescript/no-explicit-any": { "count": 4 } @@ -3256,11 +3120,6 @@ "count": 1 } }, - "web/app/components/workflow/block-selector/use-sticky-scroll.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/workflow/comment/comment-input.tsx": { "jsx-a11y/no-autofocus": { "count": 1 @@ -3312,9 +3171,6 @@ "dify/require-disable-directive-description": { "count": 1 }, - "erasable-syntax-only/enums": { - "count": 1 - }, "react/only-export-components": { "count": 1 } @@ -3464,17 +3320,11 @@ } }, "web/app/components/workflow/nodes/_base/components/entry-node-container.tsx": { - "erasable-syntax-only/enums": { - "count": 1 - }, "react/only-export-components": { "count": 1 } }, "web/app/components/workflow/nodes/_base/components/error-handle/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - }, "typescript/no-explicit-any": { "count": 1 } @@ -3706,9 +3556,6 @@ } }, "web/app/components/workflow/nodes/_base/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - }, "typescript/no-explicit-any": { "count": 1 } @@ -3742,9 +3589,6 @@ } }, "web/app/components/workflow/nodes/agent/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - }, "typescript/no-explicit-any": { "count": 1 } @@ -3765,9 +3609,6 @@ } }, "web/app/components/workflow/nodes/assigner/types.ts": { - "erasable-syntax-only/enums": { - "count": 2 - }, "typescript/no-explicit-any": { "count": 1 } @@ -3782,11 +3623,6 @@ "count": 1 } }, - "web/app/components/workflow/nodes/code/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/workflow/nodes/code/use-config.ts": { "eslint-react/set-state-in-effect": { "count": 2 @@ -3829,9 +3665,6 @@ } }, "web/app/components/workflow/nodes/data-source/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - }, "typescript/no-explicit-any": { "count": 1 } @@ -3875,11 +3708,6 @@ "count": 2 } }, - "web/app/components/workflow/nodes/http/types.ts": { - "erasable-syntax-only/enums": { - "count": 5 - } - }, "web/app/components/workflow/nodes/http/use-config.ts": { "eslint-react/set-state-in-effect": { "count": 1 @@ -3940,11 +3768,6 @@ "count": 2 } }, - "web/app/components/workflow/nodes/human-input/types.ts": { - "erasable-syntax-only/enums": { - "count": 2 - } - }, "web/app/components/workflow/nodes/if-else/components/condition-list/condition-input.tsx": { "typescript/no-explicit-any": { "count": 1 @@ -3966,11 +3789,6 @@ "count": 1 } }, - "web/app/components/workflow/nodes/if-else/types.ts": { - "erasable-syntax-only/enums": { - "count": 2 - } - }, "web/app/components/workflow/nodes/if-else/use-single-run-form-params.ts": { "dify/require-disable-directive-description": { "count": 3 @@ -4005,9 +3823,6 @@ } }, "web/app/components/workflow/nodes/knowledge-base/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - }, "no-barrel-files/no-barrel-files": { "count": 8 } @@ -4017,11 +3832,6 @@ "count": 3 } }, - "web/app/components/workflow/nodes/knowledge-base/utils.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/workflow/nodes/knowledge-retrieval/components/metadata/condition-list/condition-common-variable-selector.tsx": { "jsx-a11y/click-events-have-key-events": { "count": 1 @@ -4079,9 +3889,6 @@ } }, "web/app/components/workflow/nodes/knowledge-retrieval/types.ts": { - "erasable-syntax-only/enums": { - "count": 4 - }, "typescript/no-explicit-any": { "count": 1 } @@ -4101,11 +3908,6 @@ "count": 1 } }, - "web/app/components/workflow/nodes/list-operator/types.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/workflow/nodes/llm/components/config-prompt.tsx": { "typescript/no-explicit-any": { "count": 1 @@ -4136,11 +3938,6 @@ "count": 2 } }, - "web/app/components/workflow/nodes/llm/types.ts": { - "erasable-syntax-only/enums": { - "count": 2 - } - }, "web/app/components/workflow/nodes/llm/use-config.ts": { "eslint-react/set-state-in-effect": { "count": 1 @@ -4152,9 +3949,6 @@ } }, "web/app/components/workflow/nodes/llm/utils.ts": { - "erasable-syntax-only/enums": { - "count": 1 - }, "typescript/no-explicit-any": { "count": 7 } @@ -4199,9 +3993,6 @@ } }, "web/app/components/workflow/nodes/loop/types.ts": { - "erasable-syntax-only/enums": { - "count": 2 - }, "typescript/no-explicit-any": { "count": 1 } @@ -4229,11 +4020,6 @@ "count": 1 } }, - "web/app/components/workflow/nodes/parameter-extractor/types.ts": { - "erasable-syntax-only/enums": { - "count": 2 - } - }, "web/app/components/workflow/nodes/parameter-extractor/use-config.ts": { "eslint-react/set-state-in-effect": { "count": 2 @@ -4547,11 +4333,6 @@ "count": 1 } }, - "web/app/components/workflow/panel/chat-variable-panel/type.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/app/components/workflow/panel/comments-panel/index.tsx": { "jsx-a11y/click-events-have-key-events": { "count": 3 @@ -4829,9 +4610,6 @@ } }, "web/app/components/workflow/types.ts": { - "erasable-syntax-only/enums": { - "count": 16 - }, "typescript/no-empty-object-type": { "count": 3 }, @@ -5131,33 +4909,21 @@ } }, "web/models/datasets.ts": { - "erasable-syntax-only/enums": { - "count": 7 - }, "typescript/no-explicit-any": { "count": 5 } }, "web/models/debug.ts": { - "erasable-syntax-only/enums": { - "count": 2 - }, "typescript/no-explicit-any": { "count": 4 } }, "web/models/log.ts": { - "erasable-syntax-only/enums": { - "count": 1 - }, "typescript/no-explicit-any": { "count": 6 } }, "web/models/pipeline.ts": { - "erasable-syntax-only/enums": { - "count": 3 - }, "typescript/no-explicit-any": { "count": 6 } @@ -5373,9 +5139,6 @@ } }, "web/service/share.ts": { - "erasable-syntax-only/enums": { - "count": 1 - }, "no-restricted-imports": { "count": 2 }, @@ -5558,11 +5321,6 @@ "count": 5 } }, - "web/types/common.ts": { - "erasable-syntax-only/enums": { - "count": 1 - } - }, "web/types/pipeline.tsx": { "typescript/no-explicit-any": { "count": 3 diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type.ts b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type.ts index 737111a7ef1..83cc6be2637 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type.ts +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/type.ts @@ -1,15 +1,17 @@ -export enum TracingProvider { - arize = 'arize', - phoenix = 'phoenix', - langSmith = 'langsmith', - langfuse = 'langfuse', - opik = 'opik', - weave = 'weave', - aliyun = 'aliyun', - mlflow = 'mlflow', - databricks = 'databricks', - tencent = 'tencent', -} +export const TracingProvider = { + arize: 'arize', + phoenix: 'phoenix', + langSmith: 'langsmith', + langfuse: 'langfuse', + opik: 'opik', + weave: 'weave', + aliyun: 'aliyun', + mlflow: 'mlflow', + databricks: 'databricks', + tencent: 'tencent', +} as const + +export type TracingProvider = (typeof TracingProvider)[keyof typeof TracingProvider] export type ArizeConfig = { api_key: string diff --git a/web/app/components/app/annotation/add-annotation-modal/edit-item/index.tsx b/web/app/components/app/annotation/add-annotation-modal/edit-item/index.tsx index c383753e2ab..7936fbd0ca5 100644 --- a/web/app/components/app/annotation/add-annotation-modal/edit-item/index.tsx +++ b/web/app/components/app/annotation/add-annotation-modal/edit-item/index.tsx @@ -5,10 +5,12 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { Robot, User } from '@/app/components/base/icons/src/public/avatar' -export enum EditItemType { - Query = 'query', - Answer = 'answer', -} +export const EditItemType = { + Query: 'query', + Answer: 'answer', +} as const + +export type EditItemType = (typeof EditItemType)[keyof typeof EditItemType] type Props = Readonly<{ type: EditItemType content: string diff --git a/web/app/components/app/annotation/batch-add-annotation-modal/index.tsx b/web/app/components/app/annotation/batch-add-annotation-modal/index.tsx index 4fb651b70e7..cd1dd99c70e 100644 --- a/web/app/components/app/annotation/batch-add-annotation-modal/index.tsx +++ b/web/app/components/app/annotation/batch-add-annotation-modal/index.tsx @@ -16,12 +16,14 @@ import { consoleQuery } from '@/service/console' import CSVDownloader from './csv-downloader' import CSVUploader from './csv-uploader' -export enum ProcessStatus { - WAITING = 'waiting', - PROCESSING = 'processing', - COMPLETED = 'completed', - ERROR = 'error', -} +export const ProcessStatus = { + WAITING: 'waiting', + PROCESSING: 'processing', + COMPLETED: 'completed', + ERROR: 'error', +} as const + +export type ProcessStatus = (typeof ProcessStatus)[keyof typeof ProcessStatus] export type IBatchModalProps = { appId: string diff --git a/web/app/components/app/annotation/edit-annotation-modal/edit-item/index.tsx b/web/app/components/app/annotation/edit-annotation-modal/edit-item/index.tsx index c114b8ca1b3..dfba12270c3 100644 --- a/web/app/components/app/annotation/edit-annotation-modal/edit-item/index.tsx +++ b/web/app/components/app/annotation/edit-annotation-modal/edit-item/index.tsx @@ -9,10 +9,12 @@ import { useEffect, useState } from 'react' import { useTranslation } from 'react-i18next' import { Robot, User } from '@/app/components/base/icons/src/public/avatar' -export enum EditItemType { - Query = 'query', - Answer = 'answer', -} +export const EditItemType = { + Query: 'query', + Answer: 'answer', +} as const + +export type EditItemType = (typeof EditItemType)[keyof typeof EditItemType] type Props = Readonly<{ type: EditItemType content: string diff --git a/web/app/components/app/annotation/type.ts b/web/app/components/app/annotation/type.ts index 076ef8f9bdf..160b971cbff 100644 --- a/web/app/components/app/annotation/type.ts +++ b/web/app/components/app/annotation/type.ts @@ -33,11 +33,14 @@ export type EmbeddingModelConfig = { embedding_model_name: string } -export enum AnnotationEnableStatus { - enable = 'enable', - disable = 'disable', -} +export const AnnotationEnableStatus = { + enable: 'enable', + disable: 'disable', +} as const -export enum JobStatus { - completed = 'completed', -} +export type AnnotationEnableStatus = + (typeof AnnotationEnableStatus)[keyof typeof AnnotationEnableStatus] + +export const JobStatus = { + completed: 'completed', +} as const diff --git a/web/app/components/app/annotation/view-annotation-modal/index.tsx b/web/app/components/app/annotation/view-annotation-modal/index.tsx index 314fbf31420..78428f99dbd 100644 --- a/web/app/components/app/annotation/view-annotation-modal/index.tsx +++ b/web/app/components/app/annotation/view-annotation-modal/index.tsx @@ -41,10 +41,12 @@ type Props = Readonly<{ onRemove: () => void }> -enum TabType { - annotation = 'annotation', - hitHistory = 'hitHistory', -} +const TabType = { + annotation: 'annotation', + hitHistory: 'hitHistory', +} as const + +type TabType = (typeof TabType)[keyof typeof TabType] const ViewAnnotationModal: FC = ({ appId, isShow, onHide, item, onSave, onRemove }) => { const { id, question, answer, created_at: createdAt } = item @@ -86,7 +88,7 @@ const ViewAnnotationModal: FC = ({ appId, isShow, onHide, item, onSave, o if (isShow && id) fetchHitHistory(1) }, [id, isShow]) - const [activeTab, setActiveTab] = useState(TabType.annotation) + const [activeTab, setActiveTab] = useState(TabType.annotation) const handleSave = async (type: EditItemType, editedContent: string) => { try { if (type === EditItemType.Query) { diff --git a/web/app/components/app/configuration/config-var/config-modal/form-fields.tsx b/web/app/components/app/configuration/config-var/config-modal/form-fields.tsx index eb844a55e99..613130f08d3 100644 --- a/web/app/components/app/configuration/config-var/config-modal/form-fields.tsx +++ b/web/app/components/app/configuration/config-var/config-modal/form-fields.tsx @@ -81,6 +81,8 @@ const ConfigModalFormFields: FC = ({ validationError, t: rawTranslate, }) => { + const fileInputTypes: readonly InputVarType[] = [InputVarType.singleFile, InputVarType.multiFiles] + const t = getStringSelectorTranslate(rawTranslate) const { type, label, variable } = tempPayload const numberDefault = @@ -88,7 +90,7 @@ const ConfigModalFormFields: FC = ({ (typeof tempPayload.default === 'string' && tempPayload.default.trim() !== '') ? Number(tempPayload.default) : Number.NaN - const isFileInput = [InputVarType.singleFile, InputVarType.multiFiles].includes(type) + const isFileInput = fileInputTypes.includes(type) const docLink = useDocLink() const fieldId = React.useId() const errorId = `${fieldId}-error` diff --git a/web/app/components/app/configuration/config-var/config-modal/utils.ts b/web/app/components/app/configuration/config-var/config-modal/utils.ts index e2601f11802..03f5794d0a3 100644 --- a/web/app/components/app/configuration/config-var/config-modal/utils.ts +++ b/web/app/components/app/configuration/config-var/config-modal/utils.ts @@ -91,6 +91,11 @@ export const updatePayloadField = (payload: InputVar, key: string, value: unknow export const createPayloadForType = (payload: InputVar, type: InputVarType) => { return produce(payload, (draft) => { + const fileInputTypes: readonly InputVarType[] = [ + InputVarType.singleFile, + InputVarType.multiFiles, + ] + draft.type = type if (type === InputVarType.select) draft.default = undefined if (isStringInputType(type) && typeof draft.default === 'number') @@ -103,7 +108,7 @@ export const createPayloadForType = (payload: InputVar, type: InputVarType) => { draft.default = Number.isFinite(value) ? value : undefined } - if ([InputVarType.singleFile, InputVarType.multiFiles].includes(type)) { + if (fileInputTypes.includes(type)) { draft.hide = false const fileUploadSettingKeys = Object.keys(DEFAULT_FILE_UPLOAD_SETTING) as Array< keyof typeof DEFAULT_FILE_UPLOAD_SETTING @@ -178,10 +183,10 @@ export const validateConfigModalPayload = ({ maxFileUploadLimit, t: rawTranslate, }: ValidateConfigModalPayloadOptions): ValidateConfigModalPayloadResult => { + const fileInputTypes: readonly InputVarType[] = [InputVarType.singleFile, InputVarType.multiFiles] + const t = getStringSelectorTranslate(rawTranslate) - const normalizedTempPayload = [InputVarType.singleFile, InputVarType.multiFiles].includes( - tempPayload.type, - ) + const normalizedTempPayload = fileInputTypes.includes(tempPayload.type) ? { ...tempPayload, hide: false, @@ -250,7 +255,7 @@ export const validateConfigModalPayload = ({ } } - if ([InputVarType.singleFile, InputVarType.multiFiles].includes(normalizedTempPayload.type)) { + if (fileInputTypes.includes(normalizedTempPayload.type)) { if (!normalizedTempPayload.allowed_file_types?.length) { return { errorField: 'allowed_file_types', diff --git a/web/app/components/app/configuration/config/automatic/types.ts b/web/app/components/app/configuration/config/automatic/types.ts index cc975694998..d2a386aa1c9 100644 --- a/web/app/components/app/configuration/config/automatic/types.ts +++ b/web/app/components/app/configuration/config/automatic/types.ts @@ -1,4 +1,6 @@ -export enum GeneratorType { - prompt = 'prompt', - code = 'code', -} +export const GeneratorType = { + prompt: 'prompt', + code: 'code', +} as const + +export type GeneratorType = (typeof GeneratorType)[keyof typeof GeneratorType] diff --git a/web/app/components/app/configuration/hooks/use-configuration.ts b/web/app/components/app/configuration/hooks/use-configuration.ts index 571bd5830b8..7b5aeafe1dc 100644 --- a/web/app/components/app/configuration/hooks/use-configuration.ts +++ b/web/app/components/app/configuration/hooks/use-configuration.ts @@ -144,7 +144,7 @@ export const useConfiguration = (): ConfigurationViewModel => { modelModeTypeRef.current = resolvedModelModeType }, [modelModeTypeRef, resolvedModelModeType]) - const [promptMode, setPromptMode] = useState(PromptMode.simple) + const [promptMode, setPromptMode] = useState(PromptMode.simple) const isAdvancedMode = promptMode === PromptMode.advanced const [canReturnToSimpleMode, setCanReturnToSimpleMode] = useState(true) diff --git a/web/app/components/app/create-app-dialog/app-list/sidebar.tsx b/web/app/components/app/create-app-dialog/app-list/sidebar.tsx index 226597d3487..c654022af1f 100644 --- a/web/app/components/app/create-app-dialog/app-list/sidebar.tsx +++ b/web/app/components/app/create-app-dialog/app-list/sidebar.tsx @@ -4,9 +4,11 @@ import { Separator } from '@langgenius/dify-ui/separator' import { RiStickyNoteAddLine } from '@remixicon/react' import { useTranslation } from 'react-i18next' -export enum AppCategories { - RECOMMENDED = 'Recommended', -} +export const AppCategories = { + RECOMMENDED: 'Recommended', +} as const + +export type AppCategories = (typeof AppCategories)[keyof typeof AppCategories] type SidebarProps = { current: AppCategories | string diff --git a/web/app/components/base/badge/index.tsx b/web/app/components/base/badge/index.tsx index 8b0f33dec52..4aeb59f39b4 100644 --- a/web/app/components/base/badge/index.tsx +++ b/web/app/components/base/badge/index.tsx @@ -4,11 +4,13 @@ import { cn } from '@langgenius/dify-ui/cn' import { cva } from 'class-variance-authority' import * as React from 'react' -enum BadgeState { - Warning = 'warning', - Accent = 'accent', - Default = '', -} +const BadgeState = { + Warning: 'warning', + Accent: 'accent', + Default: '', +} as const + +type BadgeState = (typeof BadgeState)[keyof typeof BadgeState] const BadgeVariants = cva('badge', { variants: { diff --git a/web/app/components/base/chat/chat/answer/human-input-content/__tests__/utils.spec.ts b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/utils.spec.ts index bfa327af3e0..7ca58b420f6 100644 --- a/web/app/components/base/chat/chat/answer/human-input-content/__tests__/utils.spec.ts +++ b/web/app/components/base/chat/chat/answer/human-input-content/__tests__/utils.spec.ts @@ -17,7 +17,7 @@ import { } from '../utils' const paragraphInput = ( - overrides: Partial> = {}, + overrides: Partial> = {}, ): FormInputItem => ({ type: InputVarType.paragraph, output_variable_name: 'field', @@ -30,7 +30,7 @@ const paragraphInput = ( }) const selectInput = ( - overrides: Partial> = {}, + overrides: Partial> = {}, ): FormInputItem => ({ type: InputVarType.select, output_variable_name: 'field', @@ -43,7 +43,7 @@ const selectInput = ( }) const fileInput = ( - overrides: Partial> = {}, + overrides: Partial> = {}, ): FormInputItem => ({ type: InputVarType.singleFile, output_variable_name: 'field', @@ -54,7 +54,7 @@ const fileInput = ( }) const fileListInput = ( - overrides: Partial> = {}, + overrides: Partial> = {}, ): FormInputItem => ({ type: InputVarType.multiFiles, output_variable_name: 'field', diff --git a/web/app/components/base/date-and-time-picker/date-picker/index.tsx b/web/app/components/base/date-and-time-picker/date-picker/index.tsx index 362ef9f1e15..029a3210f1e 100644 --- a/web/app/components/base/date-and-time-picker/date-picker/index.tsx +++ b/web/app/components/base/date-and-time-picker/date-picker/index.tsx @@ -38,7 +38,8 @@ const DatePicker = ({ }: DatePickerProps) => { const { t } = useTranslation() const [isOpen, setIsOpen] = useState(false) - const [view, setView] = useState(ViewType.date) + const [view, setView] = useState(ViewType.date) + const dateConfirmationViews: readonly ViewType[] = [ViewType.date, ViewType.time] const isInitialRef = useRef(true) const triggerAreaRef = useRef(null) @@ -366,7 +367,7 @@ const DatePicker = ({ )} {/* Footer */} - {[ViewType.date, ViewType.time].includes(view) && !noConfirm && ( + {dateConfirmationViews.includes(view) && !noConfirm && ( )} - {![ViewType.date, ViewType.time].includes(view) && ( + {!dateConfirmationViews.includes(view) && ( , React.ReactElement> type TriggerRenderProps = Parameters[0] diff --git a/web/app/components/base/features/new-feature-panel/annotation-reply/type.ts b/web/app/components/base/features/new-feature-panel/annotation-reply/type.ts index 910453478cd..611bd5122a7 100644 --- a/web/app/components/base/features/new-feature-panel/annotation-reply/type.ts +++ b/web/app/components/base/features/new-feature-panel/annotation-reply/type.ts @@ -1,4 +1,6 @@ -export enum PageType { - log = 'log', - annotation = 'annotation', -} +export const PageType = { + log: 'log', + annotation: 'annotation', +} as const + +export type PageType = (typeof PageType)[keyof typeof PageType] diff --git a/web/app/components/base/features/types.ts b/web/app/components/base/features/types.ts index 10b0e8e4128..e5007e0101e 100644 --- a/web/app/components/base/features/types.ts +++ b/web/app/components/base/features/types.ts @@ -32,10 +32,12 @@ type SensitiveWordAvoidance = EnabledOrDisabled & { config?: any } -export enum PreviewMode { - NewPage = 'new_page', - CurrentPage = 'current_page', -} +export const PreviewMode = { + NewPage: 'new_page', + CurrentPage: 'current_page', +} as const + +export type PreviewMode = (typeof PreviewMode)[keyof typeof PreviewMode] export type FileUpload = { image?: EnabledOrDisabled & { @@ -80,17 +82,19 @@ type AnnotationReplyConfig = { } } -export enum FeatureEnum { - moreLikeThis = 'moreLikeThis', - opening = 'opening', - suggested = 'suggested', - text2speech = 'text2speech', - speech2text = 'speech2text', - citation = 'citation', - moderation = 'moderation', - file = 'file', - annotationReply = 'annotationReply', -} +export const FeatureEnum = { + moreLikeThis: 'moreLikeThis', + opening: 'opening', + suggested: 'suggested', + text2speech: 'text2speech', + speech2text: 'speech2text', + citation: 'citation', + moderation: 'moderation', + file: 'file', + annotationReply: 'annotationReply', +} as const + +export type FeatureEnum = (typeof FeatureEnum)[keyof typeof FeatureEnum] export type Features = { [FeatureEnum.moreLikeThis]?: MoreLikeThis diff --git a/web/app/components/base/file-uploader/types.ts b/web/app/components/base/file-uploader/types.ts index 285023f0aff..84f5a0e906f 100644 --- a/web/app/components/base/file-uploader/types.ts +++ b/web/app/components/base/file-uploader/types.ts @@ -1,19 +1,22 @@ import type { TransferMethod } from '@/types/app' -export enum FileAppearanceTypeEnum { - image = 'image', - video = 'video', - audio = 'audio', - document = 'document', - code = 'code', - pdf = 'pdf', - markdown = 'markdown', - excel = 'excel', - word = 'word', - ppt = 'ppt', - gif = 'gif', - custom = 'custom', -} +export const FileAppearanceTypeEnum = { + image: 'image', + video: 'video', + audio: 'audio', + document: 'document', + code: 'code', + pdf: 'pdf', + markdown: 'markdown', + excel: 'excel', + word: 'word', + ppt: 'ppt', + gif: 'gif', + custom: 'custom', +} as const + +export type FileAppearanceTypeEnum = + (typeof FileAppearanceTypeEnum)[keyof typeof FileAppearanceTypeEnum] export type FileAppearanceType = keyof typeof FileAppearanceTypeEnum diff --git a/web/app/components/base/form/components/base/base-field.tsx b/web/app/components/base/form/components/base/base-field.tsx index fe0496d0375..8de915f833d 100644 --- a/web/app/components/base/form/components/base/base-field.tsx +++ b/web/app/components/base/form/components/base/base-field.tsx @@ -125,6 +125,13 @@ const BaseField = ({ onChange, fieldState, }: BaseFieldProps) => { + const inputFieldTypes: readonly FormTypeEnum[] = [ + FormTypeEnum.textInput, + FormTypeEnum.secretInput, + FormTypeEnum.textNumber, + ] + const textFieldTypes: readonly FormTypeEnum[] = [FormTypeEnum.textInput, FormTypeEnum.secretInput] + const renderI18nObject = useRenderI18nObject() const { t } = useTranslation() const { @@ -170,11 +177,7 @@ const BaseField = ({ } const isDynamicSelect = formItemType === FormTypeEnum.dynamicSelect const isSelect = formItemType === FormTypeEnum.select || isDynamicSelect - const isSingleControl = [ - FormTypeEnum.textInput, - FormTypeEnum.secretInput, - FormTypeEnum.textNumber, - ].includes(formItemType) + const isSingleControl = inputFieldTypes.includes(formItemType) const [ translatedLabel, @@ -320,7 +323,7 @@ const BaseField = ({ )}
- {[FormTypeEnum.textInput, FormTypeEnum.secretInput].includes(formItemType) && ( + {textFieldTypes.includes(formItemType) && ( { const shape: Record = {} fields.forEach((field) => { + const textFieldTypes: readonly BaseFieldType[] = [ + BaseFieldType.textInput, + BaseFieldType.paragraph, + ] + const numberFieldTypes: readonly BaseFieldType[] = [BaseFieldType.numberInput] + let zodType switch (field.type) { @@ -29,7 +35,7 @@ export const generateZodSchema = (fields: BaseConfiguration[]) => { } if (field.maxLength) { - if ([BaseFieldType.textInput, BaseFieldType.paragraph].includes(field.type)) + if (textFieldTypes.includes(field.type)) zodType = (zodType as ZodString).max( field.maxLength, `${field.label} exceeds max length of ${field.maxLength}`, @@ -37,7 +43,7 @@ export const generateZodSchema = (fields: BaseConfiguration[]) => { } if (field.min) { - if ([BaseFieldType.numberInput].includes(field.type)) + if (numberFieldTypes.includes(field.type)) zodType = (zodType as ZodNumber).min( field.min, `${field.label} must be at least ${field.min}`, @@ -45,7 +51,7 @@ export const generateZodSchema = (fields: BaseConfiguration[]) => { } if (field.max) { - if ([BaseFieldType.numberInput].includes(field.type)) + if (numberFieldTypes.includes(field.type)) zodType = (zodType as ZodNumber).max( field.max, `${field.label} exceeds max value of ${field.max}`, @@ -53,7 +59,7 @@ export const generateZodSchema = (fields: BaseConfiguration[]) => { } if (field.required) { - if ([BaseFieldType.textInput, BaseFieldType.paragraph].includes(field.type)) + if (textFieldTypes.includes(field.type)) zodType = (zodType as ZodString).nonempty(`${field.label} is required`) } else { zodType = zodType.optional().nullable() diff --git a/web/app/components/base/form/form-scenarios/input-field/types.ts b/web/app/components/base/form/form-scenarios/input-field/types.ts index 0d6820b3971..a7020f20f6f 100644 --- a/web/app/components/base/form/form-scenarios/input-field/types.ts +++ b/web/app/components/base/form/form-scenarios/input-field/types.ts @@ -1,17 +1,19 @@ import type { DeepKeys, FieldListeners } from '@tanstack/react-form' import type { NumberConfiguration, SelectConfiguration, ShowCondition } from '../base/types' -export enum InputFieldType { - textInput = 'textInput', - numberInput = 'numberInput', - numberSlider = 'numberSlider', - checkbox = 'checkbox', - options = 'options', - select = 'select', - inputTypeSelect = 'inputTypeSelect', - uploadMethod = 'uploadMethod', - fileTypes = 'fileTypes', -} +export const InputFieldType = { + textInput: 'textInput', + numberInput: 'numberInput', + numberSlider: 'numberSlider', + checkbox: 'checkbox', + options: 'options', + select: 'select', + inputTypeSelect: 'inputTypeSelect', + uploadMethod: 'uploadMethod', + fileTypes: 'fileTypes', +} as const + +export type InputFieldType = (typeof InputFieldType)[keyof typeof InputFieldType] type InputTypeSelectConfiguration = { supportFile: boolean diff --git a/web/app/components/base/form/types.ts b/web/app/components/base/form/types.ts index d93220ea3d4..e85c97ad6b7 100644 --- a/web/app/components/base/form/types.ts +++ b/web/app/components/base/form/types.ts @@ -13,22 +13,24 @@ type FormShowOnObject = { value: string } -export enum FormTypeEnum { - textInput = 'text-input', - textNumber = 'number-input', - secretInput = 'secret-input', - select = 'select', - radio = 'radio', - checkbox = 'checkbox', - files = 'files', - file = 'file', - modelSelector = 'model-selector', - toolSelector = 'tool-selector', - multiToolSelector = 'array[tools]', - appSelector = 'app-selector', - dynamicSelect = 'dynamic-select', - boolean = 'boolean', -} +export const FormTypeEnum = { + textInput: 'text-input', + textNumber: 'number-input', + secretInput: 'secret-input', + select: 'select', + radio: 'radio', + checkbox: 'checkbox', + files: 'files', + file: 'file', + modelSelector: 'model-selector', + toolSelector: 'tool-selector', + multiToolSelector: 'array[tools]', + appSelector: 'app-selector', + dynamicSelect: 'dynamic-select', + boolean: 'boolean', +} as const + +export type FormTypeEnum = (typeof FormTypeEnum)[keyof typeof FormTypeEnum] export type FormOption = { label: string | TypeWithI18N | Record @@ -39,12 +41,15 @@ export type FormOption = { type AnyValidators = FieldValidators -export enum FormItemValidateStatusEnum { - Success = 'success', - Warning = 'warning', - Error = 'error', - Validating = 'validating', -} +export const FormItemValidateStatusEnum = { + Success: 'success', + Warning: 'warning', + Error: 'error', + Validating: 'validating', +} as const + +export type FormItemValidateStatusEnum = + (typeof FormItemValidateStatusEnum)[keyof typeof FormItemValidateStatusEnum] export type FormSchema = { type: FormTypeEnum diff --git a/web/app/components/base/node-status/index.tsx b/web/app/components/base/node-status/index.tsx index ea200999653..e96dd4f3cdb 100644 --- a/web/app/components/base/node-status/index.tsx +++ b/web/app/components/base/node-status/index.tsx @@ -7,10 +7,12 @@ import { cva } from 'class-variance-authority' import * as React from 'react' import AlertTriangle from '@/app/components/base/icons/src/vender/solid/alertsAndFeedback/AlertTriangle' -export enum NodeStatusEnum { - warning = 'warning', - error = 'error', -} +export const NodeStatusEnum = { + warning: 'warning', + error: 'error', +} as const + +export type NodeStatusEnum = (typeof NodeStatusEnum)[keyof typeof NodeStatusEnum] const nodeStatusVariants = cva('flex items-center gap-1 rounded-md px-2 py-1 system-xs-medium', { variants: { diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/pre-populate.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/pre-populate.tsx index 2a87c122d89..4710d132c8f 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/pre-populate.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/pre-populate.tsx @@ -92,7 +92,8 @@ const PrePopulate: FC = ({ onChange: onValueSelectorChange!, readonly: false, filterVar: (varPayload: Var) => { - return [VarType.string, VarType.number, VarType.secret].includes(varPayload.type) + const textVariableTypes: readonly VarType[] = [VarType.string, VarType.number, VarType.secret] + return textVariableTypes.includes(varPayload.type) }, } diff --git a/web/app/components/base/voice-input/types.ts b/web/app/components/base/voice-input/types.ts index a221feb2d91..0b2adc99abd 100644 --- a/web/app/components/base/voice-input/types.ts +++ b/web/app/components/base/voice-input/types.ts @@ -9,12 +9,12 @@ export type SpeechToTextTarget = | { type: 'app' appId?: string - appSourceType: AppSourceType.webApp + appSourceType: typeof AppSourceType.webApp } | { type: 'app' appId: string - appSourceType: Exclude + appSourceType: Exclude } | { type: 'consoleApp' diff --git a/web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/hooks/use-dsl-import.ts b/web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/hooks/use-dsl-import.ts index 4737b6192fb..bcb9ada1cb2 100644 --- a/web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/hooks/use-dsl-import.ts +++ b/web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/hooks/use-dsl-import.ts @@ -8,10 +8,13 @@ import { DSLImportMode, DSLImportStatus } from '@/models/app' import { useRouter } from '@/next/navigation' import { useImportPipelineDSL, useImportPipelineDSLConfirm } from '@/service/use-pipeline' -export enum CreateFromDSLModalTab { - FROM_FILE = 'from-file', - FROM_URL = 'from-url', -} +export const CreateFromDSLModalTab = { + FROM_FILE: 'from-file', + FROM_URL: 'from-url', +} as const + +export type CreateFromDSLModalTab = + (typeof CreateFromDSLModalTab)[keyof typeof CreateFromDSLModalTab] type UseDSLImportOptions = { activeTab?: CreateFromDSLModalTab dslUrl?: string diff --git a/web/app/components/datasets/create-from-pipeline/list/template-card/details/types.ts b/web/app/components/datasets/create-from-pipeline/list/template-card/details/types.ts index ade8068510c..f1dd57f2801 100644 --- a/web/app/components/datasets/create-from-pipeline/list/template-card/details/types.ts +++ b/web/app/components/datasets/create-from-pipeline/list/template-card/details/types.ts @@ -1,11 +1,13 @@ import type { ReactNode } from 'react' -export enum EffectColor { - indigo = 'indigo', - blueLight = 'blue-light', - green = 'green', - none = 'none', -} +export const EffectColor = { + indigo: 'indigo', + blueLight: 'blue-light', + green: 'green', + none: 'none', +} as const + +export type EffectColor = (typeof EffectColor)[keyof typeof EffectColor] export type Option = { icon: ReactNode diff --git a/web/app/components/datasets/create/step-two/__tests__/index.spec.tsx b/web/app/components/datasets/create/step-two/__tests__/index.spec.tsx index cc03749fff2..53ac83a45b4 100644 --- a/web/app/components/datasets/create/step-two/__tests__/index.spec.tsx +++ b/web/app/components/datasets/create/step-two/__tests__/index.spec.tsx @@ -8,6 +8,7 @@ import type { CrawlOptions, CrawlResultItem, CustomFile, + DataSet, FileIndexingEstimateResponse, FullDocumentDetail, PreProcessingRule, @@ -42,7 +43,15 @@ import escape from '../hooks/escape' import unescape from '../hooks/unescape' import StepTwo from '../index' -const mockDataset = { +const mockDataset: Pick< + DataSet, + | 'id' + | 'doc_form' + | 'data_source_type' + | 'embedding_model' + | 'embedding_model_provider' + | 'retrieval_model_dict' +> = { id: 'test-dataset-id', doc_form: ChunkingMode.text, data_source_type: DataSourceType.FILE, diff --git a/web/app/components/datasets/create/step-two/hooks/use-indexing-config.ts b/web/app/components/datasets/create/step-two/hooks/use-indexing-config.ts index e87a337d1c6..7fba539f0c5 100644 --- a/web/app/components/datasets/create/step-two/hooks/use-indexing-config.ts +++ b/web/app/components/datasets/create/step-two/hooks/use-indexing-config.ts @@ -11,10 +11,12 @@ import { import { consoleQuery } from '@/service/console' import { RETRIEVE_METHOD } from '@/types/app' -export enum IndexingType { - QUALIFIED = 'high_quality', - ECONOMICAL = 'economy', -} +export const IndexingType = { + QUALIFIED: 'high_quality', + ECONOMICAL: 'economy', +} as const + +export type IndexingType = (typeof IndexingType)[keyof typeof IndexingType] const DEFAULT_RETRIEVAL_CONFIG: RetrievalConfig = { search_method: RETRIEVE_METHOD.semantic, diff --git a/web/app/components/datasets/create/step-two/index.tsx b/web/app/components/datasets/create/step-two/index.tsx index 18efe55e5e9..0c19a161e16 100644 --- a/web/app/components/datasets/create/step-two/index.tsx +++ b/web/app/components/datasets/create/step-two/index.tsx @@ -56,6 +56,8 @@ const StepTwo: FC = ({ onCancel, updateRetrievalMethodCache, }) => { + const generalChunkingModes: readonly ChunkingMode[] = [ChunkingMode.text, ChunkingMode.qa] + const { t } = useTranslation() const locale = useLocale() const isMobile = useBreakpoints() === MediaType.mobile @@ -256,7 +258,7 @@ const StepTwo: FC = ({ // Show options conditions const showGeneralOption = - (isInUpload && [ChunkingMode.text, ChunkingMode.qa].includes(currentDataset!.doc_form)) || + (isInUpload && generalChunkingModes.includes(currentDataset!.doc_form)) || isUploadInEmptyDataset || isInInit const showParentChildOption = @@ -280,7 +282,7 @@ const StepTwo: FC = ({ rules={segmentation.rules} currentDocForm={currentDocForm} docLanguage={docLanguage} - isActive={[ChunkingMode.text, ChunkingMode.qa].includes(currentDocForm)} + isActive={generalChunkingModes.includes(currentDocForm)} isInUpload={isInUpload} isNotUploadInEmptyDataset={isNotUploadInEmptyDataset} hasCurrentDatasetDocForm={!!currentDataset?.doc_form} diff --git a/web/app/components/datasets/documents/components/document-list/components/document-source-icon.tsx b/web/app/components/datasets/documents/components/document-list/components/document-source-icon.tsx index 5fd76db95cf..6a43e2edfe0 100644 --- a/web/app/components/datasets/documents/components/document-list/components/document-source-icon.tsx +++ b/web/app/components/datasets/documents/components/document-list/components/document-source-icon.tsx @@ -30,7 +30,7 @@ const isOnlineDocument = (dataSourceType: DataSourceType | DatasourceType) => { } const isWebsiteCrawl = (dataSourceType: DataSourceType | DatasourceType) => { - return dataSourceType === DatasourceType.websiteCrawl || dataSourceType === DataSourceType.WEB + return dataSourceType === DatasourceType.websiteCrawl } const isOnlineDrive = (dataSourceType: DataSourceType | DatasourceType) => { diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/__tests__/index.spec.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/__tests__/index.spec.tsx index 54a3f65b2d1..b0c26ac25c9 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/__tests__/index.spec.tsx +++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/__tests__/index.spec.tsx @@ -57,7 +57,18 @@ vi.mock('@/service/use-pipeline', () => ({ // Note: zustand/react/shallow useShallow is imported directly (simple utility function) -const mockStoreState = { +const mockStoreState: { + crawlResult: { data: CrawlResultItem[]; time_consuming: number | string } | undefined + step: CrawlStep + websitePages: CrawlResultItem[] + previewIndex: number + currentCredentialId: string + setWebsitePages: ReturnType + setCurrentWebsite: ReturnType + setPreviewIndex: ReturnType + setStep: ReturnType + setCrawlResult: ReturnType +} = { crawlResult: undefined as | { data: CrawlResultItem[]; time_consuming: number | string } | undefined, diff --git a/web/app/components/datasets/documents/create-from-pipeline/hooks/__tests__/use-datasource-actions.spec.ts b/web/app/components/datasets/documents/create-from-pipeline/hooks/__tests__/use-datasource-actions.spec.ts index 9f199fb3b59..3ad4b2e8ef2 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/hooks/__tests__/use-datasource-actions.spec.ts +++ b/web/app/components/datasets/documents/create-from-pipeline/hooks/__tests__/use-datasource-actions.spec.ts @@ -22,7 +22,9 @@ vi.mock('@/app/components/base/amplitude', () => ({ describe('useDatasourceActions', () => { let store: ReturnType - const defaultParams = () => ({ + const defaultParams = (): Parameters[0] & { + datasourceType: DatasourceType + } => ({ datasource: { nodeId: 'node-1', nodeData: { provider_type: DatasourceType.localFile }, diff --git a/web/app/components/datasets/documents/create-from-pipeline/types.tsx b/web/app/components/datasets/documents/create-from-pipeline/types.tsx index 06c7f7ae095..e4f106ae14a 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/types.tsx +++ b/web/app/components/datasets/documents/create-from-pipeline/types.tsx @@ -1,5 +1,5 @@ -export enum AddDocumentsStep { - dataSource = 'dataSource', - processDocuments = 'processDocuments', - processingDocuments = 'processingDocuments', -} +export const AddDocumentsStep = { + dataSource: 'dataSource', + processDocuments: 'processDocuments', + processingDocuments: 'processingDocuments', +} as const diff --git a/web/app/components/datasets/documents/detail/__tests__/new-segment.spec.tsx b/web/app/components/datasets/documents/detail/__tests__/new-segment.spec.tsx index a39adfedf6d..b8af9cf9587 100644 --- a/web/app/components/datasets/documents/detail/__tests__/new-segment.spec.tsx +++ b/web/app/components/datasets/documents/detail/__tests__/new-segment.spec.tsx @@ -17,7 +17,7 @@ const toastErrorSpy = vi.spyOn(toast, 'error') const toastSuccessSpy = vi.spyOn(toast, 'success') // Mock dataset detail context -let mockIndexingTechnique = IndexingType.QUALIFIED +let mockIndexingTechnique: IndexingType = IndexingType.QUALIFIED vi.mock('@/context/dataset-detail', () => ({ useDatasetDetailContextWithSelector: ( selector: (state: { dataset: { indexing_technique: string } }) => unknown, diff --git a/web/app/components/datasets/documents/detail/completed/__tests__/permission-transitions.spec.tsx b/web/app/components/datasets/documents/detail/completed/__tests__/permission-transitions.spec.tsx index 8991e15b3ab..d090e0306f7 100644 --- a/web/app/components/datasets/documents/detail/completed/__tests__/permission-transitions.spec.tsx +++ b/web/app/components/datasets/documents/detail/completed/__tests__/permission-transitions.spec.tsx @@ -29,7 +29,7 @@ const onUpdate = vi.fn() const content = '![image](/files/image-id/file-preview)' const signContent = '![image](/files/image-id/file-preview?timestamp=123&sign=signed)' -function detail(canEdit: boolean, docForm = ChunkingMode.text) { +function detail(canEdit: boolean, docForm: ChunkingMode = ChunkingMode.text) { return ( // oxlint-disable-next-line eslint-react/no-context-provider -- use-context-selector contexts are not React 19 context components. diff --git a/web/app/components/datasets/documents/detail/completed/__tests__/permissions.spec.tsx b/web/app/components/datasets/documents/detail/completed/__tests__/permissions.spec.tsx index 09f697a1768..e596021277e 100644 --- a/web/app/components/datasets/documents/detail/completed/__tests__/permissions.spec.tsx +++ b/web/app/components/datasets/documents/detail/completed/__tests__/permissions.spec.tsx @@ -90,7 +90,7 @@ vi.mock('@/app/components/datasets/common/image-uploader/image-uploader-in-chunk default: () => null, })) -function renderChunks(canEdit: boolean, docForm = ChunkingMode.text) { +function renderChunks(canEdit: boolean, docForm: ChunkingMode = ChunkingMode.text) { return render( // oxlint-disable-next-line eslint-react/no-context-provider -- use-context-selector contexts are not React 19 context components. ({ useDatasetDetailContextWithSelector: ( diff --git a/web/app/components/datasets/documents/detail/completed/__tests__/segment-list.spec.tsx b/web/app/components/datasets/documents/detail/completed/__tests__/segment-list.spec.tsx index 094f049c906..4f7c11b72fa 100644 --- a/web/app/components/datasets/documents/detail/completed/__tests__/segment-list.spec.tsx +++ b/web/app/components/datasets/documents/detail/completed/__tests__/segment-list.spec.tsx @@ -5,7 +5,7 @@ import { ChunkingMode } from '@/models/datasets' import SegmentList from '../segment-list' // Mock document context -let mockDocForm = ChunkingMode.text +let mockDocForm: ChunkingMode = ChunkingMode.text let mockParentMode = 'paragraph' vi.mock('../../context', () => ({ useDocumentContext: ( diff --git a/web/app/components/datasets/documents/detail/completed/segment-card/__tests__/index.spec.tsx b/web/app/components/datasets/documents/detail/completed/segment-card/__tests__/index.spec.tsx index 229ddbe4850..21fd0951e12 100644 --- a/web/app/components/datasets/documents/detail/completed/segment-card/__tests__/index.spec.tsx +++ b/web/app/components/datasets/documents/detail/completed/segment-card/__tests__/index.spec.tsx @@ -14,7 +14,7 @@ import SegmentCard from '../index' // Context Mocks - need to control test scenarios -const mockDocForm = { current: ChunkingMode.text } +const mockDocForm: { current: ChunkingMode } = { current: ChunkingMode.text } const mockParentMode = { current: 'paragraph' as ParentMode } const mockCanEdit = { current: true } diff --git a/web/app/components/datasets/metadata/metadata-dataset/create-content.tsx b/web/app/components/datasets/metadata/metadata-dataset/create-content.tsx index d0fae5241fd..ed89726e69d 100644 --- a/web/app/components/datasets/metadata/metadata-dataset/create-content.tsx +++ b/web/app/components/datasets/metadata/metadata-dataset/create-content.tsx @@ -20,7 +20,7 @@ export type Props = Readonly<{ export function CreateContent({ onClose = noop, hasBack, onBack, onSave }: Props) { const { t } = useTranslation() - const [type, setType] = useState(DataType.string) + const [type, setType] = useState(DataType.string) const handleTypeChange = useCallback( (newType: DataType) => { diff --git a/web/app/components/datasets/metadata/types.ts b/web/app/components/datasets/metadata/types.ts index 5545acb4007..f0d39a39aaa 100644 --- a/web/app/components/datasets/metadata/types.ts +++ b/web/app/components/datasets/metadata/types.ts @@ -1,8 +1,10 @@ -export enum DataType { - string = 'string', - number = 'number', - time = 'time', -} +export const DataType = { + string: 'string', + number: 'number', + time: 'time', +} as const + +export type DataType = (typeof DataType)[keyof typeof DataType] export type BuiltInMetadataItem = { type: DataType @@ -31,10 +33,12 @@ export type MetadataBatchEditToServer = { partial_update?: boolean }[] -export enum UpdateType { - changeValue = 'changeValue', - delete = 'delete', -} +export const UpdateType = { + changeValue: 'changeValue', + delete: 'delete', +} as const + +export type UpdateType = (typeof UpdateType)[keyof typeof UpdateType] export type MetadataItemWithEdit = MetadataItemWithValue & { isMultipleValue?: boolean diff --git a/web/app/components/datasets/settings/chunk-structure/types.ts b/web/app/components/datasets/settings/chunk-structure/types.ts index f92b24de47e..ba4d0eb2a91 100644 --- a/web/app/components/datasets/settings/chunk-structure/types.ts +++ b/web/app/components/datasets/settings/chunk-structure/types.ts @@ -1,11 +1,13 @@ import type { ChunkingMode } from '@/models/datasets' -export enum EffectColor { - indigo = 'indigo', - blueLight = 'blue-light', - orange = 'orange', - purple = 'purple', -} +export const EffectColor = { + indigo: 'indigo', + blueLight: 'blue-light', + orange: 'orange', + purple: 'purple', +} as const + +export type EffectColor = (typeof EffectColor)[keyof typeof EffectColor] export type Option = { id: ChunkingMode diff --git a/web/app/components/datasets/settings/form/components/__tests__/indexing-section.spec.tsx b/web/app/components/datasets/settings/form/components/__tests__/indexing-section.spec.tsx index b062556555b..fa32f68d14a 100644 --- a/web/app/components/datasets/settings/form/components/__tests__/indexing-section.spec.tsx +++ b/web/app/components/datasets/settings/form/components/__tests__/indexing-section.spec.tsx @@ -1,4 +1,5 @@ import type { ProviderWithModelsResponse } from '@dify/contracts/api/console/workspaces/types.gen' +import type { ComponentProps } from 'react' import type { DefaultModel } from '@/app/components/header/account-setting/model-provider-page/declarations' import type { DataSet, SummaryIndexSetting } from '@/models/datasets' import type { RetrievalConfig } from '@/types/app' @@ -241,7 +242,7 @@ describe('IndexingSection', () => { enable: false, } - const defaultProps = { + const defaultProps: ComponentProps = { currentDataset: mockDataset, indexMethod: IndexingType.QUALIFIED, setIndexMethod: vi.fn(), diff --git a/web/app/components/datasets/settings/form/components/indexing-section.tsx b/web/app/components/datasets/settings/form/components/indexing-section.tsx index bd0d69b5c2d..392f27f87e6 100644 --- a/web/app/components/datasets/settings/form/components/indexing-section.tsx +++ b/web/app/components/datasets/settings/form/components/indexing-section.tsx @@ -57,6 +57,11 @@ const IndexingSection = ({ showMultiModalTip, readonly = false, }: IndexingSectionProps) => { + const embeddingChunkingModes: readonly ChunkingMode[] = [ + ChunkingMode.text, + ChunkingMode.parentChild, + ] + const { t } = useTranslation() const { data: deploymentEdition } = useSuspenseQuery({ ...systemFeaturesQueryOptions(), @@ -77,9 +82,7 @@ const IndexingSection = ({ const showSummaryIndexSetting = indexMethod === IndexingType.QUALIFIED && - [ChunkingMode.text, ChunkingMode.parentChild].includes( - currentDataset?.doc_form as ChunkingMode, - ) && + embeddingChunkingModes.includes(currentDataset?.doc_form as ChunkingMode) && isNonCloudEdition return ( diff --git a/web/app/components/header/account-setting/model-provider-page/declarations.ts b/web/app/components/header/account-setting/model-provider-page/declarations.ts index 9f49e9a86a5..27bcd0b3b1a 100644 --- a/web/app/components/header/account-setting/model-provider-page/declarations.ts +++ b/web/app/components/header/account-setting/model-provider-page/declarations.ts @@ -8,27 +8,29 @@ export type TypeWithI18N = { [key: string]: T } -export enum FormTypeEnum { - textInput = 'text-input', - textNumber = 'number-input', - secretInput = 'secret-input', - select = 'select', - radio = 'radio', - checkbox = 'checkbox', - boolean = 'boolean', - files = 'files', - file = 'file', - modelSelector = 'model-selector', - toolSelector = 'tool-selector', - multiToolSelector = 'array[tools]', - appSelector = 'app-selector', - any = 'any', - object = 'object', - array = 'array', - dynamicSelect = 'dynamic-select', - date = 'date', - dateRange = 'date-range', -} +export const FormTypeEnum = { + textInput: 'text-input', + textNumber: 'number-input', + secretInput: 'secret-input', + select: 'select', + radio: 'radio', + checkbox: 'checkbox', + boolean: 'boolean', + files: 'files', + file: 'file', + modelSelector: 'model-selector', + toolSelector: 'tool-selector', + multiToolSelector: 'array[tools]', + appSelector: 'app-selector', + any: 'any', + object: 'object', + array: 'array', + dynamicSelect: 'dynamic-select', + date: 'date', + dateRange: 'date-range', +} as const + +export type FormTypeEnum = (typeof FormTypeEnum)[keyof typeof FormTypeEnum] export type FormOption = { label: TypeWithI18N @@ -37,14 +39,16 @@ export type FormOption = { icon?: string } -export enum ModelTypeEnum { - textGeneration = 'llm', - textEmbedding = 'text-embedding', - rerank = 'rerank', - speech2text = 'speech2text', - moderation = 'moderation', - tts = 'tts', -} +export const ModelTypeEnum = { + textGeneration: 'llm', + textEmbedding: 'text-embedding', + rerank: 'rerank', + speech2text: 'speech2text', + moderation: 'moderation', + tts: 'tts', +} as const + +export type ModelTypeEnum = (typeof ModelTypeEnum)[keyof typeof ModelTypeEnum] export const MODEL_TYPE_TEXT = { [ModelTypeEnum.textGeneration]: 'LLM', @@ -55,45 +59,55 @@ export const MODEL_TYPE_TEXT = { [ModelTypeEnum.tts]: 'TTS', } -export enum ConfigurationMethodEnum { - predefinedModel = 'predefined-model', - customizableModel = 'customizable-model', - fetchFromRemote = 'fetch-from-remote', -} +export const ConfigurationMethodEnum = { + predefinedModel: 'predefined-model', + customizableModel: 'customizable-model', + fetchFromRemote: 'fetch-from-remote', +} as const -export enum ModelFeatureEnum { - toolCall = 'tool-call', - multiToolCall = 'multi-tool-call', - agentThought = 'agent-thought', - streamToolCall = 'stream-tool-call', - vision = 'vision', - video = 'video', - document = 'document', - audio = 'audio', - polling = 'polling', - StructuredOutput = 'structured-output', -} +export type ConfigurationMethodEnum = + (typeof ConfigurationMethodEnum)[keyof typeof ConfigurationMethodEnum] -export enum ModelFeatureTextEnum { - vision = 'Vision', - video = 'Video', - document = 'Document', - audio = 'Audio', -} +export const ModelFeatureEnum = { + toolCall: 'tool-call', + multiToolCall: 'multi-tool-call', + agentThought: 'agent-thought', + streamToolCall: 'stream-tool-call', + vision: 'vision', + video: 'video', + document: 'document', + audio: 'audio', + polling: 'polling', + StructuredOutput: 'structured-output', +} as const -export enum ModelStatusEnum { - active = 'active', - noConfigure = 'no-configure', - quotaExceeded = 'quota-exceeded', - noPermission = 'no-permission', - disabled = 'disabled', - credentialRemoved = 'credential-removed', -} +export type ModelFeatureEnum = (typeof ModelFeatureEnum)[keyof typeof ModelFeatureEnum] -export enum CustomConfigurationStatusEnum { - active = 'active', - noConfigure = 'no-configure', -} +export const ModelFeatureTextEnum = { + vision: 'Vision', + video: 'Video', + document: 'Document', + audio: 'Audio', +} as const + +export const ModelStatusEnum = { + active: 'active', + noConfigure: 'no-configure', + quotaExceeded: 'quota-exceeded', + noPermission: 'no-permission', + disabled: 'disabled', + credentialRemoved: 'credential-removed', +} as const + +export type ModelStatusEnum = (typeof ModelStatusEnum)[keyof typeof ModelStatusEnum] + +export const CustomConfigurationStatusEnum = { + active: 'active', + noConfigure: 'no-configure', +} as const + +export type CustomConfigurationStatusEnum = + (typeof CustomConfigurationStatusEnum)[keyof typeof CustomConfigurationStatusEnum] type FormShowOnObject = { variable: string @@ -156,20 +170,28 @@ export type ModelItem = { has_invalid_load_balancing_configs?: boolean } -export enum PreferredProviderTypeEnum { - system = 'system', - custom = 'custom', -} +export const PreferredProviderTypeEnum = { + system: 'system', + custom: 'custom', +} as const -export enum CurrentSystemQuotaTypeEnum { - trial = 'trial', - free = 'free', - paid = 'paid', -} +export type PreferredProviderTypeEnum = + (typeof PreferredProviderTypeEnum)[keyof typeof PreferredProviderTypeEnum] -export enum QuotaUnitEnum { - times = 'times', -} +export const CurrentSystemQuotaTypeEnum = { + trial: 'trial', + free: 'free', + paid: 'paid', +} as const + +export type CurrentSystemQuotaTypeEnum = + (typeof CurrentSystemQuotaTypeEnum)[keyof typeof CurrentSystemQuotaTypeEnum] + +export const QuotaUnitEnum = { + times: 'times', +} as const + +export type QuotaUnitEnum = (typeof QuotaUnitEnum)[keyof typeof QuotaUnitEnum] type QuotaConfiguration = { quota_type: CurrentSystemQuotaTypeEnum @@ -320,9 +342,11 @@ export type ModelCredentialPayload = { credential_id?: string } -export enum ModelModalModeEnum { - configProviderCredential = 'config-provider-credential', - configCustomModel = 'config-custom-model', - addCustomModelToModelList = 'add-custom-model-to-model-list', - configModelCredential = 'config-model-credential', -} +export const ModelModalModeEnum = { + configProviderCredential: 'config-provider-credential', + configCustomModel: 'config-custom-model', + addCustomModelToModelList: 'add-custom-model-to-model-list', + configModelCredential: 'config-model-credential', +} as const + +export type ModelModalModeEnum = (typeof ModelModalModeEnum)[keyof typeof ModelModalModeEnum] diff --git a/web/app/components/header/account-setting/model-provider-page/model-selector/popup.tsx b/web/app/components/header/account-setting/model-provider-page/model-selector/popup.tsx index 7712cfbbee3..68d78f2250c 100644 --- a/web/app/components/header/account-setting/model-provider-page/model-selector/popup.tsx +++ b/web/app/components/header/account-setting/model-provider-page/model-selector/popup.tsx @@ -350,6 +350,11 @@ function ModelSelectorPreviewCard({ if (!payload) return null const { provider, modelItem } = payload + const modelTypesWithCapabilities: ModelTypeEnum[] = [ + ModelTypeEnum.textGeneration, + ModelTypeEnum.textEmbedding, + ModelTypeEnum.rerank, + ] return ( {sizeFormat(modelItem.model_properties.context_size as number)} )}
- {[ModelTypeEnum.textGeneration, ModelTypeEnum.textEmbedding, ModelTypeEnum.rerank].includes( - modelItem.model_type as ModelTypeEnum, - ) && + {modelTypesWithCapabilities.includes(modelItem.model_type as ModelTypeEnum) && modelItem.features?.some((feature) => [ ModelFeatureEnum.vision, diff --git a/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-list-item.tsx b/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-list-item.tsx index 89e8d5a529e..2802942530a 100644 --- a/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-list-item.tsx +++ b/web/app/components/header/account-setting/model-provider-page/provider-added-card/model-list-item.tsx @@ -51,6 +51,7 @@ const ModelListItem = ({ }), ) const workspacePermissionKeys = useAtomValue(workspacePermissionKeysAtom) + const configurableStatuses: ModelStatusEnum[] = [ModelStatusEnum.active, ModelStatusEnum.disabled] const canConfigureModels = hasPermission(workspacePermissionKeys, 'plugin.model_config') const queryClient = useQueryClient() const updateModelList = useUpdateModelList() @@ -140,7 +141,7 @@ const ModelListItem = ({ features?.model_load_balancing_enabled || features?.plan === 'sandbox') && !model.deprecated && - [ModelStatusEnum.active, ModelStatusEnum.disabled].includes(model.status) && ( + configurableStatuses.includes(model.status) && ( onModifyLoadBalancing?.(model)} loading={isLoadingLoadBalancing} @@ -170,7 +171,7 @@ const ModelListItem = ({ diff --git a/web/app/components/plugins/install-plugin/base/check-task-status.ts b/web/app/components/plugins/install-plugin/base/check-task-status.ts index 1a9c9a3f246..9206aa727a1 100644 --- a/web/app/components/plugins/install-plugin/base/check-task-status.ts +++ b/web/app/components/plugins/install-plugin/base/check-task-status.ts @@ -13,7 +13,7 @@ type Params = { } function checkTaskStatus() { - let nextStatus = TaskStatus.running + let nextStatus: TaskStatus = TaskStatus.running let isStop = false const doCheckStatus = async ({ taskId, pluginUniqueIdentifier }: Params) => { diff --git a/web/app/components/plugins/install-plugin/install-bundle/index.tsx b/web/app/components/plugins/install-plugin/install-bundle/index.tsx index 129205b6009..027fcb42b56 100644 --- a/web/app/components/plugins/install-plugin/install-bundle/index.tsx +++ b/web/app/components/plugins/install-plugin/install-bundle/index.tsx @@ -19,11 +19,13 @@ export type InstallBundleCompleteCallback = ( versionInfo: VersionProps[], ) => void -export enum InstallType { - fromLocal = 'fromLocal', - fromMarketplace = 'fromMarketplace', - fromDSL = 'fromDSL', -} +export const InstallType = { + fromLocal: 'fromLocal', + fromMarketplace: 'fromMarketplace', + fromDSL: 'fromDSL', +} as const + +export type InstallType = (typeof InstallType)[keyof typeof InstallType] type Props = Readonly<{ installType?: InstallType diff --git a/web/app/components/plugins/install-plugin/install-from-github/index.tsx b/web/app/components/plugins/install-plugin/install-from-github/index.tsx index 58745548189..89869b2304d 100644 --- a/web/app/components/plugins/install-plugin/install-from-github/index.tsx +++ b/web/app/components/plugins/install-plugin/install-from-github/index.tsx @@ -171,6 +171,16 @@ const InstallFromGitHub: React.FC = ({ }) } + const completedSteps: InstallStepFromGitHub[] = [ + InstallStepFromGitHub.uploadFailed, + InstallStepFromGitHub.installed, + InstallStepFromGitHub.installFailed, + ] + const failedSteps: InstallStepFromGitHub[] = [ + InstallStepFromGitHub.uploadFailed, + InstallStepFromGitHub.installFailed, + ] + return ( = ({ {getTitle()}
- {![ - InstallStepFromGitHub.uploadFailed, - InstallStepFromGitHub.installed, - InstallStepFromGitHub.installFailed, - ].includes(state.step) && + {!completedSteps.includes(state.step) && t(($) => $['installFromGitHub.installNote'], { ns: 'plugin' })}
- {[ - InstallStepFromGitHub.uploadFailed, - InstallStepFromGitHub.installed, - InstallStepFromGitHub.installFailed, - ].includes(state.step) ? ( + {completedSteps.includes(state.step) ? ( = ({ [onError, onStepChange, setIsInstalling], ) + const completedSteps: InstallStep[] = [ + InstallStep.uploadFailed, + InstallStep.installed, + InstallStep.installFailed, + ] + const failedSteps: InstallStep[] = [InstallStep.uploadFailed, InstallStep.installFailed] + return ( <> {step === InstallStep.readyToInstall && ( @@ -65,12 +72,10 @@ const ReadyToInstall: FC = ({ onStartToInstall={onStartToInstall} /> )} - {[InstallStep.uploadFailed, InstallStep.installed, InstallStep.installFailed].includes( - step, - ) && ( + {completedSteps.includes(step) && ( = ({ [setIsInstalling], ) + const completedSteps: InstallStep[] = [InstallStep.installed, InstallStep.installFailed] + return ( = ({ onTaskStarted={foldIntoTaskTrigger} /> )} - {[InstallStep.installed, InstallStep.installFailed].includes(step) && ( + {completedSteps.includes(step) && ( { - if ( - [ - PluginCategoryEnum.tool, - PluginCategoryEnum.agent, - PluginCategoryEnum.model, - PluginCategoryEnum.datasource, - PluginCategoryEnum.trigger, - ].includes(pluginType as PluginCategoryEnum) - ) + const marketplaceCategories: PluginCategoryEnum[] = [ + PluginCategoryEnum.tool, + PluginCategoryEnum.agent, + PluginCategoryEnum.model, + PluginCategoryEnum.datasource, + PluginCategoryEnum.trigger, + ] + if (marketplaceCategories.includes(pluginType as PluginCategoryEnum)) return `category=${pluginType}` if (pluginType === PluginCategoryEnum.extension) return 'category=endpoint' diff --git a/web/app/components/plugins/plugin-auth/types.ts b/web/app/components/plugins/plugin-auth/types.ts index d66d09a9eb8..201b78533d3 100644 --- a/web/app/components/plugins/plugin-auth/types.ts +++ b/web/app/components/plugins/plugin-auth/types.ts @@ -4,12 +4,14 @@ import type { PluginDetail } from '../types' export type { AddApiKeyButtonProps } from './authorize/add-api-key-button' export type { AddOAuthButtonProps } from './authorize/add-oauth-button' -export enum AuthCategory { - tool = 'tool', - datasource = 'datasource', - model = 'model', - trigger = 'trigger', -} +export const AuthCategory = { + tool: 'tool', + datasource: 'datasource', + model: 'model', + trigger: 'trigger', +} as const + +export type AuthCategory = (typeof AuthCategory)[keyof typeof AuthCategory] export type PluginPayload = { category: AuthCategory @@ -18,10 +20,12 @@ export type PluginPayload = { detail?: PluginDetail } -export enum CredentialTypeEnum { - OAUTH2 = 'oauth2', - API_KEY = 'api-key', -} +export const CredentialTypeEnum = { + OAUTH2: 'oauth2', + API_KEY: 'api-key', +} as const + +export type CredentialTypeEnum = (typeof CredentialTypeEnum)[keyof typeof CredentialTypeEnum] export type Credential = { id: string diff --git a/web/app/components/plugins/plugin-detail-panel/app-selector/hooks/use-app-inputs-form-schema.ts b/web/app/components/plugins/plugin-detail-panel/app-selector/hooks/use-app-inputs-form-schema.ts index de3fa4869a6..7e4551792b6 100644 --- a/web/app/components/plugins/plugin-detail-panel/app-selector/hooks/use-app-inputs-form-schema.ts +++ b/web/app/components/plugins/plugin-detail-panel/app-selector/hooks/use-app-inputs-form-schema.ts @@ -26,7 +26,10 @@ const BASIC_INPUT_TYPE_MAP: Record = { const FILE_INPUT_TYPES = new Set(['file-list', 'file']) -const WORKFLOW_FILE_VAR_TYPES = new Set([InputVarType.multiFiles, InputVarType.singleFile]) +const WORKFLOW_FILE_VAR_TYPES = new Set([ + InputVarType.multiFiles, + InputVarType.singleFile, +]) type InputSchemaItem = { label?: string diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/create/hooks/use-common-modal-state.ts b/web/app/components/plugins/plugin-detail-panel/subscription-list/create/hooks/use-common-modal-state.ts index 13be8852817..86c8aca415c 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/create/hooks/use-common-modal-state.ts +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/create/hooks/use-common-modal-state.ts @@ -37,10 +37,12 @@ import { // Types // ============================================================================ -export enum ApiKeyStep { - Verify = 'verify', - Configuration = 'configuration', -} +export const ApiKeyStep = { + Verify: 'verify', + Configuration: 'configuration', +} as const + +export type ApiKeyStep = (typeof ApiKeyStep)[keyof typeof ApiKeyStep] const CREDENTIAL_TYPE_MAP: Record = { [SupportedCreationMethods.APIKEY]: TriggerCredentialType.ApiKey, diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/create/types.ts b/web/app/components/plugins/plugin-detail-panel/subscription-list/create/types.ts index 637846b6064..52bcf5827f9 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/create/types.ts +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/create/types.ts @@ -1,6 +1,8 @@ -export enum CreateButtonType { - FULL_BUTTON = 'full-button', - ICON_BUTTON = 'icon-button', -} +export const CreateButtonType = { + FULL_BUTTON: 'full-button', + ICON_BUTTON: 'icon-button', +} as const + +export type CreateButtonType = (typeof CreateButtonType)[keyof typeof CreateButtonType] export const DEFAULT_METHOD = 'default' diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/log-viewer.tsx b/web/app/components/plugins/plugin-detail-panel/subscription-list/log-viewer.tsx index e80fa31f880..f01ad8eede3 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/log-viewer.tsx +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/log-viewer.tsx @@ -21,10 +21,12 @@ type Props = Readonly<{ className?: string }> -enum LogTypeEnum { - REQUEST = 'request', - RESPONSE = 'response', -} +const LogTypeEnum = { + REQUEST: 'request', + RESPONSE: 'response', +} as const + +type LogTypeEnum = (typeof LogTypeEnum)[keyof typeof LogTypeEnum] const LogViewer = ({ logs, className }: Props) => { const { t } = useTranslation() diff --git a/web/app/components/plugins/plugin-detail-panel/subscription-list/types.ts b/web/app/components/plugins/plugin-detail-panel/subscription-list/types.ts index adfda165477..80cb8eeb664 100644 --- a/web/app/components/plugins/plugin-detail-panel/subscription-list/types.ts +++ b/web/app/components/plugins/plugin-detail-panel/subscription-list/types.ts @@ -1,7 +1,9 @@ -export enum SubscriptionListMode { - PANEL = 'panel', - SELECTOR = 'selector', -} +export const SubscriptionListMode = { + PANEL: 'panel', + SELECTOR: 'selector', +} as const + +export type SubscriptionListMode = (typeof SubscriptionListMode)[keyof typeof SubscriptionListMode] export type SimpleSubscription = { id: string diff --git a/web/app/components/plugins/plugin-detail-panel/tool-selector/components/reasoning-config-form.helpers.ts b/web/app/components/plugins/plugin-detail-panel/tool-selector/components/reasoning-config-form.helpers.ts index 8500194112c..7cf92a4bb58 100644 --- a/web/app/components/plugins/plugin-detail-panel/tool-selector/components/reasoning-config-form.helpers.ts +++ b/web/app/components/plugins/plugin-detail-panel/tool-selector/components/reasoning-config-form.helpers.ts @@ -22,18 +22,16 @@ export type ReasoningConfigValue = Record export const getVarKindType = (type: string) => { if (type === FormTypeEnum.file || type === FormTypeEnum.files) return VarKindType.variable - if ( - [ - FormTypeEnum.select, - FormTypeEnum.checkbox, - FormTypeEnum.textNumber, - FormTypeEnum.array, - FormTypeEnum.object, - FormTypeEnum.date, - FormTypeEnum.dateRange, - ].includes(type as FormTypeEnum) - ) - return VarKindType.constant + const constantInputTypes: FormTypeEnum[] = [ + FormTypeEnum.select, + FormTypeEnum.checkbox, + FormTypeEnum.textNumber, + FormTypeEnum.array, + FormTypeEnum.object, + FormTypeEnum.date, + FormTypeEnum.dateRange, + ] + if (constantInputTypes.includes(type as FormTypeEnum)) return VarKindType.constant if (type === FormTypeEnum.textInput || type === FormTypeEnum.secretInput) return VarKindType.mixed @@ -61,11 +59,16 @@ export const createFilterVar = (type: string) => { type === FormTypeEnum.secretInput || type === FormTypeEnum.date ) - return (varPayload: Var) => - [VarType.string, VarType.number, VarType.secret].includes(varPayload.type) + return (varPayload: Var) => { + const textVarTypes: VarType[] = [VarType.string, VarType.number, VarType.secret] + return textVarTypes.includes(varPayload.type) + } if (type === FormTypeEnum.file || type === FormTypeEnum.files) - return (varPayload: Var) => [VarType.file, VarType.arrayFile].includes(varPayload.type) + return (varPayload: Var) => { + const fileVarTypes: VarType[] = [VarType.file, VarType.arrayFile] + return fileVarTypes.includes(varPayload.type) + } if (type === FormTypeEnum.checkbox) return (varPayload: Var) => varPayload.type === VarType.boolean @@ -73,10 +76,15 @@ export const createFilterVar = (type: string) => { if (type === FormTypeEnum.object) return (varPayload: Var) => varPayload.type === VarType.object if (type === FormTypeEnum.array) - return (varPayload: Var) => - [VarType.array, VarType.arrayString, VarType.arrayNumber, VarType.arrayObject].includes( - varPayload.type, - ) + return (varPayload: Var) => { + const arrayVarTypes: VarType[] = [ + VarType.array, + VarType.arrayString, + VarType.arrayNumber, + VarType.arrayObject, + ] + return arrayVarTypes.includes(varPayload.type) + } return undefined } diff --git a/web/app/components/plugins/plugin-item/index.tsx b/web/app/components/plugins/plugin-item/index.tsx index 41dff4feabe..cbb087c19c8 100644 --- a/web/app/components/plugins/plugin-item/index.tsx +++ b/web/app/components/plugins/plugin-item/index.tsx @@ -79,7 +79,8 @@ const PluginItem: FC = ({ const hasEndpointDeclaration = !!plugin.declaration.endpoint const orgName = useMemo(() => { - return [PluginSource.github, PluginSource.marketplace].includes(source) ? author : '' + const sourcesWithAuthor: PluginSource[] = [PluginSource.github, PluginSource.marketplace] + return sourcesWithAuthor.includes(source) ? author : '' }, [source, author]) const { data: currentVersion } = useSuspenseQuery({ diff --git a/web/app/components/plugins/reference-setting-modal/auto-update-setting/types.ts b/web/app/components/plugins/reference-setting-modal/auto-update-setting/types.ts index b734150b492..34e1f75c1f2 100644 --- a/web/app/components/plugins/reference-setting-modal/auto-update-setting/types.ts +++ b/web/app/components/plugins/reference-setting-modal/auto-update-setting/types.ts @@ -1,14 +1,18 @@ -export enum AUTO_UPDATE_STRATEGY { - fixOnly = 'fix_only', - disabled = 'disabled', - latest = 'latest', -} +export const AUTO_UPDATE_STRATEGY = { + fixOnly: 'fix_only', + disabled: 'disabled', + latest: 'latest', +} as const -export enum AUTO_UPDATE_MODE { - partial = 'partial', - exclude = 'exclude', - update_all = 'all', -} +export type AUTO_UPDATE_STRATEGY = (typeof AUTO_UPDATE_STRATEGY)[keyof typeof AUTO_UPDATE_STRATEGY] + +export const AUTO_UPDATE_MODE = { + partial: 'partial', + exclude: 'exclude', + update_all: 'all', +} as const + +export type AUTO_UPDATE_MODE = (typeof AUTO_UPDATE_MODE)[keyof typeof AUTO_UPDATE_MODE] export type AutoUpdateConfig = { strategy_setting: AUTO_UPDATE_STRATEGY diff --git a/web/app/components/plugins/types.ts b/web/app/components/plugins/types.ts index 6412894bd9a..87edd55b329 100644 --- a/web/app/components/plugins/types.ts +++ b/web/app/components/plugins/types.ts @@ -6,21 +6,25 @@ import type { ToolCredential } from '@/app/components/tools/types' import type { Locale } from '@/i18n/locale' import type { PluginLanguage } from '@/i18n/metadata' -export enum PluginCategoryEnum { - tool = 'tool', - model = 'model', - extension = 'extension', - agent = 'agent-strategy', - datasource = 'datasource', - trigger = 'trigger', -} +export const PluginCategoryEnum = { + tool: 'tool', + model: 'model', + extension: 'extension', + agent: 'agent-strategy', + datasource: 'datasource', + trigger: 'trigger', +} as const -export enum PluginSource { - marketplace = 'marketplace', - github = 'github', - local = 'package', - debugging = 'remote', -} +export type PluginCategoryEnum = (typeof PluginCategoryEnum)[keyof typeof PluginCategoryEnum] + +export const PluginSource = { + marketplace: 'marketplace', + github: 'github', + local: 'package', + debugging: 'remote', +} as const + +export type PluginSource = (typeof PluginSource)[keyof typeof PluginSource] type PluginToolDeclaration = { identity: { @@ -197,11 +201,14 @@ export type PluginManifestInMarket = { from: Dependency['type'] } -export enum SupportedCreationMethods { - OAUTH = 'OAUTH', - APIKEY = 'APIKEY', - MANUAL = 'MANUAL', -} +export const SupportedCreationMethods = { + OAUTH: 'OAUTH', + APIKEY: 'APIKEY', + MANUAL: 'MANUAL', +} as const + +export type SupportedCreationMethods = + (typeof SupportedCreationMethods)[keyof typeof SupportedCreationMethods] export type PluginDetail = { id: string @@ -264,11 +271,13 @@ export type Plugin = { from: Dependency['type'] } -export enum PermissionType { - everyone = 'everyone', - admin = 'admins', - noOne = 'noone', -} +export const PermissionType = { + everyone: 'everyone', + admin: 'admins', + noOne: 'noone', +} as const + +export type PermissionType = (typeof PermissionType)[keyof typeof PermissionType] export type Permissions = { install_permission: PermissionType @@ -314,14 +323,17 @@ export type UpdatePluginModalType = UpdatePluginPayload & { onSave: () => void | Promise } -export enum InstallStepFromGitHub { - setUrl = 'url', - selectPackage = 'selecting', - readyToInstall = 'readyToInstall', - uploadFailed = 'uploadFailed', - installed = 'installed', - installFailed = 'failed', -} +export const InstallStepFromGitHub = { + setUrl: 'url', + selectPackage: 'selecting', + readyToInstall: 'readyToInstall', + uploadFailed: 'uploadFailed', + installed: 'installed', + installFailed: 'failed', +} as const + +export type InstallStepFromGitHub = + (typeof InstallStepFromGitHub)[keyof typeof InstallStepFromGitHub] export type InstallState = { step: InstallStepFromGitHub @@ -345,14 +357,16 @@ export type EndpointsResponse = { total: number page: number } -export enum InstallStep { - uploading = 'uploading', - uploadFailed = 'uploadFailed', - readyToInstall = 'readyToInstall', - installing = 'installing', - installed = 'installed', - installFailed = 'failed', -} +export const InstallStep = { + uploading: 'uploading', + uploadFailed: 'uploadFailed', + readyToInstall: 'readyToInstall', + installing: 'installing', + installed: 'installed', + installFailed: 'failed', +} as const + +export type InstallStep = (typeof InstallStep)[keyof typeof InstallStep] type GitHubAsset = { id: number @@ -400,12 +414,14 @@ export type DebugInfo = { port: number } -export enum TaskStatus { - pending = 'pending', - running = 'running', - success = 'success', - failed = 'failed', -} +export const TaskStatus = { + pending: 'pending', + running: 'running', + success: 'success', + failed: 'failed', +} as const + +export type TaskStatus = (typeof TaskStatus)[keyof typeof TaskStatus] export type PluginStatus = { plugin_unique_identifier: string diff --git a/web/app/components/rag-pipeline/components/panel/input-field/editor/form/hooks.ts b/web/app/components/rag-pipeline/components/panel/input-field/editor/form/hooks.ts index 648c8f01c2f..bd3450409fb 100644 --- a/web/app/components/rag-pipeline/components/panel/input-field/editor/form/hooks.ts +++ b/web/app/components/rag-pipeline/components/panel/input-field/editor/form/hooks.ts @@ -76,7 +76,12 @@ export const useConfigurations = (props: { const handleTypeChange = useCallback( (type: PipelineInputVarType) => { - if ([PipelineInputVarType.singleFile, PipelineInputVarType.multiFiles].includes(type)) { + const fileInputTypes: readonly PipelineInputVarType[] = [ + PipelineInputVarType.singleFile, + PipelineInputVarType.multiFiles, + ] + + if (fileInputTypes.includes(type)) { setFieldValue( 'allowedFileUploadMethods', DEFAULT_FILE_UPLOAD_SETTING.allowed_file_upload_methods, diff --git a/web/app/components/rag-pipeline/hooks/use-input-fields.ts b/web/app/components/rag-pipeline/hooks/use-input-fields.ts index dfa27771c2c..12b6950a767 100644 --- a/web/app/components/rag-pipeline/hooks/use-input-fields.ts +++ b/web/app/components/rag-pipeline/hooks/use-input-fields.ts @@ -11,15 +11,23 @@ export const useInitialData = ( const initialData = useMemo(() => { return variables.reduce( (acc, item) => { + const stringFieldTypes: readonly BaseFieldType[] = [ + BaseFieldType.textInput, + BaseFieldType.paragraph, + BaseFieldType.select, + ] + const fileFieldTypes: readonly BaseFieldType[] = [ + BaseFieldType.file, + BaseFieldType.fileList, + ] + const type = VAR_TYPE_MAP[item.type] const variableName = item.variable const defaultValue = lastRunInputData?.[variableName] || item.default_value - if ([BaseFieldType.textInput, BaseFieldType.paragraph, BaseFieldType.select].includes(type)) - acc[variableName] = defaultValue ?? '' + if (stringFieldTypes.includes(type)) acc[variableName] = defaultValue ?? '' if (type === BaseFieldType.numberInput) acc[variableName] = defaultValue ?? 0 if (type === BaseFieldType.checkbox) acc[variableName] = defaultValue ?? false - if ([BaseFieldType.file, BaseFieldType.fileList].includes(type)) - acc[variableName] = defaultValue ?? [] + if (fileFieldTypes.includes(type)) acc[variableName] = defaultValue ?? [] return acc }, {} as Record, diff --git a/web/app/components/share/text-generation/hooks/use-text-generation-batch.ts b/web/app/components/share/text-generation/hooks/use-text-generation-batch.ts index bfd8ecf4805..c2429d7d4dc 100644 --- a/web/app/components/share/text-generation/hooks/use-text-generation-batch.ts +++ b/web/app/components/share/text-generation/hooks/use-text-generation-batch.ts @@ -232,9 +232,10 @@ export const useTextGenerationBatch = ({ const pendingTaskList = latestTaskList.filter((task) => task.status === TaskStatus.pending) const runTasksCount = 1 + - latestTaskList.filter((task) => - [TaskStatus.completed, TaskStatus.failed].includes(task.status), - ).length + latestTaskList.filter((task) => { + const finishedStatuses: readonly TaskStatus[] = [TaskStatus.completed, TaskStatus.failed] + return finishedStatuses.includes(task.status) + }).length const shouldStartNextGroup = currGroupNumRef.current !== runTasksCount && pendingTaskList.length > 0 && @@ -271,9 +272,10 @@ export const useTextGenerationBatch = ({ const allSuccessTaskList = allTaskList.filter((task) => task.status === TaskStatus.completed) const allFailedTaskList = allTaskList.filter((task) => task.status === TaskStatus.failed) const allTasksFinished = allTaskList.every((task) => task.status === TaskStatus.completed) - const allTasksRun = allTaskList.every((task) => - [TaskStatus.completed, TaskStatus.failed].includes(task.status), - ) + const allTasksRun = allTaskList.every((task) => { + const finishedStatuses: readonly TaskStatus[] = [TaskStatus.completed, TaskStatus.failed] + return finishedStatuses.includes(task.status) + }) const exportRes = useMemo(() => { return allTaskList.map((task) => { diff --git a/web/app/components/share/text-generation/result/workflow-stream-handlers.ts b/web/app/components/share/text-generation/result/workflow-stream-handlers.ts index 7ab402aba93..f73c8fc3082 100644 --- a/web/app/components/share/text-generation/result/workflow-stream-handlers.ts +++ b/web/app/components/share/text-generation/result/workflow-stream-handlers.ts @@ -134,11 +134,12 @@ const markNodesStopped = (traces?: WorkflowProcess['tracing']) => { if (!traces) return const markTrace = (trace: WorkflowProcess['tracing'][number]) => { - if ( - [NodeRunningStatus.Running, NodeRunningStatus.Waiting].includes( - trace.status as NodeRunningStatus, - ) - ) + const unfinishedStatuses: readonly NodeRunningStatus[] = [ + NodeRunningStatus.Running, + NodeRunningStatus.Waiting, + ] + + if (unfinishedStatuses.includes(trace.status as NodeRunningStatus)) trace.status = NodeRunningStatus.Stopped trace.details?.forEach((detailGroup) => detailGroup.forEach(markTrace)) @@ -155,10 +156,14 @@ const applyWorkflowFinishedState = ( error?: string, ) => { return updateWorkflowProcess(current, (draft) => { + const errorStatuses: readonly WorkflowRunningStatus[] = [ + WorkflowRunningStatus.Stopped, + WorkflowRunningStatus.Failed, + ] + draft.status = status draft.error = error - if ([WorkflowRunningStatus.Stopped, WorkflowRunningStatus.Failed].includes(status)) - markNodesStopped(draft.tracing) + if (errorStatuses.includes(status)) markNodesStopped(draft.tracing) }) } diff --git a/web/app/components/share/text-generation/types.ts b/web/app/components/share/text-generation/types.ts index c25e1504bb1..17aa43c57a0 100644 --- a/web/app/components/share/text-generation/types.ts +++ b/web/app/components/share/text-generation/types.ts @@ -16,12 +16,14 @@ export type Task = { params: TaskParam } -export enum TaskStatus { - pending = 'pending', - running = 'running', - completed = 'completed', - failed = 'failed', -} +export const TaskStatus = { + pending: 'pending', + running: 'running', + completed: 'completed', + failed: 'failed', +} as const + +export type TaskStatus = (typeof TaskStatus)[keyof typeof TaskStatus] export type InputValueTypes = | string diff --git a/web/app/components/snippets/components/snippet-main.tsx b/web/app/components/snippets/components/snippet-main.tsx index 632f5a42a39..37c2946ed4e 100644 --- a/web/app/components/snippets/components/snippet-main.tsx +++ b/web/app/components/snippets/components/snippet-main.tsx @@ -51,7 +51,7 @@ type SnippetMainContentProps = { onSaved: (syncedDraftPayload?: Omit | void) => void } -const unsupportedSnippetBlockTypes = new Set([ +const unsupportedSnippetBlockTypes = new Set([ BlockEnum.HumanInput, BlockEnum.End, BlockEnum.KnowledgeRetrieval, diff --git a/web/app/components/tools/mcp/hooks/use-mcp-modal-form.ts b/web/app/components/tools/mcp/hooks/use-mcp-modal-form.ts index e49609fcc87..a14f8e04236 100644 --- a/web/app/components/tools/mcp/hooks/use-mcp-modal-form.ts +++ b/web/app/components/tools/mcp/hooks/use-mcp-modal-form.ts @@ -102,7 +102,7 @@ export const useMCPModalForm = (data?: ToolWithProvider) => { const [isFetchingIcon, setIsFetchingIcon] = useState(false) const appIconRef = useRef(null) // Auth state - const [authMethod, setAuthMethod] = useState(MCPAuthMethod.authentication) + const [authMethod, setAuthMethod] = useState(MCPAuthMethod.authentication) const [isDynamicRegistration, setIsDynamicRegistration] = useState(() => isCreate ? true : (data?.is_dynamic_registration ?? true), ) diff --git a/web/app/components/tools/types.ts b/web/app/components/tools/types.ts index 210dd6c8770..22884c21803 100644 --- a/web/app/components/tools/types.ts +++ b/web/app/components/tools/types.ts @@ -10,18 +10,22 @@ type LocalizedText = { [key: string]: T } -export enum AuthType { - none = 'none', - apiKey = 'api_key', // backward compatibility - apiKeyHeader = 'api_key_header', - apiKeyQuery = 'api_key_query', -} +export const AuthType = { + none: 'none', + apiKey: 'api_key', // backward compatibility + apiKeyHeader: 'api_key_header', + apiKeyQuery: 'api_key_query', +} as const -export enum AuthHeaderPrefix { - basic = 'basic', - bearer = 'bearer', - custom = 'custom', -} +export type AuthType = (typeof AuthType)[keyof typeof AuthType] + +export const AuthHeaderPrefix = { + basic: 'basic', + bearer: 'bearer', + custom: 'custom', +} as const + +export type AuthHeaderPrefix = (typeof AuthHeaderPrefix)[keyof typeof AuthHeaderPrefix] export type Credential = { auth_type: AuthType @@ -279,8 +283,10 @@ export type MCPServerDetail = { headers?: Record } -export enum MCPAuthMethod { - authentication = 'authentication', - headers = 'headers', - configurations = 'configurations', -} +export const MCPAuthMethod = { + authentication: 'authentication', + headers: 'headers', + configurations: 'configurations', +} as const + +export type MCPAuthMethod = (typeof MCPAuthMethod)[keyof typeof MCPAuthMethod] diff --git a/web/app/components/workflow-app/hooks/use-workflow-run-utils.ts b/web/app/components/workflow-app/hooks/use-workflow-run-utils.ts index dd85dacec26..552b3eaab61 100644 --- a/web/app/components/workflow-app/hooks/use-workflow-run-utils.ts +++ b/web/app/components/workflow-app/hooks/use-workflow-run-utils.ts @@ -20,7 +20,7 @@ export type HandleRunOptions = { allNodeIds?: string[] } -type DebuggableTriggerType = Exclude +type DebuggableTriggerType = Exclude type AppDetailLike = { id?: string diff --git a/web/app/components/workflow/__tests__/fixtures.ts b/web/app/components/workflow/__tests__/fixtures.ts index 05958e015d6..1fa4a1ab294 100644 --- a/web/app/components/workflow/__tests__/fixtures.ts +++ b/web/app/components/workflow/__tests__/fixtures.ts @@ -59,9 +59,9 @@ export function createNodeDataFactory, 'data'> & { data?: Partial & Record } = {}, diff --git a/web/app/components/workflow/block-selector/index.tsx b/web/app/components/workflow/block-selector/index.tsx index 84b2f0fd9f7..4a20ff0840e 100644 --- a/web/app/components/workflow/block-selector/index.tsx +++ b/web/app/components/workflow/block-selector/index.tsx @@ -266,7 +266,7 @@ export function BlockSelectorContent({ if (blocksFromProps) return blocksFromProps return (availableNodesMetaData?.nodes ?? []).filter((block) => { - return ![ + const excludedBlockTypes: readonly BlockEnum[] = [ BlockEnum.Start, BlockEnum.StartPlaceholder, BlockEnum.DataSource, @@ -274,7 +274,9 @@ export function BlockSelectorContent({ BlockEnum.IterationStart, BlockEnum.LoopStart, BlockEnum.DataSourceEmpty, - ].includes(block.metaData.type) + ] + + return !excludedBlockTypes.includes(block.metaData.type) }) }, [availableNodesMetaData?.nodes, blocksFromProps]) const dataSources = dataSourcesFromProps ?? fallbackDataSources ?? [] diff --git a/web/app/components/workflow/block-selector/use-sticky-scroll.ts b/web/app/components/workflow/block-selector/use-sticky-scroll.ts index ad3f0be8762..895dc87ef06 100644 --- a/web/app/components/workflow/block-selector/use-sticky-scroll.ts +++ b/web/app/components/workflow/block-selector/use-sticky-scroll.ts @@ -1,11 +1,13 @@ import { useThrottleFn } from 'ahooks' import * as React from 'react' -export enum ScrollPosition { - belowTheWrap = 'belowTheWrap', - showing = 'showing', - aboveTheWrap = 'aboveTheWrap', -} +export const ScrollPosition = { + belowTheWrap: 'belowTheWrap', + showing: 'showing', + aboveTheWrap: 'aboveTheWrap', +} as const + +export type ScrollPosition = (typeof ScrollPosition)[keyof typeof ScrollPosition] type Params = { wrapElemRef: React.RefObject diff --git a/web/app/components/workflow/comment/cursor.spec.tsx b/web/app/components/workflow/comment/cursor.spec.tsx index b393b7911a2..a70547336a3 100644 --- a/web/app/components/workflow/comment/cursor.spec.tsx +++ b/web/app/components/workflow/comment/cursor.spec.tsx @@ -3,7 +3,11 @@ import { beforeEach, describe, expect, it, vi } from 'vite-plus/test' import { ControlMode } from '../types' import { CommentCursor } from './cursor' -const mockState = { +const mockState: { + controlMode: ControlMode + isCommentPlacing: boolean + mousePosition: { elementX: number; elementY: number } +} = { controlMode: ControlMode.Pointer, isCommentPlacing: false, mousePosition: { diff --git a/web/app/components/workflow/constants.ts b/web/app/components/workflow/constants.ts index a73227662f0..6d1fd2745ac 100644 --- a/web/app/components/workflow/constants.ts +++ b/web/app/components/workflow/constants.ts @@ -100,7 +100,7 @@ export const RETRIEVAL_OUTPUT_STRUCT = `{ } }` -export const SUPPORT_OUTPUT_VARS_NODE = [ +export const SUPPORT_OUTPUT_VARS_NODE: BlockEnum[] = [ BlockEnum.Start, BlockEnum.TriggerWebhook, BlockEnum.TriggerPlugin, diff --git a/web/app/components/workflow/header/test-run-menu.tsx b/web/app/components/workflow/header/test-run-menu.tsx index 78785973f60..67f43661350 100644 --- a/web/app/components/workflow/header/test-run-menu.tsx +++ b/web/app/components/workflow/header/test-run-menu.tsx @@ -18,13 +18,15 @@ import { import { useTranslation } from 'react-i18next' import { OptionRow, SingleOptionTrigger, useShortcutMenu } from './test-run-menu-helpers' -export enum TriggerType { - UserInput = 'user_input', - Schedule = 'schedule', - Webhook = 'webhook', - Plugin = 'plugin', - All = 'all', -} +export const TriggerType = { + UserInput: 'user_input', + Schedule: 'schedule', + Webhook: 'webhook', + Plugin: 'plugin', + All: 'all', +} as const + +export type TriggerType = (typeof TriggerType)[keyof typeof TriggerType] export type TriggerOption = { id: string diff --git a/web/app/components/workflow/header/view-history.tsx b/web/app/components/workflow/header/view-history.tsx index 52e4886387e..21b1adbc7fd 100644 --- a/web/app/components/workflow/header/view-history.tsx +++ b/web/app/components/workflow/header/view-history.tsx @@ -118,56 +118,59 @@ const ViewHistory = ({ withText, onClearLogAndMessageModal, historyUrl }: ViewHi )} - {data?.data.map((item) => ( -
{ - workflowStore.setState({ - historyWorkflowData: item, - showInputsPanel: false, - showEnvPanel: false, - }) - closeAllInputFieldPanels() - handleBackupDraft() - setOpen(false) - handleNodesCancelSelected() - handleCancelDebugAndPreviewPanel() - setControlMode(ControlMode.Hand) - }} - > - {!isChatMode && - [WorkflowRunningStatus.Stopped, WorkflowRunningStatus.Paused].includes( - item.status, - ) && ( + {data?.data.map((item) => { + const interruptedStatuses: readonly WorkflowRunningStatus[] = [ + WorkflowRunningStatus.Stopped, + WorkflowRunningStatus.Paused, + ] + return ( +
{ + workflowStore.setState({ + historyWorkflowData: item, + showInputsPanel: false, + showEnvPanel: false, + }) + closeAllInputFieldPanels() + handleBackupDraft() + setOpen(false) + handleNodesCancelSelected() + handleCancelDebugAndPreviewPanel() + setControlMode(ControlMode.Hand) + }} + > + {!isChatMode && interruptedStatuses.includes(item.status) && ( )} - {!isChatMode && item.status === WorkflowRunningStatus.Failed && ( - - )} - {!isChatMode && item.status === WorkflowRunningStatus.Succeeded && ( - - )} -
-
- {`Test ${isChatMode ? 'Chat' : 'Run'}${formatWorkflowRunIdentifier(item.finished_at, item.status)}`} -
-
- {item.created_by_account?.name} · - {formatTimeFromNow((item.finished_at || item.created_at) * 1000)} + {!isChatMode && item.status === WorkflowRunningStatus.Failed && ( + + )} + {!isChatMode && item.status === WorkflowRunningStatus.Succeeded && ( + + )} +
+
+ {`Test ${isChatMode ? 'Chat' : 'Run'}${formatWorkflowRunIdentifier(item.finished_at, item.status)}`} +
+
+ {item.created_by_account?.name} · + {formatTimeFromNow((item.finished_at || item.created_at) * 1000)} +
-
- ))} + ) + })}
)}
diff --git a/web/app/components/workflow/hooks/__tests__/use-nodes-interactions.spec.ts b/web/app/components/workflow/hooks/__tests__/use-nodes-interactions.spec.ts index 2d2353b6971..5f1c24262b7 100644 --- a/web/app/components/workflow/hooks/__tests__/use-nodes-interactions.spec.ts +++ b/web/app/components/workflow/hooks/__tests__/use-nodes-interactions.spec.ts @@ -1205,7 +1205,7 @@ describe('useNodesInteractions', () => { }) const pasteNodeIntoContainer = async ( - containerType: BlockEnum.Iteration | BlockEnum.Loop, + containerType: typeof BlockEnum.Iteration | typeof BlockEnum.Loop, nodeType: BlockEnum, ) => { runtimeNodesMetaDataMap.value = { diff --git a/web/app/components/workflow/hooks/use-nodes-interactions.ts b/web/app/components/workflow/hooks/use-nodes-interactions.ts index 1a52451f33f..bfc2fe05d4f 100644 --- a/web/app/components/workflow/hooks/use-nodes-interactions.ts +++ b/web/app/components/workflow/hooks/use-nodes-interactions.ts @@ -1780,7 +1780,7 @@ export const useNodesInteractions = () => { const selectedNodes = nodes.filter((node) => node.selected) // Keep this list aligned with availableBlocksFilter(inContainer) // in use-available-blocks.ts. - const commonNestedDisallowPasteNodes = [ + const commonNestedDisallowPasteNodes: BlockEnum[] = [ BlockEnum.End, BlockEnum.Iteration, BlockEnum.Loop, diff --git a/web/app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx b/web/app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx index 129b3c3a3c9..c53f4974328 100644 --- a/web/app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx +++ b/web/app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx @@ -52,6 +52,11 @@ const FormItem: FC = ({ autoFocus, inStepRun = false, }) => { + const collectionInputTypes: readonly InputVarType[] = [ + InputVarType.contexts, + InputVarType.iterator, + ] + const { t } = useTranslation() const labelId = React.useId() const { type } = payload @@ -124,7 +129,7 @@ const FormItem: FC = ({ })() const isBooleanType = type === InputVarType.checkbox - const isArrayLikeType = [InputVarType.contexts, InputVarType.iterator].includes(type) + const isArrayLikeType = collectionInputTypes.includes(type) const isContext = type === InputVarType.contexts const isIterator = type === InputVarType.iterator const isIteratorItemFile = isIterator && payload.isFileItem diff --git a/web/app/components/workflow/nodes/_base/components/before-run-form/form.tsx b/web/app/components/workflow/nodes/_base/components/before-run-form/form.tsx index 2bdaf5528d1..b6e74dc0ae0 100644 --- a/web/app/components/workflow/nodes/_base/components/before-run-form/form.tsx +++ b/web/app/components/workflow/nodes/_base/components/before-run-form/form.tsx @@ -19,6 +19,11 @@ export type Props = Readonly<{ }> const Form: FC = ({ className, label, inputs, values, onChange }) => { + const collectionInputTypes: readonly InputVarType[] = [ + InputVarType.contexts, + InputVarType.iterator, + ] + const { t } = useTranslation() const mapKeysWithSameValueSelector = useMemo(() => { const keysWithSameValueSelector = (key: string) => { @@ -54,7 +59,7 @@ const Form: FC = ({ className, label, inputs, values, onChange }) => { }, [valuesRef, onChange, mapKeysWithSameValueSelector], ) - const isArrayLikeType = [InputVarType.contexts, InputVarType.iterator].includes(inputs[0]?.type!) + const isArrayLikeType = collectionInputTypes.includes(inputs[0]?.type!) const isIteratorItemFile = inputs[0]?.type === InputVarType.iterator && inputs[0]?.isFileItem const isContext = inputs[0]?.type === InputVarType.contexts diff --git a/web/app/components/workflow/nodes/_base/components/config-vision.tsx b/web/app/components/workflow/nodes/_base/components/config-vision.tsx index aa1155ddcf9..0dc2c4d395a 100644 --- a/web/app/components/workflow/nodes/_base/components/config-vision.tsx +++ b/web/app/components/workflow/nodes/_base/components/config-vision.tsx @@ -40,7 +40,9 @@ const ConfigVision: FC = ({ const { t } = useTranslation() const filterVar = useCallback((payload: Var) => { - return [VarType.file, VarType.arrayFile].includes(payload.type) + const fileVariableTypes: readonly VarType[] = [VarType.file, VarType.arrayFile] + + return fileVariableTypes.includes(payload.type) }, []) const handleVisionResolutionChange = useCallback( (resolution: Resolution) => { diff --git a/web/app/components/workflow/nodes/_base/components/entry-node-container.tsx b/web/app/components/workflow/nodes/_base/components/entry-node-container.tsx index 53528b65ef9..cd38785bca4 100644 --- a/web/app/components/workflow/nodes/_base/components/entry-node-container.tsx +++ b/web/app/components/workflow/nodes/_base/components/entry-node-container.tsx @@ -2,10 +2,12 @@ import type { FC, ReactNode } from 'react' import { useMemo } from 'react' import { useTranslation } from 'react-i18next' -export enum StartNodeTypeEnum { - Start = 'start', - Trigger = 'trigger', -} +export const StartNodeTypeEnum = { + Start: 'start', + Trigger: 'trigger', +} as const + +export type StartNodeTypeEnum = (typeof StartNodeTypeEnum)[keyof typeof StartNodeTypeEnum] type EntryNodeContainerProps = { children: ReactNode diff --git a/web/app/components/workflow/nodes/_base/components/error-handle/types.ts b/web/app/components/workflow/nodes/_base/components/error-handle/types.ts index 29493641b0b..d11341022d5 100644 --- a/web/app/components/workflow/nodes/_base/components/error-handle/types.ts +++ b/web/app/components/workflow/nodes/_base/components/error-handle/types.ts @@ -1,10 +1,12 @@ import type { VarType } from '@/app/components/workflow/types' -export enum ErrorHandleTypeEnum { - none = 'none', - failBranch = 'fail-branch', - defaultValue = 'default-value', -} +export const ErrorHandleTypeEnum = { + none: 'none', + failBranch: 'fail-branch', + defaultValue: 'default-value', +} as const + +export type ErrorHandleTypeEnum = (typeof ErrorHandleTypeEnum)[keyof typeof ErrorHandleTypeEnum] export type DefaultValueForm = { key: string diff --git a/web/app/components/workflow/nodes/_base/components/file-type-item.tsx b/web/app/components/workflow/nodes/_base/components/file-type-item.tsx index 2d707b0850f..890e0376ccc 100644 --- a/web/app/components/workflow/nodes/_base/components/file-type-item.tsx +++ b/web/app/components/workflow/nodes/_base/components/file-type-item.tsx @@ -13,11 +13,11 @@ import { SupportUploadFileTypes } from '../../../types' type Props = Readonly<{ type: - | SupportUploadFileTypes.image - | SupportUploadFileTypes.document - | SupportUploadFileTypes.audio - | SupportUploadFileTypes.video - | SupportUploadFileTypes.custom + | typeof SupportUploadFileTypes.image + | typeof SupportUploadFileTypes.document + | typeof SupportUploadFileTypes.audio + | typeof SupportUploadFileTypes.video + | typeof SupportUploadFileTypes.custom selected: boolean onToggle: (type: SupportUploadFileTypes) => void onCustomFileTypesChange?: (customFileTypes: string[]) => void diff --git a/web/app/components/workflow/nodes/_base/components/file-upload-setting.tsx b/web/app/components/workflow/nodes/_base/components/file-upload-setting.tsx index face9c3e887..edd8dc71600 100644 --- a/web/app/components/workflow/nodes/_base/components/file-upload-setting.tsx +++ b/web/app/components/workflow/nodes/_base/components/file-upload-setting.tsx @@ -149,10 +149,10 @@ const FileUploadSetting: FC = ({ key={type} type={ type as - | SupportUploadFileTypes.image - | SupportUploadFileTypes.document - | SupportUploadFileTypes.audio - | SupportUploadFileTypes.video + | typeof SupportUploadFileTypes.image + | typeof SupportUploadFileTypes.document + | typeof SupportUploadFileTypes.audio + | typeof SupportUploadFileTypes.video } selected={allowed_file_types.includes(type)} onToggle={handleSupportFileTypeChange} @@ -248,10 +248,10 @@ const FileUploadSetting: FC = ({ key={type} type={ type as - | SupportUploadFileTypes.image - | SupportUploadFileTypes.document - | SupportUploadFileTypes.audio - | SupportUploadFileTypes.video + | typeof SupportUploadFileTypes.image + | typeof SupportUploadFileTypes.document + | typeof SupportUploadFileTypes.audio + | typeof SupportUploadFileTypes.video } selected={allowed_file_types.includes(type)} onToggle={handleSupportFileTypeChange} diff --git a/web/app/components/workflow/nodes/_base/components/form-input-item.helpers.ts b/web/app/components/workflow/nodes/_base/components/form-input-item.helpers.ts index 5d6c63bdf65..b36bcc75322 100644 --- a/web/app/components/workflow/nodes/_base/components/form-input-item.helpers.ts +++ b/web/app/components/workflow/nodes/_base/components/form-input-item.helpers.ts @@ -157,19 +157,32 @@ export const getTargetVarType = (state: FormInputState) => { export const getFilterVar = (state: FormInputState) => { if (state.isNumber) return (varPayload: Var) => varPayload.type === VarType.number if (state.isSelect && state.isMultipleSelect) - return (varPayload: Var) => [VarType.array, VarType.arrayString].includes(varPayload.type) + return (varPayload: Var) => { + const stringArrayVariableTypes: readonly VarType[] = [VarType.array, VarType.arrayString] + return stringArrayVariableTypes.includes(varPayload.type) + } if (state.isString || state.isDate) - return (varPayload: Var) => - [VarType.string, VarType.number, VarType.secret].includes(varPayload.type) + return (varPayload: Var) => { + const textVariableTypes: readonly VarType[] = [VarType.string, VarType.number, VarType.secret] + return textVariableTypes.includes(varPayload.type) + } if (state.isFile) - return (varPayload: Var) => [VarType.file, VarType.arrayFile].includes(varPayload.type) + return (varPayload: Var) => { + const fileVariableTypes: readonly VarType[] = [VarType.file, VarType.arrayFile] + return fileVariableTypes.includes(varPayload.type) + } if (state.isBoolean) return (varPayload: Var) => varPayload.type === VarType.boolean if (state.isObject) return (varPayload: Var) => varPayload.type === VarType.object if (state.isArray) - return (varPayload: Var) => - [VarType.array, VarType.arrayString, VarType.arrayNumber, VarType.arrayObject].includes( - varPayload.type, - ) + return (varPayload: Var) => { + const arrayVariableTypes: readonly VarType[] = [ + VarType.array, + VarType.arrayString, + VarType.arrayNumber, + VarType.arrayObject, + ] + return arrayVariableTypes.includes(varPayload.type) + } return undefined } diff --git a/web/app/components/workflow/nodes/_base/components/form-input-item.tsx b/web/app/components/workflow/nodes/_base/components/form-input-item.tsx index 4e8a1235f84..e0cfdc967ec 100644 --- a/web/app/components/workflow/nodes/_base/components/form-input-item.tsx +++ b/web/app/components/workflow/nodes/_base/components/form-input-item.tsx @@ -141,7 +141,9 @@ const FormInputItem: FC = ({ const { availableVars, availableNodesWithParent } = useAvailableVarList(nodeId, { onlyLeafNodeVar: false, filterVar: (varPayload: Var) => { - return [VarType.string, VarType.number, VarType.secret].includes(varPayload.type) + const textVariableTypes: readonly VarType[] = [VarType.string, VarType.number, VarType.secret] + + return textVariableTypes.includes(varPayload.type) }, }) diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-full-path-panel.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-full-path-panel.tsx index 2320db9f588..534df047142 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-full-path-panel.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-full-path-panel.tsx @@ -31,7 +31,7 @@ const VarFullPathPanel: FC = ({ nodeName, path, varType, nodeType = Block properties: {}, } as Field current = current.properties[name!] as { - type: Type.object + type: typeof Type.object properties: { [key: string]: Field } required: never[] additionalProperties: false diff --git a/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx b/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx index 52649a222c4..b922c828883 100644 --- a/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx +++ b/web/app/components/workflow/nodes/_base/components/variable/var-reference-vars.tsx @@ -98,10 +98,12 @@ const Item: FC = ({ isSelected, onActivate, }) => { + const nestedVariableTypes: readonly VarType[] = [VarType.object, VarType.file] + const isStructureOutput = itemData.type === VarType.object && (itemData.children as StructuredOutput)?.schema?.properties const isObj = - [VarType.object, VarType.file].includes(itemData.type) && + nestedVariableTypes.includes(itemData.type) && itemData.children && (itemData.children as Var[]).length > 0 const isEnv = itemData.variable.startsWith('env.') diff --git a/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx b/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx index b5fbec9be63..cabdcd646a2 100644 --- a/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx +++ b/web/app/components/workflow/nodes/_base/components/workflow-panel/index.tsx @@ -321,13 +321,15 @@ const BasePanel: FC = ({ id, data, children }) => { }, [pendingSingleRun, id, handleSingleRun, handleStop, setPendingSingleRun]) const logParams = useLogs() - const passedLogParams = useMemo( - () => - [BlockEnum.Tool, BlockEnum.Agent, BlockEnum.Iteration, BlockEnum.Loop].includes(data.type) - ? logParams - : {}, - [data.type, logParams], - ) + const passedLogParams = useMemo(() => { + const nestedLogBlockTypes: readonly BlockEnum[] = [ + BlockEnum.Tool, + BlockEnum.Agent, + BlockEnum.Iteration, + BlockEnum.Loop, + ] + return nestedLogBlockTypes.includes(data.type) ? logParams : {} + }, [data.type, logParams]) const storeBuildInTools = useStore((s) => s.buildInTools) const { data: buildInTools } = useAllBuiltInTools() diff --git a/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/index.tsx b/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/index.tsx index 75851efa97f..f1efd30fe52 100644 --- a/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/index.tsx +++ b/web/app/components/workflow/nodes/_base/components/workflow-panel/last-run/index.tsx @@ -39,6 +39,15 @@ const LastRun: FC = ({ isPaused, ...otherResultPanelProps }) => { + const finishedStatuses: readonly NodeRunningStatus[] = [ + NodeRunningStatus.Succeeded, + NodeRunningStatus.Failed, + ] + const activeStatuses: readonly NodeRunningStatus[] = [ + NodeRunningStatus.Running, + NodeRunningStatus.NotStart, + ] + const configsMap = useHooksStore((s) => s.configsMap) const isOneStepRunSucceed = oneStepRunRunningStatus === NodeRunningStatus.Succeeded const isOneStepRunFailed = oneStepRunRunningStatus === NodeRunningStatus.Failed @@ -48,10 +57,7 @@ const LastRun: FC = ({ const [pageHasHide, setPageHasHide] = useState(false) const [pageShowed, setPageShowed] = useState(false) - const hidePageOneStepRunFinished = [ - NodeRunningStatus.Succeeded, - NodeRunningStatus.Failed, - ].includes(hidePageOneStepFinishedStatus!) + const hidePageOneStepRunFinished = finishedStatuses.includes(hidePageOneStepFinishedStatus!) const canRunLastRun = !isRunAfterSingleRun || isOneStepRunSucceed || @@ -71,8 +77,7 @@ const LastRun: FC = ({ const isRunning = !isPaused && (isRunAfterSingleRun - ? !hasAuthoritativeLastRun && - [NodeRunningStatus.Running, NodeRunningStatus.NotStart].includes(oneStepRunRunningStatus!) + ? !hasAuthoritativeLastRun && activeStatuses.includes(oneStepRunRunningStatus!) : isFetching) const noLastRun = (error as any)?.status === 404 @@ -107,7 +112,12 @@ const LastRun: FC = ({ ]) useEffect(() => { - if ([NodeRunningStatus.Succeeded, NodeRunningStatus.Failed].includes(oneStepRunRunningStatus!)) + const finishedStatuses: readonly NodeRunningStatus[] = [ + NodeRunningStatus.Succeeded, + NodeRunningStatus.Failed, + ] + + if (finishedStatuses.includes(oneStepRunRunningStatus!)) setHidePageOneStepFinishedStatus(oneStepRunRunningStatus!) }, [oneStepRunRunningStatus]) diff --git a/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts b/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts index 508b9af846d..46ddadc6547 100644 --- a/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts +++ b/web/app/components/workflow/nodes/_base/hooks/use-one-step-run.ts @@ -131,20 +131,19 @@ const varTypeToInputVarType = ( isParagraph: boolean }, ) => { + const structuredVariableTypes: readonly VarType[] = [ + VarType.object, + VarType.array, + VarType.arrayNumber, + VarType.arrayString, + VarType.arrayObject, + ] + if (isSelect) return InputVarType.select if (isParagraph) return InputVarType.paragraph if (type === VarType.number) return InputVarType.number if (type === VarType.boolean) return InputVarType.checkbox - if ( - [ - VarType.object, - VarType.array, - VarType.arrayNumber, - VarType.arrayString, - VarType.arrayObject, - ].includes(type) - ) - return InputVarType.json + if (structuredVariableTypes.includes(type)) return InputVarType.json if (type === VarType.file) return InputVarType.singleFile if (type === VarType.arrayFile) return InputVarType.multiFiles diff --git a/web/app/components/workflow/nodes/_base/types.ts b/web/app/components/workflow/nodes/_base/types.ts index a7f74a5e6e5..2243a820e77 100644 --- a/web/app/components/workflow/nodes/_base/types.ts +++ b/web/app/components/workflow/nodes/_base/types.ts @@ -1,11 +1,13 @@ import type { ValueSelector } from '@/app/components/workflow/types' // Generic variable types for all resource forms -export enum VarKindType { - variable = 'variable', - constant = 'constant', - mixed = 'mixed', -} +export const VarKindType = { + variable: 'variable', + constant: 'constant', + mixed: 'mixed', +} as const + +export type VarKindType = (typeof VarKindType)[keyof typeof VarKindType] // Generic resource variable inputs export type ResourceVarInputs = Record< diff --git a/web/app/components/workflow/nodes/agent-v2/components/save-inline-agent-to-roster-dialog.tsx b/web/app/components/workflow/nodes/agent-v2/components/save-inline-agent-to-roster-dialog.tsx index 2662213eda5..d86fbc8cf02 100644 --- a/web/app/components/workflow/nodes/agent-v2/components/save-inline-agent-to-roster-dialog.tsx +++ b/web/app/components/workflow/nodes/agent-v2/components/save-inline-agent-to-roster-dialog.tsx @@ -29,7 +29,7 @@ import { FlowType } from '@/types/common' type SaveInlineAgentToRosterDialogProps = { flowId: string - flowType: FlowType.appFlow | FlowType.snippet + flowType: typeof FlowType.appFlow | typeof FlowType.snippet initialAgent: AgentComposerAgentResponse nodeId: string open: boolean diff --git a/web/app/components/workflow/nodes/agent/types.ts b/web/app/components/workflow/nodes/agent/types.ts index efc7c0cd9a2..c2d53b29b4f 100644 --- a/web/app/components/workflow/nodes/agent/types.ts +++ b/web/app/components/workflow/nodes/agent/types.ts @@ -15,6 +15,6 @@ export type AgentNodeType = CommonNodeType & { tool_node_version?: string } -export enum AgentFeature { - HISTORY_MESSAGES = 'history-messages', -} +export const AgentFeature = { + HISTORY_MESSAGES: 'history-messages', +} as const diff --git a/web/app/components/workflow/nodes/agent/use-config.ts b/web/app/components/workflow/nodes/agent/use-config.ts index 138e7e9589e..e8fd23c8a37 100644 --- a/web/app/components/workflow/nodes/agent/use-config.ts +++ b/web/app/components/workflow/nodes/agent/use-config.ts @@ -164,7 +164,7 @@ const useConfig = (id: string, payload: AgentNodeType) => { // vars const filterMemoryPromptVar = useCallback((varPayload: Var) => { - return [ + const supportedVariableTypes: readonly VarKindType[] = [ VarKindType.arrayObject, VarKindType.array, VarKindType.number, @@ -174,7 +174,9 @@ const useConfig = (id: string, payload: AgentNodeType) => { VarKindType.arrayNumber, VarKindType.file, VarKindType.arrayFile, - ].includes(varPayload.type) + ] + + return supportedVariableTypes.includes(varPayload.type) }, []) const { availableVars, availableNodesWithParent } = useAvailableVarList(id, { diff --git a/web/app/components/workflow/nodes/assigner/types.ts b/web/app/components/workflow/nodes/assigner/types.ts index 58697cd83fc..62cb5eff08b 100644 --- a/web/app/components/workflow/nodes/assigner/types.ts +++ b/web/app/components/workflow/nodes/assigner/types.ts @@ -1,23 +1,28 @@ import type { CommonNodeType, ValueSelector } from '@/app/components/workflow/types' -export enum WriteMode { - overwrite = 'over-write', - clear = 'clear', - append = 'append', - extend = 'extend', - set = 'set', - increment = '+=', - decrement = '-=', - multiply = '*=', - divide = '/=', - removeFirst = 'remove-first', - removeLast = 'remove-last', -} +export const WriteMode = { + overwrite: 'over-write', + clear: 'clear', + append: 'append', + extend: 'extend', + set: 'set', + increment: '+=', + decrement: '-=', + multiply: '*=', + divide: '/=', + removeFirst: 'remove-first', + removeLast: 'remove-last', +} as const -export enum AssignerNodeInputType { - variable = 'variable', - constant = 'constant', -} +export type WriteMode = (typeof WriteMode)[keyof typeof WriteMode] + +export const AssignerNodeInputType = { + variable: 'variable', + constant: 'constant', +} as const + +export type AssignerNodeInputType = + (typeof AssignerNodeInputType)[keyof typeof AssignerNodeInputType] export type AssignerNodeOperation = { variable_selector: ValueSelector @@ -31,7 +36,7 @@ export type AssignerNodeType = CommonNodeType & { items: AssignerNodeOperation[] } -export const writeModeTypesNum = [ +export const writeModeTypesNum: WriteMode[] = [ WriteMode.increment, WriteMode.decrement, WriteMode.multiply, diff --git a/web/app/components/workflow/nodes/code/code-parser.ts b/web/app/components/workflow/nodes/code/code-parser.ts index 4bfc308af15..8a62e92c368 100644 --- a/web/app/components/workflow/nodes/code/code-parser.ts +++ b/web/app/components/workflow/nodes/code/code-parser.ts @@ -5,7 +5,7 @@ import { CodeLanguage } from './types' export const extractFunctionParams = (code: string, language: CodeLanguage) => { if (language === CodeLanguage.json) return [] - const patterns: Record, RegExp> = { + const patterns: Record, RegExp> = { [CodeLanguage.python3]: /def\s+main\s*\((.*?)\)/, [CodeLanguage.javascript]: /function\s+main\s*\((.*?)\)/, } diff --git a/web/app/components/workflow/nodes/code/types.ts b/web/app/components/workflow/nodes/code/types.ts index ee79821ee6b..e15f6772836 100644 --- a/web/app/components/workflow/nodes/code/types.ts +++ b/web/app/components/workflow/nodes/code/types.ts @@ -1,10 +1,12 @@ import type { CommonNodeType, Variable, VarType } from '@/app/components/workflow/types' -export enum CodeLanguage { - python3 = 'python3', - javascript = 'javascript', - json = 'json', -} +export const CodeLanguage = { + python3: 'python3', + javascript: 'javascript', + json: 'json', +} as const + +export type CodeLanguage = (typeof CodeLanguage)[keyof typeof CodeLanguage] export type OutputVar = Record< string, diff --git a/web/app/components/workflow/nodes/code/use-config.ts b/web/app/components/workflow/nodes/code/use-config.ts index ea56af2c2bb..60d070a7ba1 100644 --- a/web/app/components/workflow/nodes/code/use-config.ts +++ b/web/app/components/workflow/nodes/code/use-config.ts @@ -188,7 +188,7 @@ const useConfig = (id: string, payload: CodeNodeType) => { }) const filterVar = useCallback((varPayload: Var) => { - return [ + const supportedVariableTypes: readonly VarType[] = [ VarType.string, VarType.number, VarType.boolean, @@ -201,7 +201,9 @@ const useConfig = (id: string, payload: CodeNodeType) => { VarType.arrayBoolean, VarType.file, VarType.arrayFile, - ].includes(varPayload.type) + ] + + return supportedVariableTypes.includes(varPayload.type) }, []) const handleCodeAndVarsChange = useCallback( diff --git a/web/app/components/workflow/nodes/data-source/types.ts b/web/app/components/workflow/nodes/data-source/types.ts index a4d7f2601ef..7729a3be422 100644 --- a/web/app/components/workflow/nodes/data-source/types.ts +++ b/web/app/components/workflow/nodes/data-source/types.ts @@ -5,9 +5,9 @@ import type { CommonNodeType, Node } from '@/app/components/workflow/types' import type { FlowType } from '@/types/common' import type { NodeRunResult, VarInInspect } from '@/types/workflow' -export enum DataSourceClassification { - localFile = 'local_file', -} +export const DataSourceClassification = { + localFile: 'local_file', +} as const export type ToolVarInputs = ResourceVarInputs diff --git a/web/app/components/workflow/nodes/http/components/api-input.tsx b/web/app/components/workflow/nodes/http/components/api-input.tsx index 7546476441d..d1488aeef33 100644 --- a/web/app/components/workflow/nodes/http/components/api-input.tsx +++ b/web/app/components/workflow/nodes/http/components/api-input.tsx @@ -36,7 +36,9 @@ const ApiInput: FC = ({ nodeId, readonly, method, onMethodChange, url, on const { availableVars, availableNodesWithParent } = useAvailableVarList(nodeId, { onlyLeafNodeVar: false, filterVar: (varPayload: Var) => { - return [VarType.string, VarType.number, VarType.secret].includes(varPayload.type) + const textVariableTypes: readonly VarType[] = [VarType.string, VarType.number, VarType.secret] + + return textVariableTypes.includes(varPayload.type) }, }) diff --git a/web/app/components/workflow/nodes/http/components/authorization/index.tsx b/web/app/components/workflow/nodes/http/components/authorization/index.tsx index aa8aae946da..7fb7d8a6d72 100644 --- a/web/app/components/workflow/nodes/http/components/authorization/index.tsx +++ b/web/app/components/workflow/nodes/http/components/authorization/index.tsx @@ -56,7 +56,9 @@ const Authorization: FC = ({ nodeId, payload, onChange, isShow, onHide }) const { availableVars, availableNodesWithParent } = useAvailableVarList(nodeId, { onlyLeafNodeVar: false, filterVar: (varPayload: Var) => { - return [VarType.string, VarType.number, VarType.secret].includes(varPayload.type) + const textVariableTypes: readonly VarType[] = [VarType.string, VarType.number, VarType.secret] + + return textVariableTypes.includes(varPayload.type) }, }) diff --git a/web/app/components/workflow/nodes/http/components/edit-body/index.tsx b/web/app/components/workflow/nodes/http/components/edit-body/index.tsx index d346080d92a..9733ceb9b8c 100644 --- a/web/app/components/workflow/nodes/http/components/edit-body/index.tsx +++ b/web/app/components/workflow/nodes/http/components/edit-body/index.tsx @@ -42,6 +42,8 @@ const bodyTextMap = { } const EditBody: FC = ({ readonly, nodeId, payload, onChange }) => { + const keyValueBodyTypes: readonly BodyType[] = [BodyType.formData, BodyType.xWwwFormUrlencoded] + const { type, data } = payload const bodyPayload = useMemo(() => { if (typeof data === 'string') { @@ -50,9 +52,7 @@ const EditBody: FC = ({ readonly, nodeId, payload, onChange }) => { } return data }, [data]) - const stringValue = [BodyType.formData, BodyType.xWwwFormUrlencoded].includes(type) - ? '' - : bodyPayload[0]?.value || '' + const stringValue = keyValueBodyTypes.includes(type) ? '' : bodyPayload[0]?.value || '' const { availableVars, availableNodes } = useAvailableVarList(nodeId, { onlyLeafNodeVar: false, @@ -63,8 +63,13 @@ const EditBody: FC = ({ readonly, nodeId, payload, onChange }) => { const handleTypeChange = useCallback( (e: React.ChangeEvent) => { + const keyValueBodyTypes: readonly BodyType[] = [ + BodyType.formData, + BodyType.xWwwFormUrlencoded, + ] + const newType = e.target.value as BodyType - const hasKeyValue = [BodyType.formData, BodyType.xWwwFormUrlencoded].includes(newType) + const hasKeyValue = keyValueBodyTypes.includes(newType) onChange({ type: newType, data: hasKeyValue @@ -105,7 +110,9 @@ const EditBody: FC = ({ readonly, nodeId, payload, onChange }) => { ) const filterOnlyFileVariable = (varPayload: Var) => { - return [VarType.file, VarType.arrayFile].includes(varPayload.type) + const fileVariableTypes: readonly VarType[] = [VarType.file, VarType.arrayFile] + + return fileVariableTypes.includes(varPayload.type) } const handleBodyValueChange = useCallback( diff --git a/web/app/components/workflow/nodes/http/components/key-value/key-value-edit/input-item.tsx b/web/app/components/workflow/nodes/http/components/key-value/key-value-edit/input-item.tsx index 17ecc747be4..88fe959e0eb 100644 --- a/web/app/components/workflow/nodes/http/components/key-value/key-value-edit/input-item.tsx +++ b/web/app/components/workflow/nodes/http/components/key-value/key-value-edit/input-item.tsx @@ -45,7 +45,7 @@ const InputItem: FC = ({ const { availableVars, availableNodesWithParent } = useAvailableVarList(nodeId, { onlyLeafNodeVar: false, filterVar: (varPayload: Var) => { - const supportVarTypes = [VarType.string, VarType.number, VarType.secret] + const supportVarTypes: VarType[] = [VarType.string, VarType.number, VarType.secret] if (isSupportFile) supportVarTypes.push(VarType.file, VarType.arrayFile) return supportVarTypes.includes(varPayload.type) diff --git a/web/app/components/workflow/nodes/http/components/key-value/key-value-edit/item.tsx b/web/app/components/workflow/nodes/http/components/key-value/key-value-edit/item.tsx index fc59b229bb6..4fa634ec2d8 100644 --- a/web/app/components/workflow/nodes/http/components/key-value/key-value-edit/item.tsx +++ b/web/app/components/workflow/nodes/http/components/key-value/key-value-edit/item.tsx @@ -82,7 +82,9 @@ const KeyValueItem: FC = ({ ) const filterOnlyFileVariable = (varPayload: Var) => { - return [VarType.file, VarType.arrayFile].includes(varPayload.type) + const fileVariableTypes: readonly VarType[] = [VarType.file, VarType.arrayFile] + + return fileVariableTypes.includes(varPayload.type) } const handleValueContainerClick = useCallback(() => { diff --git a/web/app/components/workflow/nodes/http/types.ts b/web/app/components/workflow/nodes/http/types.ts index 0e3fbc0d91d..6d89b7fa018 100644 --- a/web/app/components/workflow/nodes/http/types.ts +++ b/web/app/components/workflow/nodes/http/types.ts @@ -1,22 +1,26 @@ import type { CommonNodeType, ValueSelector, Variable } from '@/app/components/workflow/types' -export enum Method { - get = 'get', - post = 'post', - head = 'head', - patch = 'patch', - put = 'put', - delete = 'delete', -} +export const Method = { + get: 'get', + post: 'post', + head: 'head', + patch: 'patch', + put: 'put', + delete: 'delete', +} as const -export enum BodyType { - none = 'none', - formData = 'form-data', - xWwwFormUrlencoded = 'x-www-form-urlencoded', - rawText = 'raw-text', - json = 'json', - binary = 'binary', -} +export type Method = (typeof Method)[keyof typeof Method] + +export const BodyType = { + none: 'none', + formData: 'form-data', + xWwwFormUrlencoded: 'x-www-form-urlencoded', + rawText: 'raw-text', + json: 'json', + binary: 'binary', +} as const + +export type BodyType = (typeof BodyType)[keyof typeof BodyType] export type KeyValue = { id?: string @@ -26,10 +30,12 @@ export type KeyValue = { file?: ValueSelector } -export enum BodyPayloadValueType { - text = 'text', - file = 'file', -} +export const BodyPayloadValueType = { + text: 'text', + file: 'file', +} as const + +export type BodyPayloadValueType = (typeof BodyPayloadValueType)[keyof typeof BodyPayloadValueType] export type BodyPayload = { id?: string @@ -43,16 +49,20 @@ export type Body = { data: string | BodyPayload // string is deprecated, it would convert to BodyPayload after loaded } -export enum AuthorizationType { - none = 'no-auth', - apiKey = 'api-key', -} +export const AuthorizationType = { + none: 'no-auth', + apiKey: 'api-key', +} as const -export enum APIType { - basic = 'basic', - bearer = 'bearer', - custom = 'custom', -} +export type AuthorizationType = (typeof AuthorizationType)[keyof typeof AuthorizationType] + +export const APIType = { + basic: 'basic', + bearer: 'bearer', + custom: 'custom', +} as const + +export type APIType = (typeof APIType)[keyof typeof APIType] export type Authorization = { type: AuthorizationType diff --git a/web/app/components/workflow/nodes/http/use-config.ts b/web/app/components/workflow/nodes/http/use-config.ts index dc87c7ce2b4..032267bfe59 100644 --- a/web/app/components/workflow/nodes/http/use-config.ts +++ b/web/app/components/workflow/nodes/http/use-config.ts @@ -135,7 +135,9 @@ const useConfig = (id: string, payload: HttpNodeType) => { ) const filterVar = useCallback((varPayload: Var) => { - return [VarType.string, VarType.number, VarType.secret].includes(varPayload.type) + const textVariableTypes: readonly VarType[] = [VarType.string, VarType.number, VarType.secret] + + return textVariableTypes.includes(varPayload.type) }, []) // curl import panel diff --git a/web/app/components/workflow/nodes/human-input/components/delivery-method/test-email-sender.tsx b/web/app/components/workflow/nodes/human-input/components/delivery-method/test-email-sender.tsx index a48bcd74be0..adb093417d6 100644 --- a/web/app/components/workflow/nodes/human-input/components/delivery-method/test-email-sender.tsx +++ b/web/app/components/workflow/nodes/human-input/components/delivery-method/test-email-sender.tsx @@ -75,18 +75,17 @@ const getOriginVar = (valueSelector: string[], list: NodeOutPutVar[]) => { } const varTypeToInputVarType = (type: VarType) => { + const structuredVariableTypes: readonly VarType[] = [ + VarType.object, + VarType.array, + VarType.arrayNumber, + VarType.arrayString, + VarType.arrayObject, + ] + if (type === VarType.number) return InputVarType.number if (type === VarType.boolean) return InputVarType.checkbox - if ( - [ - VarType.object, - VarType.array, - VarType.arrayNumber, - VarType.arrayString, - VarType.arrayObject, - ].includes(type) - ) - return InputVarType.json + if (structuredVariableTypes.includes(type)) return InputVarType.json if (type === VarType.file) return InputVarType.singleFile if (type === VarType.arrayFile) return InputVarType.multiFiles diff --git a/web/app/components/workflow/nodes/human-input/panel.tsx b/web/app/components/workflow/nodes/human-input/panel.tsx index c5f920085ed..df220f34fdb 100644 --- a/web/app/components/workflow/nodes/human-input/panel.tsx +++ b/web/app/components/workflow/nodes/human-input/panel.tsx @@ -63,9 +63,14 @@ const Panel: FC> = ({ id, data }) => { const { availableVars, availableNodesWithParent } = useAvailableVarList(id, { onlyLeafNodeVar: false, filterVar: (varPayload: Var) => { - return [VarType.string, VarType.number, VarType.secret, VarType.arrayString].includes( - varPayload.type, - ) + const supportedVariableTypes: readonly VarType[] = [ + VarType.string, + VarType.number, + VarType.secret, + VarType.arrayString, + ] + + return supportedVariableTypes.includes(varPayload.type) }, }) diff --git a/web/app/components/workflow/nodes/human-input/types.ts b/web/app/components/workflow/nodes/human-input/types.ts index a6b4796abb7..7d9ab0db011 100644 --- a/web/app/components/workflow/nodes/human-input/types.ts +++ b/web/app/components/workflow/nodes/human-input/types.ts @@ -15,13 +15,15 @@ export type HumanInputNodeType = CommonNodeType & { timeout_unit: 'hour' | 'day' } -export enum DeliveryMethodType { - WebApp = 'webapp', - Email = 'email', - Slack = 'slack', - Teams = 'teams', - Discord = 'discord', -} +export const DeliveryMethodType = { + WebApp: 'webapp', + Email: 'email', + Slack: 'slack', + Teams: 'teams', + Discord: 'discord', +} as const + +export type DeliveryMethodType = (typeof DeliveryMethodType)[keyof typeof DeliveryMethodType] export type Recipient = { type: 'member' | 'external' @@ -48,12 +50,14 @@ export type DeliveryMethod = { config?: EmailConfig } -export enum UserActionButtonType { - Primary = 'primary', - Default = 'default', - Accent = 'accent', - Ghost = 'ghost', -} +export const UserActionButtonType = { + Primary: 'primary', + Default: 'default', + Accent: 'accent', + Ghost: 'ghost', +} as const + +export type UserActionButtonType = (typeof UserActionButtonType)[keyof typeof UserActionButtonType] export type UserAction = { id: string @@ -81,12 +85,12 @@ type BaseFormInputItem = { } export type ParagraphFormInput = BaseFormInputItem & { - type: InputVarType.paragraph + type: typeof InputVarType.paragraph default: StringDefault } export type SelectFormInput = BaseFormInputItem & { - type: InputVarType.select + type: typeof InputVarType.select option_source: StringListSource } @@ -97,12 +101,12 @@ type SharedFileFormInput = Pick< export type FileFormInput = BaseFormInputItem & SharedFileFormInput & { - type: InputVarType.singleFile + type: typeof InputVarType.singleFile } export type FileListFormInput = BaseFormInputItem & SharedFileFormInput & { - type: InputVarType.multiFiles + type: typeof InputVarType.multiFiles number_limits?: UploadFileSetting['number_limits'] } diff --git a/web/app/components/workflow/nodes/if-else/components/condition-list/condition-item.tsx b/web/app/components/workflow/nodes/if-else/components/condition-list/condition-item.tsx index fbb30e6460c..59f35cfc016 100644 --- a/web/app/components/workflow/nodes/if-else/components/condition-list/condition-item.tsx +++ b/web/app/components/workflow/nodes/if-else/components/condition-list/condition-item.tsx @@ -91,6 +91,16 @@ const ConditionItem = ({ numberVariables, filterVar, }: ConditionItemProps) => { + const containmentOperators: readonly ComparisonOperator[] = [ + ComparisonOperator.contains, + ComparisonOperator.notContains, + ComparisonOperator.allOf, + ] + const membershipOperators: readonly ComparisonOperator[] = [ + ComparisonOperator.in, + ComparisonOperator.notIn, + ] + const { t } = useTranslation() const isChatMode = useIsChatMode() const [isHovered, setIsHovered] = useState(false) @@ -151,11 +161,7 @@ const ConditionItem = ({ const isSubVariable = condition.varType === VarType.arrayFile && - [ - ComparisonOperator.contains, - ComparisonOperator.notContains, - ComparisonOperator.allOf, - ].includes(condition.comparison_operator!) + containmentOperators.includes(condition.comparison_operator!) const fileAttr = useMemo(() => { if (file) return file @@ -186,8 +192,7 @@ const ConditionItem = ({ ) const isSelect = - condition.comparison_operator && - [ComparisonOperator.in, ComparisonOperator.notIn].includes(condition.comparison_operator) + condition.comparison_operator && membershipOperators.includes(condition.comparison_operator) const selectOptions = useMemo>(() => { if (isSelect) { if (fileAttr?.key === 'type' || condition.comparison_operator === ComparisonOperator.allOf) { @@ -291,13 +296,16 @@ const ConditionItem = ({ ) const showBooleanInput = useMemo(() => { + const itemContainmentOperators: readonly ComparisonOperator[] = [ + ComparisonOperator.contains, + ComparisonOperator.notContains, + ] + if (condition.varType === VarType.boolean) return true if ( condition.varType === VarType.arrayBoolean && - [ComparisonOperator.contains, ComparisonOperator.notContains].includes( - condition.comparison_operator!, - ) + itemContainmentOperators.includes(condition.comparison_operator!) ) return true return false diff --git a/web/app/components/workflow/nodes/if-else/types.ts b/web/app/components/workflow/nodes/if-else/types.ts index 9e884585f1b..6917091eca3 100644 --- a/web/app/components/workflow/nodes/if-else/types.ts +++ b/web/app/components/workflow/nodes/if-else/types.ts @@ -1,34 +1,38 @@ import type { VarType as NumberVarType } from '../tool/types' import type { CommonNodeType, ValueSelector, Var, VarType } from '@/app/components/workflow/types' -export enum LogicalOperator { - and = 'and', - or = 'or', -} +export const LogicalOperator = { + and: 'and', + or: 'or', +} as const -export enum ComparisonOperator { - contains = 'contains', - notContains = 'not contains', - startWith = 'start with', - endWith = 'end with', - is = 'is', - isNot = 'is not', - empty = 'empty', - notEmpty = 'not empty', - equal = '=', - notEqual = '≠', - largerThan = '>', - lessThan = '<', - largerThanOrEqual = '≥', - lessThanOrEqual = '≤', - isNull = 'is null', - isNotNull = 'is not null', - in = 'in', - notIn = 'not in', - allOf = 'all of', - exists = 'exists', - notExists = 'not exists', -} +export type LogicalOperator = (typeof LogicalOperator)[keyof typeof LogicalOperator] + +export const ComparisonOperator = { + contains: 'contains', + notContains: 'not contains', + startWith: 'start with', + endWith: 'end with', + is: 'is', + isNot: 'is not', + empty: 'empty', + notEmpty: 'not empty', + equal: '=', + notEqual: '≠', + largerThan: '>', + lessThan: '<', + largerThanOrEqual: '≥', + lessThanOrEqual: '≤', + isNull: 'is null', + isNotNull: 'is not null', + in: 'in', + notIn: 'not in', + allOf: 'all of', + exists: 'exists', + notExists: 'not exists', +} as const + +export type ComparisonOperator = (typeof ComparisonOperator)[keyof typeof ComparisonOperator] export type Condition = { id: string diff --git a/web/app/components/workflow/nodes/if-else/utils.ts b/web/app/components/workflow/nodes/if-else/utils.ts index 504efd729ea..fefabc15d87 100644 --- a/web/app/components/workflow/nodes/if-else/utils.ts +++ b/web/app/components/workflow/nodes/if-else/utils.ts @@ -3,14 +3,16 @@ import { VarType } from '@/app/components/workflow/types' import { ComparisonOperator } from './types' export const isEmptyRelatedOperator = (operator: ComparisonOperator) => { - return [ + const valueFreeOperators: readonly ComparisonOperator[] = [ ComparisonOperator.empty, ComparisonOperator.notEmpty, ComparisonOperator.isNull, ComparisonOperator.isNotNull, ComparisonOperator.exists, ComparisonOperator.notExists, - ].includes(operator) + ] + + return valueFreeOperators.includes(operator) } const notTranslateKey = [ @@ -168,16 +170,18 @@ export const getOperators = (type?: VarType, file?: { key: string }) => { } export const comparisonOperatorNotRequireValue = (operator?: ComparisonOperator) => { - if (!operator) return false - - return [ + const valueFreeOperators: readonly ComparisonOperator[] = [ ComparisonOperator.empty, ComparisonOperator.notEmpty, ComparisonOperator.isNull, ComparisonOperator.isNotNull, ComparisonOperator.exists, ComparisonOperator.notExists, - ].includes(operator) + ] + + if (!operator) return false + + return valueFreeOperators.includes(operator) } export const branchNameCorrect = (branches: Branch[]) => { diff --git a/web/app/components/workflow/nodes/iteration/__tests__/use-single-run-form-params.spec.ts b/web/app/components/workflow/nodes/iteration/__tests__/use-single-run-form-params.spec.ts index 48baecee7d0..d87ab7accfe 100644 --- a/web/app/components/workflow/nodes/iteration/__tests__/use-single-run-form-params.spec.ts +++ b/web/app/components/workflow/nodes/iteration/__tests__/use-single-run-form-params.spec.ts @@ -42,7 +42,7 @@ const createInputVar = (variable: string): InputVar => ({ required: false, }) -const createNode = (id: string, title: string, type = BlockEnum.Tool): Node => +const createNode = (id: string, title: string, type: BlockEnum = BlockEnum.Tool): Node => ({ id, position: { x: 0, y: 0 }, diff --git a/web/app/components/workflow/nodes/iteration/use-config.ts b/web/app/components/workflow/nodes/iteration/use-config.ts index 05edb30c935..d3db60e588d 100644 --- a/web/app/components/workflow/nodes/iteration/use-config.ts +++ b/web/app/components/workflow/nodes/iteration/use-config.ts @@ -30,14 +30,16 @@ const useConfig = (id: string, payload: IterationNodeType) => { const { inputs, setInputs } = useNodeCrud(id, payload) const filterInputVar = useCallback((varPayload: Var) => { - return [ + const arrayVariableTypes: readonly VarType[] = [ VarType.array, VarType.arrayString, VarType.arrayBoolean, VarType.arrayNumber, VarType.arrayObject, VarType.arrayFile, - ].includes(varPayload.type) + ] + + return arrayVariableTypes.includes(varPayload.type) }, []) const handleInputChange = useCallback( diff --git a/web/app/components/workflow/nodes/knowledge-base/components/retrieval-setting/__tests__/search-method-option.spec.tsx b/web/app/components/workflow/nodes/knowledge-base/components/retrieval-setting/__tests__/search-method-option.spec.tsx index 271d2345b05..b9af3251470 100644 --- a/web/app/components/workflow/nodes/knowledge-base/components/retrieval-setting/__tests__/search-method-option.spec.tsx +++ b/web/app/components/workflow/nodes/knowledge-base/components/retrieval-setting/__tests__/search-method-option.spec.tsx @@ -1,4 +1,5 @@ import type { ComponentType, SVGProps } from 'react' +import type { SearchMethodOptionProps } from '../search-method-option' import { Field } from '@langgenius/dify-ui/field' import { Fieldset, FieldsetLegend } from '@langgenius/dify-ui/fieldset' import { RadioGroup } from '@langgenius/dify-ui/radio-group' @@ -80,7 +81,11 @@ const createProps = () => ({ }, }) -function renderSearchMethodOption(props: ReturnType) { +function renderSearchMethodOption( + props: SearchMethodOptionProps & { + onRetrievalSearchMethodChange: (value: RetrievalSearchMethodEnum) => void + }, +) { const { onRetrievalSearchMethodChange, ...optionProps } = props render( diff --git a/web/app/components/workflow/nodes/knowledge-base/panel.tsx b/web/app/components/workflow/nodes/knowledge-base/panel.tsx index f2d2f58d721..c60b5f3dc4b 100644 --- a/web/app/components/workflow/nodes/knowledge-base/panel.tsx +++ b/web/app/components/workflow/nodes/knowledge-base/panel.tsx @@ -28,6 +28,11 @@ import { ChunkStructureEnum, IndexMethodEnum } from './types' import { getKnowledgeBaseValidationIssue, KnowledgeBaseValidationIssueCode } from './utils' const Panel: FC> = ({ id, data }) => { + const rerankingChunkStructures: readonly ChunkStructureEnum[] = [ + ChunkStructureEnum.general, + ChunkStructureEnum.parent_child, + ] + const { t } = useTranslation() const { data: deploymentEdition } = useSuspenseQuery({ ...systemFeaturesQueryOptions(), @@ -254,9 +259,7 @@ const Panel: FC> = ({ id, data }) => { {data.indexing_technique === IndexMethodEnum.QUALIFIED && - [ChunkStructureEnum.general, ChunkStructureEnum.parent_child].includes( - data.chunk_structure, - ) && + rerankingChunkStructures.includes(data.chunk_structure) && isNonCloudEdition && ( <> { } export const comparisonOperatorNotRequireValue = (operator?: ComparisonOperator) => { - if (!operator) return false - - return [ + const valueFreeOperators: readonly ComparisonOperator[] = [ ComparisonOperator.empty, ComparisonOperator.notEmpty, ComparisonOperator.isNull, ComparisonOperator.isNotNull, ComparisonOperator.exists, ComparisonOperator.notExists, - ].includes(operator) + ] + + if (!operator) return false + + return valueFreeOperators.includes(operator) } export const VARIABLE_REGEX = /\{\{(#[\w-]{1,50}(\.[a-z_]\w{0,29}){1,10}#)\}\}/gi diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/types.ts b/web/app/components/workflow/nodes/knowledge-retrieval/types.ts index 766311cdc50..caa95eb7b96 100644 --- a/web/app/components/workflow/nodes/knowledge-retrieval/types.ts +++ b/web/app/components/workflow/nodes/knowledge-retrieval/types.ts @@ -39,49 +39,59 @@ export type SingleRetrievalConfig = { model: ModelConfig } -export enum LogicalOperator { - and = 'and', - or = 'or', -} +export const LogicalOperator = { + and: 'and', + or: 'or', +} as const -export enum ComparisonOperator { - contains = 'contains', - notContains = 'not contains', - startWith = 'start with', - endWith = 'end with', - is = 'is', - isNot = 'is not', - empty = 'empty', - notEmpty = 'not empty', - equal = '=', - notEqual = '≠', - largerThan = '>', - lessThan = '<', - largerThanOrEqual = '≥', - lessThanOrEqual = '≤', - isNull = 'is null', - isNotNull = 'is not null', - in = 'in', - notIn = 'not in', - allOf = 'all of', - exists = 'exists', - notExists = 'not exists', - before = 'before', - after = 'after', -} +export type LogicalOperator = (typeof LogicalOperator)[keyof typeof LogicalOperator] -export enum MetadataFilteringModeEnum { - disabled = 'disabled', - automatic = 'automatic', - manual = 'manual', -} +export const ComparisonOperator = { + contains: 'contains', + notContains: 'not contains', + startWith: 'start with', + endWith: 'end with', + is: 'is', + isNot: 'is not', + empty: 'empty', + notEmpty: 'not empty', + equal: '=', + notEqual: '≠', + largerThan: '>', + lessThan: '<', + largerThanOrEqual: '≥', + lessThanOrEqual: '≤', + isNull: 'is null', + isNotNull: 'is not null', + in: 'in', + notIn: 'not in', + allOf: 'all of', + exists: 'exists', + notExists: 'not exists', + before: 'before', + after: 'after', +} as const -export enum MetadataFilteringVariableType { - string = 'string', - number = 'number', - time = 'time', - select = 'select', -} +export type ComparisonOperator = (typeof ComparisonOperator)[keyof typeof ComparisonOperator] + +export const MetadataFilteringModeEnum = { + disabled: 'disabled', + automatic: 'automatic', + manual: 'manual', +} as const + +export type MetadataFilteringModeEnum = + (typeof MetadataFilteringModeEnum)[keyof typeof MetadataFilteringModeEnum] + +export const MetadataFilteringVariableType = { + string: 'string', + number: 'number', + time: 'time', + select: 'select', +} as const + +export type MetadataFilteringVariableType = + (typeof MetadataFilteringVariableType)[keyof typeof MetadataFilteringVariableType] export type MetadataFilteringCondition = { id: string diff --git a/web/app/components/workflow/nodes/knowledge-retrieval/use-single-run-form-params.ts b/web/app/components/workflow/nodes/knowledge-retrieval/use-single-run-form-params.ts index 87449c3ce76..02fff29ae11 100644 --- a/web/app/components/workflow/nodes/knowledge-retrieval/use-single-run-form-params.ts +++ b/web/app/components/workflow/nodes/knowledge-retrieval/use-single-run-form-params.ts @@ -54,7 +54,9 @@ const useSingleRunFormParams = ({ ) const filterFileVar = useCallback((varPayload: Var) => { - return [VarType.file, VarType.arrayFile].includes(varPayload.type) + const fileVariableTypes: readonly VarType[] = [VarType.file, VarType.arrayFile] + + return fileVariableTypes.includes(varPayload.type) }, []) // Get all variables from previous nodes that are file or array of file diff --git a/web/app/components/workflow/nodes/list-operator/components/extract-input.tsx b/web/app/components/workflow/nodes/list-operator/components/extract-input.tsx index 6e0b15482bc..8f2785b3640 100644 --- a/web/app/components/workflow/nodes/list-operator/components/extract-input.tsx +++ b/web/app/components/workflow/nodes/list-operator/components/extract-input.tsx @@ -23,7 +23,9 @@ const ExtractInput: FC = ({ nodeId, readOnly, value, onChange }) => { const { availableVars, availableNodesWithParent } = useAvailableVarList(nodeId, { onlyLeafNodeVar: false, filterVar: (varPayload: Var) => { - return [VarType.number].includes(varPayload.type) + const numberVariableTypes: readonly VarType[] = [VarType.number] + + return numberVariableTypes.includes(varPayload.type) }, }) diff --git a/web/app/components/workflow/nodes/list-operator/components/filter-condition.tsx b/web/app/components/workflow/nodes/list-operator/components/filter-condition.tsx index 8ea87d00fe2..2c95adfb4a1 100644 --- a/web/app/components/workflow/nodes/list-operator/components/filter-condition.tsx +++ b/web/app/components/workflow/nodes/list-operator/components/filter-condition.tsx @@ -205,6 +205,12 @@ const FilterCondition: FC = ({ readOnly, nodeId, }) => { + const arrayOperators: readonly ComparisonOperator[] = [ + ComparisonOperator.in, + ComparisonOperator.notIn, + ComparisonOperator.allOf, + ] + const { t } = useTranslation() const expectedVarType = getExpectedVarType(condition, varType) @@ -217,11 +223,7 @@ const FilterCondition: FC = ({ }, }) - const isSelect = [ - ComparisonOperator.in, - ComparisonOperator.notIn, - ComparisonOperator.allOf, - ].includes(condition.comparison_operator) + const isSelect = arrayOperators.includes(condition.comparison_operator) const isArrayValue = condition.key === 'transfer_method' || condition.key === 'type' const isBoolean = varType === VarType.boolean diff --git a/web/app/components/workflow/nodes/list-operator/types.ts b/web/app/components/workflow/nodes/list-operator/types.ts index 44203cd0ff2..8e99238668f 100644 --- a/web/app/components/workflow/nodes/list-operator/types.ts +++ b/web/app/components/workflow/nodes/list-operator/types.ts @@ -1,10 +1,12 @@ import type { ComparisonOperator } from '../if-else/types' import type { CommonNodeType, ValueSelector, VarType } from '@/app/components/workflow/types' -export enum OrderBy { - ASC = 'asc', - DESC = 'desc', -} +export const OrderBy = { + ASC: 'asc', + DESC: 'desc', +} as const + +export type OrderBy = (typeof OrderBy)[keyof typeof OrderBy] export type Limit = { enabled: boolean diff --git a/web/app/components/workflow/nodes/list-operator/use-config.helpers.ts b/web/app/components/workflow/nodes/list-operator/use-config.helpers.ts index 19573face29..cdc69bf54b5 100644 --- a/web/app/components/workflow/nodes/list-operator/use-config.helpers.ts +++ b/web/app/components/workflow/nodes/list-operator/use-config.helpers.ts @@ -32,12 +32,14 @@ export const getItemVarTypeShowName = (itemVarType?: VarType, hasVariable?: bool export const supportsSubVariable = (varType?: VarType) => varType === WorkflowVarType.arrayFile export const canFilterVariable = (varPayload: Var) => { - return [ + const supportedVariableTypes: readonly WorkflowVarType[] = [ WorkflowVarType.arrayNumber, WorkflowVarType.arrayString, WorkflowVarType.arrayBoolean, WorkflowVarType.arrayFile, - ].includes(varPayload.type) + ] + + return supportedVariableTypes.includes(varPayload.type) } export const buildFilterCondition = ({ diff --git a/web/app/components/workflow/nodes/llm/hooks/use-llm-prompt-config.ts b/web/app/components/workflow/nodes/llm/hooks/use-llm-prompt-config.ts index e4b5bb7b3d5..25ae8d7c126 100644 --- a/web/app/components/workflow/nodes/llm/hooks/use-llm-prompt-config.ts +++ b/web/app/components/workflow/nodes/llm/hooks/use-llm-prompt-config.ts @@ -38,7 +38,7 @@ const ensurePromptConfig = (draft: Draft): { jinja2_variables: Vari } const filterInputVar = (varPayload: Var) => { - return [ + const basicPromptVariableTypes: readonly VarType[] = [ VarType.number, VarType.string, VarType.secret, @@ -46,11 +46,13 @@ const filterInputVar = (varPayload: Var) => { VarType.arrayNumber, VarType.file, VarType.arrayFile, - ].includes(varPayload.type) + ] + + return basicPromptVariableTypes.includes(varPayload.type) } const filterJinja2InputVar = (varPayload: Var) => { - return [ + const jinjaPromptVariableTypes: readonly VarType[] = [ VarType.number, VarType.string, VarType.secret, @@ -61,11 +63,13 @@ const filterJinja2InputVar = (varPayload: Var) => { VarType.object, VarType.array, VarType.boolean, - ].includes(varPayload.type) + ] + + return jinjaPromptVariableTypes.includes(varPayload.type) } const filterMemoryPromptVar = (varPayload: Var) => { - return [ + const memoryPromptVariableTypes: readonly VarType[] = [ VarType.arrayObject, VarType.array, VarType.number, @@ -75,7 +79,9 @@ const filterMemoryPromptVar = (varPayload: Var) => { VarType.arrayNumber, VarType.file, VarType.arrayFile, - ].includes(varPayload.type) + ] + + return memoryPromptVariableTypes.includes(varPayload.type) } const useLLMPromptConfig = ({ inputs, inputRef, isChatMode, isChatModel, setInputs }: Params) => { diff --git a/web/app/components/workflow/nodes/llm/types.ts b/web/app/components/workflow/nodes/llm/types.ts index ad67cf22ed5..82a2eeb14d6 100644 --- a/web/app/components/workflow/nodes/llm/types.ts +++ b/web/app/components/workflow/nodes/llm/types.ts @@ -29,29 +29,33 @@ export type LLMNodeType = CommonNodeType & { reasoning_format?: 'tagged' | 'separated' } -export enum Type { - string = 'string', - number = 'number', - boolean = 'boolean', - object = 'object', - array = 'array', - arrayString = 'array[string]', - arrayNumber = 'array[number]', - arrayObject = 'array[object]', - file = 'file', - enumType = 'enum', -} +export const Type = { + string: 'string', + number: 'number', + boolean: 'boolean', + object: 'object', + array: 'array', + arrayString: 'array[string]', + arrayNumber: 'array[number]', + arrayObject: 'array[object]', + file: 'file', + enumType: 'enum', +} as const -export enum ArrayType { - string = 'array[string]', - number = 'array[number]', - boolean = 'array[boolean]', - object = 'array[object]', -} +export type Type = (typeof Type)[keyof typeof Type] + +export const ArrayType = { + string: 'array[string]', + number: 'array[number]', + boolean: 'array[boolean]', + object: 'array[object]', +} as const + +export type ArrayType = (typeof ArrayType)[keyof typeof ArrayType] export type TypeWithArray = Type | ArrayType -type ArrayItemType = Exclude +type ArrayItemType = Exclude export type ArrayItems = Omit & { type: ArrayItemType } export type SchemaEnumType = string[] | number[] @@ -75,7 +79,7 @@ export type StructuredOutput = { } export type SchemaRoot = { - type: Type.object + type: typeof Type.object properties: Record required?: string[] additionalProperties: false diff --git a/web/app/components/workflow/nodes/llm/use-single-run-form-params.ts b/web/app/components/workflow/nodes/llm/use-single-run-form-params.ts index fb49995c3f8..1349a9f3de5 100644 --- a/web/app/components/workflow/nodes/llm/use-single-run-form-params.ts +++ b/web/app/components/workflow/nodes/llm/use-single-run-form-params.ts @@ -87,7 +87,7 @@ const useSingleRunFormParams = ({ })() const filterMemoryPromptVar = useCallback((varPayload: Var) => { - return [ + const supportedVariableTypes: readonly VarType[] = [ VarType.arrayObject, VarType.array, VarType.number, @@ -97,7 +97,9 @@ const useSingleRunFormParams = ({ VarType.arrayNumber, VarType.file, VarType.arrayFile, - ].includes(varPayload.type) + ] + + return supportedVariableTypes.includes(varPayload.type) }, []) const { availableVars } = useAvailableVarList(id, { diff --git a/web/app/components/workflow/nodes/llm/utils.ts b/web/app/components/workflow/nodes/llm/utils.ts index d0fab3edff5..5a65127f4aa 100644 --- a/web/app/components/workflow/nodes/llm/utils.ts +++ b/web/app/components/workflow/nodes/llm/utils.ts @@ -12,10 +12,10 @@ import { draft07Validator, forbidBooleanProperties } from '@/utils/validators' import { extractPluginId } from '../../utils/plugin' import { ArrayType, Type } from './types' -export enum LLMModelIssueCode { - providerRequired = 'provider-required', - providerPluginUnavailable = 'provider-plugin-unavailable', -} +export const LLMModelIssueCode = { + providerRequired: 'provider-required', + providerPluginUnavailable: 'provider-plugin-unavailable', +} as const export const isEnvironmentModelSource = (modelSelector: ValueSelector | undefined) => modelSelector != null && (modelSelector.length === 0 || modelSelector[0] === 'env') @@ -86,7 +86,7 @@ export const getFieldType = (field: Field) => { } export const getHasChildren = (schema: Field) => { - const complexTypes = [Type.object, Type.array] + const complexTypes: Type[] = [Type.object, Type.array] if (!complexTypes.includes(schema.type)) return false if (schema.type === Type.object) return schema.properties && Object.keys(schema.properties).length > 0 diff --git a/web/app/components/workflow/nodes/loop/__tests__/use-single-run-form-params.helpers.spec.ts b/web/app/components/workflow/nodes/loop/__tests__/use-single-run-form-params.helpers.spec.ts index 042726037b0..910c54cd91d 100644 --- a/web/app/components/workflow/nodes/loop/__tests__/use-single-run-form-params.helpers.spec.ts +++ b/web/app/components/workflow/nodes/loop/__tests__/use-single-run-form-params.helpers.spec.ts @@ -24,7 +24,7 @@ vi.mock('../../_base/components/variable/utils', () => ({ isSystemVar: (...args: unknown[]) => mockIsSystemVar(...args), })) -const createNode = (id: string, title: string, type = BlockEnum.Tool): Node => +const createNode = (id: string, title: string, type: BlockEnum = BlockEnum.Tool): Node => ({ id, position: { x: 0, y: 0 }, diff --git a/web/app/components/workflow/nodes/loop/__tests__/use-single-run-form-params.spec.ts b/web/app/components/workflow/nodes/loop/__tests__/use-single-run-form-params.spec.ts index bb69323d058..cf6451b4611 100644 --- a/web/app/components/workflow/nodes/loop/__tests__/use-single-run-form-params.spec.ts +++ b/web/app/components/workflow/nodes/loop/__tests__/use-single-run-form-params.spec.ts @@ -49,7 +49,7 @@ const createLoopNode = (overrides: Partial = {}): LoopNodeType => ...overrides, }) -const createVariableNode = (id: string, title: string, type = BlockEnum.Tool): Node => +const createVariableNode = (id: string, title: string, type: BlockEnum = BlockEnum.Tool): Node => ({ id, position: { x: 0, y: 0 }, diff --git a/web/app/components/workflow/nodes/loop/components/condition-list/condition-item.tsx b/web/app/components/workflow/nodes/loop/components/condition-list/condition-item.tsx index ff7a6e79243..6939492b2c8 100644 --- a/web/app/components/workflow/nodes/loop/components/condition-list/condition-item.tsx +++ b/web/app/components/workflow/nodes/loop/components/condition-list/condition-item.tsx @@ -77,6 +77,16 @@ const ConditionItem = ({ numberVariables, availableVars, }: ConditionItemProps) => { + const containmentOperators: readonly ComparisonOperator[] = [ + ComparisonOperator.contains, + ComparisonOperator.notContains, + ComparisonOperator.allOf, + ] + const membershipOperators: readonly ComparisonOperator[] = [ + ComparisonOperator.in, + ComparisonOperator.notIn, + ] + const { t } = useTranslation() const [isHovered, setIsHovered] = useState(false) @@ -122,11 +132,7 @@ const ConditionItem = ({ const isSubVariable = condition.varType === VarType.arrayFile && - [ - ComparisonOperator.contains, - ComparisonOperator.notContains, - ComparisonOperator.allOf, - ].includes(condition.comparison_operator!) + containmentOperators.includes(condition.comparison_operator!) const fileAttr = useMemo(() => { if (file) return file if (isSubVariableKey) { @@ -156,8 +162,7 @@ const ConditionItem = ({ ) const isSelect = - condition.comparison_operator && - [ComparisonOperator.in, ComparisonOperator.notIn].includes(condition.comparison_operator) + condition.comparison_operator && membershipOperators.includes(condition.comparison_operator) const selectOptions = useMemo>(() => { if (isSelect) { if (fileAttr?.key === 'type' || condition.comparison_operator === ComparisonOperator.allOf) { diff --git a/web/app/components/workflow/nodes/loop/default.ts b/web/app/components/workflow/nodes/loop/default.ts index f98694938af..364dbf516a2 100644 --- a/web/app/components/workflow/nodes/loop/default.ts +++ b/web/app/components/workflow/nodes/loop/default.ts @@ -41,6 +41,11 @@ const nodeDefault: NodeDefault = { }) payload.break_conditions!.forEach((condition) => { + const emptyOperators: readonly ComparisonOperator[] = [ + ComparisonOperator.empty, + ComparisonOperator.notEmpty, + ] + if ( !errorMessages && (!condition.variable_selector || condition.variable_selector.length === 0) @@ -57,9 +62,7 @@ const nodeDefault: NodeDefault = { if (!errorMessages) { if ( condition.sub_variable_condition && - ![ComparisonOperator.empty, ComparisonOperator.notEmpty].includes( - condition.comparison_operator!, - ) + !emptyOperators.includes(condition.comparison_operator!) ) { const isSet = condition.sub_variable_condition.conditions.every((c) => { if (!c.comparison_operator) return false diff --git a/web/app/components/workflow/nodes/loop/types.ts b/web/app/components/workflow/nodes/loop/types.ts index 191bad91415..0ef69b29115 100644 --- a/web/app/components/workflow/nodes/loop/types.ts +++ b/web/app/components/workflow/nodes/loop/types.ts @@ -9,34 +9,38 @@ import type { VarType, } from '@/app/components/workflow/types' -export enum LogicalOperator { - and = 'and', - or = 'or', -} +export const LogicalOperator = { + and: 'and', + or: 'or', +} as const -export enum ComparisonOperator { - contains = 'contains', - notContains = 'not contains', - startWith = 'start with', - endWith = 'end with', - is = 'is', - isNot = 'is not', - empty = 'empty', - notEmpty = 'not empty', - equal = '=', - notEqual = '≠', - largerThan = '>', - lessThan = '<', - largerThanOrEqual = '≥', - lessThanOrEqual = '≤', - isNull = 'is null', - isNotNull = 'is not null', - in = 'in', - notIn = 'not in', - allOf = 'all of', - exists = 'exists', - notExists = 'not exists', -} +export type LogicalOperator = (typeof LogicalOperator)[keyof typeof LogicalOperator] + +export const ComparisonOperator = { + contains: 'contains', + notContains: 'not contains', + startWith: 'start with', + endWith: 'end with', + is: 'is', + isNot: 'is not', + empty: 'empty', + notEmpty: 'not empty', + equal: '=', + notEqual: '≠', + largerThan: '>', + lessThan: '<', + largerThanOrEqual: '≥', + lessThanOrEqual: '≤', + isNull: 'is null', + isNotNull: 'is not null', + in: 'in', + notIn: 'not in', + allOf: 'all of', + exists: 'exists', + notExists: 'not exists', +} as const + +export type ComparisonOperator = (typeof ComparisonOperator)[keyof typeof ComparisonOperator] export type Condition = { id: string diff --git a/web/app/components/workflow/nodes/loop/use-config.helpers.ts b/web/app/components/workflow/nodes/loop/use-config.helpers.ts index 16596ef38bc..de8dc62864c 100644 --- a/web/app/components/workflow/nodes/loop/use-config.helpers.ts +++ b/web/app/components/workflow/nodes/loop/use-config.helpers.ts @@ -7,13 +7,15 @@ import { LogicalOperator } from './types' import { getOperators } from './utils' export const canUseAsLoopInput = (variable: Var) => { - return [ + const arrayVariableTypes: readonly VarType[] = [ VarType.array, VarType.arrayString, VarType.arrayNumber, VarType.arrayObject, VarType.arrayFile, - ].includes(variable.type) + ] + + return arrayVariableTypes.includes(variable.type) } export const updateErrorHandleMode = (inputs: LoopNodeType, mode: ErrorHandleMode) => diff --git a/web/app/components/workflow/nodes/loop/utils.ts b/web/app/components/workflow/nodes/loop/utils.ts index 8d587efc538..d1c88e32f11 100644 --- a/web/app/components/workflow/nodes/loop/utils.ts +++ b/web/app/components/workflow/nodes/loop/utils.ts @@ -2,14 +2,16 @@ import { VarType } from '@/app/components/workflow/types' import { ComparisonOperator } from './types' export const isEmptyRelatedOperator = (operator: ComparisonOperator) => { - return [ + const valueFreeOperators: readonly ComparisonOperator[] = [ ComparisonOperator.empty, ComparisonOperator.notEmpty, ComparisonOperator.isNull, ComparisonOperator.isNotNull, ComparisonOperator.exists, ComparisonOperator.notExists, - ].includes(operator) + ] + + return valueFreeOperators.includes(operator) } const notTranslateKey = [ @@ -161,14 +163,16 @@ export const getOperators = (type?: VarType, file?: { key: string }) => { } export const comparisonOperatorNotRequireValue = (operator?: ComparisonOperator) => { - if (!operator) return false - - return [ + const valueFreeOperators: readonly ComparisonOperator[] = [ ComparisonOperator.empty, ComparisonOperator.notEmpty, ComparisonOperator.isNull, ComparisonOperator.isNotNull, ComparisonOperator.exists, ComparisonOperator.notExists, - ].includes(operator) + ] + + if (!operator) return false + + return valueFreeOperators.includes(operator) } diff --git a/web/app/components/workflow/nodes/parameter-extractor/types.ts b/web/app/components/workflow/nodes/parameter-extractor/types.ts index 5fe851be9c8..1021dd56a47 100644 --- a/web/app/components/workflow/nodes/parameter-extractor/types.ts +++ b/web/app/components/workflow/nodes/parameter-extractor/types.ts @@ -6,16 +6,18 @@ import type { VisionSetting, } from '@/app/components/workflow/types' -export enum ParamType { - string = 'string', - number = 'number', - bool = 'boolean', - select = 'select', - arrayString = 'array[string]', - arrayNumber = 'array[number]', - arrayObject = 'array[object]', - arrayBool = 'array[boolean]', -} +export const ParamType = { + string: 'string', + number: 'number', + bool: 'boolean', + select: 'select', + arrayString: 'array[string]', + arrayNumber: 'array[number]', + arrayObject: 'array[object]', + arrayBool: 'array[boolean]', +} as const + +export type ParamType = (typeof ParamType)[keyof typeof ParamType] export type Param = { name: string @@ -25,10 +27,12 @@ export type Param = { required?: boolean } -export enum ReasoningModeType { - prompt = 'prompt', - functionCall = 'function_call', -} +export const ReasoningModeType = { + prompt: 'prompt', + functionCall: 'function_call', +} as const + +export type ReasoningModeType = (typeof ReasoningModeType)[keyof typeof ReasoningModeType] export type ParameterExtractorNodeType = CommonNodeType & { model: ModelConfig diff --git a/web/app/components/workflow/nodes/parameter-extractor/use-config.ts b/web/app/components/workflow/nodes/parameter-extractor/use-config.ts index d79d6d79e4e..1779edfc9b0 100644 --- a/web/app/components/workflow/nodes/parameter-extractor/use-config.ts +++ b/web/app/components/workflow/nodes/parameter-extractor/use-config.ts @@ -50,7 +50,9 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => { ) const filterVar = useCallback((varPayload: Var) => { - return [VarType.string].includes(varPayload.type) + const stringVariableTypes: readonly VarType[] = [VarType.string] + + return stringVariableTypes.includes(varPayload.type) }, []) const handleInputVarChange = useCallback( @@ -190,7 +192,9 @@ const useConfig = (id: string, payload: ParameterExtractorNodeType) => { const isSupportFunctionCall = supportFunctionCall(currModel?.features) const filterInputVar = useCallback((varPayload: Var) => { - return [VarType.number, VarType.string].includes(varPayload.type) + const scalarVariableTypes: readonly VarType[] = [VarType.number, VarType.string] + + return scalarVariableTypes.includes(varPayload.type) }, []) const { availableVars, availableNodesWithParent } = useAvailableVarList(id, { diff --git a/web/app/components/workflow/nodes/parameter-extractor/use-single-run-form-params.ts b/web/app/components/workflow/nodes/parameter-extractor/use-single-run-form-params.ts index be4cbeda896..804a9193845 100644 --- a/web/app/components/workflow/nodes/parameter-extractor/use-single-run-form-params.ts +++ b/web/app/components/workflow/nodes/parameter-extractor/use-single-run-form-params.ts @@ -76,7 +76,9 @@ const useSingleRunFormParams = ({ ) const filterVisionInputVar = useCallback((varPayload: Var) => { - return [VarType.file, VarType.arrayFile].includes(varPayload.type) + const fileVariableTypes: readonly VarType[] = [VarType.file, VarType.arrayFile] + + return fileVariableTypes.includes(varPayload.type) }, []) const { availableVars: availableVisionVars } = useAvailableVarList(id, { onlyLeafNodeVar: false, diff --git a/web/app/components/workflow/nodes/question-classifier/use-config.ts b/web/app/components/workflow/nodes/question-classifier/use-config.ts index a2c8f9c2434..b87f888d3de 100644 --- a/web/app/components/workflow/nodes/question-classifier/use-config.ts +++ b/web/app/components/workflow/nodes/question-classifier/use-config.ts @@ -181,11 +181,15 @@ const useConfig = (id: string, payload: QuestionClassifierNodeType) => { ) const filterInputVar = useCallback((varPayload: Var) => { - return [VarType.number, VarType.string].includes(varPayload.type) + const scalarVariableTypes: readonly VarType[] = [VarType.number, VarType.string] + + return scalarVariableTypes.includes(varPayload.type) }, []) const filterVisionInputVar = useCallback((varPayload: Var) => { - return [VarType.file, VarType.arrayFile].includes(varPayload.type) + const fileVariableTypes: readonly VarType[] = [VarType.file, VarType.arrayFile] + + return fileVariableTypes.includes(varPayload.type) }, []) const { availableVars, availableNodesWithParent } = useAvailableVarList(id, { diff --git a/web/app/components/workflow/nodes/question-classifier/use-single-run-form-params.ts b/web/app/components/workflow/nodes/question-classifier/use-single-run-form-params.ts index dadfc44d43d..593e93bd8e0 100644 --- a/web/app/components/workflow/nodes/question-classifier/use-single-run-form-params.ts +++ b/web/app/components/workflow/nodes/question-classifier/use-single-run-form-params.ts @@ -75,7 +75,9 @@ const useSingleRunFormParams = ({ ) const filterVisionInputVar = useCallback((varPayload: Var) => { - return [VarType.file, VarType.arrayFile].includes(varPayload.type) + const fileVariableTypes: readonly VarType[] = [VarType.file, VarType.arrayFile] + + return fileVariableTypes.includes(varPayload.type) }, []) const { availableVars: availableVisionVars } = useAvailableVarList(id, { onlyLeafNodeVar: false, diff --git a/web/app/components/workflow/nodes/template-transform/use-config.ts b/web/app/components/workflow/nodes/template-transform/use-config.ts index 2b8c572fc93..32a2ba6153e 100644 --- a/web/app/components/workflow/nodes/template-transform/use-config.ts +++ b/web/app/components/workflow/nodes/template-transform/use-config.ts @@ -87,7 +87,7 @@ const useConfig = (id: string, payload: TemplateTransformNodeType) => { ) const filterVar = useCallback((varPayload: Var) => { - return [ + const supportedVariableTypes: readonly VarType[] = [ VarType.string, VarType.number, VarType.boolean, @@ -97,7 +97,9 @@ const useConfig = (id: string, payload: TemplateTransformNodeType) => { VarType.arrayString, VarType.arrayBoolean, VarType.arrayObject, - ].includes(varPayload.type) + ] + + return supportedVariableTypes.includes(varPayload.type) }, []) return { diff --git a/web/app/components/workflow/nodes/trigger-plugin/default.ts b/web/app/components/workflow/nodes/trigger-plugin/default.ts index 551ebba9e58..1256faf4cb2 100644 --- a/web/app/components/workflow/nodes/trigger-plugin/default.ts +++ b/web/app/components/workflow/nodes/trigger-plugin/default.ts @@ -122,9 +122,9 @@ const toFieldType = (normalizedType: string | undefined, schemaType?: string): T } } -const toArrayItemType = (type: Type): Exclude => { +const toArrayItemType = (type: Type): Exclude => { if (type === Type.array) return Type.object - return type as Exclude + return type as Exclude } const convertJsonSchemaToField = ( diff --git a/web/app/components/workflow/nodes/variable-assigner/components/__tests__/node-group-item.spec.tsx b/web/app/components/workflow/nodes/variable-assigner/components/__tests__/node-group-item.spec.tsx index 59c4e71e992..97572f22c23 100644 --- a/web/app/components/workflow/nodes/variable-assigner/components/__tests__/node-group-item.spec.tsx +++ b/web/app/components/workflow/nodes/variable-assigner/components/__tests__/node-group-item.spec.tsx @@ -1,3 +1,4 @@ +import type { VariableAssignerNodeType } from '../../types' import { fireEvent, screen } from '@testing-library/react' import { createNode, @@ -22,7 +23,7 @@ vi.mock('../../hooks', () => ({ useGetAvailableVars: () => mockGetAvailableVars, })) -const createData = () => ({ +const createData = (): VariableAssignerNodeType => ({ title: 'Variable Assigner', desc: '', type: BlockEnum.VariableAssigner, diff --git a/web/app/components/workflow/panel/chat-variable-panel/type.ts b/web/app/components/workflow/panel/chat-variable-panel/type.ts index 44c321d734f..bff874148db 100644 --- a/web/app/components/workflow/panel/chat-variable-panel/type.ts +++ b/web/app/components/workflow/panel/chat-variable-panel/type.ts @@ -1,10 +1,12 @@ -export enum ChatVarType { - Number = 'number', - String = 'string', - Boolean = 'boolean', - Object = 'object', - ArrayString = 'array[string]', - ArrayNumber = 'array[number]', - ArrayBoolean = 'array[boolean]', - ArrayObject = 'array[object]', -} +export const ChatVarType = { + Number: 'number', + String: 'string', + Boolean: 'boolean', + Object: 'object', + ArrayString: 'array[string]', + ArrayNumber: 'array[number]', + ArrayBoolean: 'array[boolean]', + ArrayObject: 'array[object]', +} as const + +export type ChatVarType = (typeof ChatVarType)[keyof typeof ChatVarType] diff --git a/web/app/components/workflow/panel/version-history-panel/index.tsx b/web/app/components/workflow/panel/version-history-panel/index.tsx index 536461e50b1..a31ee13360c 100644 --- a/web/app/components/workflow/panel/version-history-panel/index.tsx +++ b/web/app/components/workflow/panel/version-history-panel/index.tsx @@ -63,7 +63,9 @@ export const VersionHistoryPanel = ({ updateVersionUrl, latestVersionId, }: VersionHistoryPanelProps) => { - const [filterValue, setFilterValue] = useState(WorkflowVersionFilterOptions.all) + const [filterValue, setFilterValue] = useState( + WorkflowVersionFilterOptions.all, + ) const [isOnlyShowNamedVersions, setIsOnlyShowNamedVersions] = useState(false) const [operatedItem, setOperatedItem] = useState() const [restoreConfirmOpen, setRestoreConfirmOpen] = useState(false) diff --git a/web/app/components/workflow/run/utils/format-log/agent/__tests__/index.spec.ts b/web/app/components/workflow/run/utils/format-log/agent/__tests__/index.spec.ts index 0593effb424..90e310efd0c 100644 --- a/web/app/components/workflow/run/utils/format-log/agent/__tests__/index.spec.ts +++ b/web/app/components/workflow/run/utils/format-log/agent/__tests__/index.spec.ts @@ -2,7 +2,10 @@ import type { AgentLogItem, NodeTracing } from '@/types/workflow' import { BlockEnum } from '@/app/components/workflow/types' import format from '..' -const createTrace = (agentLog: AgentLogItem[], nodeType = BlockEnum.Agent): NodeTracing => +const createTrace = ( + agentLog: AgentLogItem[], + nodeType: BlockEnum = BlockEnum.Agent, +): NodeTracing => ({ node_id: 'agent-node', node_type: nodeType, diff --git a/web/app/components/workflow/run/utils/format-log/agent/index.ts b/web/app/components/workflow/run/utils/format-log/agent/index.ts index ec36cf3182b..326353c18ee 100644 --- a/web/app/components/workflow/run/utils/format-log/agent/index.ts +++ b/web/app/components/workflow/run/utils/format-log/agent/index.ts @@ -2,7 +2,7 @@ import type { AgentLogItem, AgentLogItemWithChildren, NodeTracing } from '@/type import { cloneDeep } from 'es-toolkit/object' import { BlockEnum } from '@/app/components/workflow/types' -const supportedAgentLogNodes = [BlockEnum.Agent, BlockEnum.Tool] +const supportedAgentLogNodes: BlockEnum[] = [BlockEnum.Agent, BlockEnum.Tool] const remove = (node: AgentLogItemWithChildren, removeId: string) => { let { children } = node diff --git a/web/app/components/workflow/types.ts b/web/app/components/workflow/types.ts index 6ffba0b4713..e4613ddd9df 100644 --- a/web/app/components/workflow/types.ts +++ b/web/app/components/workflow/types.ts @@ -24,51 +24,57 @@ import type { PanelProps, } from '@/types/workflow' -export enum BlockEnum { - Start = 'start', - StartPlaceholder = 'start-placeholder', - End = 'end', - Answer = 'answer', - LLM = 'llm', - KnowledgeRetrieval = 'knowledge-retrieval', - QuestionClassifier = 'question-classifier', - IfElse = 'if-else', - Code = 'code', - TemplateTransform = 'template-transform', - HttpRequest = 'http-request', - VariableAssigner = 'variable-assigner', - VariableAggregator = 'variable-aggregator', - Tool = 'tool', - ParameterExtractor = 'parameter-extractor', - Iteration = 'iteration', - DocExtractor = 'document-extractor', - ListFilter = 'list-operator', - IterationStart = 'iteration-start', - Assigner = 'assigner', // is now named as VariableAssigner - Agent = 'agent', - AgentV2 = 'agent-v2', - Loop = 'loop', - LoopStart = 'loop-start', - LoopEnd = 'loop-end', - HumanInput = 'human-input', - DataSource = 'datasource', - DataSourceEmpty = 'datasource-empty', - KnowledgeBase = 'knowledge-index', - TriggerSchedule = 'trigger-schedule', - TriggerWebhook = 'trigger-webhook', - TriggerPlugin = 'trigger-plugin', -} +export const BlockEnum = { + Start: 'start', + StartPlaceholder: 'start-placeholder', + End: 'end', + Answer: 'answer', + LLM: 'llm', + KnowledgeRetrieval: 'knowledge-retrieval', + QuestionClassifier: 'question-classifier', + IfElse: 'if-else', + Code: 'code', + TemplateTransform: 'template-transform', + HttpRequest: 'http-request', + VariableAssigner: 'variable-assigner', + VariableAggregator: 'variable-aggregator', + Tool: 'tool', + ParameterExtractor: 'parameter-extractor', + Iteration: 'iteration', + DocExtractor: 'document-extractor', + ListFilter: 'list-operator', + IterationStart: 'iteration-start', + Assigner: 'assigner', // is now named as VariableAssigner + Agent: 'agent', + AgentV2: 'agent-v2', + Loop: 'loop', + LoopStart: 'loop-start', + LoopEnd: 'loop-end', + HumanInput: 'human-input', + DataSource: 'datasource', + DataSourceEmpty: 'datasource-empty', + KnowledgeBase: 'knowledge-index', + TriggerSchedule: 'trigger-schedule', + TriggerWebhook: 'trigger-webhook', + TriggerPlugin: 'trigger-plugin', +} as const -export enum ControlMode { - Pointer = 'pointer', - Hand = 'hand', - Comment = 'comment', -} -export enum ErrorHandleMode { - Terminated = 'terminated', - ContinueOnError = 'continue-on-error', - RemoveAbnormalOutput = 'remove-abnormal-output', -} +export type BlockEnum = (typeof BlockEnum)[keyof typeof BlockEnum] + +export const ControlMode = { + Pointer: 'pointer', + Hand: 'hand', + Comment: 'comment', +} as const + +export type ControlMode = (typeof ControlMode)[keyof typeof ControlMode] +export const ErrorHandleMode = { + Terminated: 'terminated', + ContinueOnError: 'continue-on-error', + RemoveAbnormalOutput: 'remove-abnormal-output', +} as const + +export type ErrorHandleMode = (typeof ErrorHandleMode)[keyof typeof ErrorHandleMode] export type Branch = { id: string name: string @@ -203,22 +209,24 @@ export type GlobalVariable = { description: string } -export enum InputVarType { - textInput = 'text-input', - paragraph = 'paragraph', - select = 'select', - number = 'number', - url = 'url', - files = 'files', - json = 'json', // obj, array - jsonObject = 'json_object', // only object support define json schema - contexts = 'contexts', // knowledge retrieval - iterator = 'iterator', // iteration input - singleFile = 'file', - multiFiles = 'file-list', - loop = 'loop', // loop input - checkbox = 'checkbox', -} +export const InputVarType = { + textInput: 'text-input', + paragraph: 'paragraph', + select: 'select', + number: 'number', + url: 'url', + files: 'files', + json: 'json', // obj, array + jsonObject: 'json_object', // only object support define json schema + contexts: 'contexts', // knowledge retrieval + iterator: 'iterator', // iteration input + singleFile: 'file', + multiFiles: 'file-list', + loop: 'loop', // loop input + checkbox: 'checkbox', +} as const + +export type InputVarType = (typeof InputVarType)[keyof typeof InputVarType] export type InputVar = { type: InputVarType @@ -249,16 +257,20 @@ export type ModelConfig = LLMEnvironmentVariableValue & { completion_params: LLMCompletionParams } -export enum PromptRole { - system = 'system', - user = 'user', - assistant = 'assistant', -} +export const PromptRole = { + system: 'system', + user: 'user', + assistant: 'assistant', +} as const -export enum EditionType { - basic = 'basic', - jinja2 = 'jinja2', -} +export type PromptRole = (typeof PromptRole)[keyof typeof PromptRole] + +export const EditionType = { + basic: 'basic', + jinja2: 'jinja2', +} as const + +export type EditionType = (typeof EditionType)[keyof typeof EditionType] export type PromptItem = { id?: string @@ -268,10 +280,12 @@ export type PromptItem = { jinja2_text?: string } -export enum MemoryRole { - user = 'user', - assistant = 'assistant', -} +export const MemoryRole = { + user: 'user', + assistant: 'assistant', +} as const + +export type MemoryRole = (typeof MemoryRole)[keyof typeof MemoryRole] export type RolePrefix = { user: string @@ -287,28 +301,32 @@ export type Memory = { query_prompt_template: string } -export enum VarType { - string = 'string', - number = 'number', - integer = 'integer', - secret = 'secret', - boolean = 'boolean', - object = 'object', - file = 'file', - array = 'array', - arrayString = 'array[string]', - arrayNumber = 'array[number]', - arrayObject = 'array[object]', - arrayBoolean = 'array[boolean]', - arrayFile = 'array[file]', - any = 'any', - arrayAny = 'array[any]', -} +export const VarType = { + string: 'string', + number: 'number', + integer: 'integer', + secret: 'secret', + boolean: 'boolean', + object: 'object', + file: 'file', + array: 'array', + arrayString: 'array[string]', + arrayNumber: 'array[number]', + arrayObject: 'array[object]', + arrayBoolean: 'array[boolean]', + arrayFile: 'array[file]', + any: 'any', + arrayAny: 'array[any]', +} as const -export enum ValueType { - variable = 'variable', - constant = 'constant', -} +export type VarType = (typeof VarType)[keyof typeof VarType] + +export const ValueType = { + variable: 'variable', + constant: 'constant', +} as const + +export type ValueType = (typeof ValueType)[keyof typeof ValueType] export type Var = { variable: string @@ -369,32 +387,37 @@ export type NodeDefault = { export type OnSelectBlock = (type: BlockEnum, defaultValue?: BlockDefaultValue) => void -export enum WorkflowRunningStatus { - Waiting = 'waiting', - Running = 'running', - Succeeded = 'succeeded', - Failed = 'failed', - Stopped = 'stopped', - Paused = 'paused', -} +export const WorkflowRunningStatus = { + Waiting: 'waiting', + Running: 'running', + Succeeded: 'succeeded', + Failed: 'failed', + Stopped: 'stopped', + Paused: 'paused', +} as const -export enum WorkflowVersion { - Draft = 'draft', - Latest = 'latest', -} +export type WorkflowRunningStatus = + (typeof WorkflowRunningStatus)[keyof typeof WorkflowRunningStatus] -export enum NodeRunningStatus { - NotStart = 'not-start', - Waiting = 'waiting', - Listening = 'listening', - Running = 'running', - Succeeded = 'succeeded', - Failed = 'failed', - Exception = 'exception', - Retry = 'retry', - Stopped = 'stopped', - Paused = 'paused', -} +export const WorkflowVersion = { + Draft: 'draft', + Latest: 'latest', +} as const + +export const NodeRunningStatus = { + NotStart: 'not-start', + Waiting: 'waiting', + Listening: 'listening', + Running: 'running', + Succeeded: 'succeeded', + Failed: 'failed', + Exception: 'exception', + Retry: 'retry', + Stopped: 'stopped', + Paused: 'paused', +} as const + +export type NodeRunningStatus = (typeof NodeRunningStatus)[keyof typeof NodeRunningStatus] export type OnNodeAdd = ( newNodePayload: { @@ -459,10 +482,12 @@ export type HistoryWorkflowData = { finished_at?: number } -export enum ChangeType { - changeVarName = 'changeVarName', - remove = 'remove', -} +export const ChangeType = { + changeVarName: 'changeVarName', + remove: 'remove', +} as const + +export type ChangeType = (typeof ChangeType)[keyof typeof ChangeType] export type MoreInfo = { type: ChangeType @@ -483,13 +508,16 @@ export type RAGRecommendedPlugins = { uninstalled_recommended_plugins: Plugin[] } -export enum SupportUploadFileTypes { - image = 'image', - document = 'document', - audio = 'audio', - video = 'video', - custom = 'custom', -} +export const SupportUploadFileTypes = { + image: 'image', + document: 'document', + audio: 'audio', + video: 'video', + custom: 'custom', +} as const + +export type SupportUploadFileTypes = + (typeof SupportUploadFileTypes)[keyof typeof SupportUploadFileTypes] export type UploadFileSetting = { allowed_file_upload_methods: TransferMethod[] @@ -505,18 +533,24 @@ export type VisionSetting = { detail: Resolution } -export enum WorkflowVersionFilterOptions { - all = 'all', - onlyYours = 'onlyYours', -} +export const WorkflowVersionFilterOptions = { + all: 'all', + onlyYours: 'onlyYours', +} as const -export enum VersionHistoryContextMenuOptions { - restore = 'restore', - edit = 'edit', - delete = 'delete', - exportDSL = 'exportDSL', - copyId = 'copyId', -} +export type WorkflowVersionFilterOptions = + (typeof WorkflowVersionFilterOptions)[keyof typeof WorkflowVersionFilterOptions] + +export const VersionHistoryContextMenuOptions = { + restore: 'restore', + edit: 'edit', + delete: 'delete', + exportDSL: 'exportDSL', + copyId: 'copyId', +} as const + +export type VersionHistoryContextMenuOptions = + (typeof VersionHistoryContextMenuOptions)[keyof typeof VersionHistoryContextMenuOptions] export type ChildNodeTypeCount = { [key: string]: number diff --git a/web/app/components/workflow/update-dsl-modal.helpers.ts b/web/app/components/workflow/update-dsl-modal.helpers.ts index 67a6563cd5b..0aaab0a260c 100644 --- a/web/app/components/workflow/update-dsl-modal.helpers.ts +++ b/web/app/components/workflow/update-dsl-modal.helpers.ts @@ -45,7 +45,7 @@ type ImportNotificationPayload = { children?: string } -export const getInvalidNodeTypes = (mode?: AppModeEnum) => { +export const getInvalidNodeTypes = (mode?: AppModeEnum): BlockEnum[] => { if (mode === AppModeEnum.ADVANCED_CHAT) { return [ BlockEnum.End, diff --git a/web/models/datasets.ts b/web/models/datasets.ts index 61181fbd74a..d8e20c29d60 100644 --- a/web/models/datasets.ts +++ b/web/models/datasets.ts @@ -15,23 +15,27 @@ import { } from '@/app/components/base/icons/src/public/knowledge/dataset-card' import { PermissionLevel } from './permission' -export enum DataSourceType { - FILE = 'upload_file', - NOTION = 'notion_import', - WEB = 'website_crawl', -} +export const DataSourceType = { + FILE: 'upload_file', + NOTION: 'notion_import', + WEB: 'website_crawl', +} as const + +export type DataSourceType = (typeof DataSourceType)[keyof typeof DataSourceType] // Re-export PermissionLevel as DatasetPermission for backward compatibility export const DatasetPermission = PermissionLevel export type DatasetPermission = PermissionLevel -export enum ChunkingMode { - text = 'text_model', // General text - qa = 'qa_model', // General QA - parentChild = 'hierarchical_model', // Parent-Child +export const ChunkingMode = { + text: 'text_model', // General text + qa: 'qa_model', // General QA + parentChild: 'hierarchical_model', // Parent-Child // graph = 'graph', // todo: Graph RAG -} +} as const + +export type ChunkingMode = (typeof ChunkingMode)[keyof typeof ChunkingMode] export type MetadataInDoc = { value: string @@ -183,11 +187,13 @@ export type CrawlResult = { time_consuming: number | string } -export enum CrawlStep { - init = 'init', - running = 'running', - finished = 'finished', -} +export const CrawlStep = { + init: 'init', + running: 'running', + finished: 'finished', +} as const + +export type CrawlStep = (typeof CrawlStep)[keyof typeof CrawlStep] export type FileItem = { fileID: string @@ -262,10 +268,12 @@ export type IndexingStatusBatchResponse = { data: IndexingStatusResponse[] } -export enum ProcessMode { - general = 'custom', - parentChild = 'hierarchical', -} +export const ProcessMode = { + general: 'custom', + parentChild: 'hierarchical', +} as const + +export type ProcessMode = (typeof ProcessMode)[keyof typeof ProcessMode] export type ParentMode = 'full-doc' | 'paragraph' @@ -725,16 +733,20 @@ export type SelectedDatasetsMode = { inconsistentEmbeddingModel: boolean } -export enum WeightedScoreEnum { - SemanticFirst = 'semantic_first', - KeywordFirst = 'keyword_first', - Customized = 'customized', -} +export const WeightedScoreEnum = { + SemanticFirst: 'semantic_first', + KeywordFirst: 'keyword_first', + Customized: 'customized', +} as const -export enum RerankingModeEnum { - RerankingModel = 'reranking_model', - WeightedScore = 'weighted_score', -} +export type WeightedScoreEnum = (typeof WeightedScoreEnum)[keyof typeof WeightedScoreEnum] + +export const RerankingModeEnum = { + RerankingModel: 'reranking_model', + WeightedScore: 'weighted_score', +} as const + +export type RerankingModeEnum = (typeof RerankingModeEnum)[keyof typeof RerankingModeEnum] export const DEFAULT_WEIGHTED_SCORE = { allHighQualityVectorSearch: { @@ -773,14 +785,16 @@ export type ChildSegmentsResponse = { } // Used in api url -export enum DocumentActionType { - enable = 'enable', - disable = 'disable', - archive = 'archive', - unArchive = 'un_archive', - delete = 'delete', - summary = 'summary', -} +export const DocumentActionType = { + enable: 'enable', + disable: 'disable', + archive: 'archive', + unArchive: 'un_archive', + delete: 'delete', + summary: 'summary', +} as const + +export type DocumentActionType = (typeof DocumentActionType)[keyof typeof DocumentActionType] export type UpdateDocumentBatchParams = { datasetId: string diff --git a/web/models/debug.ts b/web/models/debug.ts index 946bbf6e1a5..ecb053fedca 100644 --- a/web/models/debug.ts +++ b/web/models/debug.ts @@ -17,10 +17,12 @@ import type { export type Inputs = Record -export enum PromptMode { - simple = 'simple', - advanced = 'advanced', -} +export const PromptMode = { + simple: 'simple', + advanced: 'advanced', +} as const + +export type PromptMode = (typeof PromptMode)[keyof typeof PromptMode] export type PromptItem = { role?: PromptRole @@ -46,11 +48,13 @@ export type BlockStatus = { query: boolean } -export enum PromptRole { - system = 'system', - user = 'user', - assistant = 'assistant', -} +export const PromptRole = { + system: 'system', + user: 'user', + assistant: 'assistant', +} as const + +export type PromptRole = (typeof PromptRole)[keyof typeof PromptRole] export type PromptVariable = { key: string diff --git a/web/models/log.ts b/web/models/log.ts index fb2f202e710..c00ca7a1be9 100644 --- a/web/models/log.ts +++ b/web/models/log.ts @@ -205,15 +205,18 @@ export type LogMessageAnnotationsRequest = Omit = { [PipelineInputVarType.textInput]: BaseFieldType.textInput, @@ -280,11 +284,13 @@ export type ConversionResponse = { status: 'success' | 'failed' } -export enum OnlineDriveFileType { - file = 'file', - folder = 'folder', - bucket = 'bucket', -} +export const OnlineDriveFileType = { + file: 'file', + folder: 'folder', + bucket: 'bucket', +} as const + +export type OnlineDriveFileType = (typeof OnlineDriveFileType)[keyof typeof OnlineDriveFileType] export type OnlineDriveFile = { id: string diff --git a/web/service/knowledge/use-create-dataset.ts b/web/service/knowledge/use-create-dataset.ts index 963b2f09e58..aa146694536 100644 --- a/web/service/knowledge/use-create-dataset.ts +++ b/web/service/knowledge/use-create-dataset.ts @@ -78,7 +78,7 @@ type GetFileIndexingEstimateParamsOptionBase = { } type GetFileIndexingEstimateParamsOptionFile = GetFileIndexingEstimateParamsOptionBase & { - dataSourceType: DataSourceType.FILE + dataSourceType: typeof DataSourceType.FILE files: CustomFile[] } @@ -121,7 +121,7 @@ export const useFetchFileIndexingEstimateForFile = ( } type GetFileIndexingEstimateParamsOptionNotion = GetFileIndexingEstimateParamsOptionBase & { - dataSourceType: DataSourceType.NOTION + dataSourceType: typeof DataSourceType.NOTION notionPages: NotionPage[] credential_id: string } @@ -162,7 +162,7 @@ export const useFetchFileIndexingEstimateForNotion = ( } type GetFileIndexingEstimateParamsOptionWeb = GetFileIndexingEstimateParamsOptionBase & { - dataSourceType: DataSourceType.WEB + dataSourceType: typeof DataSourceType.WEB websitePages: CrawlResultItem[] crawlOptions?: CrawlOptions websiteCrawlProvider: DataSourceProvider diff --git a/web/service/share.ts b/web/service/share.ts index 246409f7d07..a446c3ddde7 100644 --- a/web/service/share.ts +++ b/web/service/share.ts @@ -21,11 +21,13 @@ import { import { resolveWebAppAddress } from './webapp-address' import { getOrCreateWebAppSessionId, getWebAppAccessToken } from './webapp-auth' -export enum AppSourceType { - webApp = 'webApp', - installedApp = 'installedApp', - tryApp = 'tryApp', -} +export const AppSourceType = { + webApp: 'webApp', + installedApp: 'installedApp', + tryApp: 'tryApp', +} as const + +export type AppSourceType = (typeof AppSourceType)[keyof typeof AppSourceType] const apiPrefix = { [AppSourceType.webApp]: '', diff --git a/web/types/common.ts b/web/types/common.ts index 6c7cbebf20a..f2097b02cdd 100644 --- a/web/types/common.ts +++ b/web/types/common.ts @@ -1,5 +1,7 @@ -export enum FlowType { - appFlow = 'appFlow', - ragPipeline = 'ragPipeline', - snippet = 'snippet', -} +export const FlowType = { + appFlow: 'appFlow', + ragPipeline: 'ragPipeline', + snippet: 'snippet', +} as const + +export type FlowType = (typeof FlowType)[keyof typeof FlowType] diff --git a/web/utils/var.ts b/web/utils/var.ts index acccd7211ce..167ae9cef69 100644 --- a/web/utils/var.ts +++ b/web/utils/var.ts @@ -36,7 +36,10 @@ export const getNewVar = (key: string, type: string) => { } } -export const getNewVarInWorkflow = (key: string, type = InputVarType.textInput): InputVar => { +export const getNewVarInWorkflow = ( + key: string, + type: InputVarType = InputVarType.textInput, +): InputVar => { const { ...rest } = VAR_ITEM_TEMPLATE_IN_WORKFLOW if (type !== InputVarType.textInput) { return {