From 52b1bc5b09ff73f259407409deec36367347af77 Mon Sep 17 00:00:00 2001 From: Stephen Zhou Date: Thu, 2 Apr 2026 15:58:15 +0800 Subject: [PATCH 01/29] refactor: split icon collections (#34453) --- .gitignore | 2 +- .../assets/public/avatar/robot.svg | 0 .../assets/public/avatar/user.svg | 0 .../assets/public/billing/ar-cube-1.svg | 0 .../assets/public/billing/asterisk.svg | 0 .../public/billing/aws-marketplace-dark.svg | 0 .../public/billing/aws-marketplace-light.svg | 0 .../assets/public/billing/azure.svg | 0 .../assets/public/billing/buildings.svg | 0 .../assets/public/billing/diamond.svg | 0 .../assets/public/billing/google-cloud.svg | 0 .../assets/public/billing/group-2.svg | 0 .../assets/public/billing/keyframe.svg | 0 .../assets/public/billing/sparkles-soft.svg | 0 .../assets/public/billing/sparkles.svg | 0 .../assets/public/common/d.svg | 0 .../public/common/diagonal-dividing-line.svg | 0 .../assets/public/common/dify.svg | 0 .../assets/public/common/gdpr.svg | 0 .../assets/public/common/github.svg | 0 .../assets/public/common/highlight.svg | 0 .../assets/public/common/iso.svg | 0 .../assets/public/common/line-3.svg | 0 .../assets/public/common/lock.svg | 0 .../public/common/message-chat-square.svg | 0 .../public/common/multi-path-retrieval.svg | 0 .../assets/public/common/n-to-1-retrieval.svg | 0 .../assets/public/common/notion.svg | 0 .../assets/public/common/soc2.svg | 0 .../public/common/sparkles-soft-accent.svg | 0 .../assets/public/common/sparkles-soft.svg | 0 .../assets/public/education/triangle.svg | 0 .../assets/public/files/csv.svg | 0 .../assets/public/files/doc.svg | 0 .../assets/public/files/docx.svg | 0 .../assets/public/files/html.svg | 0 .../assets/public/files/json.svg | 0 .../assets/public/files/md.svg | 0 .../assets/public/files/pdf.svg | 0 .../assets/public/files/txt.svg | 0 .../assets/public/files/unknown.svg | 0 .../assets/public/files/xlsx.svg | 0 .../assets/public/files/yaml.svg | 0 .../dataset-card/external-knowledge-base.svg | 0 .../public/knowledge/dataset-card/general.svg | 0 .../public/knowledge/dataset-card/graph.svg | 0 .../knowledge/dataset-card/parent-child.svg | 0 .../public/knowledge/dataset-card/qa.svg | 0 .../assets/public/knowledge/file.svg | 0 .../knowledge/online-drive/buckets-blue.svg | 0 .../knowledge/online-drive/buckets-gray.svg | 0 .../public/knowledge/online-drive/folder.svg | 0 .../option-card-effect-blue-light.svg | 0 .../knowledge/option-card-effect-blue.svg | 0 .../knowledge/option-card-effect-orange.svg | 0 .../knowledge/option-card-effect-purple.svg | 0 .../knowledge/option-card-effect-teal.svg | 0 .../assets/public/knowledge/selection-mod.svg | 0 .../assets/public/knowledge/watercrawl.svg | 0 .../assets/public/llm/Anthropic-dark.svg | 0 .../assets/public/llm/Anthropic-light.svg | 0 .../assets/public/llm/Tongyi.svg | 0 .../public/llm/anthropic-short-light.svg | 0 .../assets/public/llm/anthropic-text.svg | 0 .../assets/public/llm/anthropic.svg | 0 .../public/llm/azure-openai-service-text.svg | 0 .../public/llm/azure-openai-service.svg | 0 .../assets/public/llm/azureai-text.svg | 0 .../assets/public/llm/azureai.svg | 0 .../assets/public/llm/baichuan-text.svg | 0 .../assets/public/llm/baichuan.svg | 0 .../assets/public/llm/chatglm-text.svg | 0 .../assets/public/llm/chatglm.svg | 0 .../assets/public/llm/cohere-text.svg | 0 .../assets/public/llm/cohere.svg | 0 .../assets/public/llm/deepseek.svg | 0 .../assets/public/llm/gemini.svg | 0 .../assets/public/llm/gpt-3.svg | 0 .../assets/public/llm/gpt-4.svg | 0 .../assets/public/llm/grok.svg | 0 .../public/llm/huggingface-text-hub.svg | 0 .../assets/public/llm/huggingface-text.svg | 0 .../assets/public/llm/huggingface.svg | 0 .../public/llm/iflytek-spark-text-cn.svg | 0 .../assets/public/llm/iflytek-spark-text.svg | 0 .../assets/public/llm/iflytek-spark.svg | 0 .../assets/public/llm/jina-text.svg | 0 .../assets/public/llm/jina.svg | 0 .../assets/public/llm/localai-text.svg | 0 .../assets/public/llm/localai.svg | 0 .../assets/public/llm/microsoft.svg | 0 .../assets/public/llm/openai-black.svg | 0 .../assets/public/llm/openai-blue.svg | 0 .../assets/public/llm/openai-green.svg | 0 .../assets/public/llm/openai-small.svg | 0 .../assets/public/llm/openai-teal.svg | 0 .../assets/public/llm/openai-text.svg | 0 .../assets/public/llm/openai-transparent.svg | 0 .../assets/public/llm/openai-violet.svg | 0 .../assets/public/llm/openai-yellow.svg | 0 .../assets/public/llm/openllm-text.svg | 0 .../assets/public/llm/openllm.svg | 0 .../assets/public/llm/replicate-text.svg | 0 .../assets/public/llm/replicate.svg | 0 .../public/llm/xorbits-inference-text.svg | 0 .../assets/public/llm/xorbits-inference.svg | 0 .../assets/public/llm/zhipuai-text-cn.svg | 0 .../assets/public/llm/zhipuai-text.svg | 0 .../assets/public/llm/zhipuai.svg | 0 .../assets/public/model/checked.svg | 0 .../assets/public/other/Icon-3-dots.svg | 0 .../assets/public/other/default-tool-icon.svg | 0 .../assets/public/other/message-3-fill.svg | 0 .../assets/public/other/row-struct.svg | 0 .../assets/public/other/slack.svg | 0 .../assets/public/other/teams.svg | 0 .../assets/public/plugins/google.svg | 0 .../assets/public/plugins/partner-dark.svg | 0 .../assets/public/plugins/partner-light.svg | 0 .../assets/public/plugins/verified-dark.svg | 0 .../assets/public/plugins/verified-light.svg | 0 .../assets/public/plugins/web-reader.svg | 0 .../assets/public/plugins/wikipedia.svg | 0 .../assets/public/thought/data-set.svg | 0 .../assets/public/thought/loading.svg | 0 .../assets/public/thought/search.svg | 0 .../assets/public/thought/thought-list.svg | 0 .../assets/public/thought/web-reader.svg | 0 .../assets/public/tracing/aliyun-icon-big.svg | 0 .../assets/public/tracing/aliyun-icon.svg | 0 .../assets/public/tracing/arize-icon-big.svg | 0 .../assets/public/tracing/arize-icon.svg | 0 .../public/tracing/databricks-icon-big.svg | 0 .../assets/public/tracing/databricks-icon.svg | 0 .../public/tracing/langfuse-icon-big.svg | 0 .../assets/public/tracing/langfuse-icon.svg | 0 .../public/tracing/langsmith-icon-big.svg | 0 .../assets/public/tracing/langsmith-icon.svg | 0 .../assets/public/tracing/mlflow-icon-big.svg | 0 .../assets/public/tracing/mlflow-icon.svg | 0 .../assets/public/tracing/opik-icon-big.svg | 0 .../assets/public/tracing/opik-icon.svg | 0 .../public/tracing/phoenix-icon-big.svg | 0 .../assets/public/tracing/phoenix-icon.svg | 0 .../public/tracing/tencent-icon-big.svg | 0 .../assets/public/tracing/tencent-icon.svg | 0 .../assets/public/tracing/tracing-icon.svg | 0 .../assets/public/tracing/weave-icon-big.svg | 0 .../assets/public/tracing/weave-icon.svg | 0 .../assets/vender/features/citations.svg | 0 .../vender/features/content-moderation.svg | 0 .../assets/vender/features/document.svg | 0 .../assets/vender/features/folder-upload.svg | 0 .../assets/vender/features/love-message.svg | 0 .../assets/vender/features/message-fast.svg | 0 .../assets/vender/features/microphone-01.svg | 0 .../assets/vender/features/text-to-audio.svg | 0 .../vender/features/virtual-assistant.svg | 0 .../assets/vender/features/vision.svg | 0 .../assets/vender/knowledge/add-chunks.svg | 0 .../assets/vender/knowledge/api-aggregate.svg | 0 .../assets/vender/knowledge/arrow-shape.svg | 0 .../assets/vender/knowledge/chunk.svg | 0 .../assets/vender/knowledge/collapse.svg | 0 .../assets/vender/knowledge/divider.svg | 0 .../assets/vender/knowledge/economic.svg | 0 .../vender/knowledge/full-text-search.svg | 0 .../assets/vender/knowledge/general-chunk.svg | 0 .../assets/vender/knowledge/high-quality.svg | 0 .../assets/vender/knowledge/hybrid-search.svg | 0 .../vender/knowledge/parent-child-chunk.svg | 0 .../vender/knowledge/question-and-answer.svg | 0 .../vender/knowledge/search-lines-sparkle.svg | 0 .../assets/vender/knowledge/search-menu.svg | 0 .../assets/vender/knowledge/vector-search.svg | 0 .../line/alertsAndFeedback/alert-triangle.svg | 0 .../line/alertsAndFeedback/thumbs-down.svg | 0 .../line/alertsAndFeedback/thumbs-up.svg | 0 .../vender/line/alertsAndFeedback/warning.svg | 0 .../assets/vender/line/arrows/IconR.svg | 0 .../vender/line/arrows/arrow-narrow-left.svg | 0 .../vender/line/arrows/arrow-up-right.svg | 0 .../line/arrows/chevron-down-double.svg | 0 .../vender/line/arrows/chevron-right.svg | 0 .../line/arrows/chevron-selector-vertical.svg | 0 .../vender/line/arrows/refresh-ccw-01.svg | 0 .../vender/line/arrows/refresh-cw-05.svg | 0 .../vender/line/arrows/reverse-left.svg | 0 .../vender/line/communication/ai-text.svg | 0 .../line/communication/chat-bot-slim.svg | 0 .../vender/line/communication/chat-bot.svg | 0 .../vender/line/communication/cute-robot.svg | 0 .../communication/message-check-remove.svg | 0 .../line/communication/message-fast-plus.svg | 0 .../line/development/artificial-brain.svg | 0 .../line/development/bar-chart-square-02.svg | 0 .../vender/line/development/brackets-x.svg | 0 .../vender/line/development/code-browser.svg | 0 .../vender/line/development/container.svg | 0 .../vender/line/development/database-01.svg | 0 .../vender/line/development/database-03.svg | 0 .../vender/line/development/file-heart-02.svg | 0 .../vender/line/development/git-branch-01.svg | 0 .../line/development/prompt-engineering.svg | 0 .../line/development/puzzle-piece-01.svg | 0 .../line/development/terminal-square.svg | 0 .../vender/line/development/variable.svg | 0 .../vender/line/development/webhooks.svg | 0 .../assets/vender/line/editor/align-left.svg | 0 .../vender/line/editor/bezier-curve-03.svg | 0 .../assets/vender/line/editor/collapse.svg | 0 .../assets/vender/line/editor/colors.svg | 0 .../vender/line/editor/image-indent-left.svg | 0 .../vender/line/editor/left-indent-02.svg | 0 .../vender/line/editor/letter-spacing-01.svg | 0 .../assets/vender/line/editor/type-square.svg | 0 .../vender/line/education/book-open-01.svg | 0 .../assets/vender/line/files/copy-check.svg | 0 .../assets/vender/line/files/copy.svg | 0 .../assets/vender/line/files/file-02.svg | 0 .../vender/line/files/file-arrow-01.svg | 0 .../vender/line/files/file-check-02.svg | 0 .../vender/line/files/file-download-02.svg | 0 .../assets/vender/line/files/file-plus-01.svg | 0 .../assets/vender/line/files/file-plus-02.svg | 0 .../assets/vender/line/files/file-text.svg | 0 .../assets/vender/line/files/file-upload.svg | 0 .../assets/vender/line/files/folder.svg | 0 .../line/financeAndECommerce/balance.svg | 0 .../financeAndECommerce/coins-stacked-01.svg | 0 .../line/financeAndECommerce/credits-coin.svg | 0 .../line/financeAndECommerce/gold-coin.svg | 0 .../line/financeAndECommerce/receipt-list.svg | 0 .../line/financeAndECommerce/tag-01.svg | 0 .../line/financeAndECommerce/tag-03.svg | 0 .../assets/vender/line/general/at-sign.svg | 0 .../assets/vender/line/general/bookmark.svg | 0 .../vender/line/general/check-done-01.svg | 0 .../assets/vender/line/general/check.svg | 0 .../vender/line/general/checklist-square.svg | 0 .../vender/line/general/code-assistant.svg | 0 .../assets/vender/line/general/dots-grid.svg | 0 .../assets/vender/line/general/edit-02.svg | 0 .../assets/vender/line/general/edit-04.svg | 0 .../assets/vender/line/general/edit-05.svg | 0 .../assets/vender/line/general/hash-02.svg | 0 .../vender/line/general/info-circle.svg | 0 .../assets/vender/line/general/link-03.svg | 0 .../vender/line/general/link-external-02.svg | 0 .../assets/vender/line/general/log-in-04.svg | 0 .../assets/vender/line/general/log-out-01.svg | 0 .../assets/vender/line/general/log-out-04.svg | 0 .../assets/vender/line/general/magic-edit.svg | 0 .../assets/vender/line/general/menu-01.svg | 0 .../assets/vender/line/general/pin-01.svg | 0 .../assets/vender/line/general/pin-02.svg | 0 .../assets/vender/line/general/plus-02.svg | 0 .../assets/vender/line/general/refresh.svg | 0 .../vender/line/general/search-menu.svg | 0 .../vender/line/general/settings-01.svg | 0 .../vender/line/general/settings-04.svg | 0 .../assets/vender/line/general/target-04.svg | 0 .../assets/vender/line/general/upload-03.svg | 0 .../vender/line/general/upload-cloud-01.svg | 0 .../assets/vender/line/general/x.svg | 0 .../assets/vender/line/images/image-plus.svg | 0 .../vender/line/layout/align-left-01.svg | 0 .../vender/line/layout/align-right-01.svg | 0 .../assets/vender/line/layout/grid-01.svg | 0 .../vender/line/layout/layout-grid-02.svg | 0 .../line/mediaAndDevices/microphone-01.svg | 0 .../line/mediaAndDevices/play-circle.svg | 0 .../vender/line/mediaAndDevices/sliders-h.svg | 0 .../vender/line/mediaAndDevices/speaker.svg | 0 .../line/mediaAndDevices/stop-circle.svg | 0 .../vender/line/mediaAndDevices/stop.svg | 0 .../assets/vender/line/others/bubble-x.svg | 0 .../assets/vender/line/others/colors.svg | 0 .../assets/vender/line/others/drag-handle.svg | 0 .../assets/vender/line/others/env.svg | 0 .../vender/line/others/global-variable.svg | 0 .../assets/vender/line/others/icon-3-dots.svg | 0 .../vender/line/others/long-arrow-left.svg | 0 .../vender/line/others/long-arrow-right.svg | 0 .../assets/vender/line/others/search-menu.svg | 0 .../assets/vender/line/others/tools.svg | 0 .../vender/line/shapes/cube-outline.svg | 0 .../vender/line/time/clock-fast-forward.svg | 0 .../vender/line/time/clock-play-slim.svg | 0 .../assets/vender/line/time/clock-play.svg | 0 .../assets/vender/line/time/clock-refresh.svg | 0 .../assets/vender/line/users/user-01.svg | 0 .../assets/vender/line/users/users-01.svg | 0 .../assets/vender/line/weather/stars-02.svg | 0 .../assets/vender/other/anthropic-text.svg | 0 .../assets/vender/other/generator.svg | 0 .../assets/vender/other/group.svg | 0 .../assets/vender/other/hourglass-shape.svg | 0 .../assets/vender/other/mcp.svg | 0 .../vender/other/no-tool-placeholder.svg | 0 .../assets/vender/other/openai.svg | 0 .../assets/vender/other/replay-line.svg | 0 .../assets/vender/other/square-checklist.svg | 0 .../assets/vender/pipeline/input-field.svg | 0 .../assets/vender/pipeline/pipeline-fill.svg | 0 .../assets/vender/pipeline/pipeline-line.svg | 0 .../assets/vender/plugin/box-sparkle-fill.svg | 0 .../assets/vender/plugin/left-corner.svg | 0 .../assets/vender/plugin/trigger.svg | 0 .../solid/FinanceAndECommerce/gold-coin.svg | 0 .../solid/FinanceAndECommerce/scales-02.svg | 0 .../alertsAndFeedback/alert-triangle.svg | 0 .../solid/arrows/arrow-down-double-line.svg | 0 .../solid/arrows/arrow-down-round-fill.svg | 0 .../solid/arrows/arrow-up-double-line.svg | 0 .../vender/solid/arrows/chevron-down.svg | 0 .../vender/solid/arrows/high-priority.svg | 0 .../vender/solid/communication/ai-text.svg | 0 .../solid/communication/bubble-text-mod.svg | 0 .../vender/solid/communication/chat-bot.svg | 0 .../vender/solid/communication/cute-robot.svg | 0 .../vender/solid/communication/edit-list.svg | 0 .../solid/communication/list-sparkle.svg | 0 .../vender/solid/communication/logic.svg | 0 .../communication/message-dots-circle.svg | 0 .../solid/communication/message-fast.svg | 0 .../communication/message-heart-circle.svg | 0 .../communication/message-smile-square.svg | 0 .../vender/solid/communication/send-03.svg | 0 .../solid/development/api-connection-mod.svg | 0 .../solid/development/api-connection.svg | 0 .../solid/development/bar-chart-square-02.svg | 0 .../vender/solid/development/container.svg | 0 .../vender/solid/development/database-02.svg | 0 .../vender/solid/development/database-03.svg | 0 .../solid/development/file-heart-02.svg | 0 .../solid/development/pattern-recognition.svg | 0 .../solid/development/prompt-engineering.svg | 0 .../solid/development/puzzle-piece-01.svg | 0 .../vender/solid/development/semantic.svg | 0 .../solid/development/terminal-square.svg | 0 .../vender/solid/development/variable-02.svg | 0 .../assets/vender/solid/editor/brush-01.svg | 0 .../assets/vender/solid/editor/citations.svg | 0 .../assets/vender/solid/editor/colors.svg | 0 .../assets/vender/solid/editor/paragraph.svg | 0 .../vender/solid/editor/type-square.svg | 0 .../vender/solid/education/beaker-02.svg | 0 .../vender/solid/education/bubble-text.svg | 0 .../vender/solid/education/heart-02.svg | 0 .../assets/vender/solid/education/unblur.svg | 0 .../assets/vender/solid/files/file-05.svg | 0 .../vender/solid/files/file-search-02.svg | 0 .../assets/vender/solid/files/file-zip.svg | 0 .../assets/vender/solid/files/folder.svg | 0 .../vender/solid/general/answer-triangle.svg | 0 .../solid/general/arrow-down-round-fill.svg | 0 .../vender/solid/general/check-circle.svg | 0 .../vender/solid/general/check-done-01.svg | 0 .../vender/solid/general/download-02.svg | 0 .../assets/vender/solid/general/edit-03.svg | 0 .../assets/vender/solid/general/edit-04.svg | 0 .../assets/vender/solid/general/eye.svg | 0 .../assets/vender/solid/general/github.svg | 0 .../solid/general/message-clock-circle.svg | 0 .../vender/solid/general/plus-circle.svg | 0 .../solid/general/question-triangle.svg | 0 .../assets/vender/solid/general/search-md.svg | 0 .../assets/vender/solid/general/target-04.svg | 0 .../assets/vender/solid/general/tool-03.svg | 0 .../assets/vender/solid/general/x-circle.svg | 0 .../assets/vender/solid/general/zap-fast.svg | 0 .../vender/solid/general/zap-narrow.svg | 0 .../assets/vender/solid/layout/grid-01.svg | 0 .../mediaAndDevices/audio-support-icon.svg | 0 .../mediaAndDevices/document-support-icon.svg | 0 .../solid/mediaAndDevices/magic-box.svg | 0 .../solid/mediaAndDevices/magic-eyes.svg | 0 .../solid/mediaAndDevices/magic-wand.svg | 0 .../solid/mediaAndDevices/microphone-01.svg | 0 .../vender/solid/mediaAndDevices/play.svg | 0 .../vender/solid/mediaAndDevices/robot.svg | 0 .../solid/mediaAndDevices/sliders-02.svg | 0 .../vender/solid/mediaAndDevices/speaker.svg | 0 .../solid/mediaAndDevices/stop-circle.svg | 0 .../mediaAndDevices/video-support-icon.svg | 0 .../assets/vender/solid/security/lock-01.svg | 0 .../assets/vender/solid/shapes/corner.svg | 0 .../assets/vender/solid/shapes/star-04.svg | 0 .../assets/vender/solid/shapes/star-06.svg | 0 .../assets/vender/solid/users/user-01.svg | 0 .../vender/solid/users/user-edit-02.svg | 0 .../assets/vender/solid/users/users-01.svg | 0 .../assets/vender/solid/users/users-plus.svg | 0 .../assets/vender/system/auto-update-line.svg | 0 .../assets/vender/workflow/agent.svg | 0 .../assets/vender/workflow/answer.svg | 0 .../assets/vender/workflow/api-aggregate.svg | 0 .../assets/vender/workflow/assigner.svg | 0 .../assets/vender/workflow/asterisk.svg | 0 .../vender/workflow/calendar-check-line.svg | 0 .../assets/vender/workflow/code.svg | 0 .../assets/vender/workflow/datasource.svg | 0 .../assets/vender/workflow/docs-extractor.svg | 0 .../assets/vender/workflow/end.svg | 0 .../assets/vender/workflow/home.svg | 0 .../assets/vender/workflow/http.svg | 0 .../assets/vender/workflow/human-in-loop.svg | 0 .../assets/vender/workflow/if-else.svg | 0 .../vender/workflow/iteration-start.svg | 0 .../assets/vender/workflow/iteration.svg | 0 .../assets/vender/workflow/jinja.svg | 0 .../assets/vender/workflow/knowledge-base.svg | 0 .../vender/workflow/knowledge-retrieval.svg | 0 .../assets/vender/workflow/list-filter.svg | 0 .../assets/vender/workflow/llm.svg | 0 .../assets/vender/workflow/loop-end.svg | 0 .../assets/vender/workflow/loop.svg | 0 .../vender/workflow/parameter-extractor.svg | 0 .../vender/workflow/question-classifier.svg | 0 .../assets/vender/workflow/schedule.svg | 0 .../vender/workflow/templating-transform.svg | 0 .../assets/vender/workflow/trigger-all.svg | 0 .../assets/vender/workflow/variable-x.svg | 0 .../assets/vender/workflow/webhook-line.svg | 0 .../assets/vender/workflow/window-cursor.svg | 0 .../custom-public/chars.json | 1 + .../custom-public/icons.json | 572 +++++++++ .../custom-public/index.d.ts | 55 + .../custom-public/index.js | 9 + .../custom-public/index.mjs | 7 + .../custom-public/info.json | 24 + .../custom-public/metadata.json | 1 + .../custom-vender/chars.json | 1 + .../custom-vender/icons.json | 1098 +++++++++++++++++ .../custom-vender/index.d.ts | 55 + .../custom-vender/index.js | 9 + .../custom-vender/index.mjs | 7 + .../custom-vender/info.json | 24 + .../custom-vender/metadata.json | 1 + packages/iconify-collections/package.json | 31 + .../scripts/generate-collections.mjs | 178 +++ pnpm-lock.yaml | 12 +- pnpm-workspace.yaml | 1 + .../src/image/llm/BaichuanTextCn.module.css | 2 - .../icons/src/image/llm/Minimax.module.css | 2 - .../src/image/llm/MinimaxText.module.css | 2 - .../icons/src/image/llm/Tongyi.module.css | 2 - .../icons/src/image/llm/TongyiText.module.css | 2 - .../src/image/llm/TongyiTextCn.module.css | 2 - .../base/icons/src/image/llm/Wxyy.module.css | 2 - .../icons/src/image/llm/WxyyText.module.css | 2 - .../icons/src/image/llm/WxyyTextCn.module.css | 2 - .../icons/src/vender/workflow/HumanInLoop.tsx | 2 +- web/package.json | 4 +- web/scripts/gen-icons.mjs | 27 +- web/tailwind-common-config.ts | 36 +- 457 files changed, 2105 insertions(+), 70 deletions(-) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/avatar/robot.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/avatar/user.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/billing/ar-cube-1.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/billing/asterisk.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/billing/aws-marketplace-dark.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/billing/aws-marketplace-light.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/billing/azure.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/billing/buildings.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/billing/diamond.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/billing/google-cloud.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/billing/group-2.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/billing/keyframe.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/billing/sparkles-soft.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/billing/sparkles.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/d.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/diagonal-dividing-line.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/dify.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/gdpr.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/github.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/highlight.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/iso.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/line-3.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/lock.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/message-chat-square.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/multi-path-retrieval.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/n-to-1-retrieval.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/notion.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/soc2.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/sparkles-soft-accent.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/common/sparkles-soft.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/education/triangle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/files/csv.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/files/doc.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/files/docx.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/files/html.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/files/json.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/files/md.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/files/pdf.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/files/txt.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/files/unknown.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/files/xlsx.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/files/yaml.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/dataset-card/external-knowledge-base.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/dataset-card/general.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/dataset-card/graph.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/dataset-card/parent-child.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/dataset-card/qa.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/file.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/online-drive/buckets-blue.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/online-drive/buckets-gray.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/online-drive/folder.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/option-card-effect-blue-light.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/option-card-effect-blue.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/option-card-effect-orange.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/option-card-effect-purple.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/option-card-effect-teal.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/selection-mod.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/knowledge/watercrawl.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/Anthropic-dark.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/Anthropic-light.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/Tongyi.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/anthropic-short-light.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/anthropic-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/anthropic.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/azure-openai-service-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/azure-openai-service.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/azureai-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/azureai.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/baichuan-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/baichuan.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/chatglm-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/chatglm.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/cohere-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/cohere.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/deepseek.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/gemini.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/gpt-3.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/gpt-4.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/grok.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/huggingface-text-hub.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/huggingface-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/huggingface.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/iflytek-spark-text-cn.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/iflytek-spark-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/iflytek-spark.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/jina-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/jina.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/localai-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/localai.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/microsoft.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/openai-black.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/openai-blue.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/openai-green.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/openai-small.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/openai-teal.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/openai-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/openai-transparent.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/openai-violet.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/openai-yellow.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/openllm-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/openllm.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/replicate-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/replicate.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/xorbits-inference-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/xorbits-inference.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/zhipuai-text-cn.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/zhipuai-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/llm/zhipuai.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/model/checked.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/other/Icon-3-dots.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/other/default-tool-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/other/message-3-fill.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/other/row-struct.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/other/slack.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/other/teams.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/plugins/google.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/plugins/partner-dark.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/plugins/partner-light.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/plugins/verified-dark.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/plugins/verified-light.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/plugins/web-reader.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/plugins/wikipedia.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/thought/data-set.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/thought/loading.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/thought/search.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/thought/thought-list.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/thought/web-reader.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/aliyun-icon-big.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/aliyun-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/arize-icon-big.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/arize-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/databricks-icon-big.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/databricks-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/langfuse-icon-big.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/langfuse-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/langsmith-icon-big.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/langsmith-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/mlflow-icon-big.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/mlflow-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/opik-icon-big.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/opik-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/phoenix-icon-big.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/phoenix-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/tencent-icon-big.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/tencent-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/tracing-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/weave-icon-big.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/public/tracing/weave-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/features/citations.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/features/content-moderation.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/features/document.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/features/folder-upload.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/features/love-message.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/features/message-fast.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/features/microphone-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/features/text-to-audio.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/features/virtual-assistant.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/features/vision.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/add-chunks.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/api-aggregate.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/arrow-shape.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/chunk.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/collapse.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/divider.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/economic.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/full-text-search.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/general-chunk.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/high-quality.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/hybrid-search.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/parent-child-chunk.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/question-and-answer.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/search-lines-sparkle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/search-menu.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/knowledge/vector-search.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/alertsAndFeedback/alert-triangle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/alertsAndFeedback/thumbs-down.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/alertsAndFeedback/thumbs-up.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/alertsAndFeedback/warning.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/arrows/IconR.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/arrows/arrow-narrow-left.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/arrows/arrow-up-right.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/arrows/chevron-down-double.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/arrows/chevron-right.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/arrows/chevron-selector-vertical.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/arrows/refresh-ccw-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/arrows/refresh-cw-05.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/arrows/reverse-left.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/communication/ai-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/communication/chat-bot-slim.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/communication/chat-bot.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/communication/cute-robot.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/communication/message-check-remove.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/communication/message-fast-plus.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/development/artificial-brain.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/development/bar-chart-square-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/development/brackets-x.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/development/code-browser.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/development/container.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/development/database-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/development/database-03.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/development/file-heart-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/development/git-branch-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/development/prompt-engineering.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/development/puzzle-piece-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/development/terminal-square.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/development/variable.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/development/webhooks.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/editor/align-left.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/editor/bezier-curve-03.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/editor/collapse.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/editor/colors.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/editor/image-indent-left.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/editor/left-indent-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/editor/letter-spacing-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/editor/type-square.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/education/book-open-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/files/copy-check.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/files/copy.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/files/file-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/files/file-arrow-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/files/file-check-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/files/file-download-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/files/file-plus-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/files/file-plus-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/files/file-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/files/file-upload.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/files/folder.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/financeAndECommerce/balance.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/financeAndECommerce/coins-stacked-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/financeAndECommerce/credits-coin.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/financeAndECommerce/gold-coin.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/financeAndECommerce/receipt-list.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/financeAndECommerce/tag-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/financeAndECommerce/tag-03.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/at-sign.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/bookmark.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/check-done-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/check.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/checklist-square.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/code-assistant.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/dots-grid.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/edit-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/edit-04.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/edit-05.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/hash-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/info-circle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/link-03.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/link-external-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/log-in-04.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/log-out-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/log-out-04.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/magic-edit.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/menu-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/pin-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/pin-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/plus-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/refresh.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/search-menu.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/settings-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/settings-04.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/target-04.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/upload-03.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/upload-cloud-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/general/x.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/images/image-plus.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/layout/align-left-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/layout/align-right-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/layout/grid-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/layout/layout-grid-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/mediaAndDevices/microphone-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/mediaAndDevices/play-circle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/mediaAndDevices/sliders-h.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/mediaAndDevices/speaker.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/mediaAndDevices/stop-circle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/mediaAndDevices/stop.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/others/bubble-x.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/others/colors.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/others/drag-handle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/others/env.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/others/global-variable.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/others/icon-3-dots.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/others/long-arrow-left.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/others/long-arrow-right.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/others/search-menu.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/others/tools.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/shapes/cube-outline.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/time/clock-fast-forward.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/time/clock-play-slim.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/time/clock-play.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/time/clock-refresh.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/users/user-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/users/users-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/line/weather/stars-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/other/anthropic-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/other/generator.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/other/group.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/other/hourglass-shape.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/other/mcp.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/other/no-tool-placeholder.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/other/openai.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/other/replay-line.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/other/square-checklist.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/pipeline/input-field.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/pipeline/pipeline-fill.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/pipeline/pipeline-line.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/plugin/box-sparkle-fill.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/plugin/left-corner.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/plugin/trigger.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/FinanceAndECommerce/gold-coin.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/FinanceAndECommerce/scales-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/alertsAndFeedback/alert-triangle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/arrows/arrow-down-double-line.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/arrows/arrow-down-round-fill.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/arrows/arrow-up-double-line.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/arrows/chevron-down.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/arrows/high-priority.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/communication/ai-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/communication/bubble-text-mod.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/communication/chat-bot.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/communication/cute-robot.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/communication/edit-list.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/communication/list-sparkle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/communication/logic.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/communication/message-dots-circle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/communication/message-fast.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/communication/message-heart-circle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/communication/message-smile-square.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/communication/send-03.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/development/api-connection-mod.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/development/api-connection.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/development/bar-chart-square-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/development/container.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/development/database-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/development/database-03.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/development/file-heart-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/development/pattern-recognition.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/development/prompt-engineering.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/development/puzzle-piece-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/development/semantic.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/development/terminal-square.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/development/variable-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/editor/brush-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/editor/citations.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/editor/colors.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/editor/paragraph.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/editor/type-square.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/education/beaker-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/education/bubble-text.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/education/heart-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/education/unblur.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/files/file-05.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/files/file-search-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/files/file-zip.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/files/folder.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/answer-triangle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/arrow-down-round-fill.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/check-circle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/check-done-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/download-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/edit-03.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/edit-04.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/eye.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/github.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/message-clock-circle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/plus-circle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/question-triangle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/search-md.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/target-04.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/tool-03.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/x-circle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/zap-fast.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/general/zap-narrow.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/layout/grid-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/mediaAndDevices/audio-support-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/mediaAndDevices/document-support-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/mediaAndDevices/magic-box.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/mediaAndDevices/magic-eyes.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/mediaAndDevices/magic-wand.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/mediaAndDevices/microphone-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/mediaAndDevices/play.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/mediaAndDevices/robot.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/mediaAndDevices/sliders-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/mediaAndDevices/speaker.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/mediaAndDevices/stop-circle.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/mediaAndDevices/video-support-icon.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/security/lock-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/shapes/corner.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/shapes/star-04.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/shapes/star-06.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/users/user-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/users/user-edit-02.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/users/users-01.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/solid/users/users-plus.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/system/auto-update-line.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/agent.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/answer.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/api-aggregate.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/assigner.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/asterisk.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/calendar-check-line.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/code.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/datasource.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/docs-extractor.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/end.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/home.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/http.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/human-in-loop.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/if-else.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/iteration-start.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/iteration.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/jinja.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/knowledge-base.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/knowledge-retrieval.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/list-filter.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/llm.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/loop-end.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/loop.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/parameter-extractor.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/question-classifier.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/schedule.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/templating-transform.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/trigger-all.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/variable-x.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/webhook-line.svg (100%) rename {web/app/components/base/icons => packages/iconify-collections}/assets/vender/workflow/window-cursor.svg (100%) create mode 100644 packages/iconify-collections/custom-public/chars.json create mode 100644 packages/iconify-collections/custom-public/icons.json create mode 100644 packages/iconify-collections/custom-public/index.d.ts create mode 100644 packages/iconify-collections/custom-public/index.js create mode 100644 packages/iconify-collections/custom-public/index.mjs create mode 100644 packages/iconify-collections/custom-public/info.json create mode 100644 packages/iconify-collections/custom-public/metadata.json create mode 100644 packages/iconify-collections/custom-vender/chars.json create mode 100644 packages/iconify-collections/custom-vender/icons.json create mode 100644 packages/iconify-collections/custom-vender/index.d.ts create mode 100644 packages/iconify-collections/custom-vender/index.js create mode 100644 packages/iconify-collections/custom-vender/index.mjs create mode 100644 packages/iconify-collections/custom-vender/info.json create mode 100644 packages/iconify-collections/custom-vender/metadata.json create mode 100644 packages/iconify-collections/package.json create mode 100644 packages/iconify-collections/scripts/generate-collections.mjs diff --git a/.gitignore b/.gitignore index f703fc02e9..53dea88899 100644 --- a/.gitignore +++ b/.gitignore @@ -212,7 +212,7 @@ api/.vscode # pnpm /.pnpm-store -/node_modules +node_modules .vite-hooks/_ # plugin migrate diff --git a/web/app/components/base/icons/assets/public/avatar/robot.svg b/packages/iconify-collections/assets/public/avatar/robot.svg similarity index 100% rename from web/app/components/base/icons/assets/public/avatar/robot.svg rename to packages/iconify-collections/assets/public/avatar/robot.svg diff --git a/web/app/components/base/icons/assets/public/avatar/user.svg b/packages/iconify-collections/assets/public/avatar/user.svg similarity index 100% rename from web/app/components/base/icons/assets/public/avatar/user.svg rename to packages/iconify-collections/assets/public/avatar/user.svg diff --git a/web/app/components/base/icons/assets/public/billing/ar-cube-1.svg b/packages/iconify-collections/assets/public/billing/ar-cube-1.svg similarity index 100% rename from web/app/components/base/icons/assets/public/billing/ar-cube-1.svg rename to packages/iconify-collections/assets/public/billing/ar-cube-1.svg diff --git a/web/app/components/base/icons/assets/public/billing/asterisk.svg b/packages/iconify-collections/assets/public/billing/asterisk.svg similarity index 100% rename from web/app/components/base/icons/assets/public/billing/asterisk.svg rename to packages/iconify-collections/assets/public/billing/asterisk.svg diff --git a/web/app/components/base/icons/assets/public/billing/aws-marketplace-dark.svg b/packages/iconify-collections/assets/public/billing/aws-marketplace-dark.svg similarity index 100% rename from web/app/components/base/icons/assets/public/billing/aws-marketplace-dark.svg rename to packages/iconify-collections/assets/public/billing/aws-marketplace-dark.svg diff --git a/web/app/components/base/icons/assets/public/billing/aws-marketplace-light.svg b/packages/iconify-collections/assets/public/billing/aws-marketplace-light.svg similarity index 100% rename from web/app/components/base/icons/assets/public/billing/aws-marketplace-light.svg rename to packages/iconify-collections/assets/public/billing/aws-marketplace-light.svg diff --git a/web/app/components/base/icons/assets/public/billing/azure.svg b/packages/iconify-collections/assets/public/billing/azure.svg similarity index 100% rename from web/app/components/base/icons/assets/public/billing/azure.svg rename to packages/iconify-collections/assets/public/billing/azure.svg diff --git a/web/app/components/base/icons/assets/public/billing/buildings.svg b/packages/iconify-collections/assets/public/billing/buildings.svg similarity index 100% rename from web/app/components/base/icons/assets/public/billing/buildings.svg rename to packages/iconify-collections/assets/public/billing/buildings.svg diff --git a/web/app/components/base/icons/assets/public/billing/diamond.svg b/packages/iconify-collections/assets/public/billing/diamond.svg similarity index 100% rename from web/app/components/base/icons/assets/public/billing/diamond.svg rename to packages/iconify-collections/assets/public/billing/diamond.svg diff --git a/web/app/components/base/icons/assets/public/billing/google-cloud.svg b/packages/iconify-collections/assets/public/billing/google-cloud.svg similarity index 100% rename from web/app/components/base/icons/assets/public/billing/google-cloud.svg rename to packages/iconify-collections/assets/public/billing/google-cloud.svg diff --git a/web/app/components/base/icons/assets/public/billing/group-2.svg b/packages/iconify-collections/assets/public/billing/group-2.svg similarity index 100% rename from web/app/components/base/icons/assets/public/billing/group-2.svg rename to packages/iconify-collections/assets/public/billing/group-2.svg diff --git a/web/app/components/base/icons/assets/public/billing/keyframe.svg b/packages/iconify-collections/assets/public/billing/keyframe.svg similarity index 100% rename from web/app/components/base/icons/assets/public/billing/keyframe.svg rename to packages/iconify-collections/assets/public/billing/keyframe.svg diff --git a/web/app/components/base/icons/assets/public/billing/sparkles-soft.svg b/packages/iconify-collections/assets/public/billing/sparkles-soft.svg similarity index 100% rename from web/app/components/base/icons/assets/public/billing/sparkles-soft.svg rename to packages/iconify-collections/assets/public/billing/sparkles-soft.svg diff --git a/web/app/components/base/icons/assets/public/billing/sparkles.svg b/packages/iconify-collections/assets/public/billing/sparkles.svg similarity index 100% rename from web/app/components/base/icons/assets/public/billing/sparkles.svg rename to packages/iconify-collections/assets/public/billing/sparkles.svg diff --git a/web/app/components/base/icons/assets/public/common/d.svg b/packages/iconify-collections/assets/public/common/d.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/d.svg rename to packages/iconify-collections/assets/public/common/d.svg diff --git a/web/app/components/base/icons/assets/public/common/diagonal-dividing-line.svg b/packages/iconify-collections/assets/public/common/diagonal-dividing-line.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/diagonal-dividing-line.svg rename to packages/iconify-collections/assets/public/common/diagonal-dividing-line.svg diff --git a/web/app/components/base/icons/assets/public/common/dify.svg b/packages/iconify-collections/assets/public/common/dify.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/dify.svg rename to packages/iconify-collections/assets/public/common/dify.svg diff --git a/web/app/components/base/icons/assets/public/common/gdpr.svg b/packages/iconify-collections/assets/public/common/gdpr.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/gdpr.svg rename to packages/iconify-collections/assets/public/common/gdpr.svg diff --git a/web/app/components/base/icons/assets/public/common/github.svg b/packages/iconify-collections/assets/public/common/github.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/github.svg rename to packages/iconify-collections/assets/public/common/github.svg diff --git a/web/app/components/base/icons/assets/public/common/highlight.svg b/packages/iconify-collections/assets/public/common/highlight.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/highlight.svg rename to packages/iconify-collections/assets/public/common/highlight.svg diff --git a/web/app/components/base/icons/assets/public/common/iso.svg b/packages/iconify-collections/assets/public/common/iso.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/iso.svg rename to packages/iconify-collections/assets/public/common/iso.svg diff --git a/web/app/components/base/icons/assets/public/common/line-3.svg b/packages/iconify-collections/assets/public/common/line-3.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/line-3.svg rename to packages/iconify-collections/assets/public/common/line-3.svg diff --git a/web/app/components/base/icons/assets/public/common/lock.svg b/packages/iconify-collections/assets/public/common/lock.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/lock.svg rename to packages/iconify-collections/assets/public/common/lock.svg diff --git a/web/app/components/base/icons/assets/public/common/message-chat-square.svg b/packages/iconify-collections/assets/public/common/message-chat-square.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/message-chat-square.svg rename to packages/iconify-collections/assets/public/common/message-chat-square.svg diff --git a/web/app/components/base/icons/assets/public/common/multi-path-retrieval.svg b/packages/iconify-collections/assets/public/common/multi-path-retrieval.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/multi-path-retrieval.svg rename to packages/iconify-collections/assets/public/common/multi-path-retrieval.svg diff --git a/web/app/components/base/icons/assets/public/common/n-to-1-retrieval.svg b/packages/iconify-collections/assets/public/common/n-to-1-retrieval.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/n-to-1-retrieval.svg rename to packages/iconify-collections/assets/public/common/n-to-1-retrieval.svg diff --git a/web/app/components/base/icons/assets/public/common/notion.svg b/packages/iconify-collections/assets/public/common/notion.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/notion.svg rename to packages/iconify-collections/assets/public/common/notion.svg diff --git a/web/app/components/base/icons/assets/public/common/soc2.svg b/packages/iconify-collections/assets/public/common/soc2.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/soc2.svg rename to packages/iconify-collections/assets/public/common/soc2.svg diff --git a/web/app/components/base/icons/assets/public/common/sparkles-soft-accent.svg b/packages/iconify-collections/assets/public/common/sparkles-soft-accent.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/sparkles-soft-accent.svg rename to packages/iconify-collections/assets/public/common/sparkles-soft-accent.svg diff --git a/web/app/components/base/icons/assets/public/common/sparkles-soft.svg b/packages/iconify-collections/assets/public/common/sparkles-soft.svg similarity index 100% rename from web/app/components/base/icons/assets/public/common/sparkles-soft.svg rename to packages/iconify-collections/assets/public/common/sparkles-soft.svg diff --git a/web/app/components/base/icons/assets/public/education/triangle.svg b/packages/iconify-collections/assets/public/education/triangle.svg similarity index 100% rename from web/app/components/base/icons/assets/public/education/triangle.svg rename to packages/iconify-collections/assets/public/education/triangle.svg diff --git a/web/app/components/base/icons/assets/public/files/csv.svg b/packages/iconify-collections/assets/public/files/csv.svg similarity index 100% rename from web/app/components/base/icons/assets/public/files/csv.svg rename to packages/iconify-collections/assets/public/files/csv.svg diff --git a/web/app/components/base/icons/assets/public/files/doc.svg b/packages/iconify-collections/assets/public/files/doc.svg similarity index 100% rename from web/app/components/base/icons/assets/public/files/doc.svg rename to packages/iconify-collections/assets/public/files/doc.svg diff --git a/web/app/components/base/icons/assets/public/files/docx.svg b/packages/iconify-collections/assets/public/files/docx.svg similarity index 100% rename from web/app/components/base/icons/assets/public/files/docx.svg rename to packages/iconify-collections/assets/public/files/docx.svg diff --git a/web/app/components/base/icons/assets/public/files/html.svg b/packages/iconify-collections/assets/public/files/html.svg similarity index 100% rename from web/app/components/base/icons/assets/public/files/html.svg rename to packages/iconify-collections/assets/public/files/html.svg diff --git a/web/app/components/base/icons/assets/public/files/json.svg b/packages/iconify-collections/assets/public/files/json.svg similarity index 100% rename from web/app/components/base/icons/assets/public/files/json.svg rename to packages/iconify-collections/assets/public/files/json.svg diff --git a/web/app/components/base/icons/assets/public/files/md.svg b/packages/iconify-collections/assets/public/files/md.svg similarity index 100% rename from web/app/components/base/icons/assets/public/files/md.svg rename to packages/iconify-collections/assets/public/files/md.svg diff --git a/web/app/components/base/icons/assets/public/files/pdf.svg b/packages/iconify-collections/assets/public/files/pdf.svg similarity index 100% rename from web/app/components/base/icons/assets/public/files/pdf.svg rename to packages/iconify-collections/assets/public/files/pdf.svg diff --git a/web/app/components/base/icons/assets/public/files/txt.svg b/packages/iconify-collections/assets/public/files/txt.svg similarity index 100% rename from web/app/components/base/icons/assets/public/files/txt.svg rename to packages/iconify-collections/assets/public/files/txt.svg diff --git a/web/app/components/base/icons/assets/public/files/unknown.svg b/packages/iconify-collections/assets/public/files/unknown.svg similarity index 100% rename from web/app/components/base/icons/assets/public/files/unknown.svg rename to packages/iconify-collections/assets/public/files/unknown.svg diff --git a/web/app/components/base/icons/assets/public/files/xlsx.svg b/packages/iconify-collections/assets/public/files/xlsx.svg similarity index 100% rename from web/app/components/base/icons/assets/public/files/xlsx.svg rename to packages/iconify-collections/assets/public/files/xlsx.svg diff --git a/web/app/components/base/icons/assets/public/files/yaml.svg b/packages/iconify-collections/assets/public/files/yaml.svg similarity index 100% rename from web/app/components/base/icons/assets/public/files/yaml.svg rename to packages/iconify-collections/assets/public/files/yaml.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/dataset-card/external-knowledge-base.svg b/packages/iconify-collections/assets/public/knowledge/dataset-card/external-knowledge-base.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/dataset-card/external-knowledge-base.svg rename to packages/iconify-collections/assets/public/knowledge/dataset-card/external-knowledge-base.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/dataset-card/general.svg b/packages/iconify-collections/assets/public/knowledge/dataset-card/general.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/dataset-card/general.svg rename to packages/iconify-collections/assets/public/knowledge/dataset-card/general.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/dataset-card/graph.svg b/packages/iconify-collections/assets/public/knowledge/dataset-card/graph.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/dataset-card/graph.svg rename to packages/iconify-collections/assets/public/knowledge/dataset-card/graph.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/dataset-card/parent-child.svg b/packages/iconify-collections/assets/public/knowledge/dataset-card/parent-child.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/dataset-card/parent-child.svg rename to packages/iconify-collections/assets/public/knowledge/dataset-card/parent-child.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/dataset-card/qa.svg b/packages/iconify-collections/assets/public/knowledge/dataset-card/qa.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/dataset-card/qa.svg rename to packages/iconify-collections/assets/public/knowledge/dataset-card/qa.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/file.svg b/packages/iconify-collections/assets/public/knowledge/file.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/file.svg rename to packages/iconify-collections/assets/public/knowledge/file.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/online-drive/buckets-blue.svg b/packages/iconify-collections/assets/public/knowledge/online-drive/buckets-blue.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/online-drive/buckets-blue.svg rename to packages/iconify-collections/assets/public/knowledge/online-drive/buckets-blue.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/online-drive/buckets-gray.svg b/packages/iconify-collections/assets/public/knowledge/online-drive/buckets-gray.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/online-drive/buckets-gray.svg rename to packages/iconify-collections/assets/public/knowledge/online-drive/buckets-gray.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/online-drive/folder.svg b/packages/iconify-collections/assets/public/knowledge/online-drive/folder.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/online-drive/folder.svg rename to packages/iconify-collections/assets/public/knowledge/online-drive/folder.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/option-card-effect-blue-light.svg b/packages/iconify-collections/assets/public/knowledge/option-card-effect-blue-light.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/option-card-effect-blue-light.svg rename to packages/iconify-collections/assets/public/knowledge/option-card-effect-blue-light.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/option-card-effect-blue.svg b/packages/iconify-collections/assets/public/knowledge/option-card-effect-blue.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/option-card-effect-blue.svg rename to packages/iconify-collections/assets/public/knowledge/option-card-effect-blue.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/option-card-effect-orange.svg b/packages/iconify-collections/assets/public/knowledge/option-card-effect-orange.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/option-card-effect-orange.svg rename to packages/iconify-collections/assets/public/knowledge/option-card-effect-orange.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/option-card-effect-purple.svg b/packages/iconify-collections/assets/public/knowledge/option-card-effect-purple.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/option-card-effect-purple.svg rename to packages/iconify-collections/assets/public/knowledge/option-card-effect-purple.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/option-card-effect-teal.svg b/packages/iconify-collections/assets/public/knowledge/option-card-effect-teal.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/option-card-effect-teal.svg rename to packages/iconify-collections/assets/public/knowledge/option-card-effect-teal.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/selection-mod.svg b/packages/iconify-collections/assets/public/knowledge/selection-mod.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/selection-mod.svg rename to packages/iconify-collections/assets/public/knowledge/selection-mod.svg diff --git a/web/app/components/base/icons/assets/public/knowledge/watercrawl.svg b/packages/iconify-collections/assets/public/knowledge/watercrawl.svg similarity index 100% rename from web/app/components/base/icons/assets/public/knowledge/watercrawl.svg rename to packages/iconify-collections/assets/public/knowledge/watercrawl.svg diff --git a/web/app/components/base/icons/assets/public/llm/Anthropic-dark.svg b/packages/iconify-collections/assets/public/llm/Anthropic-dark.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/Anthropic-dark.svg rename to packages/iconify-collections/assets/public/llm/Anthropic-dark.svg diff --git a/web/app/components/base/icons/assets/public/llm/Anthropic-light.svg b/packages/iconify-collections/assets/public/llm/Anthropic-light.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/Anthropic-light.svg rename to packages/iconify-collections/assets/public/llm/Anthropic-light.svg diff --git a/web/app/components/base/icons/assets/public/llm/Tongyi.svg b/packages/iconify-collections/assets/public/llm/Tongyi.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/Tongyi.svg rename to packages/iconify-collections/assets/public/llm/Tongyi.svg diff --git a/web/app/components/base/icons/assets/public/llm/anthropic-short-light.svg b/packages/iconify-collections/assets/public/llm/anthropic-short-light.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/anthropic-short-light.svg rename to packages/iconify-collections/assets/public/llm/anthropic-short-light.svg diff --git a/web/app/components/base/icons/assets/public/llm/anthropic-text.svg b/packages/iconify-collections/assets/public/llm/anthropic-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/anthropic-text.svg rename to packages/iconify-collections/assets/public/llm/anthropic-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/anthropic.svg b/packages/iconify-collections/assets/public/llm/anthropic.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/anthropic.svg rename to packages/iconify-collections/assets/public/llm/anthropic.svg diff --git a/web/app/components/base/icons/assets/public/llm/azure-openai-service-text.svg b/packages/iconify-collections/assets/public/llm/azure-openai-service-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/azure-openai-service-text.svg rename to packages/iconify-collections/assets/public/llm/azure-openai-service-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/azure-openai-service.svg b/packages/iconify-collections/assets/public/llm/azure-openai-service.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/azure-openai-service.svg rename to packages/iconify-collections/assets/public/llm/azure-openai-service.svg diff --git a/web/app/components/base/icons/assets/public/llm/azureai-text.svg b/packages/iconify-collections/assets/public/llm/azureai-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/azureai-text.svg rename to packages/iconify-collections/assets/public/llm/azureai-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/azureai.svg b/packages/iconify-collections/assets/public/llm/azureai.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/azureai.svg rename to packages/iconify-collections/assets/public/llm/azureai.svg diff --git a/web/app/components/base/icons/assets/public/llm/baichuan-text.svg b/packages/iconify-collections/assets/public/llm/baichuan-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/baichuan-text.svg rename to packages/iconify-collections/assets/public/llm/baichuan-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/baichuan.svg b/packages/iconify-collections/assets/public/llm/baichuan.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/baichuan.svg rename to packages/iconify-collections/assets/public/llm/baichuan.svg diff --git a/web/app/components/base/icons/assets/public/llm/chatglm-text.svg b/packages/iconify-collections/assets/public/llm/chatglm-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/chatglm-text.svg rename to packages/iconify-collections/assets/public/llm/chatglm-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/chatglm.svg b/packages/iconify-collections/assets/public/llm/chatglm.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/chatglm.svg rename to packages/iconify-collections/assets/public/llm/chatglm.svg diff --git a/web/app/components/base/icons/assets/public/llm/cohere-text.svg b/packages/iconify-collections/assets/public/llm/cohere-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/cohere-text.svg rename to packages/iconify-collections/assets/public/llm/cohere-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/cohere.svg b/packages/iconify-collections/assets/public/llm/cohere.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/cohere.svg rename to packages/iconify-collections/assets/public/llm/cohere.svg diff --git a/web/app/components/base/icons/assets/public/llm/deepseek.svg b/packages/iconify-collections/assets/public/llm/deepseek.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/deepseek.svg rename to packages/iconify-collections/assets/public/llm/deepseek.svg diff --git a/web/app/components/base/icons/assets/public/llm/gemini.svg b/packages/iconify-collections/assets/public/llm/gemini.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/gemini.svg rename to packages/iconify-collections/assets/public/llm/gemini.svg diff --git a/web/app/components/base/icons/assets/public/llm/gpt-3.svg b/packages/iconify-collections/assets/public/llm/gpt-3.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/gpt-3.svg rename to packages/iconify-collections/assets/public/llm/gpt-3.svg diff --git a/web/app/components/base/icons/assets/public/llm/gpt-4.svg b/packages/iconify-collections/assets/public/llm/gpt-4.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/gpt-4.svg rename to packages/iconify-collections/assets/public/llm/gpt-4.svg diff --git a/web/app/components/base/icons/assets/public/llm/grok.svg b/packages/iconify-collections/assets/public/llm/grok.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/grok.svg rename to packages/iconify-collections/assets/public/llm/grok.svg diff --git a/web/app/components/base/icons/assets/public/llm/huggingface-text-hub.svg b/packages/iconify-collections/assets/public/llm/huggingface-text-hub.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/huggingface-text-hub.svg rename to packages/iconify-collections/assets/public/llm/huggingface-text-hub.svg diff --git a/web/app/components/base/icons/assets/public/llm/huggingface-text.svg b/packages/iconify-collections/assets/public/llm/huggingface-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/huggingface-text.svg rename to packages/iconify-collections/assets/public/llm/huggingface-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/huggingface.svg b/packages/iconify-collections/assets/public/llm/huggingface.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/huggingface.svg rename to packages/iconify-collections/assets/public/llm/huggingface.svg diff --git a/web/app/components/base/icons/assets/public/llm/iflytek-spark-text-cn.svg b/packages/iconify-collections/assets/public/llm/iflytek-spark-text-cn.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/iflytek-spark-text-cn.svg rename to packages/iconify-collections/assets/public/llm/iflytek-spark-text-cn.svg diff --git a/web/app/components/base/icons/assets/public/llm/iflytek-spark-text.svg b/packages/iconify-collections/assets/public/llm/iflytek-spark-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/iflytek-spark-text.svg rename to packages/iconify-collections/assets/public/llm/iflytek-spark-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/iflytek-spark.svg b/packages/iconify-collections/assets/public/llm/iflytek-spark.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/iflytek-spark.svg rename to packages/iconify-collections/assets/public/llm/iflytek-spark.svg diff --git a/web/app/components/base/icons/assets/public/llm/jina-text.svg b/packages/iconify-collections/assets/public/llm/jina-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/jina-text.svg rename to packages/iconify-collections/assets/public/llm/jina-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/jina.svg b/packages/iconify-collections/assets/public/llm/jina.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/jina.svg rename to packages/iconify-collections/assets/public/llm/jina.svg diff --git a/web/app/components/base/icons/assets/public/llm/localai-text.svg b/packages/iconify-collections/assets/public/llm/localai-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/localai-text.svg rename to packages/iconify-collections/assets/public/llm/localai-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/localai.svg b/packages/iconify-collections/assets/public/llm/localai.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/localai.svg rename to packages/iconify-collections/assets/public/llm/localai.svg diff --git a/web/app/components/base/icons/assets/public/llm/microsoft.svg b/packages/iconify-collections/assets/public/llm/microsoft.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/microsoft.svg rename to packages/iconify-collections/assets/public/llm/microsoft.svg diff --git a/web/app/components/base/icons/assets/public/llm/openai-black.svg b/packages/iconify-collections/assets/public/llm/openai-black.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/openai-black.svg rename to packages/iconify-collections/assets/public/llm/openai-black.svg diff --git a/web/app/components/base/icons/assets/public/llm/openai-blue.svg b/packages/iconify-collections/assets/public/llm/openai-blue.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/openai-blue.svg rename to packages/iconify-collections/assets/public/llm/openai-blue.svg diff --git a/web/app/components/base/icons/assets/public/llm/openai-green.svg b/packages/iconify-collections/assets/public/llm/openai-green.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/openai-green.svg rename to packages/iconify-collections/assets/public/llm/openai-green.svg diff --git a/web/app/components/base/icons/assets/public/llm/openai-small.svg b/packages/iconify-collections/assets/public/llm/openai-small.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/openai-small.svg rename to packages/iconify-collections/assets/public/llm/openai-small.svg diff --git a/web/app/components/base/icons/assets/public/llm/openai-teal.svg b/packages/iconify-collections/assets/public/llm/openai-teal.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/openai-teal.svg rename to packages/iconify-collections/assets/public/llm/openai-teal.svg diff --git a/web/app/components/base/icons/assets/public/llm/openai-text.svg b/packages/iconify-collections/assets/public/llm/openai-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/openai-text.svg rename to packages/iconify-collections/assets/public/llm/openai-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/openai-transparent.svg b/packages/iconify-collections/assets/public/llm/openai-transparent.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/openai-transparent.svg rename to packages/iconify-collections/assets/public/llm/openai-transparent.svg diff --git a/web/app/components/base/icons/assets/public/llm/openai-violet.svg b/packages/iconify-collections/assets/public/llm/openai-violet.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/openai-violet.svg rename to packages/iconify-collections/assets/public/llm/openai-violet.svg diff --git a/web/app/components/base/icons/assets/public/llm/openai-yellow.svg b/packages/iconify-collections/assets/public/llm/openai-yellow.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/openai-yellow.svg rename to packages/iconify-collections/assets/public/llm/openai-yellow.svg diff --git a/web/app/components/base/icons/assets/public/llm/openllm-text.svg b/packages/iconify-collections/assets/public/llm/openllm-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/openllm-text.svg rename to packages/iconify-collections/assets/public/llm/openllm-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/openllm.svg b/packages/iconify-collections/assets/public/llm/openllm.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/openllm.svg rename to packages/iconify-collections/assets/public/llm/openllm.svg diff --git a/web/app/components/base/icons/assets/public/llm/replicate-text.svg b/packages/iconify-collections/assets/public/llm/replicate-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/replicate-text.svg rename to packages/iconify-collections/assets/public/llm/replicate-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/replicate.svg b/packages/iconify-collections/assets/public/llm/replicate.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/replicate.svg rename to packages/iconify-collections/assets/public/llm/replicate.svg diff --git a/web/app/components/base/icons/assets/public/llm/xorbits-inference-text.svg b/packages/iconify-collections/assets/public/llm/xorbits-inference-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/xorbits-inference-text.svg rename to packages/iconify-collections/assets/public/llm/xorbits-inference-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/xorbits-inference.svg b/packages/iconify-collections/assets/public/llm/xorbits-inference.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/xorbits-inference.svg rename to packages/iconify-collections/assets/public/llm/xorbits-inference.svg diff --git a/web/app/components/base/icons/assets/public/llm/zhipuai-text-cn.svg b/packages/iconify-collections/assets/public/llm/zhipuai-text-cn.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/zhipuai-text-cn.svg rename to packages/iconify-collections/assets/public/llm/zhipuai-text-cn.svg diff --git a/web/app/components/base/icons/assets/public/llm/zhipuai-text.svg b/packages/iconify-collections/assets/public/llm/zhipuai-text.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/zhipuai-text.svg rename to packages/iconify-collections/assets/public/llm/zhipuai-text.svg diff --git a/web/app/components/base/icons/assets/public/llm/zhipuai.svg b/packages/iconify-collections/assets/public/llm/zhipuai.svg similarity index 100% rename from web/app/components/base/icons/assets/public/llm/zhipuai.svg rename to packages/iconify-collections/assets/public/llm/zhipuai.svg diff --git a/web/app/components/base/icons/assets/public/model/checked.svg b/packages/iconify-collections/assets/public/model/checked.svg similarity index 100% rename from web/app/components/base/icons/assets/public/model/checked.svg rename to packages/iconify-collections/assets/public/model/checked.svg diff --git a/web/app/components/base/icons/assets/public/other/Icon-3-dots.svg b/packages/iconify-collections/assets/public/other/Icon-3-dots.svg similarity index 100% rename from web/app/components/base/icons/assets/public/other/Icon-3-dots.svg rename to packages/iconify-collections/assets/public/other/Icon-3-dots.svg diff --git a/web/app/components/base/icons/assets/public/other/default-tool-icon.svg b/packages/iconify-collections/assets/public/other/default-tool-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/public/other/default-tool-icon.svg rename to packages/iconify-collections/assets/public/other/default-tool-icon.svg diff --git a/web/app/components/base/icons/assets/public/other/message-3-fill.svg b/packages/iconify-collections/assets/public/other/message-3-fill.svg similarity index 100% rename from web/app/components/base/icons/assets/public/other/message-3-fill.svg rename to packages/iconify-collections/assets/public/other/message-3-fill.svg diff --git a/web/app/components/base/icons/assets/public/other/row-struct.svg b/packages/iconify-collections/assets/public/other/row-struct.svg similarity index 100% rename from web/app/components/base/icons/assets/public/other/row-struct.svg rename to packages/iconify-collections/assets/public/other/row-struct.svg diff --git a/web/app/components/base/icons/assets/public/other/slack.svg b/packages/iconify-collections/assets/public/other/slack.svg similarity index 100% rename from web/app/components/base/icons/assets/public/other/slack.svg rename to packages/iconify-collections/assets/public/other/slack.svg diff --git a/web/app/components/base/icons/assets/public/other/teams.svg b/packages/iconify-collections/assets/public/other/teams.svg similarity index 100% rename from web/app/components/base/icons/assets/public/other/teams.svg rename to packages/iconify-collections/assets/public/other/teams.svg diff --git a/web/app/components/base/icons/assets/public/plugins/google.svg b/packages/iconify-collections/assets/public/plugins/google.svg similarity index 100% rename from web/app/components/base/icons/assets/public/plugins/google.svg rename to packages/iconify-collections/assets/public/plugins/google.svg diff --git a/web/app/components/base/icons/assets/public/plugins/partner-dark.svg b/packages/iconify-collections/assets/public/plugins/partner-dark.svg similarity index 100% rename from web/app/components/base/icons/assets/public/plugins/partner-dark.svg rename to packages/iconify-collections/assets/public/plugins/partner-dark.svg diff --git a/web/app/components/base/icons/assets/public/plugins/partner-light.svg b/packages/iconify-collections/assets/public/plugins/partner-light.svg similarity index 100% rename from web/app/components/base/icons/assets/public/plugins/partner-light.svg rename to packages/iconify-collections/assets/public/plugins/partner-light.svg diff --git a/web/app/components/base/icons/assets/public/plugins/verified-dark.svg b/packages/iconify-collections/assets/public/plugins/verified-dark.svg similarity index 100% rename from web/app/components/base/icons/assets/public/plugins/verified-dark.svg rename to packages/iconify-collections/assets/public/plugins/verified-dark.svg diff --git a/web/app/components/base/icons/assets/public/plugins/verified-light.svg b/packages/iconify-collections/assets/public/plugins/verified-light.svg similarity index 100% rename from web/app/components/base/icons/assets/public/plugins/verified-light.svg rename to packages/iconify-collections/assets/public/plugins/verified-light.svg diff --git a/web/app/components/base/icons/assets/public/plugins/web-reader.svg b/packages/iconify-collections/assets/public/plugins/web-reader.svg similarity index 100% rename from web/app/components/base/icons/assets/public/plugins/web-reader.svg rename to packages/iconify-collections/assets/public/plugins/web-reader.svg diff --git a/web/app/components/base/icons/assets/public/plugins/wikipedia.svg b/packages/iconify-collections/assets/public/plugins/wikipedia.svg similarity index 100% rename from web/app/components/base/icons/assets/public/plugins/wikipedia.svg rename to packages/iconify-collections/assets/public/plugins/wikipedia.svg diff --git a/web/app/components/base/icons/assets/public/thought/data-set.svg b/packages/iconify-collections/assets/public/thought/data-set.svg similarity index 100% rename from web/app/components/base/icons/assets/public/thought/data-set.svg rename to packages/iconify-collections/assets/public/thought/data-set.svg diff --git a/web/app/components/base/icons/assets/public/thought/loading.svg b/packages/iconify-collections/assets/public/thought/loading.svg similarity index 100% rename from web/app/components/base/icons/assets/public/thought/loading.svg rename to packages/iconify-collections/assets/public/thought/loading.svg diff --git a/web/app/components/base/icons/assets/public/thought/search.svg b/packages/iconify-collections/assets/public/thought/search.svg similarity index 100% rename from web/app/components/base/icons/assets/public/thought/search.svg rename to packages/iconify-collections/assets/public/thought/search.svg diff --git a/web/app/components/base/icons/assets/public/thought/thought-list.svg b/packages/iconify-collections/assets/public/thought/thought-list.svg similarity index 100% rename from web/app/components/base/icons/assets/public/thought/thought-list.svg rename to packages/iconify-collections/assets/public/thought/thought-list.svg diff --git a/web/app/components/base/icons/assets/public/thought/web-reader.svg b/packages/iconify-collections/assets/public/thought/web-reader.svg similarity index 100% rename from web/app/components/base/icons/assets/public/thought/web-reader.svg rename to packages/iconify-collections/assets/public/thought/web-reader.svg diff --git a/web/app/components/base/icons/assets/public/tracing/aliyun-icon-big.svg b/packages/iconify-collections/assets/public/tracing/aliyun-icon-big.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/aliyun-icon-big.svg rename to packages/iconify-collections/assets/public/tracing/aliyun-icon-big.svg diff --git a/web/app/components/base/icons/assets/public/tracing/aliyun-icon.svg b/packages/iconify-collections/assets/public/tracing/aliyun-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/aliyun-icon.svg rename to packages/iconify-collections/assets/public/tracing/aliyun-icon.svg diff --git a/web/app/components/base/icons/assets/public/tracing/arize-icon-big.svg b/packages/iconify-collections/assets/public/tracing/arize-icon-big.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/arize-icon-big.svg rename to packages/iconify-collections/assets/public/tracing/arize-icon-big.svg diff --git a/web/app/components/base/icons/assets/public/tracing/arize-icon.svg b/packages/iconify-collections/assets/public/tracing/arize-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/arize-icon.svg rename to packages/iconify-collections/assets/public/tracing/arize-icon.svg diff --git a/web/app/components/base/icons/assets/public/tracing/databricks-icon-big.svg b/packages/iconify-collections/assets/public/tracing/databricks-icon-big.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/databricks-icon-big.svg rename to packages/iconify-collections/assets/public/tracing/databricks-icon-big.svg diff --git a/web/app/components/base/icons/assets/public/tracing/databricks-icon.svg b/packages/iconify-collections/assets/public/tracing/databricks-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/databricks-icon.svg rename to packages/iconify-collections/assets/public/tracing/databricks-icon.svg diff --git a/web/app/components/base/icons/assets/public/tracing/langfuse-icon-big.svg b/packages/iconify-collections/assets/public/tracing/langfuse-icon-big.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/langfuse-icon-big.svg rename to packages/iconify-collections/assets/public/tracing/langfuse-icon-big.svg diff --git a/web/app/components/base/icons/assets/public/tracing/langfuse-icon.svg b/packages/iconify-collections/assets/public/tracing/langfuse-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/langfuse-icon.svg rename to packages/iconify-collections/assets/public/tracing/langfuse-icon.svg diff --git a/web/app/components/base/icons/assets/public/tracing/langsmith-icon-big.svg b/packages/iconify-collections/assets/public/tracing/langsmith-icon-big.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/langsmith-icon-big.svg rename to packages/iconify-collections/assets/public/tracing/langsmith-icon-big.svg diff --git a/web/app/components/base/icons/assets/public/tracing/langsmith-icon.svg b/packages/iconify-collections/assets/public/tracing/langsmith-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/langsmith-icon.svg rename to packages/iconify-collections/assets/public/tracing/langsmith-icon.svg diff --git a/web/app/components/base/icons/assets/public/tracing/mlflow-icon-big.svg b/packages/iconify-collections/assets/public/tracing/mlflow-icon-big.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/mlflow-icon-big.svg rename to packages/iconify-collections/assets/public/tracing/mlflow-icon-big.svg diff --git a/web/app/components/base/icons/assets/public/tracing/mlflow-icon.svg b/packages/iconify-collections/assets/public/tracing/mlflow-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/mlflow-icon.svg rename to packages/iconify-collections/assets/public/tracing/mlflow-icon.svg diff --git a/web/app/components/base/icons/assets/public/tracing/opik-icon-big.svg b/packages/iconify-collections/assets/public/tracing/opik-icon-big.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/opik-icon-big.svg rename to packages/iconify-collections/assets/public/tracing/opik-icon-big.svg diff --git a/web/app/components/base/icons/assets/public/tracing/opik-icon.svg b/packages/iconify-collections/assets/public/tracing/opik-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/opik-icon.svg rename to packages/iconify-collections/assets/public/tracing/opik-icon.svg diff --git a/web/app/components/base/icons/assets/public/tracing/phoenix-icon-big.svg b/packages/iconify-collections/assets/public/tracing/phoenix-icon-big.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/phoenix-icon-big.svg rename to packages/iconify-collections/assets/public/tracing/phoenix-icon-big.svg diff --git a/web/app/components/base/icons/assets/public/tracing/phoenix-icon.svg b/packages/iconify-collections/assets/public/tracing/phoenix-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/phoenix-icon.svg rename to packages/iconify-collections/assets/public/tracing/phoenix-icon.svg diff --git a/web/app/components/base/icons/assets/public/tracing/tencent-icon-big.svg b/packages/iconify-collections/assets/public/tracing/tencent-icon-big.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/tencent-icon-big.svg rename to packages/iconify-collections/assets/public/tracing/tencent-icon-big.svg diff --git a/web/app/components/base/icons/assets/public/tracing/tencent-icon.svg b/packages/iconify-collections/assets/public/tracing/tencent-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/tencent-icon.svg rename to packages/iconify-collections/assets/public/tracing/tencent-icon.svg diff --git a/web/app/components/base/icons/assets/public/tracing/tracing-icon.svg b/packages/iconify-collections/assets/public/tracing/tracing-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/tracing-icon.svg rename to packages/iconify-collections/assets/public/tracing/tracing-icon.svg diff --git a/web/app/components/base/icons/assets/public/tracing/weave-icon-big.svg b/packages/iconify-collections/assets/public/tracing/weave-icon-big.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/weave-icon-big.svg rename to packages/iconify-collections/assets/public/tracing/weave-icon-big.svg diff --git a/web/app/components/base/icons/assets/public/tracing/weave-icon.svg b/packages/iconify-collections/assets/public/tracing/weave-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/public/tracing/weave-icon.svg rename to packages/iconify-collections/assets/public/tracing/weave-icon.svg diff --git a/web/app/components/base/icons/assets/vender/features/citations.svg b/packages/iconify-collections/assets/vender/features/citations.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/features/citations.svg rename to packages/iconify-collections/assets/vender/features/citations.svg diff --git a/web/app/components/base/icons/assets/vender/features/content-moderation.svg b/packages/iconify-collections/assets/vender/features/content-moderation.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/features/content-moderation.svg rename to packages/iconify-collections/assets/vender/features/content-moderation.svg diff --git a/web/app/components/base/icons/assets/vender/features/document.svg b/packages/iconify-collections/assets/vender/features/document.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/features/document.svg rename to packages/iconify-collections/assets/vender/features/document.svg diff --git a/web/app/components/base/icons/assets/vender/features/folder-upload.svg b/packages/iconify-collections/assets/vender/features/folder-upload.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/features/folder-upload.svg rename to packages/iconify-collections/assets/vender/features/folder-upload.svg diff --git a/web/app/components/base/icons/assets/vender/features/love-message.svg b/packages/iconify-collections/assets/vender/features/love-message.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/features/love-message.svg rename to packages/iconify-collections/assets/vender/features/love-message.svg diff --git a/web/app/components/base/icons/assets/vender/features/message-fast.svg b/packages/iconify-collections/assets/vender/features/message-fast.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/features/message-fast.svg rename to packages/iconify-collections/assets/vender/features/message-fast.svg diff --git a/web/app/components/base/icons/assets/vender/features/microphone-01.svg b/packages/iconify-collections/assets/vender/features/microphone-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/features/microphone-01.svg rename to packages/iconify-collections/assets/vender/features/microphone-01.svg diff --git a/web/app/components/base/icons/assets/vender/features/text-to-audio.svg b/packages/iconify-collections/assets/vender/features/text-to-audio.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/features/text-to-audio.svg rename to packages/iconify-collections/assets/vender/features/text-to-audio.svg diff --git a/web/app/components/base/icons/assets/vender/features/virtual-assistant.svg b/packages/iconify-collections/assets/vender/features/virtual-assistant.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/features/virtual-assistant.svg rename to packages/iconify-collections/assets/vender/features/virtual-assistant.svg diff --git a/web/app/components/base/icons/assets/vender/features/vision.svg b/packages/iconify-collections/assets/vender/features/vision.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/features/vision.svg rename to packages/iconify-collections/assets/vender/features/vision.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/add-chunks.svg b/packages/iconify-collections/assets/vender/knowledge/add-chunks.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/add-chunks.svg rename to packages/iconify-collections/assets/vender/knowledge/add-chunks.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/api-aggregate.svg b/packages/iconify-collections/assets/vender/knowledge/api-aggregate.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/api-aggregate.svg rename to packages/iconify-collections/assets/vender/knowledge/api-aggregate.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/arrow-shape.svg b/packages/iconify-collections/assets/vender/knowledge/arrow-shape.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/arrow-shape.svg rename to packages/iconify-collections/assets/vender/knowledge/arrow-shape.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/chunk.svg b/packages/iconify-collections/assets/vender/knowledge/chunk.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/chunk.svg rename to packages/iconify-collections/assets/vender/knowledge/chunk.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/collapse.svg b/packages/iconify-collections/assets/vender/knowledge/collapse.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/collapse.svg rename to packages/iconify-collections/assets/vender/knowledge/collapse.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/divider.svg b/packages/iconify-collections/assets/vender/knowledge/divider.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/divider.svg rename to packages/iconify-collections/assets/vender/knowledge/divider.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/economic.svg b/packages/iconify-collections/assets/vender/knowledge/economic.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/economic.svg rename to packages/iconify-collections/assets/vender/knowledge/economic.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/full-text-search.svg b/packages/iconify-collections/assets/vender/knowledge/full-text-search.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/full-text-search.svg rename to packages/iconify-collections/assets/vender/knowledge/full-text-search.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/general-chunk.svg b/packages/iconify-collections/assets/vender/knowledge/general-chunk.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/general-chunk.svg rename to packages/iconify-collections/assets/vender/knowledge/general-chunk.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/high-quality.svg b/packages/iconify-collections/assets/vender/knowledge/high-quality.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/high-quality.svg rename to packages/iconify-collections/assets/vender/knowledge/high-quality.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/hybrid-search.svg b/packages/iconify-collections/assets/vender/knowledge/hybrid-search.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/hybrid-search.svg rename to packages/iconify-collections/assets/vender/knowledge/hybrid-search.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/parent-child-chunk.svg b/packages/iconify-collections/assets/vender/knowledge/parent-child-chunk.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/parent-child-chunk.svg rename to packages/iconify-collections/assets/vender/knowledge/parent-child-chunk.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/question-and-answer.svg b/packages/iconify-collections/assets/vender/knowledge/question-and-answer.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/question-and-answer.svg rename to packages/iconify-collections/assets/vender/knowledge/question-and-answer.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/search-lines-sparkle.svg b/packages/iconify-collections/assets/vender/knowledge/search-lines-sparkle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/search-lines-sparkle.svg rename to packages/iconify-collections/assets/vender/knowledge/search-lines-sparkle.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/search-menu.svg b/packages/iconify-collections/assets/vender/knowledge/search-menu.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/search-menu.svg rename to packages/iconify-collections/assets/vender/knowledge/search-menu.svg diff --git a/web/app/components/base/icons/assets/vender/knowledge/vector-search.svg b/packages/iconify-collections/assets/vender/knowledge/vector-search.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/knowledge/vector-search.svg rename to packages/iconify-collections/assets/vender/knowledge/vector-search.svg diff --git a/web/app/components/base/icons/assets/vender/line/alertsAndFeedback/alert-triangle.svg b/packages/iconify-collections/assets/vender/line/alertsAndFeedback/alert-triangle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/alertsAndFeedback/alert-triangle.svg rename to packages/iconify-collections/assets/vender/line/alertsAndFeedback/alert-triangle.svg diff --git a/web/app/components/base/icons/assets/vender/line/alertsAndFeedback/thumbs-down.svg b/packages/iconify-collections/assets/vender/line/alertsAndFeedback/thumbs-down.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/alertsAndFeedback/thumbs-down.svg rename to packages/iconify-collections/assets/vender/line/alertsAndFeedback/thumbs-down.svg diff --git a/web/app/components/base/icons/assets/vender/line/alertsAndFeedback/thumbs-up.svg b/packages/iconify-collections/assets/vender/line/alertsAndFeedback/thumbs-up.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/alertsAndFeedback/thumbs-up.svg rename to packages/iconify-collections/assets/vender/line/alertsAndFeedback/thumbs-up.svg diff --git a/web/app/components/base/icons/assets/vender/line/alertsAndFeedback/warning.svg b/packages/iconify-collections/assets/vender/line/alertsAndFeedback/warning.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/alertsAndFeedback/warning.svg rename to packages/iconify-collections/assets/vender/line/alertsAndFeedback/warning.svg diff --git a/web/app/components/base/icons/assets/vender/line/arrows/IconR.svg b/packages/iconify-collections/assets/vender/line/arrows/IconR.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/arrows/IconR.svg rename to packages/iconify-collections/assets/vender/line/arrows/IconR.svg diff --git a/web/app/components/base/icons/assets/vender/line/arrows/arrow-narrow-left.svg b/packages/iconify-collections/assets/vender/line/arrows/arrow-narrow-left.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/arrows/arrow-narrow-left.svg rename to packages/iconify-collections/assets/vender/line/arrows/arrow-narrow-left.svg diff --git a/web/app/components/base/icons/assets/vender/line/arrows/arrow-up-right.svg b/packages/iconify-collections/assets/vender/line/arrows/arrow-up-right.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/arrows/arrow-up-right.svg rename to packages/iconify-collections/assets/vender/line/arrows/arrow-up-right.svg diff --git a/web/app/components/base/icons/assets/vender/line/arrows/chevron-down-double.svg b/packages/iconify-collections/assets/vender/line/arrows/chevron-down-double.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/arrows/chevron-down-double.svg rename to packages/iconify-collections/assets/vender/line/arrows/chevron-down-double.svg diff --git a/web/app/components/base/icons/assets/vender/line/arrows/chevron-right.svg b/packages/iconify-collections/assets/vender/line/arrows/chevron-right.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/arrows/chevron-right.svg rename to packages/iconify-collections/assets/vender/line/arrows/chevron-right.svg diff --git a/web/app/components/base/icons/assets/vender/line/arrows/chevron-selector-vertical.svg b/packages/iconify-collections/assets/vender/line/arrows/chevron-selector-vertical.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/arrows/chevron-selector-vertical.svg rename to packages/iconify-collections/assets/vender/line/arrows/chevron-selector-vertical.svg diff --git a/web/app/components/base/icons/assets/vender/line/arrows/refresh-ccw-01.svg b/packages/iconify-collections/assets/vender/line/arrows/refresh-ccw-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/arrows/refresh-ccw-01.svg rename to packages/iconify-collections/assets/vender/line/arrows/refresh-ccw-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/arrows/refresh-cw-05.svg b/packages/iconify-collections/assets/vender/line/arrows/refresh-cw-05.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/arrows/refresh-cw-05.svg rename to packages/iconify-collections/assets/vender/line/arrows/refresh-cw-05.svg diff --git a/web/app/components/base/icons/assets/vender/line/arrows/reverse-left.svg b/packages/iconify-collections/assets/vender/line/arrows/reverse-left.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/arrows/reverse-left.svg rename to packages/iconify-collections/assets/vender/line/arrows/reverse-left.svg diff --git a/web/app/components/base/icons/assets/vender/line/communication/ai-text.svg b/packages/iconify-collections/assets/vender/line/communication/ai-text.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/communication/ai-text.svg rename to packages/iconify-collections/assets/vender/line/communication/ai-text.svg diff --git a/web/app/components/base/icons/assets/vender/line/communication/chat-bot-slim.svg b/packages/iconify-collections/assets/vender/line/communication/chat-bot-slim.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/communication/chat-bot-slim.svg rename to packages/iconify-collections/assets/vender/line/communication/chat-bot-slim.svg diff --git a/web/app/components/base/icons/assets/vender/line/communication/chat-bot.svg b/packages/iconify-collections/assets/vender/line/communication/chat-bot.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/communication/chat-bot.svg rename to packages/iconify-collections/assets/vender/line/communication/chat-bot.svg diff --git a/web/app/components/base/icons/assets/vender/line/communication/cute-robot.svg b/packages/iconify-collections/assets/vender/line/communication/cute-robot.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/communication/cute-robot.svg rename to packages/iconify-collections/assets/vender/line/communication/cute-robot.svg diff --git a/web/app/components/base/icons/assets/vender/line/communication/message-check-remove.svg b/packages/iconify-collections/assets/vender/line/communication/message-check-remove.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/communication/message-check-remove.svg rename to packages/iconify-collections/assets/vender/line/communication/message-check-remove.svg diff --git a/web/app/components/base/icons/assets/vender/line/communication/message-fast-plus.svg b/packages/iconify-collections/assets/vender/line/communication/message-fast-plus.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/communication/message-fast-plus.svg rename to packages/iconify-collections/assets/vender/line/communication/message-fast-plus.svg diff --git a/web/app/components/base/icons/assets/vender/line/development/artificial-brain.svg b/packages/iconify-collections/assets/vender/line/development/artificial-brain.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/development/artificial-brain.svg rename to packages/iconify-collections/assets/vender/line/development/artificial-brain.svg diff --git a/web/app/components/base/icons/assets/vender/line/development/bar-chart-square-02.svg b/packages/iconify-collections/assets/vender/line/development/bar-chart-square-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/development/bar-chart-square-02.svg rename to packages/iconify-collections/assets/vender/line/development/bar-chart-square-02.svg diff --git a/web/app/components/base/icons/assets/vender/line/development/brackets-x.svg b/packages/iconify-collections/assets/vender/line/development/brackets-x.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/development/brackets-x.svg rename to packages/iconify-collections/assets/vender/line/development/brackets-x.svg diff --git a/web/app/components/base/icons/assets/vender/line/development/code-browser.svg b/packages/iconify-collections/assets/vender/line/development/code-browser.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/development/code-browser.svg rename to packages/iconify-collections/assets/vender/line/development/code-browser.svg diff --git a/web/app/components/base/icons/assets/vender/line/development/container.svg b/packages/iconify-collections/assets/vender/line/development/container.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/development/container.svg rename to packages/iconify-collections/assets/vender/line/development/container.svg diff --git a/web/app/components/base/icons/assets/vender/line/development/database-01.svg b/packages/iconify-collections/assets/vender/line/development/database-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/development/database-01.svg rename to packages/iconify-collections/assets/vender/line/development/database-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/development/database-03.svg b/packages/iconify-collections/assets/vender/line/development/database-03.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/development/database-03.svg rename to packages/iconify-collections/assets/vender/line/development/database-03.svg diff --git a/web/app/components/base/icons/assets/vender/line/development/file-heart-02.svg b/packages/iconify-collections/assets/vender/line/development/file-heart-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/development/file-heart-02.svg rename to packages/iconify-collections/assets/vender/line/development/file-heart-02.svg diff --git a/web/app/components/base/icons/assets/vender/line/development/git-branch-01.svg b/packages/iconify-collections/assets/vender/line/development/git-branch-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/development/git-branch-01.svg rename to packages/iconify-collections/assets/vender/line/development/git-branch-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/development/prompt-engineering.svg b/packages/iconify-collections/assets/vender/line/development/prompt-engineering.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/development/prompt-engineering.svg rename to packages/iconify-collections/assets/vender/line/development/prompt-engineering.svg diff --git a/web/app/components/base/icons/assets/vender/line/development/puzzle-piece-01.svg b/packages/iconify-collections/assets/vender/line/development/puzzle-piece-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/development/puzzle-piece-01.svg rename to packages/iconify-collections/assets/vender/line/development/puzzle-piece-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/development/terminal-square.svg b/packages/iconify-collections/assets/vender/line/development/terminal-square.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/development/terminal-square.svg rename to packages/iconify-collections/assets/vender/line/development/terminal-square.svg diff --git a/web/app/components/base/icons/assets/vender/line/development/variable.svg b/packages/iconify-collections/assets/vender/line/development/variable.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/development/variable.svg rename to packages/iconify-collections/assets/vender/line/development/variable.svg diff --git a/web/app/components/base/icons/assets/vender/line/development/webhooks.svg b/packages/iconify-collections/assets/vender/line/development/webhooks.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/development/webhooks.svg rename to packages/iconify-collections/assets/vender/line/development/webhooks.svg diff --git a/web/app/components/base/icons/assets/vender/line/editor/align-left.svg b/packages/iconify-collections/assets/vender/line/editor/align-left.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/editor/align-left.svg rename to packages/iconify-collections/assets/vender/line/editor/align-left.svg diff --git a/web/app/components/base/icons/assets/vender/line/editor/bezier-curve-03.svg b/packages/iconify-collections/assets/vender/line/editor/bezier-curve-03.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/editor/bezier-curve-03.svg rename to packages/iconify-collections/assets/vender/line/editor/bezier-curve-03.svg diff --git a/web/app/components/base/icons/assets/vender/line/editor/collapse.svg b/packages/iconify-collections/assets/vender/line/editor/collapse.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/editor/collapse.svg rename to packages/iconify-collections/assets/vender/line/editor/collapse.svg diff --git a/web/app/components/base/icons/assets/vender/line/editor/colors.svg b/packages/iconify-collections/assets/vender/line/editor/colors.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/editor/colors.svg rename to packages/iconify-collections/assets/vender/line/editor/colors.svg diff --git a/web/app/components/base/icons/assets/vender/line/editor/image-indent-left.svg b/packages/iconify-collections/assets/vender/line/editor/image-indent-left.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/editor/image-indent-left.svg rename to packages/iconify-collections/assets/vender/line/editor/image-indent-left.svg diff --git a/web/app/components/base/icons/assets/vender/line/editor/left-indent-02.svg b/packages/iconify-collections/assets/vender/line/editor/left-indent-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/editor/left-indent-02.svg rename to packages/iconify-collections/assets/vender/line/editor/left-indent-02.svg diff --git a/web/app/components/base/icons/assets/vender/line/editor/letter-spacing-01.svg b/packages/iconify-collections/assets/vender/line/editor/letter-spacing-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/editor/letter-spacing-01.svg rename to packages/iconify-collections/assets/vender/line/editor/letter-spacing-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/editor/type-square.svg b/packages/iconify-collections/assets/vender/line/editor/type-square.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/editor/type-square.svg rename to packages/iconify-collections/assets/vender/line/editor/type-square.svg diff --git a/web/app/components/base/icons/assets/vender/line/education/book-open-01.svg b/packages/iconify-collections/assets/vender/line/education/book-open-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/education/book-open-01.svg rename to packages/iconify-collections/assets/vender/line/education/book-open-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/files/copy-check.svg b/packages/iconify-collections/assets/vender/line/files/copy-check.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/files/copy-check.svg rename to packages/iconify-collections/assets/vender/line/files/copy-check.svg diff --git a/web/app/components/base/icons/assets/vender/line/files/copy.svg b/packages/iconify-collections/assets/vender/line/files/copy.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/files/copy.svg rename to packages/iconify-collections/assets/vender/line/files/copy.svg diff --git a/web/app/components/base/icons/assets/vender/line/files/file-02.svg b/packages/iconify-collections/assets/vender/line/files/file-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/files/file-02.svg rename to packages/iconify-collections/assets/vender/line/files/file-02.svg diff --git a/web/app/components/base/icons/assets/vender/line/files/file-arrow-01.svg b/packages/iconify-collections/assets/vender/line/files/file-arrow-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/files/file-arrow-01.svg rename to packages/iconify-collections/assets/vender/line/files/file-arrow-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/files/file-check-02.svg b/packages/iconify-collections/assets/vender/line/files/file-check-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/files/file-check-02.svg rename to packages/iconify-collections/assets/vender/line/files/file-check-02.svg diff --git a/web/app/components/base/icons/assets/vender/line/files/file-download-02.svg b/packages/iconify-collections/assets/vender/line/files/file-download-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/files/file-download-02.svg rename to packages/iconify-collections/assets/vender/line/files/file-download-02.svg diff --git a/web/app/components/base/icons/assets/vender/line/files/file-plus-01.svg b/packages/iconify-collections/assets/vender/line/files/file-plus-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/files/file-plus-01.svg rename to packages/iconify-collections/assets/vender/line/files/file-plus-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/files/file-plus-02.svg b/packages/iconify-collections/assets/vender/line/files/file-plus-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/files/file-plus-02.svg rename to packages/iconify-collections/assets/vender/line/files/file-plus-02.svg diff --git a/web/app/components/base/icons/assets/vender/line/files/file-text.svg b/packages/iconify-collections/assets/vender/line/files/file-text.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/files/file-text.svg rename to packages/iconify-collections/assets/vender/line/files/file-text.svg diff --git a/web/app/components/base/icons/assets/vender/line/files/file-upload.svg b/packages/iconify-collections/assets/vender/line/files/file-upload.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/files/file-upload.svg rename to packages/iconify-collections/assets/vender/line/files/file-upload.svg diff --git a/web/app/components/base/icons/assets/vender/line/files/folder.svg b/packages/iconify-collections/assets/vender/line/files/folder.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/files/folder.svg rename to packages/iconify-collections/assets/vender/line/files/folder.svg diff --git a/web/app/components/base/icons/assets/vender/line/financeAndECommerce/balance.svg b/packages/iconify-collections/assets/vender/line/financeAndECommerce/balance.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/financeAndECommerce/balance.svg rename to packages/iconify-collections/assets/vender/line/financeAndECommerce/balance.svg diff --git a/web/app/components/base/icons/assets/vender/line/financeAndECommerce/coins-stacked-01.svg b/packages/iconify-collections/assets/vender/line/financeAndECommerce/coins-stacked-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/financeAndECommerce/coins-stacked-01.svg rename to packages/iconify-collections/assets/vender/line/financeAndECommerce/coins-stacked-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/financeAndECommerce/credits-coin.svg b/packages/iconify-collections/assets/vender/line/financeAndECommerce/credits-coin.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/financeAndECommerce/credits-coin.svg rename to packages/iconify-collections/assets/vender/line/financeAndECommerce/credits-coin.svg diff --git a/web/app/components/base/icons/assets/vender/line/financeAndECommerce/gold-coin.svg b/packages/iconify-collections/assets/vender/line/financeAndECommerce/gold-coin.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/financeAndECommerce/gold-coin.svg rename to packages/iconify-collections/assets/vender/line/financeAndECommerce/gold-coin.svg diff --git a/web/app/components/base/icons/assets/vender/line/financeAndECommerce/receipt-list.svg b/packages/iconify-collections/assets/vender/line/financeAndECommerce/receipt-list.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/financeAndECommerce/receipt-list.svg rename to packages/iconify-collections/assets/vender/line/financeAndECommerce/receipt-list.svg diff --git a/web/app/components/base/icons/assets/vender/line/financeAndECommerce/tag-01.svg b/packages/iconify-collections/assets/vender/line/financeAndECommerce/tag-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/financeAndECommerce/tag-01.svg rename to packages/iconify-collections/assets/vender/line/financeAndECommerce/tag-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/financeAndECommerce/tag-03.svg b/packages/iconify-collections/assets/vender/line/financeAndECommerce/tag-03.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/financeAndECommerce/tag-03.svg rename to packages/iconify-collections/assets/vender/line/financeAndECommerce/tag-03.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/at-sign.svg b/packages/iconify-collections/assets/vender/line/general/at-sign.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/at-sign.svg rename to packages/iconify-collections/assets/vender/line/general/at-sign.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/bookmark.svg b/packages/iconify-collections/assets/vender/line/general/bookmark.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/bookmark.svg rename to packages/iconify-collections/assets/vender/line/general/bookmark.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/check-done-01.svg b/packages/iconify-collections/assets/vender/line/general/check-done-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/check-done-01.svg rename to packages/iconify-collections/assets/vender/line/general/check-done-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/check.svg b/packages/iconify-collections/assets/vender/line/general/check.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/check.svg rename to packages/iconify-collections/assets/vender/line/general/check.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/checklist-square.svg b/packages/iconify-collections/assets/vender/line/general/checklist-square.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/checklist-square.svg rename to packages/iconify-collections/assets/vender/line/general/checklist-square.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/code-assistant.svg b/packages/iconify-collections/assets/vender/line/general/code-assistant.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/code-assistant.svg rename to packages/iconify-collections/assets/vender/line/general/code-assistant.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/dots-grid.svg b/packages/iconify-collections/assets/vender/line/general/dots-grid.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/dots-grid.svg rename to packages/iconify-collections/assets/vender/line/general/dots-grid.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/edit-02.svg b/packages/iconify-collections/assets/vender/line/general/edit-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/edit-02.svg rename to packages/iconify-collections/assets/vender/line/general/edit-02.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/edit-04.svg b/packages/iconify-collections/assets/vender/line/general/edit-04.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/edit-04.svg rename to packages/iconify-collections/assets/vender/line/general/edit-04.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/edit-05.svg b/packages/iconify-collections/assets/vender/line/general/edit-05.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/edit-05.svg rename to packages/iconify-collections/assets/vender/line/general/edit-05.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/hash-02.svg b/packages/iconify-collections/assets/vender/line/general/hash-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/hash-02.svg rename to packages/iconify-collections/assets/vender/line/general/hash-02.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/info-circle.svg b/packages/iconify-collections/assets/vender/line/general/info-circle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/info-circle.svg rename to packages/iconify-collections/assets/vender/line/general/info-circle.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/link-03.svg b/packages/iconify-collections/assets/vender/line/general/link-03.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/link-03.svg rename to packages/iconify-collections/assets/vender/line/general/link-03.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/link-external-02.svg b/packages/iconify-collections/assets/vender/line/general/link-external-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/link-external-02.svg rename to packages/iconify-collections/assets/vender/line/general/link-external-02.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/log-in-04.svg b/packages/iconify-collections/assets/vender/line/general/log-in-04.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/log-in-04.svg rename to packages/iconify-collections/assets/vender/line/general/log-in-04.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/log-out-01.svg b/packages/iconify-collections/assets/vender/line/general/log-out-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/log-out-01.svg rename to packages/iconify-collections/assets/vender/line/general/log-out-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/log-out-04.svg b/packages/iconify-collections/assets/vender/line/general/log-out-04.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/log-out-04.svg rename to packages/iconify-collections/assets/vender/line/general/log-out-04.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/magic-edit.svg b/packages/iconify-collections/assets/vender/line/general/magic-edit.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/magic-edit.svg rename to packages/iconify-collections/assets/vender/line/general/magic-edit.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/menu-01.svg b/packages/iconify-collections/assets/vender/line/general/menu-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/menu-01.svg rename to packages/iconify-collections/assets/vender/line/general/menu-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/pin-01.svg b/packages/iconify-collections/assets/vender/line/general/pin-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/pin-01.svg rename to packages/iconify-collections/assets/vender/line/general/pin-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/pin-02.svg b/packages/iconify-collections/assets/vender/line/general/pin-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/pin-02.svg rename to packages/iconify-collections/assets/vender/line/general/pin-02.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/plus-02.svg b/packages/iconify-collections/assets/vender/line/general/plus-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/plus-02.svg rename to packages/iconify-collections/assets/vender/line/general/plus-02.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/refresh.svg b/packages/iconify-collections/assets/vender/line/general/refresh.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/refresh.svg rename to packages/iconify-collections/assets/vender/line/general/refresh.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/search-menu.svg b/packages/iconify-collections/assets/vender/line/general/search-menu.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/search-menu.svg rename to packages/iconify-collections/assets/vender/line/general/search-menu.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/settings-01.svg b/packages/iconify-collections/assets/vender/line/general/settings-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/settings-01.svg rename to packages/iconify-collections/assets/vender/line/general/settings-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/settings-04.svg b/packages/iconify-collections/assets/vender/line/general/settings-04.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/settings-04.svg rename to packages/iconify-collections/assets/vender/line/general/settings-04.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/target-04.svg b/packages/iconify-collections/assets/vender/line/general/target-04.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/target-04.svg rename to packages/iconify-collections/assets/vender/line/general/target-04.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/upload-03.svg b/packages/iconify-collections/assets/vender/line/general/upload-03.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/upload-03.svg rename to packages/iconify-collections/assets/vender/line/general/upload-03.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/upload-cloud-01.svg b/packages/iconify-collections/assets/vender/line/general/upload-cloud-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/upload-cloud-01.svg rename to packages/iconify-collections/assets/vender/line/general/upload-cloud-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/general/x.svg b/packages/iconify-collections/assets/vender/line/general/x.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/general/x.svg rename to packages/iconify-collections/assets/vender/line/general/x.svg diff --git a/web/app/components/base/icons/assets/vender/line/images/image-plus.svg b/packages/iconify-collections/assets/vender/line/images/image-plus.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/images/image-plus.svg rename to packages/iconify-collections/assets/vender/line/images/image-plus.svg diff --git a/web/app/components/base/icons/assets/vender/line/layout/align-left-01.svg b/packages/iconify-collections/assets/vender/line/layout/align-left-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/layout/align-left-01.svg rename to packages/iconify-collections/assets/vender/line/layout/align-left-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/layout/align-right-01.svg b/packages/iconify-collections/assets/vender/line/layout/align-right-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/layout/align-right-01.svg rename to packages/iconify-collections/assets/vender/line/layout/align-right-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/layout/grid-01.svg b/packages/iconify-collections/assets/vender/line/layout/grid-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/layout/grid-01.svg rename to packages/iconify-collections/assets/vender/line/layout/grid-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/layout/layout-grid-02.svg b/packages/iconify-collections/assets/vender/line/layout/layout-grid-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/layout/layout-grid-02.svg rename to packages/iconify-collections/assets/vender/line/layout/layout-grid-02.svg diff --git a/web/app/components/base/icons/assets/vender/line/mediaAndDevices/microphone-01.svg b/packages/iconify-collections/assets/vender/line/mediaAndDevices/microphone-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/mediaAndDevices/microphone-01.svg rename to packages/iconify-collections/assets/vender/line/mediaAndDevices/microphone-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/mediaAndDevices/play-circle.svg b/packages/iconify-collections/assets/vender/line/mediaAndDevices/play-circle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/mediaAndDevices/play-circle.svg rename to packages/iconify-collections/assets/vender/line/mediaAndDevices/play-circle.svg diff --git a/web/app/components/base/icons/assets/vender/line/mediaAndDevices/sliders-h.svg b/packages/iconify-collections/assets/vender/line/mediaAndDevices/sliders-h.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/mediaAndDevices/sliders-h.svg rename to packages/iconify-collections/assets/vender/line/mediaAndDevices/sliders-h.svg diff --git a/web/app/components/base/icons/assets/vender/line/mediaAndDevices/speaker.svg b/packages/iconify-collections/assets/vender/line/mediaAndDevices/speaker.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/mediaAndDevices/speaker.svg rename to packages/iconify-collections/assets/vender/line/mediaAndDevices/speaker.svg diff --git a/web/app/components/base/icons/assets/vender/line/mediaAndDevices/stop-circle.svg b/packages/iconify-collections/assets/vender/line/mediaAndDevices/stop-circle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/mediaAndDevices/stop-circle.svg rename to packages/iconify-collections/assets/vender/line/mediaAndDevices/stop-circle.svg diff --git a/web/app/components/base/icons/assets/vender/line/mediaAndDevices/stop.svg b/packages/iconify-collections/assets/vender/line/mediaAndDevices/stop.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/mediaAndDevices/stop.svg rename to packages/iconify-collections/assets/vender/line/mediaAndDevices/stop.svg diff --git a/web/app/components/base/icons/assets/vender/line/others/bubble-x.svg b/packages/iconify-collections/assets/vender/line/others/bubble-x.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/others/bubble-x.svg rename to packages/iconify-collections/assets/vender/line/others/bubble-x.svg diff --git a/web/app/components/base/icons/assets/vender/line/others/colors.svg b/packages/iconify-collections/assets/vender/line/others/colors.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/others/colors.svg rename to packages/iconify-collections/assets/vender/line/others/colors.svg diff --git a/web/app/components/base/icons/assets/vender/line/others/drag-handle.svg b/packages/iconify-collections/assets/vender/line/others/drag-handle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/others/drag-handle.svg rename to packages/iconify-collections/assets/vender/line/others/drag-handle.svg diff --git a/web/app/components/base/icons/assets/vender/line/others/env.svg b/packages/iconify-collections/assets/vender/line/others/env.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/others/env.svg rename to packages/iconify-collections/assets/vender/line/others/env.svg diff --git a/web/app/components/base/icons/assets/vender/line/others/global-variable.svg b/packages/iconify-collections/assets/vender/line/others/global-variable.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/others/global-variable.svg rename to packages/iconify-collections/assets/vender/line/others/global-variable.svg diff --git a/web/app/components/base/icons/assets/vender/line/others/icon-3-dots.svg b/packages/iconify-collections/assets/vender/line/others/icon-3-dots.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/others/icon-3-dots.svg rename to packages/iconify-collections/assets/vender/line/others/icon-3-dots.svg diff --git a/web/app/components/base/icons/assets/vender/line/others/long-arrow-left.svg b/packages/iconify-collections/assets/vender/line/others/long-arrow-left.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/others/long-arrow-left.svg rename to packages/iconify-collections/assets/vender/line/others/long-arrow-left.svg diff --git a/web/app/components/base/icons/assets/vender/line/others/long-arrow-right.svg b/packages/iconify-collections/assets/vender/line/others/long-arrow-right.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/others/long-arrow-right.svg rename to packages/iconify-collections/assets/vender/line/others/long-arrow-right.svg diff --git a/web/app/components/base/icons/assets/vender/line/others/search-menu.svg b/packages/iconify-collections/assets/vender/line/others/search-menu.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/others/search-menu.svg rename to packages/iconify-collections/assets/vender/line/others/search-menu.svg diff --git a/web/app/components/base/icons/assets/vender/line/others/tools.svg b/packages/iconify-collections/assets/vender/line/others/tools.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/others/tools.svg rename to packages/iconify-collections/assets/vender/line/others/tools.svg diff --git a/web/app/components/base/icons/assets/vender/line/shapes/cube-outline.svg b/packages/iconify-collections/assets/vender/line/shapes/cube-outline.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/shapes/cube-outline.svg rename to packages/iconify-collections/assets/vender/line/shapes/cube-outline.svg diff --git a/web/app/components/base/icons/assets/vender/line/time/clock-fast-forward.svg b/packages/iconify-collections/assets/vender/line/time/clock-fast-forward.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/time/clock-fast-forward.svg rename to packages/iconify-collections/assets/vender/line/time/clock-fast-forward.svg diff --git a/web/app/components/base/icons/assets/vender/line/time/clock-play-slim.svg b/packages/iconify-collections/assets/vender/line/time/clock-play-slim.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/time/clock-play-slim.svg rename to packages/iconify-collections/assets/vender/line/time/clock-play-slim.svg diff --git a/web/app/components/base/icons/assets/vender/line/time/clock-play.svg b/packages/iconify-collections/assets/vender/line/time/clock-play.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/time/clock-play.svg rename to packages/iconify-collections/assets/vender/line/time/clock-play.svg diff --git a/web/app/components/base/icons/assets/vender/line/time/clock-refresh.svg b/packages/iconify-collections/assets/vender/line/time/clock-refresh.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/time/clock-refresh.svg rename to packages/iconify-collections/assets/vender/line/time/clock-refresh.svg diff --git a/web/app/components/base/icons/assets/vender/line/users/user-01.svg b/packages/iconify-collections/assets/vender/line/users/user-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/users/user-01.svg rename to packages/iconify-collections/assets/vender/line/users/user-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/users/users-01.svg b/packages/iconify-collections/assets/vender/line/users/users-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/users/users-01.svg rename to packages/iconify-collections/assets/vender/line/users/users-01.svg diff --git a/web/app/components/base/icons/assets/vender/line/weather/stars-02.svg b/packages/iconify-collections/assets/vender/line/weather/stars-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/line/weather/stars-02.svg rename to packages/iconify-collections/assets/vender/line/weather/stars-02.svg diff --git a/web/app/components/base/icons/assets/vender/other/anthropic-text.svg b/packages/iconify-collections/assets/vender/other/anthropic-text.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/other/anthropic-text.svg rename to packages/iconify-collections/assets/vender/other/anthropic-text.svg diff --git a/web/app/components/base/icons/assets/vender/other/generator.svg b/packages/iconify-collections/assets/vender/other/generator.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/other/generator.svg rename to packages/iconify-collections/assets/vender/other/generator.svg diff --git a/web/app/components/base/icons/assets/vender/other/group.svg b/packages/iconify-collections/assets/vender/other/group.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/other/group.svg rename to packages/iconify-collections/assets/vender/other/group.svg diff --git a/web/app/components/base/icons/assets/vender/other/hourglass-shape.svg b/packages/iconify-collections/assets/vender/other/hourglass-shape.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/other/hourglass-shape.svg rename to packages/iconify-collections/assets/vender/other/hourglass-shape.svg diff --git a/web/app/components/base/icons/assets/vender/other/mcp.svg b/packages/iconify-collections/assets/vender/other/mcp.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/other/mcp.svg rename to packages/iconify-collections/assets/vender/other/mcp.svg diff --git a/web/app/components/base/icons/assets/vender/other/no-tool-placeholder.svg b/packages/iconify-collections/assets/vender/other/no-tool-placeholder.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/other/no-tool-placeholder.svg rename to packages/iconify-collections/assets/vender/other/no-tool-placeholder.svg diff --git a/web/app/components/base/icons/assets/vender/other/openai.svg b/packages/iconify-collections/assets/vender/other/openai.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/other/openai.svg rename to packages/iconify-collections/assets/vender/other/openai.svg diff --git a/web/app/components/base/icons/assets/vender/other/replay-line.svg b/packages/iconify-collections/assets/vender/other/replay-line.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/other/replay-line.svg rename to packages/iconify-collections/assets/vender/other/replay-line.svg diff --git a/web/app/components/base/icons/assets/vender/other/square-checklist.svg b/packages/iconify-collections/assets/vender/other/square-checklist.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/other/square-checklist.svg rename to packages/iconify-collections/assets/vender/other/square-checklist.svg diff --git a/web/app/components/base/icons/assets/vender/pipeline/input-field.svg b/packages/iconify-collections/assets/vender/pipeline/input-field.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/pipeline/input-field.svg rename to packages/iconify-collections/assets/vender/pipeline/input-field.svg diff --git a/web/app/components/base/icons/assets/vender/pipeline/pipeline-fill.svg b/packages/iconify-collections/assets/vender/pipeline/pipeline-fill.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/pipeline/pipeline-fill.svg rename to packages/iconify-collections/assets/vender/pipeline/pipeline-fill.svg diff --git a/web/app/components/base/icons/assets/vender/pipeline/pipeline-line.svg b/packages/iconify-collections/assets/vender/pipeline/pipeline-line.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/pipeline/pipeline-line.svg rename to packages/iconify-collections/assets/vender/pipeline/pipeline-line.svg diff --git a/web/app/components/base/icons/assets/vender/plugin/box-sparkle-fill.svg b/packages/iconify-collections/assets/vender/plugin/box-sparkle-fill.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/plugin/box-sparkle-fill.svg rename to packages/iconify-collections/assets/vender/plugin/box-sparkle-fill.svg diff --git a/web/app/components/base/icons/assets/vender/plugin/left-corner.svg b/packages/iconify-collections/assets/vender/plugin/left-corner.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/plugin/left-corner.svg rename to packages/iconify-collections/assets/vender/plugin/left-corner.svg diff --git a/web/app/components/base/icons/assets/vender/plugin/trigger.svg b/packages/iconify-collections/assets/vender/plugin/trigger.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/plugin/trigger.svg rename to packages/iconify-collections/assets/vender/plugin/trigger.svg diff --git a/web/app/components/base/icons/assets/vender/solid/FinanceAndECommerce/gold-coin.svg b/packages/iconify-collections/assets/vender/solid/FinanceAndECommerce/gold-coin.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/FinanceAndECommerce/gold-coin.svg rename to packages/iconify-collections/assets/vender/solid/FinanceAndECommerce/gold-coin.svg diff --git a/web/app/components/base/icons/assets/vender/solid/FinanceAndECommerce/scales-02.svg b/packages/iconify-collections/assets/vender/solid/FinanceAndECommerce/scales-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/FinanceAndECommerce/scales-02.svg rename to packages/iconify-collections/assets/vender/solid/FinanceAndECommerce/scales-02.svg diff --git a/web/app/components/base/icons/assets/vender/solid/alertsAndFeedback/alert-triangle.svg b/packages/iconify-collections/assets/vender/solid/alertsAndFeedback/alert-triangle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/alertsAndFeedback/alert-triangle.svg rename to packages/iconify-collections/assets/vender/solid/alertsAndFeedback/alert-triangle.svg diff --git a/web/app/components/base/icons/assets/vender/solid/arrows/arrow-down-double-line.svg b/packages/iconify-collections/assets/vender/solid/arrows/arrow-down-double-line.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/arrows/arrow-down-double-line.svg rename to packages/iconify-collections/assets/vender/solid/arrows/arrow-down-double-line.svg diff --git a/web/app/components/base/icons/assets/vender/solid/arrows/arrow-down-round-fill.svg b/packages/iconify-collections/assets/vender/solid/arrows/arrow-down-round-fill.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/arrows/arrow-down-round-fill.svg rename to packages/iconify-collections/assets/vender/solid/arrows/arrow-down-round-fill.svg diff --git a/web/app/components/base/icons/assets/vender/solid/arrows/arrow-up-double-line.svg b/packages/iconify-collections/assets/vender/solid/arrows/arrow-up-double-line.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/arrows/arrow-up-double-line.svg rename to packages/iconify-collections/assets/vender/solid/arrows/arrow-up-double-line.svg diff --git a/web/app/components/base/icons/assets/vender/solid/arrows/chevron-down.svg b/packages/iconify-collections/assets/vender/solid/arrows/chevron-down.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/arrows/chevron-down.svg rename to packages/iconify-collections/assets/vender/solid/arrows/chevron-down.svg diff --git a/web/app/components/base/icons/assets/vender/solid/arrows/high-priority.svg b/packages/iconify-collections/assets/vender/solid/arrows/high-priority.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/arrows/high-priority.svg rename to packages/iconify-collections/assets/vender/solid/arrows/high-priority.svg diff --git a/web/app/components/base/icons/assets/vender/solid/communication/ai-text.svg b/packages/iconify-collections/assets/vender/solid/communication/ai-text.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/communication/ai-text.svg rename to packages/iconify-collections/assets/vender/solid/communication/ai-text.svg diff --git a/web/app/components/base/icons/assets/vender/solid/communication/bubble-text-mod.svg b/packages/iconify-collections/assets/vender/solid/communication/bubble-text-mod.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/communication/bubble-text-mod.svg rename to packages/iconify-collections/assets/vender/solid/communication/bubble-text-mod.svg diff --git a/web/app/components/base/icons/assets/vender/solid/communication/chat-bot.svg b/packages/iconify-collections/assets/vender/solid/communication/chat-bot.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/communication/chat-bot.svg rename to packages/iconify-collections/assets/vender/solid/communication/chat-bot.svg diff --git a/web/app/components/base/icons/assets/vender/solid/communication/cute-robot.svg b/packages/iconify-collections/assets/vender/solid/communication/cute-robot.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/communication/cute-robot.svg rename to packages/iconify-collections/assets/vender/solid/communication/cute-robot.svg diff --git a/web/app/components/base/icons/assets/vender/solid/communication/edit-list.svg b/packages/iconify-collections/assets/vender/solid/communication/edit-list.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/communication/edit-list.svg rename to packages/iconify-collections/assets/vender/solid/communication/edit-list.svg diff --git a/web/app/components/base/icons/assets/vender/solid/communication/list-sparkle.svg b/packages/iconify-collections/assets/vender/solid/communication/list-sparkle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/communication/list-sparkle.svg rename to packages/iconify-collections/assets/vender/solid/communication/list-sparkle.svg diff --git a/web/app/components/base/icons/assets/vender/solid/communication/logic.svg b/packages/iconify-collections/assets/vender/solid/communication/logic.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/communication/logic.svg rename to packages/iconify-collections/assets/vender/solid/communication/logic.svg diff --git a/web/app/components/base/icons/assets/vender/solid/communication/message-dots-circle.svg b/packages/iconify-collections/assets/vender/solid/communication/message-dots-circle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/communication/message-dots-circle.svg rename to packages/iconify-collections/assets/vender/solid/communication/message-dots-circle.svg diff --git a/web/app/components/base/icons/assets/vender/solid/communication/message-fast.svg b/packages/iconify-collections/assets/vender/solid/communication/message-fast.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/communication/message-fast.svg rename to packages/iconify-collections/assets/vender/solid/communication/message-fast.svg diff --git a/web/app/components/base/icons/assets/vender/solid/communication/message-heart-circle.svg b/packages/iconify-collections/assets/vender/solid/communication/message-heart-circle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/communication/message-heart-circle.svg rename to packages/iconify-collections/assets/vender/solid/communication/message-heart-circle.svg diff --git a/web/app/components/base/icons/assets/vender/solid/communication/message-smile-square.svg b/packages/iconify-collections/assets/vender/solid/communication/message-smile-square.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/communication/message-smile-square.svg rename to packages/iconify-collections/assets/vender/solid/communication/message-smile-square.svg diff --git a/web/app/components/base/icons/assets/vender/solid/communication/send-03.svg b/packages/iconify-collections/assets/vender/solid/communication/send-03.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/communication/send-03.svg rename to packages/iconify-collections/assets/vender/solid/communication/send-03.svg diff --git a/web/app/components/base/icons/assets/vender/solid/development/api-connection-mod.svg b/packages/iconify-collections/assets/vender/solid/development/api-connection-mod.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/development/api-connection-mod.svg rename to packages/iconify-collections/assets/vender/solid/development/api-connection-mod.svg diff --git a/web/app/components/base/icons/assets/vender/solid/development/api-connection.svg b/packages/iconify-collections/assets/vender/solid/development/api-connection.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/development/api-connection.svg rename to packages/iconify-collections/assets/vender/solid/development/api-connection.svg diff --git a/web/app/components/base/icons/assets/vender/solid/development/bar-chart-square-02.svg b/packages/iconify-collections/assets/vender/solid/development/bar-chart-square-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/development/bar-chart-square-02.svg rename to packages/iconify-collections/assets/vender/solid/development/bar-chart-square-02.svg diff --git a/web/app/components/base/icons/assets/vender/solid/development/container.svg b/packages/iconify-collections/assets/vender/solid/development/container.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/development/container.svg rename to packages/iconify-collections/assets/vender/solid/development/container.svg diff --git a/web/app/components/base/icons/assets/vender/solid/development/database-02.svg b/packages/iconify-collections/assets/vender/solid/development/database-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/development/database-02.svg rename to packages/iconify-collections/assets/vender/solid/development/database-02.svg diff --git a/web/app/components/base/icons/assets/vender/solid/development/database-03.svg b/packages/iconify-collections/assets/vender/solid/development/database-03.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/development/database-03.svg rename to packages/iconify-collections/assets/vender/solid/development/database-03.svg diff --git a/web/app/components/base/icons/assets/vender/solid/development/file-heart-02.svg b/packages/iconify-collections/assets/vender/solid/development/file-heart-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/development/file-heart-02.svg rename to packages/iconify-collections/assets/vender/solid/development/file-heart-02.svg diff --git a/web/app/components/base/icons/assets/vender/solid/development/pattern-recognition.svg b/packages/iconify-collections/assets/vender/solid/development/pattern-recognition.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/development/pattern-recognition.svg rename to packages/iconify-collections/assets/vender/solid/development/pattern-recognition.svg diff --git a/web/app/components/base/icons/assets/vender/solid/development/prompt-engineering.svg b/packages/iconify-collections/assets/vender/solid/development/prompt-engineering.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/development/prompt-engineering.svg rename to packages/iconify-collections/assets/vender/solid/development/prompt-engineering.svg diff --git a/web/app/components/base/icons/assets/vender/solid/development/puzzle-piece-01.svg b/packages/iconify-collections/assets/vender/solid/development/puzzle-piece-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/development/puzzle-piece-01.svg rename to packages/iconify-collections/assets/vender/solid/development/puzzle-piece-01.svg diff --git a/web/app/components/base/icons/assets/vender/solid/development/semantic.svg b/packages/iconify-collections/assets/vender/solid/development/semantic.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/development/semantic.svg rename to packages/iconify-collections/assets/vender/solid/development/semantic.svg diff --git a/web/app/components/base/icons/assets/vender/solid/development/terminal-square.svg b/packages/iconify-collections/assets/vender/solid/development/terminal-square.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/development/terminal-square.svg rename to packages/iconify-collections/assets/vender/solid/development/terminal-square.svg diff --git a/web/app/components/base/icons/assets/vender/solid/development/variable-02.svg b/packages/iconify-collections/assets/vender/solid/development/variable-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/development/variable-02.svg rename to packages/iconify-collections/assets/vender/solid/development/variable-02.svg diff --git a/web/app/components/base/icons/assets/vender/solid/editor/brush-01.svg b/packages/iconify-collections/assets/vender/solid/editor/brush-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/editor/brush-01.svg rename to packages/iconify-collections/assets/vender/solid/editor/brush-01.svg diff --git a/web/app/components/base/icons/assets/vender/solid/editor/citations.svg b/packages/iconify-collections/assets/vender/solid/editor/citations.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/editor/citations.svg rename to packages/iconify-collections/assets/vender/solid/editor/citations.svg diff --git a/web/app/components/base/icons/assets/vender/solid/editor/colors.svg b/packages/iconify-collections/assets/vender/solid/editor/colors.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/editor/colors.svg rename to packages/iconify-collections/assets/vender/solid/editor/colors.svg diff --git a/web/app/components/base/icons/assets/vender/solid/editor/paragraph.svg b/packages/iconify-collections/assets/vender/solid/editor/paragraph.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/editor/paragraph.svg rename to packages/iconify-collections/assets/vender/solid/editor/paragraph.svg diff --git a/web/app/components/base/icons/assets/vender/solid/editor/type-square.svg b/packages/iconify-collections/assets/vender/solid/editor/type-square.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/editor/type-square.svg rename to packages/iconify-collections/assets/vender/solid/editor/type-square.svg diff --git a/web/app/components/base/icons/assets/vender/solid/education/beaker-02.svg b/packages/iconify-collections/assets/vender/solid/education/beaker-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/education/beaker-02.svg rename to packages/iconify-collections/assets/vender/solid/education/beaker-02.svg diff --git a/web/app/components/base/icons/assets/vender/solid/education/bubble-text.svg b/packages/iconify-collections/assets/vender/solid/education/bubble-text.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/education/bubble-text.svg rename to packages/iconify-collections/assets/vender/solid/education/bubble-text.svg diff --git a/web/app/components/base/icons/assets/vender/solid/education/heart-02.svg b/packages/iconify-collections/assets/vender/solid/education/heart-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/education/heart-02.svg rename to packages/iconify-collections/assets/vender/solid/education/heart-02.svg diff --git a/web/app/components/base/icons/assets/vender/solid/education/unblur.svg b/packages/iconify-collections/assets/vender/solid/education/unblur.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/education/unblur.svg rename to packages/iconify-collections/assets/vender/solid/education/unblur.svg diff --git a/web/app/components/base/icons/assets/vender/solid/files/file-05.svg b/packages/iconify-collections/assets/vender/solid/files/file-05.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/files/file-05.svg rename to packages/iconify-collections/assets/vender/solid/files/file-05.svg diff --git a/web/app/components/base/icons/assets/vender/solid/files/file-search-02.svg b/packages/iconify-collections/assets/vender/solid/files/file-search-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/files/file-search-02.svg rename to packages/iconify-collections/assets/vender/solid/files/file-search-02.svg diff --git a/web/app/components/base/icons/assets/vender/solid/files/file-zip.svg b/packages/iconify-collections/assets/vender/solid/files/file-zip.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/files/file-zip.svg rename to packages/iconify-collections/assets/vender/solid/files/file-zip.svg diff --git a/web/app/components/base/icons/assets/vender/solid/files/folder.svg b/packages/iconify-collections/assets/vender/solid/files/folder.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/files/folder.svg rename to packages/iconify-collections/assets/vender/solid/files/folder.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/answer-triangle.svg b/packages/iconify-collections/assets/vender/solid/general/answer-triangle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/answer-triangle.svg rename to packages/iconify-collections/assets/vender/solid/general/answer-triangle.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/arrow-down-round-fill.svg b/packages/iconify-collections/assets/vender/solid/general/arrow-down-round-fill.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/arrow-down-round-fill.svg rename to packages/iconify-collections/assets/vender/solid/general/arrow-down-round-fill.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/check-circle.svg b/packages/iconify-collections/assets/vender/solid/general/check-circle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/check-circle.svg rename to packages/iconify-collections/assets/vender/solid/general/check-circle.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/check-done-01.svg b/packages/iconify-collections/assets/vender/solid/general/check-done-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/check-done-01.svg rename to packages/iconify-collections/assets/vender/solid/general/check-done-01.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/download-02.svg b/packages/iconify-collections/assets/vender/solid/general/download-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/download-02.svg rename to packages/iconify-collections/assets/vender/solid/general/download-02.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/edit-03.svg b/packages/iconify-collections/assets/vender/solid/general/edit-03.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/edit-03.svg rename to packages/iconify-collections/assets/vender/solid/general/edit-03.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/edit-04.svg b/packages/iconify-collections/assets/vender/solid/general/edit-04.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/edit-04.svg rename to packages/iconify-collections/assets/vender/solid/general/edit-04.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/eye.svg b/packages/iconify-collections/assets/vender/solid/general/eye.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/eye.svg rename to packages/iconify-collections/assets/vender/solid/general/eye.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/github.svg b/packages/iconify-collections/assets/vender/solid/general/github.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/github.svg rename to packages/iconify-collections/assets/vender/solid/general/github.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/message-clock-circle.svg b/packages/iconify-collections/assets/vender/solid/general/message-clock-circle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/message-clock-circle.svg rename to packages/iconify-collections/assets/vender/solid/general/message-clock-circle.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/plus-circle.svg b/packages/iconify-collections/assets/vender/solid/general/plus-circle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/plus-circle.svg rename to packages/iconify-collections/assets/vender/solid/general/plus-circle.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/question-triangle.svg b/packages/iconify-collections/assets/vender/solid/general/question-triangle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/question-triangle.svg rename to packages/iconify-collections/assets/vender/solid/general/question-triangle.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/search-md.svg b/packages/iconify-collections/assets/vender/solid/general/search-md.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/search-md.svg rename to packages/iconify-collections/assets/vender/solid/general/search-md.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/target-04.svg b/packages/iconify-collections/assets/vender/solid/general/target-04.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/target-04.svg rename to packages/iconify-collections/assets/vender/solid/general/target-04.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/tool-03.svg b/packages/iconify-collections/assets/vender/solid/general/tool-03.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/tool-03.svg rename to packages/iconify-collections/assets/vender/solid/general/tool-03.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/x-circle.svg b/packages/iconify-collections/assets/vender/solid/general/x-circle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/x-circle.svg rename to packages/iconify-collections/assets/vender/solid/general/x-circle.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/zap-fast.svg b/packages/iconify-collections/assets/vender/solid/general/zap-fast.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/zap-fast.svg rename to packages/iconify-collections/assets/vender/solid/general/zap-fast.svg diff --git a/web/app/components/base/icons/assets/vender/solid/general/zap-narrow.svg b/packages/iconify-collections/assets/vender/solid/general/zap-narrow.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/general/zap-narrow.svg rename to packages/iconify-collections/assets/vender/solid/general/zap-narrow.svg diff --git a/web/app/components/base/icons/assets/vender/solid/layout/grid-01.svg b/packages/iconify-collections/assets/vender/solid/layout/grid-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/layout/grid-01.svg rename to packages/iconify-collections/assets/vender/solid/layout/grid-01.svg diff --git a/web/app/components/base/icons/assets/vender/solid/mediaAndDevices/audio-support-icon.svg b/packages/iconify-collections/assets/vender/solid/mediaAndDevices/audio-support-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/mediaAndDevices/audio-support-icon.svg rename to packages/iconify-collections/assets/vender/solid/mediaAndDevices/audio-support-icon.svg diff --git a/web/app/components/base/icons/assets/vender/solid/mediaAndDevices/document-support-icon.svg b/packages/iconify-collections/assets/vender/solid/mediaAndDevices/document-support-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/mediaAndDevices/document-support-icon.svg rename to packages/iconify-collections/assets/vender/solid/mediaAndDevices/document-support-icon.svg diff --git a/web/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-box.svg b/packages/iconify-collections/assets/vender/solid/mediaAndDevices/magic-box.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-box.svg rename to packages/iconify-collections/assets/vender/solid/mediaAndDevices/magic-box.svg diff --git a/web/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-eyes.svg b/packages/iconify-collections/assets/vender/solid/mediaAndDevices/magic-eyes.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-eyes.svg rename to packages/iconify-collections/assets/vender/solid/mediaAndDevices/magic-eyes.svg diff --git a/web/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-wand.svg b/packages/iconify-collections/assets/vender/solid/mediaAndDevices/magic-wand.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/mediaAndDevices/magic-wand.svg rename to packages/iconify-collections/assets/vender/solid/mediaAndDevices/magic-wand.svg diff --git a/web/app/components/base/icons/assets/vender/solid/mediaAndDevices/microphone-01.svg b/packages/iconify-collections/assets/vender/solid/mediaAndDevices/microphone-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/mediaAndDevices/microphone-01.svg rename to packages/iconify-collections/assets/vender/solid/mediaAndDevices/microphone-01.svg diff --git a/web/app/components/base/icons/assets/vender/solid/mediaAndDevices/play.svg b/packages/iconify-collections/assets/vender/solid/mediaAndDevices/play.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/mediaAndDevices/play.svg rename to packages/iconify-collections/assets/vender/solid/mediaAndDevices/play.svg diff --git a/web/app/components/base/icons/assets/vender/solid/mediaAndDevices/robot.svg b/packages/iconify-collections/assets/vender/solid/mediaAndDevices/robot.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/mediaAndDevices/robot.svg rename to packages/iconify-collections/assets/vender/solid/mediaAndDevices/robot.svg diff --git a/web/app/components/base/icons/assets/vender/solid/mediaAndDevices/sliders-02.svg b/packages/iconify-collections/assets/vender/solid/mediaAndDevices/sliders-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/mediaAndDevices/sliders-02.svg rename to packages/iconify-collections/assets/vender/solid/mediaAndDevices/sliders-02.svg diff --git a/web/app/components/base/icons/assets/vender/solid/mediaAndDevices/speaker.svg b/packages/iconify-collections/assets/vender/solid/mediaAndDevices/speaker.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/mediaAndDevices/speaker.svg rename to packages/iconify-collections/assets/vender/solid/mediaAndDevices/speaker.svg diff --git a/web/app/components/base/icons/assets/vender/solid/mediaAndDevices/stop-circle.svg b/packages/iconify-collections/assets/vender/solid/mediaAndDevices/stop-circle.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/mediaAndDevices/stop-circle.svg rename to packages/iconify-collections/assets/vender/solid/mediaAndDevices/stop-circle.svg diff --git a/web/app/components/base/icons/assets/vender/solid/mediaAndDevices/video-support-icon.svg b/packages/iconify-collections/assets/vender/solid/mediaAndDevices/video-support-icon.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/mediaAndDevices/video-support-icon.svg rename to packages/iconify-collections/assets/vender/solid/mediaAndDevices/video-support-icon.svg diff --git a/web/app/components/base/icons/assets/vender/solid/security/lock-01.svg b/packages/iconify-collections/assets/vender/solid/security/lock-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/security/lock-01.svg rename to packages/iconify-collections/assets/vender/solid/security/lock-01.svg diff --git a/web/app/components/base/icons/assets/vender/solid/shapes/corner.svg b/packages/iconify-collections/assets/vender/solid/shapes/corner.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/shapes/corner.svg rename to packages/iconify-collections/assets/vender/solid/shapes/corner.svg diff --git a/web/app/components/base/icons/assets/vender/solid/shapes/star-04.svg b/packages/iconify-collections/assets/vender/solid/shapes/star-04.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/shapes/star-04.svg rename to packages/iconify-collections/assets/vender/solid/shapes/star-04.svg diff --git a/web/app/components/base/icons/assets/vender/solid/shapes/star-06.svg b/packages/iconify-collections/assets/vender/solid/shapes/star-06.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/shapes/star-06.svg rename to packages/iconify-collections/assets/vender/solid/shapes/star-06.svg diff --git a/web/app/components/base/icons/assets/vender/solid/users/user-01.svg b/packages/iconify-collections/assets/vender/solid/users/user-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/users/user-01.svg rename to packages/iconify-collections/assets/vender/solid/users/user-01.svg diff --git a/web/app/components/base/icons/assets/vender/solid/users/user-edit-02.svg b/packages/iconify-collections/assets/vender/solid/users/user-edit-02.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/users/user-edit-02.svg rename to packages/iconify-collections/assets/vender/solid/users/user-edit-02.svg diff --git a/web/app/components/base/icons/assets/vender/solid/users/users-01.svg b/packages/iconify-collections/assets/vender/solid/users/users-01.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/users/users-01.svg rename to packages/iconify-collections/assets/vender/solid/users/users-01.svg diff --git a/web/app/components/base/icons/assets/vender/solid/users/users-plus.svg b/packages/iconify-collections/assets/vender/solid/users/users-plus.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/solid/users/users-plus.svg rename to packages/iconify-collections/assets/vender/solid/users/users-plus.svg diff --git a/web/app/components/base/icons/assets/vender/system/auto-update-line.svg b/packages/iconify-collections/assets/vender/system/auto-update-line.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/system/auto-update-line.svg rename to packages/iconify-collections/assets/vender/system/auto-update-line.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/agent.svg b/packages/iconify-collections/assets/vender/workflow/agent.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/agent.svg rename to packages/iconify-collections/assets/vender/workflow/agent.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/answer.svg b/packages/iconify-collections/assets/vender/workflow/answer.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/answer.svg rename to packages/iconify-collections/assets/vender/workflow/answer.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/api-aggregate.svg b/packages/iconify-collections/assets/vender/workflow/api-aggregate.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/api-aggregate.svg rename to packages/iconify-collections/assets/vender/workflow/api-aggregate.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/assigner.svg b/packages/iconify-collections/assets/vender/workflow/assigner.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/assigner.svg rename to packages/iconify-collections/assets/vender/workflow/assigner.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/asterisk.svg b/packages/iconify-collections/assets/vender/workflow/asterisk.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/asterisk.svg rename to packages/iconify-collections/assets/vender/workflow/asterisk.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/calendar-check-line.svg b/packages/iconify-collections/assets/vender/workflow/calendar-check-line.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/calendar-check-line.svg rename to packages/iconify-collections/assets/vender/workflow/calendar-check-line.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/code.svg b/packages/iconify-collections/assets/vender/workflow/code.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/code.svg rename to packages/iconify-collections/assets/vender/workflow/code.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/datasource.svg b/packages/iconify-collections/assets/vender/workflow/datasource.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/datasource.svg rename to packages/iconify-collections/assets/vender/workflow/datasource.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/docs-extractor.svg b/packages/iconify-collections/assets/vender/workflow/docs-extractor.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/docs-extractor.svg rename to packages/iconify-collections/assets/vender/workflow/docs-extractor.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/end.svg b/packages/iconify-collections/assets/vender/workflow/end.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/end.svg rename to packages/iconify-collections/assets/vender/workflow/end.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/home.svg b/packages/iconify-collections/assets/vender/workflow/home.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/home.svg rename to packages/iconify-collections/assets/vender/workflow/home.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/http.svg b/packages/iconify-collections/assets/vender/workflow/http.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/http.svg rename to packages/iconify-collections/assets/vender/workflow/http.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/human-in-loop.svg b/packages/iconify-collections/assets/vender/workflow/human-in-loop.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/human-in-loop.svg rename to packages/iconify-collections/assets/vender/workflow/human-in-loop.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/if-else.svg b/packages/iconify-collections/assets/vender/workflow/if-else.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/if-else.svg rename to packages/iconify-collections/assets/vender/workflow/if-else.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/iteration-start.svg b/packages/iconify-collections/assets/vender/workflow/iteration-start.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/iteration-start.svg rename to packages/iconify-collections/assets/vender/workflow/iteration-start.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/iteration.svg b/packages/iconify-collections/assets/vender/workflow/iteration.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/iteration.svg rename to packages/iconify-collections/assets/vender/workflow/iteration.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/jinja.svg b/packages/iconify-collections/assets/vender/workflow/jinja.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/jinja.svg rename to packages/iconify-collections/assets/vender/workflow/jinja.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/knowledge-base.svg b/packages/iconify-collections/assets/vender/workflow/knowledge-base.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/knowledge-base.svg rename to packages/iconify-collections/assets/vender/workflow/knowledge-base.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/knowledge-retrieval.svg b/packages/iconify-collections/assets/vender/workflow/knowledge-retrieval.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/knowledge-retrieval.svg rename to packages/iconify-collections/assets/vender/workflow/knowledge-retrieval.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/list-filter.svg b/packages/iconify-collections/assets/vender/workflow/list-filter.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/list-filter.svg rename to packages/iconify-collections/assets/vender/workflow/list-filter.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/llm.svg b/packages/iconify-collections/assets/vender/workflow/llm.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/llm.svg rename to packages/iconify-collections/assets/vender/workflow/llm.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/loop-end.svg b/packages/iconify-collections/assets/vender/workflow/loop-end.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/loop-end.svg rename to packages/iconify-collections/assets/vender/workflow/loop-end.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/loop.svg b/packages/iconify-collections/assets/vender/workflow/loop.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/loop.svg rename to packages/iconify-collections/assets/vender/workflow/loop.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/parameter-extractor.svg b/packages/iconify-collections/assets/vender/workflow/parameter-extractor.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/parameter-extractor.svg rename to packages/iconify-collections/assets/vender/workflow/parameter-extractor.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/question-classifier.svg b/packages/iconify-collections/assets/vender/workflow/question-classifier.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/question-classifier.svg rename to packages/iconify-collections/assets/vender/workflow/question-classifier.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/schedule.svg b/packages/iconify-collections/assets/vender/workflow/schedule.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/schedule.svg rename to packages/iconify-collections/assets/vender/workflow/schedule.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/templating-transform.svg b/packages/iconify-collections/assets/vender/workflow/templating-transform.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/templating-transform.svg rename to packages/iconify-collections/assets/vender/workflow/templating-transform.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/trigger-all.svg b/packages/iconify-collections/assets/vender/workflow/trigger-all.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/trigger-all.svg rename to packages/iconify-collections/assets/vender/workflow/trigger-all.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/variable-x.svg b/packages/iconify-collections/assets/vender/workflow/variable-x.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/variable-x.svg rename to packages/iconify-collections/assets/vender/workflow/variable-x.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/webhook-line.svg b/packages/iconify-collections/assets/vender/workflow/webhook-line.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/webhook-line.svg rename to packages/iconify-collections/assets/vender/workflow/webhook-line.svg diff --git a/web/app/components/base/icons/assets/vender/workflow/window-cursor.svg b/packages/iconify-collections/assets/vender/workflow/window-cursor.svg similarity index 100% rename from web/app/components/base/icons/assets/vender/workflow/window-cursor.svg rename to packages/iconify-collections/assets/vender/workflow/window-cursor.svg diff --git a/packages/iconify-collections/custom-public/chars.json b/packages/iconify-collections/custom-public/chars.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/iconify-collections/custom-public/chars.json @@ -0,0 +1 @@ +{} diff --git a/packages/iconify-collections/custom-public/icons.json b/packages/iconify-collections/custom-public/icons.json new file mode 100644 index 0000000000..347b6145e2 --- /dev/null +++ b/packages/iconify-collections/custom-public/icons.json @@ -0,0 +1,572 @@ +{ + "prefix": "custom-public", + "lastModified": 1775115796, + "icons": { + "avatar-user": { + "body": "", + "width": 512, + "height": 512 + }, + "billing-ar-cube-1": { + "body": "", + "width": 28 + }, + "billing-asterisk": { + "body": "", + "width": 28 + }, + "billing-aws-marketplace-dark": { + "body": "", + "width": 126, + "height": 25 + }, + "billing-aws-marketplace-light": { + "body": "", + "width": 126, + "height": 24 + }, + "billing-azure": { + "body": "", + "width": 21, + "height": 20 + }, + "billing-buildings": { + "body": "" + }, + "billing-diamond": { + "body": "" + }, + "billing-google-cloud": { + "body": "", + "width": 22, + "height": 18 + }, + "billing-group-2": { + "body": "" + }, + "billing-keyframe": { + "body": "" + }, + "billing-sparkles-soft": { + "body": "", + "width": 13, + "height": 13 + }, + "common-d": { + "body": "" + }, + "common-diagonal-dividing-line": { + "body": "", + "width": 7, + "height": 20 + }, + "common-dify": { + "body": "", + "width": 50, + "height": 26 + }, + "common-gdpr": { + "body": "", + "width": 23, + "height": 28 + }, + "common-github": { + "body": "", + "width": 18, + "height": 18 + }, + "common-highlight": { + "body": "", + "width": 46, + "height": 24 + }, + "common-iso": { + "body": "", + "width": 64, + "height": 64 + }, + "common-line-3": { + "body": "", + "width": 5, + "height": 12 + }, + "common-lock": { + "body": "" + }, + "common-message-chat-square": { + "body": "" + }, + "common-multi-path-retrieval": { + "body": "", + "width": 36, + "height": 36 + }, + "common-n-to-1-retrieval": { + "body": "", + "width": 36, + "height": 36 + }, + "common-notion": { + "body": "", + "width": 20, + "height": 20 + }, + "common-soc2": { + "body": "", + "width": 28, + "height": 28 + }, + "common-sparkles-soft": { + "body": "", + "width": 14, + "height": 14 + }, + "common-sparkles-soft-accent": { + "body": "" + }, + "education-triangle": { + "body": "", + "height": 22 + }, + "files-csv": { + "body": "" + }, + "files-doc": { + "body": "" + }, + "files-docx": { + "body": "" + }, + "files-html": { + "body": "" + }, + "files-json": { + "body": "" + }, + "files-md": { + "body": "" + }, + "files-pdf": { + "body": "" + }, + "files-txt": { + "body": "" + }, + "files-unknown": { + "body": "" + }, + "files-xlsx": { + "body": "", + "width": 24, + "height": 26 + }, + "files-yaml": { + "body": "", + "width": 24, + "height": 26 + }, + "knowledge-file": { + "body": "", + "width": 16, + "height": 16 + }, + "knowledge-option-card-effect-blue": { + "body": "", + "width": 214, + "height": 124 + }, + "knowledge-option-card-effect-blue-light": { + "body": "", + "width": 212, + "height": 74 + }, + "knowledge-option-card-effect-orange": { + "body": "" + }, + "knowledge-option-card-effect-purple": { + "body": "" + }, + "knowledge-option-card-effect-teal": { + "body": "", + "width": 212, + "height": 92 + }, + "knowledge-selection-mod": { + "body": "", + "width": 10, + "height": 10 + }, + "knowledge-watercrawl": { + "body": "", + "width": 500, + "height": 500 + }, + "knowledge-dataset-card-external-knowledge-base": { + "body": "" + }, + "knowledge-dataset-card-general": { + "body": "" + }, + "knowledge-dataset-card-graph": { + "body": "" + }, + "knowledge-dataset-card-parent-child": { + "body": "" + }, + "knowledge-dataset-card-qa": { + "body": "" + }, + "knowledge-online-drive-buckets-blue": { + "body": "", + "height": 21 + }, + "knowledge-online-drive-buckets-gray": { + "body": "", + "width": 18 + }, + "knowledge-online-drive-folder": { + "body": "" + }, + "llm-anthropic": { + "body": "" + }, + "llm-anthropic-dark": { + "body": "", + "width": 90, + "height": 10 + }, + "llm-anthropic-light": { + "body": "", + "width": 90, + "height": 10 + }, + "llm-anthropic-short-light": { + "body": "", + "width": 40, + "height": 40 + }, + "llm-anthropic-text": { + "body": "", + "width": 90, + "height": 20 + }, + "llm-azure-openai-service": { + "body": "", + "width": 56 + }, + "llm-azure-openai-service-text": { + "body": "", + "width": 212 + }, + "llm-azureai": { + "body": "" + }, + "llm-azureai-text": { + "body": "", + "width": 92 + }, + "llm-baichuan": { + "body": "" + }, + "llm-baichuan-text": { + "body": "", + "width": 130 + }, + "llm-chatglm": { + "body": "" + }, + "llm-chatglm-text": { + "body": "", + "width": 100 + }, + "llm-cohere": { + "body": "", + "width": 22, + "height": 22 + }, + "llm-cohere-text": { + "body": "", + "width": 120 + }, + "llm-deepseek": { + "body": "", + "width": 40, + "height": 40 + }, + "llm-gemini": { + "body": "", + "width": 40, + "height": 40 + }, + "llm-gpt-3": { + "body": "" + }, + "llm-gpt-4": { + "body": "" + }, + "llm-grok": { + "body": "", + "width": 40, + "height": 40 + }, + "llm-huggingface": { + "body": "" + }, + "llm-huggingface-text": { + "body": "", + "width": 120 + }, + "llm-huggingface-text-hub": { + "body": "", + "width": 151 + }, + "llm-iflytek-spark": { + "body": "" + }, + "llm-iflytek-spark-text": { + "body": "", + "width": 150 + }, + "llm-iflytek-spark-text-cn": { + "body": "", + "width": 84 + }, + "llm-jina": { + "body": "" + }, + "llm-jina-text": { + "body": "", + "width": 58 + }, + "llm-microsoft": { + "body": "", + "width": 21, + "height": 22 + }, + "llm-openai-black": { + "body": "" + }, + "llm-openai-blue": { + "body": "" + }, + "llm-openai-green": { + "body": "" + }, + "llm-openai-teal": { + "body": "" + }, + "llm-openai-text": { + "body": "", + "width": 52, + "height": 20 + }, + "llm-openai-transparent": { + "body": "" + }, + "llm-openai-violet": { + "body": "" + }, + "llm-openai-yellow": { + "body": "" + }, + "llm-openllm": { + "body": "" + }, + "llm-openllm-text": { + "body": "", + "width": 92, + "height": 25 + }, + "llm-replicate": { + "body": "" + }, + "llm-replicate-text": { + "body": "", + "width": 92 + }, + "llm-xorbits-inference": { + "body": "" + }, + "llm-xorbits-inference-text": { + "body": "", + "width": 152 + }, + "llm-zhipuai": { + "body": "" + }, + "llm-zhipuai-text": { + "body": "", + "width": 89, + "height": 32 + }, + "llm-zhipuai-text-cn": { + "body": "", + "width": 86, + "height": 32 + }, + "model-checked": { + "body": "" + }, + "other-default-tool-icon": { + "body": "" + }, + "other-icon-3-dots": { + "body": "", + "width": 16, + "height": 16 + }, + "other-message-3-fill": { + "body": "" + }, + "other-row-struct": { + "body": "", + "width": 624, + "height": 48 + }, + "other-slack": { + "body": "", + "width": 27, + "height": 27 + }, + "other-teams": { + "body": "", + "width": 28, + "height": 28 + }, + "plugins-google": { + "body": "", + "width": 24, + "height": 24 + }, + "plugins-partner-dark": { + "body": "" + }, + "plugins-partner-light": { + "body": "" + }, + "plugins-verified-dark": { + "body": "" + }, + "plugins-verified-light": { + "body": "" + }, + "plugins-web-reader": { + "body": "", + "width": 24, + "height": 24 + }, + "plugins-wikipedia": { + "body": "", + "width": 24, + "height": 24 + }, + "thought-data-set": { + "body": "" + }, + "thought-loading": { + "body": "" + }, + "thought-search": { + "body": "" + }, + "thought-thought-list": { + "body": "" + }, + "thought-web-reader": { + "body": "" + }, + "tracing-aliyun-icon": { + "body": "", + "width": 65 + }, + "tracing-aliyun-icon-big": { + "body": "", + "width": 96, + "height": 24 + }, + "tracing-arize-icon": { + "body": "" + }, + "tracing-arize-icon-big": { + "body": "", + "width": 111, + "height": 24 + }, + "tracing-databricks-icon": { + "body": "", + "width": 100 + }, + "tracing-databricks-icon-big": { + "body": "", + "width": 151, + "height": 24 + }, + "tracing-langfuse-icon": { + "body": "" + }, + "tracing-langfuse-icon-big": { + "body": "", + "width": 111, + "height": 24 + }, + "tracing-langsmith-icon": { + "body": "", + "width": 84, + "height": 14 + }, + "tracing-langsmith-icon-big": { + "body": "", + "width": 124, + "height": 20 + }, + "tracing-mlflow-icon": { + "body": "", + "width": 43 + }, + "tracing-mlflow-icon-big": { + "body": "", + "width": 65, + "height": 24 + }, + "tracing-opik-icon": { + "body": "", + "width": 47.134 + }, + "tracing-opik-icon-big": { + "body": "", + "width": 70.701, + "height": 24 + }, + "tracing-phoenix-icon": { + "body": "" + }, + "tracing-phoenix-icon-big": { + "body": "", + "width": 111, + "height": 24 + }, + "tracing-tencent-icon": { + "body": "", + "width": 80, + "height": 18 + }, + "tracing-tencent-icon-big": { + "body": "", + "width": 80, + "height": 18 + }, + "tracing-tracing-icon": { + "body": "", + "width": 20, + "height": 20 + }, + "tracing-weave-icon": { + "body": "", + "width": 120 + }, + "tracing-weave-icon-big": { + "body": "", + "width": 120 + } + } +} diff --git a/packages/iconify-collections/custom-public/index.d.ts b/packages/iconify-collections/custom-public/index.d.ts new file mode 100644 index 0000000000..ecca5633d4 --- /dev/null +++ b/packages/iconify-collections/custom-public/index.d.ts @@ -0,0 +1,55 @@ +export interface IconifyJSON { + prefix: string + icons: Record + aliases?: Record + width?: number + height?: number + lastModified?: number +} + +export interface IconifyIcon { + body: string + left?: number + top?: number + width?: number + height?: number + rotate?: 0 | 1 | 2 | 3 + hFlip?: boolean + vFlip?: boolean +} + +export interface IconifyAlias extends Omit { + parent: string +} + +export interface IconifyInfo { + prefix: string + name: string + total: number + version: string + author?: { + name: string + url?: string + } + license?: { + title: string + spdx?: string + url?: string + } + samples?: string[] + palette?: boolean +} + +export interface IconifyMetaData { + [key: string]: unknown +} + +export interface IconifyChars { + [key: string]: string +} + +export declare const icons: IconifyJSON +export declare const info: IconifyInfo +export declare const metadata: IconifyMetaData +export declare const chars: IconifyChars + diff --git a/packages/iconify-collections/custom-public/index.js b/packages/iconify-collections/custom-public/index.js new file mode 100644 index 0000000000..81c1d0f5c4 --- /dev/null +++ b/packages/iconify-collections/custom-public/index.js @@ -0,0 +1,9 @@ +'use strict' + +const icons = require('./icons.json') +const info = require('./info.json') +const metadata = require('./metadata.json') +const chars = require('./chars.json') + +module.exports = { icons, info, metadata, chars } + diff --git a/packages/iconify-collections/custom-public/index.mjs b/packages/iconify-collections/custom-public/index.mjs new file mode 100644 index 0000000000..6c1108a92d --- /dev/null +++ b/packages/iconify-collections/custom-public/index.mjs @@ -0,0 +1,7 @@ +import icons from './icons.json' with { type: 'json' } +import info from './info.json' with { type: 'json' } +import metadata from './metadata.json' with { type: 'json' } +import chars from './chars.json' with { type: 'json' } + +export { icons, info, metadata, chars } + diff --git a/packages/iconify-collections/custom-public/info.json b/packages/iconify-collections/custom-public/info.json new file mode 100644 index 0000000000..8b5572de6f --- /dev/null +++ b/packages/iconify-collections/custom-public/info.json @@ -0,0 +1,24 @@ +{ + "prefix": "custom-public", + "name": "Dify Custom Public", + "total": 142, + "version": "0.0.0-private", + "author": { + "name": "LangGenius, Inc.", + "url": "https://github.com/langgenius/dify" + }, + "license": { + "title": "Modified Apache 2.0", + "spdx": "Apache-2.0", + "url": "https://github.com/langgenius/dify/blob/main/LICENSE" + }, + "samples": [ + "avatar-user", + "billing-ar-cube-1", + "billing-asterisk", + "billing-aws-marketplace-dark", + "billing-aws-marketplace-light", + "billing-azure" + ], + "palette": false +} diff --git a/packages/iconify-collections/custom-public/metadata.json b/packages/iconify-collections/custom-public/metadata.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/iconify-collections/custom-public/metadata.json @@ -0,0 +1 @@ +{} diff --git a/packages/iconify-collections/custom-vender/chars.json b/packages/iconify-collections/custom-vender/chars.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/iconify-collections/custom-vender/chars.json @@ -0,0 +1 @@ +{} diff --git a/packages/iconify-collections/custom-vender/icons.json b/packages/iconify-collections/custom-vender/icons.json new file mode 100644 index 0000000000..a7dc8e75e0 --- /dev/null +++ b/packages/iconify-collections/custom-vender/icons.json @@ -0,0 +1,1098 @@ +{ + "prefix": "custom-vender", + "lastModified": 1775115796, + "icons": { + "features-citations": { + "body": "" + }, + "features-content-moderation": { + "body": "" + }, + "features-document": { + "body": "" + }, + "features-folder-upload": { + "body": "" + }, + "features-love-message": { + "body": "" + }, + "features-message-fast": { + "body": "" + }, + "features-microphone-01": { + "body": "" + }, + "features-text-to-audio": { + "body": "" + }, + "features-virtual-assistant": { + "body": "" + }, + "features-vision": { + "body": "" + }, + "knowledge-add-chunks": { + "body": "", + "width": 20, + "height": 20 + }, + "knowledge-api-aggregate": { + "body": "", + "width": 16 + }, + "knowledge-arrow-shape": { + "body": "", + "width": 24, + "height": 11 + }, + "knowledge-chunk": { + "body": "", + "width": 10, + "height": 10 + }, + "knowledge-collapse": { + "body": "", + "width": 16 + }, + "knowledge-divider": { + "body": "", + "width": 6, + "height": 30 + }, + "knowledge-economic": { + "body": "", + "height": 18 + }, + "knowledge-full-text-search": { + "body": "", + "width": 15 + }, + "knowledge-general-chunk": { + "body": "", + "height": 18 + }, + "knowledge-high-quality": { + "body": "", + "height": 18 + }, + "knowledge-hybrid-search": { + "body": "", + "width": 16 + }, + "knowledge-parent-child-chunk": { + "body": "", + "height": 18 + }, + "knowledge-question-and-answer": { + "body": "", + "height": 18 + }, + "knowledge-search-lines-sparkle": { + "body": "", + "width": 16 + }, + "knowledge-search-menu": { + "body": "", + "width": 32, + "height": 33 + }, + "knowledge-vector-search": { + "body": "", + "width": 16 + }, + "line-alertsAndFeedback-alert-triangle": { + "body": "" + }, + "line-alertsAndFeedback-thumbs-down": { + "body": "" + }, + "line-alertsAndFeedback-thumbs-up": { + "body": "" + }, + "line-alertsAndFeedback-warning": { + "body": "", + "width": 12, + "height": 12 + }, + "line-arrows-arrow-narrow-left": { + "body": "", + "width": 17, + "height": 16 + }, + "line-arrows-arrow-up-right": { + "body": "" + }, + "line-arrows-chevron-down-double": { + "body": "", + "width": 12, + "height": 13 + }, + "line-arrows-chevron-right": { + "body": "" + }, + "line-arrows-chevron-selector-vertical": { + "body": "", + "width": 24, + "height": 24 + }, + "line-arrows-iconr": { + "body": "" + }, + "line-arrows-refresh-ccw-01": { + "body": "", + "width": 24, + "height": 24 + }, + "line-arrows-refresh-cw-05": { + "body": "", + "width": 16, + "height": 16 + }, + "line-arrows-reverse-left": { + "body": "", + "width": 16, + "height": 16 + }, + "line-communication-ai-text": { + "body": "" + }, + "line-communication-chat-bot": { + "body": "" + }, + "line-communication-chat-bot-slim": { + "body": "", + "width": 48, + "height": 48 + }, + "line-communication-cute-robot": { + "body": "" + }, + "line-communication-message-check-remove": { + "body": "", + "width": 24, + "height": 24 + }, + "line-communication-message-fast-plus": { + "body": "", + "width": 24, + "height": 24 + }, + "line-development-artificial-brain": { + "body": "", + "width": 24, + "height": 24 + }, + "line-development-bar-chart-square-02": { + "body": "" + }, + "line-development-brackets-x": { + "body": "", + "width": 24, + "height": 24 + }, + "line-development-code-browser": { + "body": "", + "width": 24, + "height": 24 + }, + "line-development-container": { + "body": "" + }, + "line-development-database-01": { + "body": "", + "width": 17 + }, + "line-development-database-03": { + "body": "" + }, + "line-development-file-heart-02": { + "body": "" + }, + "line-development-git-branch-01": { + "body": "" + }, + "line-development-prompt-engineering": { + "body": "" + }, + "line-development-puzzle-piece-01": { + "body": "" + }, + "line-development-terminal-square": { + "body": "", + "width": 24, + "height": 24 + }, + "line-development-variable": { + "body": "" + }, + "line-development-webhooks": { + "body": "" + }, + "line-editor-align-left": { + "body": "" + }, + "line-editor-bezier-curve-03": { + "body": "", + "width": 12, + "height": 12 + }, + "line-editor-collapse": { + "body": "", + "width": 16, + "height": 16 + }, + "line-editor-colors": { + "body": "" + }, + "line-editor-image-indent-left": { + "body": "" + }, + "line-editor-left-indent-02": { + "body": "" + }, + "line-editor-letter-spacing-01": { + "body": "" + }, + "line-editor-type-square": { + "body": "", + "width": 12, + "height": 12 + }, + "line-education-book-open-01": { + "body": "", + "width": 12, + "height": 12 + }, + "line-files-copy": { + "body": "" + }, + "line-files-copy-check": { + "body": "" + }, + "line-files-file-02": { + "body": "" + }, + "line-files-file-arrow-01": { + "body": "" + }, + "line-files-file-check-02": { + "body": "" + }, + "line-files-file-download-02": { + "body": "", + "width": 24, + "height": 24 + }, + "line-files-file-plus-01": { + "body": "" + }, + "line-files-file-plus-02": { + "body": "" + }, + "line-files-file-text": { + "body": "", + "width": 24, + "height": 24 + }, + "line-files-file-upload": { + "body": "", + "width": 24, + "height": 24 + }, + "line-files-folder": { + "body": "", + "width": 14, + "height": 14 + }, + "line-financeAndECommerce-balance": { + "body": "" + }, + "line-financeAndECommerce-coins-stacked-01": { + "body": "" + }, + "line-financeAndECommerce-credits-coin": { + "body": "", + "width": 10, + "height": 10 + }, + "line-financeAndECommerce-gold-coin": { + "body": "", + "width": 16, + "height": 16 + }, + "line-financeAndECommerce-receipt-list": { + "body": "" + }, + "line-financeAndECommerce-tag-01": { + "body": "", + "width": 14, + "height": 14 + }, + "line-financeAndECommerce-tag-03": { + "body": "", + "width": 16, + "height": 16 + }, + "line-general-at-sign": { + "body": "" + }, + "line-general-bookmark": { + "body": "", + "width": 24, + "height": 24 + }, + "line-general-check": { + "body": "" + }, + "line-general-check-done-01": { + "body": "", + "width": 24, + "height": 24 + }, + "line-general-checklist-square": { + "body": "", + "width": 32, + "height": 32 + }, + "line-general-code-assistant": { + "body": "", + "width": 24, + "height": 24 + }, + "line-general-dots-grid": { + "body": "", + "width": 14, + "height": 14 + }, + "line-general-edit-02": { + "body": "", + "width": 14, + "height": 14 + }, + "line-general-edit-04": { + "body": "", + "width": 24, + "height": 24 + }, + "line-general-edit-05": { + "body": "" + }, + "line-general-hash-02": { + "body": "", + "width": 12, + "height": 12 + }, + "line-general-info-circle": { + "body": "", + "width": 12, + "height": 12 + }, + "line-general-link-03": { + "body": "", + "width": 17 + }, + "line-general-link-external-02": { + "body": "", + "width": 12, + "height": 12 + }, + "line-general-log-in-04": { + "body": "" + }, + "line-general-log-out-01": { + "body": "", + "width": 14, + "height": 14 + }, + "line-general-log-out-04": { + "body": "" + }, + "line-general-magic-edit": { + "body": "", + "width": 24, + "height": 24 + }, + "line-general-menu-01": { + "body": "" + }, + "line-general-pin-01": { + "body": "" + }, + "line-general-pin-02": { + "body": "", + "width": 24, + "height": 24 + }, + "line-general-plus-02": { + "body": "", + "width": 10, + "height": 10 + }, + "line-general-refresh": { + "body": "", + "width": 24, + "height": 24 + }, + "line-general-search-menu": { + "body": "", + "width": 32, + "height": 32 + }, + "line-general-settings-01": { + "body": "", + "width": 14, + "height": 14 + }, + "line-general-settings-04": { + "body": "", + "width": 14, + "height": 14 + }, + "line-general-target-04": { + "body": "", + "width": 12, + "height": 12 + }, + "line-general-upload-03": { + "body": "" + }, + "line-general-upload-cloud-01": { + "body": "", + "width": 24, + "height": 24 + }, + "line-general-x": { + "body": "" + }, + "line-images-image-plus": { + "body": "" + }, + "line-layout-align-left-01": { + "body": "" + }, + "line-layout-align-right-01": { + "body": "" + }, + "line-layout-grid-01": { + "body": "", + "width": 17, + "height": 16 + }, + "line-layout-layout-grid-02": { + "body": "" + }, + "line-mediaAndDevices-microphone-01": { + "body": "" + }, + "line-mediaAndDevices-play-circle": { + "body": "" + }, + "line-mediaAndDevices-sliders-h": { + "body": "", + "width": 24, + "height": 24 + }, + "line-mediaAndDevices-speaker": { + "body": "" + }, + "line-mediaAndDevices-stop": { + "body": "", + "width": 12, + "height": 12 + }, + "line-mediaAndDevices-stop-circle": { + "body": "", + "width": 17 + }, + "line-others-bubble-x": { + "body": "" + }, + "line-others-colors": { + "body": "", + "width": 14, + "height": 14 + }, + "line-others-drag-handle": { + "body": "" + }, + "line-others-env": { + "body": "" + }, + "line-others-global-variable": { + "body": "" + }, + "line-others-icon-3-dots": { + "body": "" + }, + "line-others-long-arrow-left": { + "body": "", + "width": 21, + "height": 8 + }, + "line-others-long-arrow-right": { + "body": "", + "width": 26, + "height": 8 + }, + "line-others-search-menu": { + "body": "", + "width": 32, + "height": 32 + }, + "line-others-tools": { + "body": "", + "height": 17 + }, + "line-shapes-cube-outline": { + "body": "", + "height": 17 + }, + "line-time-clock-fast-forward": { + "body": "", + "width": 24, + "height": 24 + }, + "line-time-clock-play": { + "body": "" + }, + "line-time-clock-play-slim": { + "body": "", + "width": 32, + "height": 32 + }, + "line-time-clock-refresh": { + "body": "", + "width": 12, + "height": 12 + }, + "line-users-user-01": { + "body": "" + }, + "line-users-users-01": { + "body": "" + }, + "line-weather-stars-02": { + "body": "", + "width": 24, + "height": 24 + }, + "other-anthropic-text": { + "body": "", + "width": 90, + "height": 20 + }, + "other-generator": { + "body": "" + }, + "other-group": { + "body": "", + "height": 16 + }, + "other-hourglass-shape": { + "body": "", + "width": 8 + }, + "other-mcp": { + "body": "", + "width": 16, + "height": 16 + }, + "other-no-tool-placeholder": { + "body": "", + "width": 204, + "height": 36 + }, + "other-openai": { + "body": "", + "width": 80, + "height": 22 + }, + "other-replay-line": { + "body": "", + "width": 20, + "height": 20 + }, + "other-square-checklist": { + "body": "", + "width": 24, + "height": 24 + }, + "pipeline-input-field": { + "body": "", + "width": 16, + "height": 16 + }, + "pipeline-pipeline-fill": { + "body": "" + }, + "pipeline-pipeline-line": { + "body": "" + }, + "plugin-box-sparkle-fill": { + "body": "", + "width": 14, + "height": 14 + }, + "plugin-left-corner": { + "body": "", + "width": 13, + "height": 20 + }, + "plugin-trigger": { + "body": "" + }, + "solid-FinanceAndECommerce-gold-coin": { + "body": "" + }, + "solid-FinanceAndECommerce-scales-02": { + "body": "" + }, + "solid-alertsAndFeedback-alert-triangle": { + "body": "", + "width": 12, + "height": 12 + }, + "solid-arrows-arrow-down-double-line": { + "body": "" + }, + "solid-arrows-arrow-down-round-fill": { + "body": "" + }, + "solid-arrows-arrow-up-double-line": { + "body": "" + }, + "solid-arrows-chevron-down": { + "body": "", + "width": 24, + "height": 24 + }, + "solid-arrows-high-priority": { + "body": "", + "width": 24, + "height": 24 + }, + "solid-communication-ai-text": { + "body": "" + }, + "solid-communication-bubble-text-mod": { + "body": "" + }, + "solid-communication-chat-bot": { + "body": "", + "width": 13, + "height": 12 + }, + "solid-communication-cute-robot": { + "body": "" + }, + "solid-communication-edit-list": { + "body": "" + }, + "solid-communication-list-sparkle": { + "body": "" + }, + "solid-communication-logic": { + "body": "" + }, + "solid-communication-message-dots-circle": { + "body": "" + }, + "solid-communication-message-fast": { + "body": "" + }, + "solid-communication-message-heart-circle": { + "body": "", + "width": 16, + "height": 16 + }, + "solid-communication-message-smile-square": { + "body": "", + "width": 16, + "height": 16 + }, + "solid-communication-send-03": { + "body": "", + "width": 20, + "height": 20 + }, + "solid-development-api-connection": { + "body": "", + "width": 24, + "height": 24 + }, + "solid-development-api-connection-mod": { + "body": "" + }, + "solid-development-bar-chart-square-02": { + "body": "" + }, + "solid-development-container": { + "body": "", + "width": 17 + }, + "solid-development-database-02": { + "body": "", + "width": 17 + }, + "solid-development-database-03": { + "body": "" + }, + "solid-development-file-heart-02": { + "body": "" + }, + "solid-development-pattern-recognition": { + "body": "", + "width": 24, + "height": 24 + }, + "solid-development-prompt-engineering": { + "body": "" + }, + "solid-development-puzzle-piece-01": { + "body": "", + "width": 17 + }, + "solid-development-semantic": { + "body": "", + "width": 24, + "height": 24 + }, + "solid-development-terminal-square": { + "body": "", + "width": 12, + "height": 12 + }, + "solid-development-variable-02": { + "body": "", + "width": 24, + "height": 24 + }, + "solid-editor-brush-01": { + "body": "" + }, + "solid-editor-citations": { + "body": "", + "width": 16, + "height": 16 + }, + "solid-editor-colors": { + "body": "" + }, + "solid-editor-paragraph": { + "body": "" + }, + "solid-editor-type-square": { + "body": "" + }, + "solid-education-beaker-02": { + "body": "", + "width": 12, + "height": 12 + }, + "solid-education-bubble-text": { + "body": "" + }, + "solid-education-heart-02": { + "body": "" + }, + "solid-education-unblur": { + "body": "" + }, + "solid-files-file-05": { + "body": "" + }, + "solid-files-file-search-02": { + "body": "" + }, + "solid-files-file-zip": { + "body": "" + }, + "solid-files-folder": { + "body": "" + }, + "solid-general-answer-triangle": { + "body": "", + "width": 8, + "height": 12 + }, + "solid-general-arrow-down-round-fill": { + "body": "", + "width": 16, + "height": 16 + }, + "solid-general-check-circle": { + "body": "", + "width": 16, + "height": 16 + }, + "solid-general-check-done-01": { + "body": "" + }, + "solid-general-download-02": { + "body": "" + }, + "solid-general-edit-03": { + "body": "", + "width": 12, + "height": 12 + }, + "solid-general-edit-04": { + "body": "" + }, + "solid-general-eye": { + "body": "" + }, + "solid-general-github": { + "body": "", + "width": 16, + "height": 16 + }, + "solid-general-message-clock-circle": { + "body": "", + "width": 16, + "height": 16 + }, + "solid-general-plus-circle": { + "body": "" + }, + "solid-general-question-triangle": { + "body": "", + "width": 8, + "height": 12 + }, + "solid-general-search-md": { + "body": "" + }, + "solid-general-target-04": { + "body": "" + }, + "solid-general-tool-03": { + "body": "", + "width": 16, + "height": 16 + }, + "solid-general-x-circle": { + "body": "", + "width": 16, + "height": 16 + }, + "solid-general-zap-fast": { + "body": "", + "width": 12, + "height": 12 + }, + "solid-general-zap-narrow": { + "body": "", + "width": 12, + "height": 12 + }, + "solid-layout-grid-01": { + "body": "" + }, + "solid-mediaAndDevices-audio-support-icon": { + "body": "" + }, + "solid-mediaAndDevices-document-support-icon": { + "body": "" + }, + "solid-mediaAndDevices-magic-box": { + "body": "" + }, + "solid-mediaAndDevices-magic-eyes": { + "body": "" + }, + "solid-mediaAndDevices-magic-wand": { + "body": "" + }, + "solid-mediaAndDevices-microphone-01": { + "body": "", + "width": 16, + "height": 16 + }, + "solid-mediaAndDevices-play": { + "body": "" + }, + "solid-mediaAndDevices-robot": { + "body": "" + }, + "solid-mediaAndDevices-sliders-02": { + "body": "", + "width": 24, + "height": 24 + }, + "solid-mediaAndDevices-speaker": { + "body": "", + "width": 16, + "height": 16 + }, + "solid-mediaAndDevices-stop-circle": { + "body": "", + "width": 20, + "height": 20 + }, + "solid-mediaAndDevices-video-support-icon": { + "body": "" + }, + "solid-security-lock-01": { + "body": "", + "width": 12, + "height": 12 + }, + "solid-shapes-corner": { + "body": "", + "width": 13, + "height": 20 + }, + "solid-shapes-star-04": { + "body": "", + "width": 11, + "height": 10 + }, + "solid-shapes-star-06": { + "body": "" + }, + "solid-users-user-01": { + "body": "" + }, + "solid-users-user-edit-02": { + "body": "", + "width": 14, + "height": 14 + }, + "solid-users-users-01": { + "body": "" + }, + "solid-users-users-plus": { + "body": "", + "width": 24, + "height": 24 + }, + "system-auto-update-line": { + "body": "", + "width": 24, + "height": 24 + }, + "workflow-agent": { + "body": "", + "width": 16, + "height": 16 + }, + "workflow-answer": { + "body": "" + }, + "workflow-api-aggregate": { + "body": "", + "width": 16, + "height": 16 + }, + "workflow-assigner": { + "body": "", + "width": 16, + "height": 16 + }, + "workflow-asterisk": { + "body": "" + }, + "workflow-calendar-check-line": { + "body": "" + }, + "workflow-code": { + "body": "" + }, + "workflow-datasource": { + "body": "" + }, + "workflow-docs-extractor": { + "body": "", + "width": 16, + "height": 16 + }, + "workflow-end": { + "body": "" + }, + "workflow-home": { + "body": "" + }, + "workflow-http": { + "body": "" + }, + "workflow-human-in-loop": { + "body": "", + "width": 16, + "height": 16 + }, + "workflow-if-else": { + "body": "" + }, + "workflow-iteration": { + "body": "" + }, + "workflow-iteration-start": { + "body": "", + "width": 12, + "height": 12 + }, + "workflow-jinja": { + "body": "", + "width": 24, + "height": 12 + }, + "workflow-knowledge-base": { + "body": "" + }, + "workflow-knowledge-retrieval": { + "body": "", + "width": 16, + "height": 16 + }, + "workflow-list-filter": { + "body": "", + "width": 16, + "height": 16 + }, + "workflow-llm": { + "body": "" + }, + "workflow-loop": { + "body": "", + "width": 18, + "height": 16 + }, + "workflow-loop-end": { + "body": "", + "width": 16, + "height": 16 + }, + "workflow-parameter-extractor": { + "body": "" + }, + "workflow-question-classifier": { + "body": "" + }, + "workflow-schedule": { + "body": "", + "width": 16, + "height": 16 + }, + "workflow-templating-transform": { + "body": "" + }, + "workflow-trigger-all": { + "body": "" + }, + "workflow-variable-x": { + "body": "" + }, + "workflow-webhook-line": { + "body": "", + "width": 16, + "height": 16 + }, + "workflow-window-cursor": { + "body": "", + "width": 16, + "height": 16 + } + } +} diff --git a/packages/iconify-collections/custom-vender/index.d.ts b/packages/iconify-collections/custom-vender/index.d.ts new file mode 100644 index 0000000000..ecca5633d4 --- /dev/null +++ b/packages/iconify-collections/custom-vender/index.d.ts @@ -0,0 +1,55 @@ +export interface IconifyJSON { + prefix: string + icons: Record + aliases?: Record + width?: number + height?: number + lastModified?: number +} + +export interface IconifyIcon { + body: string + left?: number + top?: number + width?: number + height?: number + rotate?: 0 | 1 | 2 | 3 + hFlip?: boolean + vFlip?: boolean +} + +export interface IconifyAlias extends Omit { + parent: string +} + +export interface IconifyInfo { + prefix: string + name: string + total: number + version: string + author?: { + name: string + url?: string + } + license?: { + title: string + spdx?: string + url?: string + } + samples?: string[] + palette?: boolean +} + +export interface IconifyMetaData { + [key: string]: unknown +} + +export interface IconifyChars { + [key: string]: string +} + +export declare const icons: IconifyJSON +export declare const info: IconifyInfo +export declare const metadata: IconifyMetaData +export declare const chars: IconifyChars + diff --git a/packages/iconify-collections/custom-vender/index.js b/packages/iconify-collections/custom-vender/index.js new file mode 100644 index 0000000000..81c1d0f5c4 --- /dev/null +++ b/packages/iconify-collections/custom-vender/index.js @@ -0,0 +1,9 @@ +'use strict' + +const icons = require('./icons.json') +const info = require('./info.json') +const metadata = require('./metadata.json') +const chars = require('./chars.json') + +module.exports = { icons, info, metadata, chars } + diff --git a/packages/iconify-collections/custom-vender/index.mjs b/packages/iconify-collections/custom-vender/index.mjs new file mode 100644 index 0000000000..6c1108a92d --- /dev/null +++ b/packages/iconify-collections/custom-vender/index.mjs @@ -0,0 +1,7 @@ +import icons from './icons.json' with { type: 'json' } +import info from './info.json' with { type: 'json' } +import metadata from './metadata.json' with { type: 'json' } +import chars from './chars.json' with { type: 'json' } + +export { icons, info, metadata, chars } + diff --git a/packages/iconify-collections/custom-vender/info.json b/packages/iconify-collections/custom-vender/info.json new file mode 100644 index 0000000000..0a84c45bbd --- /dev/null +++ b/packages/iconify-collections/custom-vender/info.json @@ -0,0 +1,24 @@ +{ + "prefix": "custom-vender", + "name": "Dify Custom Vender", + "total": 277, + "version": "0.0.0-private", + "author": { + "name": "LangGenius, Inc.", + "url": "https://github.com/langgenius/dify" + }, + "license": { + "title": "Modified Apache 2.0", + "spdx": "Apache-2.0", + "url": "https://github.com/langgenius/dify/blob/main/LICENSE" + }, + "samples": [ + "features-citations", + "features-content-moderation", + "features-document", + "features-folder-upload", + "features-love-message", + "features-message-fast" + ], + "palette": false +} diff --git a/packages/iconify-collections/custom-vender/metadata.json b/packages/iconify-collections/custom-vender/metadata.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/iconify-collections/custom-vender/metadata.json @@ -0,0 +1 @@ +{} diff --git a/packages/iconify-collections/package.json b/packages/iconify-collections/package.json new file mode 100644 index 0000000000..3bd7285f1a --- /dev/null +++ b/packages/iconify-collections/package.json @@ -0,0 +1,31 @@ +{ + "name": "@dify/iconify-collections", + "private": true, + "version": "0.0.0-private", + "exports": { + "./custom-public": { + "types": "./custom-public/index.d.ts", + "require": "./custom-public/index.js", + "import": "./custom-public/index.mjs" + }, + "./custom-public/icons.json": "./custom-public/icons.json", + "./custom-public/info.json": "./custom-public/info.json", + "./custom-public/metadata.json": "./custom-public/metadata.json", + "./custom-public/chars.json": "./custom-public/chars.json", + "./custom-vender": { + "types": "./custom-vender/index.d.ts", + "require": "./custom-vender/index.js", + "import": "./custom-vender/index.mjs" + }, + "./custom-vender/icons.json": "./custom-vender/icons.json", + "./custom-vender/info.json": "./custom-vender/info.json", + "./custom-vender/metadata.json": "./custom-vender/metadata.json", + "./custom-vender/chars.json": "./custom-vender/chars.json" + }, + "scripts": { + "generate": "node ./scripts/generate-collections.mjs" + }, + "devDependencies": { + "iconify-import-svg": "catalog:" + } +} diff --git a/packages/iconify-collections/scripts/generate-collections.mjs b/packages/iconify-collections/scripts/generate-collections.mjs new file mode 100644 index 0000000000..1c734731e6 --- /dev/null +++ b/packages/iconify-collections/scripts/generate-collections.mjs @@ -0,0 +1,178 @@ +import { mkdir, readFile, rm, writeFile } from 'node:fs/promises' +import path from 'node:path' +import { fileURLToPath } from 'node:url' +import { importSvgCollections } from 'iconify-import-svg' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) +const packageDir = path.resolve(__dirname, '..') + +const parseColorOptions = { + fallback: () => 'currentColor', +} +const svgOptimizeConfig = { + cleanupSVG: true, + deOptimisePaths: true, + runSVGO: true, + parseColors: parseColorOptions, +} + +const customPublicCollections = importSvgCollections({ + source: path.resolve(packageDir, 'assets/public'), + prefix: 'custom-public', + ignoreImportErrors: true, + ...svgOptimizeConfig, +}) + +const customVenderCollections = importSvgCollections({ + source: path.resolve(packageDir, 'assets/vender'), + prefix: 'custom-vender', + ignoreImportErrors: true, + ...svgOptimizeConfig, +}) + +const packageJson = JSON.parse(await readFile(path.resolve(packageDir, 'package.json'), 'utf8')) + +const flattenCollections = (collections, prefix) => { + const icons = {} + const aliases = {} + let lastModified = 0 + + for (const [collectionKey, collection] of Object.entries(collections)) { + const segment = collectionKey.slice(prefix.length + 1) + const namePrefix = segment + ? `${segment}-` + : '' + + for (const [iconName, iconData] of Object.entries(collection.icons ?? {})) + icons[`${namePrefix}${iconName}`] = iconData + + for (const [aliasName, aliasData] of Object.entries(collection.aliases ?? {})) + aliases[`${namePrefix}${aliasName}`] = aliasData + + if (typeof collection.lastModified === 'number') + lastModified = Math.max(lastModified, collection.lastModified) + } + + return { + prefix, + ...(lastModified ? { lastModified } : {}), + icons, + ...(Object.keys(aliases).length ? { aliases } : {}), + } +} + +const createCollectionInfo = (prefix, name, icons) => ({ + prefix, + name, + total: Object.keys(icons).length, + version: packageJson.version, + author: { + name: 'LangGenius, Inc.', + url: 'https://github.com/langgenius/dify', + }, + license: { + title: 'Modified Apache 2.0', + spdx: 'Apache-2.0', + url: 'https://github.com/langgenius/dify/blob/main/LICENSE', + }, + samples: Object.keys(icons).slice(0, 6), + palette: false, +}) + +const createIndexMjs = () => `import icons from './icons.json' with { type: 'json' } +import info from './info.json' with { type: 'json' } +import metadata from './metadata.json' with { type: 'json' } +import chars from './chars.json' with { type: 'json' } + +export { icons, info, metadata, chars } +` + +const createIndexJs = () => `'use strict' + +const icons = require('./icons.json') +const info = require('./info.json') +const metadata = require('./metadata.json') +const chars = require('./chars.json') + +module.exports = { icons, info, metadata, chars } +` + +const createIndexTypes = () => `export interface IconifyJSON { + prefix: string + icons: Record + aliases?: Record + width?: number + height?: number + lastModified?: number +} + +export interface IconifyIcon { + body: string + left?: number + top?: number + width?: number + height?: number + rotate?: 0 | 1 | 2 | 3 + hFlip?: boolean + vFlip?: boolean +} + +export interface IconifyAlias extends Omit { + parent: string +} + +export interface IconifyInfo { + prefix: string + name: string + total: number + version: string + author?: { + name: string + url?: string + } + license?: { + title: string + spdx?: string + url?: string + } + samples?: string[] + palette?: boolean +} + +export interface IconifyMetaData { + [key: string]: unknown +} + +export interface IconifyChars { + [key: string]: string +} + +export declare const icons: IconifyJSON +export declare const info: IconifyInfo +export declare const metadata: IconifyMetaData +export declare const chars: IconifyChars +` + +const writeCollectionPackage = async (directoryName, collection, name) => { + const targetDir = path.resolve(packageDir, directoryName) + const info = createCollectionInfo(collection.prefix, name, collection.icons) + + await mkdir(targetDir, { recursive: true }) + await writeFile(path.resolve(targetDir, 'icons.json'), `${JSON.stringify(collection, null, 2)}\n`) + await writeFile(path.resolve(targetDir, 'info.json'), `${JSON.stringify(info, null, 2)}\n`) + await writeFile(path.resolve(targetDir, 'metadata.json'), '{}\n') + await writeFile(path.resolve(targetDir, 'chars.json'), '{}\n') + await writeFile(path.resolve(targetDir, 'index.mjs'), `${createIndexMjs()}\n`) + await writeFile(path.resolve(targetDir, 'index.js'), `${createIndexJs()}\n`) + await writeFile(path.resolve(targetDir, 'index.d.ts'), `${createIndexTypes()}\n`) +} + +const mergedCustomPublicCollection = flattenCollections(customPublicCollections, 'custom-public') +const mergedCustomVenderCollection = flattenCollections(customVenderCollections, 'custom-vender') + +await rm(path.resolve(packageDir, 'src'), { recursive: true, force: true }) +await rm(path.resolve(packageDir, 'custom-public'), { recursive: true, force: true }) +await rm(path.resolve(packageDir, 'custom-vender'), { recursive: true, force: true }) + +await writeCollectionPackage('custom-public', mergedCustomPublicCollection, 'Dify Custom Public') +await writeCollectionPackage('custom-vender', mergedCustomVenderCollection, 'Dify Custom Vender') diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cdd69e783a..7a44b621b1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -640,6 +640,12 @@ importers: specifier: 'catalog:' version: 0.1.14(@types/node@25.5.0)(esbuild@0.27.2)(happy-dom@20.8.9)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(typescript@5.9.3)(vite@8.0.3(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1)(@types/node@25.5.0)(esbuild@0.27.2)(jiti@2.6.1)(sass@1.98.0)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.3))(yaml@2.8.3) + packages/iconify-collections: + devDependencies: + iconify-import-svg: + specifier: 'catalog:' + version: 0.1.2 + sdks/nodejs-client: devDependencies: '@eslint/js': @@ -982,6 +988,9 @@ importers: '@chromatic-com/storybook': specifier: 'catalog:' version: 5.1.1(storybook@10.3.3(@testing-library/dom@10.4.1)(react-dom@19.2.4(react@19.2.4))(react@19.2.4)) + '@dify/iconify-collections': + specifier: workspace:* + version: link:../packages/iconify-collections '@egoist/tailwindcss-icons': specifier: 'catalog:' version: 1.9.2(tailwindcss@4.2.2) @@ -1159,9 +1168,6 @@ importers: hono: specifier: 'catalog:' version: 4.12.9 - iconify-import-svg: - specifier: 'catalog:' - version: 0.1.2 knip: specifier: 'catalog:' version: 6.1.0(@emnapi/core@1.9.1)(@emnapi/runtime@1.9.1) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 236d6d7ade..abcbff7a68 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -11,6 +11,7 @@ packages: - web - e2e - sdks/nodejs-client + - packages/* overrides: "@lexical/code": npm:lexical-code-no-prism@0.41.0 "@monaco-editor/loader": 1.7.0 diff --git a/web/app/components/base/icons/src/image/llm/BaichuanTextCn.module.css b/web/app/components/base/icons/src/image/llm/BaichuanTextCn.module.css index 1b6bd72501..97ab9b22f9 100644 --- a/web/app/components/base/icons/src/image/llm/BaichuanTextCn.module.css +++ b/web/app/components/base/icons/src/image/llm/BaichuanTextCn.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../../styles/globals.css"; - .wrapper { display: inline-flex; background: url(~@/app/components/base/icons/assets/image/llm/baichuan-text-cn.png) center center no-repeat; diff --git a/web/app/components/base/icons/src/image/llm/Minimax.module.css b/web/app/components/base/icons/src/image/llm/Minimax.module.css index c20144d754..551ecc3c62 100644 --- a/web/app/components/base/icons/src/image/llm/Minimax.module.css +++ b/web/app/components/base/icons/src/image/llm/Minimax.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../../styles/globals.css"; - .wrapper { display: inline-flex; background: url(~@/app/components/base/icons/assets/image/llm/minimax.png) center center no-repeat; diff --git a/web/app/components/base/icons/src/image/llm/MinimaxText.module.css b/web/app/components/base/icons/src/image/llm/MinimaxText.module.css index 459b6e9b3b..a63be49e8b 100644 --- a/web/app/components/base/icons/src/image/llm/MinimaxText.module.css +++ b/web/app/components/base/icons/src/image/llm/MinimaxText.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../../styles/globals.css"; - .wrapper { display: inline-flex; background: url(~@/app/components/base/icons/assets/image/llm/minimax-text.png) center center no-repeat; diff --git a/web/app/components/base/icons/src/image/llm/Tongyi.module.css b/web/app/components/base/icons/src/image/llm/Tongyi.module.css index d510c6bc28..3ca440768c 100644 --- a/web/app/components/base/icons/src/image/llm/Tongyi.module.css +++ b/web/app/components/base/icons/src/image/llm/Tongyi.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../../styles/globals.css"; - .wrapper { display: inline-flex; background: url(~@/app/components/base/icons/assets/image/llm/tongyi.png) center center no-repeat; diff --git a/web/app/components/base/icons/src/image/llm/TongyiText.module.css b/web/app/components/base/icons/src/image/llm/TongyiText.module.css index c76ea97e69..f713671808 100644 --- a/web/app/components/base/icons/src/image/llm/TongyiText.module.css +++ b/web/app/components/base/icons/src/image/llm/TongyiText.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../../styles/globals.css"; - .wrapper { display: inline-flex; background: url(~@/app/components/base/icons/assets/image/llm/tongyi-text.png) center center no-repeat; diff --git a/web/app/components/base/icons/src/image/llm/TongyiTextCn.module.css b/web/app/components/base/icons/src/image/llm/TongyiTextCn.module.css index c6404a0ed8..d07e6e8bc4 100644 --- a/web/app/components/base/icons/src/image/llm/TongyiTextCn.module.css +++ b/web/app/components/base/icons/src/image/llm/TongyiTextCn.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../../styles/globals.css"; - .wrapper { display: inline-flex; background: url(~@/app/components/base/icons/assets/image/llm/tongyi-text-cn.png) center center no-repeat; diff --git a/web/app/components/base/icons/src/image/llm/Wxyy.module.css b/web/app/components/base/icons/src/image/llm/Wxyy.module.css index 891fb1e80c..44344a495f 100644 --- a/web/app/components/base/icons/src/image/llm/Wxyy.module.css +++ b/web/app/components/base/icons/src/image/llm/Wxyy.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../../styles/globals.css"; - .wrapper { display: inline-flex; background: url(~@/app/components/base/icons/assets/image/llm/wxyy.png) center center no-repeat; diff --git a/web/app/components/base/icons/src/image/llm/WxyyText.module.css b/web/app/components/base/icons/src/image/llm/WxyyText.module.css index cfa5523fbc..58a0c62047 100644 --- a/web/app/components/base/icons/src/image/llm/WxyyText.module.css +++ b/web/app/components/base/icons/src/image/llm/WxyyText.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../../styles/globals.css"; - .wrapper { display: inline-flex; background: url(~@/app/components/base/icons/assets/image/llm/wxyy-text.png) center center no-repeat; diff --git a/web/app/components/base/icons/src/image/llm/WxyyTextCn.module.css b/web/app/components/base/icons/src/image/llm/WxyyTextCn.module.css index a3b3b9e03e..fb5839ab07 100644 --- a/web/app/components/base/icons/src/image/llm/WxyyTextCn.module.css +++ b/web/app/components/base/icons/src/image/llm/WxyyTextCn.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../../styles/globals.css"; - .wrapper { display: inline-flex; background: url(~@/app/components/base/icons/assets/image/llm/wxyy-text-cn.png) center center no-repeat; diff --git a/web/app/components/base/icons/src/vender/workflow/HumanInLoop.tsx b/web/app/components/base/icons/src/vender/workflow/HumanInLoop.tsx index a94daf432a..8c88642476 100644 --- a/web/app/components/base/icons/src/vender/workflow/HumanInLoop.tsx +++ b/web/app/components/base/icons/src/vender/workflow/HumanInLoop.tsx @@ -11,7 +11,7 @@ const Icon = ( ref, ...props }: React.SVGProps & { - ref?: React.RefObject> + ref?: React.RefObject> }, ) => diff --git a/web/package.json b/web/package.json index b6d3ee6bc0..d72d8b1648 100644 --- a/web/package.json +++ b/web/package.json @@ -31,7 +31,7 @@ "dev:proxy": "tsx ./scripts/dev-hono-proxy.ts", "dev:vinext": "vinext dev", "gen-doc-paths": "tsx ./scripts/gen-doc-paths.ts", - "gen-icons": "node ./scripts/gen-icons.mjs && eslint --fix app/components/base/icons/src/", + "gen-icons": "pnpm --filter @dify/iconify-collections generate && node ./scripts/gen-icons.mjs && eslint --fix app/components/base/icons/src/", "i18n:check": "tsx ./scripts/check-i18n.js", "knip": "knip", "lint": "eslint --cache --concurrency=auto", @@ -158,6 +158,7 @@ "devDependencies": { "@antfu/eslint-config": "catalog:", "@chromatic-com/storybook": "catalog:", + "@dify/iconify-collections": "workspace:*", "@egoist/tailwindcss-icons": "catalog:", "@eslint-react/eslint-plugin": "catalog:", "@hono/node-server": "catalog:", @@ -217,7 +218,6 @@ "eslint-plugin-storybook": "catalog:", "happy-dom": "catalog:", "hono": "catalog:", - "iconify-import-svg": "catalog:", "knip": "catalog:", "postcss": "catalog:", "react-server-dom-webpack": "catalog:", diff --git a/web/scripts/gen-icons.mjs b/web/scripts/gen-icons.mjs index f681d65759..183cef6960 100644 --- a/web/scripts/gen-icons.mjs +++ b/web/scripts/gen-icons.mjs @@ -6,6 +6,7 @@ import { camelCase, template } from 'es-toolkit/compat' const __dirname = path.dirname(fileURLToPath(import.meta.url)) const iconsDir = path.resolve(__dirname, '../app/components/base/icons') +const svgAssetsDir = path.resolve(__dirname, '../../packages/iconify-collections/assets') const generateDir = async (currentPath) => { try { @@ -32,8 +33,8 @@ const processSvgStructure = (svgStructure, replaceFillOrStrokeColor) => { }) } } -const generateSvgComponent = async (fileHandle, entry, pathList, replaceFillOrStrokeColor) => { - const currentPath = path.resolve(iconsDir, 'src', ...pathList.slice(2)) +const generateSvgComponent = async (fileHandle, entry, relativeSegments, replaceFillOrStrokeColor) => { + const currentPath = path.resolve(iconsDir, 'src', ...relativeSegments) try { await access(currentPath) @@ -86,8 +87,8 @@ export { default as <%= svgName %> } from './<%= svgName %>' await appendFile(path.resolve(currentPath, 'index.ts'), `${indexingRender({ svgName: fileName })}\n`) } -const generateImageComponent = async (entry, pathList) => { - const currentPath = path.resolve(iconsDir, 'src', ...pathList.slice(2)) +const generateImageComponent = async (entry, relativeSegments) => { + const currentPath = path.resolve(iconsDir, 'src', ...relativeSegments) try { await access(currentPath) @@ -107,7 +108,7 @@ const generateImageComponent = async (entry, pathList) => { } `.trim()) - await writeFile(path.resolve(currentPath, `${fileName}.module.css`), `${componentCSSRender({ assetPath: path.posix.join('~@/app/components/base/icons/assets', ...pathList.slice(2), entry) })}\n`) + await writeFile(path.resolve(currentPath, `${fileName}.module.css`), `${componentCSSRender({ assetPath: path.posix.join('~@/app/components/base/icons/assets', ...relativeSegments, entry) })}\n`) const componentRender = template(` // GENERATE BY script @@ -141,8 +142,8 @@ export { default as <%= fileName %> } from './<%= fileName %>' await appendFile(path.resolve(currentPath, 'index.ts'), `${indexingRender({ fileName })}\n`) } -const walk = async (entry, pathList, replaceFillOrStrokeColor) => { - const currentPath = path.resolve(...pathList, entry) +const walk = async (basePath, entry, relativeSegments, replaceFillOrStrokeColor) => { + const currentPath = path.resolve(basePath, ...relativeSegments, entry) let fileHandle try { @@ -153,14 +154,14 @@ const walk = async (entry, pathList, replaceFillOrStrokeColor) => { const files = await readdir(currentPath) for (const file of files) - await walk(file, [...pathList, entry], replaceFillOrStrokeColor) + await walk(basePath, file, [...relativeSegments, entry], replaceFillOrStrokeColor) } if (stat.isFile() && /.+\.svg$/.test(entry)) - await generateSvgComponent(fileHandle, entry, pathList, replaceFillOrStrokeColor) + await generateSvgComponent(fileHandle, entry, relativeSegments, replaceFillOrStrokeColor) if (stat.isFile() && /.+\.png$/.test(entry)) - await generateImageComponent(entry, pathList) + await generateImageComponent(entry, relativeSegments) } finally { fileHandle?.close() @@ -169,7 +170,7 @@ const walk = async (entry, pathList, replaceFillOrStrokeColor) => { (async () => { await rm(path.resolve(iconsDir, 'src'), { recursive: true, force: true }) - await walk('public', [iconsDir, 'assets']) - await walk('vender', [iconsDir, 'assets'], true) - await walk('image', [iconsDir, 'assets']) + await walk(svgAssetsDir, 'public', [], false) + await walk(svgAssetsDir, 'vender', [], true) + await walk(path.resolve(iconsDir, 'assets'), 'image', [], false) })() diff --git a/web/tailwind-common-config.ts b/web/tailwind-common-config.ts index 0fb3524dbc..db50f2457b 100644 --- a/web/tailwind-common-config.ts +++ b/web/tailwind-common-config.ts @@ -1,28 +1,10 @@ -import path from 'node:path' -import { fileURLToPath } from 'node:url' +import { icons as customPublicIcons } from '@dify/iconify-collections/custom-public' +import { icons as customVenderIcons } from '@dify/iconify-collections/custom-vender' import { getIconCollections, iconsPlugin } from '@egoist/tailwindcss-icons' import tailwindTypography from '@tailwindcss/typography' -import { importSvgCollections } from 'iconify-import-svg' import tailwindThemeVarDefine from './themes/tailwind-theme-var-define' import typography from './typography.js' -const _dirname = typeof __dirname !== 'undefined' - ? __dirname - : path.dirname(fileURLToPath(import.meta.url)) - -const disableSVGOptimize = process.env.TAILWIND_MODE === 'ESLINT' -const parseColorOptions = { - fallback: () => 'currentColor', -} -const svgOptimizeConfig = { - cleanupSVG: !disableSVGOptimize, - deOptimisePaths: !disableSVGOptimize, - runSVGO: !disableSVGOptimize, - parseColors: !disableSVGOptimize - ? parseColorOptions - : false, -} - const config = { theme: { typography, @@ -170,18 +152,8 @@ const config = { iconsPlugin({ collections: { ...getIconCollections(['heroicons', 'ri']), - ...importSvgCollections({ - source: path.resolve(_dirname, 'app/components/base/icons/assets/public'), - prefix: 'custom-public', - ignoreImportErrors: true, - ...svgOptimizeConfig, - }), - ...importSvgCollections({ - source: path.resolve(_dirname, 'app/components/base/icons/assets/vender'), - prefix: 'custom-vender', - ignoreImportErrors: true, - ...svgOptimizeConfig, - }), + 'custom-public': customPublicIcons, + 'custom-vender': customVenderIcons, }, extraProperties: { width: '1rem', From 5bafb163cc737f2c04d1693c227097924bbc5c74 Mon Sep 17 00:00:00 2001 From: Poojan Date: Thu, 2 Apr 2026 14:05:46 +0530 Subject: [PATCH 02/29] test: add unit tests for services and tasks part-4 (#33223) Co-authored-by: akashseth-ifp Co-authored-by: rajatagarwal-oss Co-authored-by: Dev Sharma <50591491+cryptus-neoxys@users.noreply.github.com> Co-authored-by: sahil-infocusp <73810410+sahil-infocusp@users.noreply.github.com> --- api/services/variable_truncator.py | 7 +- ...est_model_provider_service_sanitization.py | 641 ++++++++++++++ .../services/test_recommended_app_service.py | 198 ++++- .../services/test_schedule_service.py | 160 +++- .../services/test_variable_truncator.py | 259 +++++- .../services/test_webhook_service.py | 754 ++++++++++++++++ .../test_workflow_run_service_pause.py | 297 +++++++ .../test_workflow_converter_additional.py | 831 ++++++++++++++++++ .../test_workflow_event_snapshot_service.py | 577 +++++++++++- .../tasks/test_dataset_indexing_task.py | 490 ++++++++++- 10 files changed, 4180 insertions(+), 34 deletions(-) create mode 100644 api/tests/unit_tests/services/workflow/test_workflow_converter_additional.py diff --git a/api/services/variable_truncator.py b/api/services/variable_truncator.py index 5427b7b3a7..4d58a9cf12 100644 --- a/api/services/variable_truncator.py +++ b/api/services/variable_truncator.py @@ -129,6 +129,7 @@ class VariableTruncator(BaseTruncator): used_size += self.calculate_json_size(key) if used_size > budget: truncated_mapping[key] = "..." + is_truncated = True continue value_budget = (budget - used_size) // (length - len(truncated_mapping)) if isinstance(value, Segment): @@ -164,9 +165,9 @@ class VariableTruncator(BaseTruncator): result = self._truncate_segment(segment, self._max_size_bytes) if result.value_size > self._max_size_bytes: - if isinstance(result.value, str): - result = self._truncate_string(result.value, self._max_size_bytes) - return TruncationResult(StringSegment(value=result.value), True) + if isinstance(result.value, StringSegment): + fallback_result = self._truncate_string(result.value.value, self._max_size_bytes) + return TruncationResult(StringSegment(value=fallback_result.value), True) # Apply final fallback - convert to JSON string and truncate json_str = dumps_with_segments(result.value, ensure_ascii=False) diff --git a/api/tests/unit_tests/services/test_model_provider_service_sanitization.py b/api/tests/unit_tests/services/test_model_provider_service_sanitization.py index 1bd979b9ec..acf5dff634 100644 --- a/api/tests/unit_tests/services/test_model_provider_service_sanitization.py +++ b/api/tests/unit_tests/services/test_model_provider_service_sanitization.py @@ -85,3 +85,644 @@ def test_get_provider_list_strips_credentials(service_with_fake_configurations: assert len(custom_models) == 1 # The sanitizer should drop credentials in list response assert custom_models[0].credentials is None + + +# === Merged from test_model_provider_service.py === + + +from types import SimpleNamespace +from typing import Any +from unittest.mock import MagicMock + +import pytest +from graphon.model_runtime.entities.common_entities import I18nObject +from graphon.model_runtime.entities.model_entities import FetchFrom, ModelType, ParameterRule, ParameterType + +from core.entities.model_entities import ModelStatus +from models.provider import ProviderType +from services import model_provider_service as service_module +from services.errors.app_model_config import ProviderNotFoundError +from services.model_provider_service import ModelProviderService + + +def _create_service_with_mocked_manager() -> tuple[ModelProviderService, MagicMock]: + manager = MagicMock() + service = ModelProviderService() + service._get_provider_manager = MagicMock(return_value=manager) + return service, manager + + +def _build_provider_configuration( + *, + provider_name: str = "openai", + supported_model_types: list[ModelType] | None = None, + custom_models: list[Any] | None = None, + custom_config_available: bool = True, +) -> SimpleNamespace: + if supported_model_types is None: + supported_model_types = [ModelType.LLM] + return SimpleNamespace( + provider=SimpleNamespace( + provider=provider_name, + label=I18nObject(en_US=provider_name), + description=None, + icon_small=None, + icon_small_dark=None, + background=None, + help=None, + supported_model_types=supported_model_types, + configurate_methods=[], + provider_credential_schema=None, + model_credential_schema=None, + ), + preferred_provider_type=ProviderType.CUSTOM, + custom_configuration=SimpleNamespace( + provider=SimpleNamespace( + current_credential_id="cred-1", + current_credential_name="Credential 1", + available_credentials=[], + ), + models=custom_models, + can_added_models=[], + ), + system_configuration=SimpleNamespace(enabled=False, current_quota_type=None, quota_configurations=[]), + is_custom_configuration_available=lambda: custom_config_available, + ) + + +def test__get_provider_configuration_should_return_configuration_when_provider_exists() -> None: + # Arrange + service, manager = _create_service_with_mocked_manager() + provider_configuration = SimpleNamespace(name="provider-config") + manager.get_configurations.return_value = {"openai": provider_configuration} + + # Act + result = service._get_provider_configuration(tenant_id="tenant-1", provider="openai") + + # Assert + assert result is provider_configuration + + +def test__get_provider_configuration_should_raise_error_when_provider_is_missing() -> None: + # Arrange + service, manager = _create_service_with_mocked_manager() + manager.get_configurations.return_value = {} + + # Act / Assert + with pytest.raises(ProviderNotFoundError, match="does not exist"): + service._get_provider_configuration(tenant_id="tenant-1", provider="missing") + + +def test_get_provider_list_should_filter_by_model_type_and_build_no_configure_status() -> None: + # Arrange + service, manager = _create_service_with_mocked_manager() + allowed = _build_provider_configuration( + provider_name="openai", + supported_model_types=[ModelType.LLM], + custom_config_available=False, + ) + filtered = _build_provider_configuration( + provider_name="embedding", + supported_model_types=[ModelType.TEXT_EMBEDDING], + custom_config_available=True, + ) + manager.get_configurations.return_value = {"openai": allowed, "embedding": filtered} + + # Act + result = service.get_provider_list(tenant_id="tenant-1", model_type=ModelType.LLM.value) + + # Assert + assert len(result) == 1 + assert result[0].provider == "openai" + assert result[0].custom_configuration.status.value == "no-configure" + + +def test_get_models_by_provider_should_wrap_model_entities_with_tenant_context() -> None: + # Arrange + service, manager = _create_service_with_mocked_manager() + + class _Model: + def __init__(self, model_name: str) -> None: + self.model_name = model_name + + def model_dump(self) -> dict[str, Any]: + return { + "model": self.model_name, + "label": {"en_US": self.model_name}, + "model_type": ModelType.LLM, + "features": [], + "fetch_from": FetchFrom.PREDEFINED_MODEL, + "model_properties": {}, + "deprecated": False, + "status": ModelStatus.ACTIVE, + "load_balancing_enabled": False, + "has_invalid_load_balancing_configs": False, + "provider": { + "provider": "openai", + "label": {"en_US": "OpenAI"}, + "icon_small": None, + "icon_small_dark": None, + "supported_model_types": [ModelType.LLM], + }, + } + + provider_configurations = SimpleNamespace( + get_models=MagicMock(return_value=[_Model("gpt-4o"), _Model("gpt-4o-mini")]) + ) + manager.get_configurations.return_value = provider_configurations + + # Act + result = service.get_models_by_provider(tenant_id="tenant-1", provider="openai") + + # Assert + assert len(result) == 2 + assert result[0].model == "gpt-4o" + assert result[1].provider.provider == "openai" + provider_configurations.get_models.assert_called_once_with(provider="openai") + + +@pytest.mark.parametrize( + ("method_name", "method_kwargs", "provider_method_name", "provider_call_kwargs", "provider_return"), + [ + ( + "get_provider_credential", + {"tenant_id": "tenant-1", "provider": "openai", "credential_id": "cred-1"}, + "get_provider_credential", + {"credential_id": "cred-1"}, + {"token": "abc"}, + ), + ( + "validate_provider_credentials", + {"tenant_id": "tenant-1", "provider": "openai", "credentials": {"token": "abc"}}, + "validate_provider_credentials", + ({"token": "abc"},), + None, + ), + ( + "create_provider_credential", + {"tenant_id": "tenant-1", "provider": "openai", "credentials": {"token": "abc"}, "credential_name": "A"}, + "create_provider_credential", + ({"token": "abc"}, "A"), + None, + ), + ( + "update_provider_credential", + { + "tenant_id": "tenant-1", + "provider": "openai", + "credentials": {"token": "abc"}, + "credential_id": "cred-1", + "credential_name": "B", + }, + "update_provider_credential", + {"credential_id": "cred-1", "credentials": {"token": "abc"}, "credential_name": "B"}, + None, + ), + ( + "remove_provider_credential", + {"tenant_id": "tenant-1", "provider": "openai", "credential_id": "cred-1"}, + "delete_provider_credential", + {"credential_id": "cred-1"}, + None, + ), + ( + "switch_active_provider_credential", + {"tenant_id": "tenant-1", "provider": "openai", "credential_id": "cred-1"}, + "switch_active_provider_credential", + {"credential_id": "cred-1"}, + None, + ), + ], +) +def test_provider_credential_methods_should_delegate_to_provider_configuration( + method_name: str, + method_kwargs: dict[str, Any], + provider_method_name: str, + provider_call_kwargs: Any, + provider_return: Any, + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + service = ModelProviderService() + provider_configuration = MagicMock() + getattr(provider_configuration, provider_method_name).return_value = provider_return + get_provider_config_mock = MagicMock(return_value=provider_configuration) + monkeypatch.setattr(service, "_get_provider_configuration", get_provider_config_mock) + + # Act + result = getattr(service, method_name)(**method_kwargs) + + # Assert + get_provider_config_mock.assert_called_once_with("tenant-1", "openai") + provider_method = getattr(provider_configuration, provider_method_name) + if isinstance(provider_call_kwargs, tuple): + provider_method.assert_called_once_with(*provider_call_kwargs) + elif isinstance(provider_call_kwargs, dict): + provider_method.assert_called_once_with(**provider_call_kwargs) + else: + provider_method.assert_called_once_with(provider_call_kwargs) + if method_name == "get_provider_credential": + assert result == {"token": "abc"} + + +@pytest.mark.parametrize( + ("method_name", "method_kwargs", "provider_method_name", "expected_kwargs", "provider_return"), + [ + ( + "get_model_credential", + { + "tenant_id": "tenant-1", + "provider": "openai", + "model_type": ModelType.LLM.value, + "model": "gpt-4o", + "credential_id": "cred-1", + }, + "get_custom_model_credential", + {"model_type": ModelType.LLM, "model": "gpt-4o", "credential_id": "cred-1"}, + {"api_key": "x"}, + ), + ( + "validate_model_credentials", + { + "tenant_id": "tenant-1", + "provider": "openai", + "model_type": ModelType.LLM.value, + "model": "gpt-4o", + "credentials": {"api_key": "x"}, + }, + "validate_custom_model_credentials", + {"model_type": ModelType.LLM, "model": "gpt-4o", "credentials": {"api_key": "x"}}, + None, + ), + ( + "create_model_credential", + { + "tenant_id": "tenant-1", + "provider": "openai", + "model_type": ModelType.LLM.value, + "model": "gpt-4o", + "credentials": {"api_key": "x"}, + "credential_name": "cred-a", + }, + "create_custom_model_credential", + { + "model_type": ModelType.LLM, + "model": "gpt-4o", + "credentials": {"api_key": "x"}, + "credential_name": "cred-a", + }, + None, + ), + ( + "update_model_credential", + { + "tenant_id": "tenant-1", + "provider": "openai", + "model_type": ModelType.LLM.value, + "model": "gpt-4o", + "credentials": {"api_key": "x"}, + "credential_id": "cred-1", + "credential_name": "cred-b", + }, + "update_custom_model_credential", + { + "model_type": ModelType.LLM, + "model": "gpt-4o", + "credentials": {"api_key": "x"}, + "credential_id": "cred-1", + "credential_name": "cred-b", + }, + None, + ), + ( + "remove_model_credential", + { + "tenant_id": "tenant-1", + "provider": "openai", + "model_type": ModelType.LLM.value, + "model": "gpt-4o", + "credential_id": "cred-1", + }, + "delete_custom_model_credential", + {"model_type": ModelType.LLM, "model": "gpt-4o", "credential_id": "cred-1"}, + None, + ), + ( + "switch_active_custom_model_credential", + { + "tenant_id": "tenant-1", + "provider": "openai", + "model_type": ModelType.LLM.value, + "model": "gpt-4o", + "credential_id": "cred-1", + }, + "switch_custom_model_credential", + {"model_type": ModelType.LLM, "model": "gpt-4o", "credential_id": "cred-1"}, + None, + ), + ( + "add_model_credential_to_model_list", + { + "tenant_id": "tenant-1", + "provider": "openai", + "model_type": ModelType.LLM.value, + "model": "gpt-4o", + "credential_id": "cred-1", + }, + "add_model_credential_to_model", + {"model_type": ModelType.LLM, "model": "gpt-4o", "credential_id": "cred-1"}, + None, + ), + ( + "remove_model", + { + "tenant_id": "tenant-1", + "provider": "openai", + "model_type": ModelType.LLM.value, + "model": "gpt-4o", + }, + "delete_custom_model", + {"model_type": ModelType.LLM, "model": "gpt-4o"}, + None, + ), + ], +) +def test_custom_model_methods_should_convert_model_type_and_delegate( + method_name: str, + method_kwargs: dict[str, Any], + provider_method_name: str, + expected_kwargs: dict[str, Any], + provider_return: Any, + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + service = ModelProviderService() + provider_configuration = MagicMock() + getattr(provider_configuration, provider_method_name).return_value = provider_return + get_provider_config_mock = MagicMock(return_value=provider_configuration) + monkeypatch.setattr(service, "_get_provider_configuration", get_provider_config_mock) + + # Act + result = getattr(service, method_name)(**method_kwargs) + + # Assert + get_provider_config_mock.assert_called_once_with("tenant-1", "openai") + getattr(provider_configuration, provider_method_name).assert_called_once_with(**expected_kwargs) + if method_name == "get_model_credential": + assert result == {"api_key": "x"} + + +def test_get_models_by_model_type_should_group_active_non_deprecated_models() -> None: + # Arrange + service, manager = _create_service_with_mocked_manager() + openai_provider = SimpleNamespace( + provider="openai", + label=I18nObject(en_US="OpenAI"), + icon_small=None, + icon_small_dark=None, + ) + anthropic_provider = SimpleNamespace( + provider="anthropic", + label=I18nObject(en_US="Anthropic"), + icon_small=None, + icon_small_dark=None, + ) + models = [ + SimpleNamespace( + provider=openai_provider, + model="gpt-4o", + label=I18nObject(en_US="GPT-4o"), + model_type=ModelType.LLM, + features=[], + fetch_from=FetchFrom.PREDEFINED_MODEL, + model_properties={}, + status=ModelStatus.ACTIVE, + load_balancing_enabled=False, + deprecated=False, + ), + SimpleNamespace( + provider=openai_provider, + model="old-openai", + label=I18nObject(en_US="Old OpenAI"), + model_type=ModelType.LLM, + features=[], + fetch_from=FetchFrom.PREDEFINED_MODEL, + model_properties={}, + status=ModelStatus.ACTIVE, + load_balancing_enabled=False, + deprecated=True, + ), + SimpleNamespace( + provider=anthropic_provider, + model="old-anthropic", + label=I18nObject(en_US="Old Anthropic"), + model_type=ModelType.LLM, + features=[], + fetch_from=FetchFrom.PREDEFINED_MODEL, + model_properties={}, + status=ModelStatus.ACTIVE, + load_balancing_enabled=False, + deprecated=True, + ), + ] + provider_configurations = SimpleNamespace(get_models=MagicMock(return_value=models)) + manager.get_configurations.return_value = provider_configurations + + # Act + result = service.get_models_by_model_type(tenant_id="tenant-1", model_type=ModelType.LLM.value) + + # Assert + provider_configurations.get_models.assert_called_once_with(model_type=ModelType.LLM, only_active=True) + assert len(result) == 1 + assert result[0].provider == "openai" + assert len(result[0].models) == 1 + assert result[0].models[0].model == "gpt-4o" + + +@pytest.mark.parametrize( + ("credentials", "schema", "expected_count"), + [ + (None, None, 0), + ({"api_key": "x"}, None, 0), + ( + {"api_key": "x"}, + SimpleNamespace( + parameter_rules=[ + ParameterRule( + name="temperature", + label=I18nObject(en_US="Temperature"), + type=ParameterType.FLOAT, + ) + ] + ), + 1, + ), + ], +) +def test_get_model_parameter_rules_should_handle_missing_credentials_and_schema( + credentials: dict[str, Any] | None, + schema: Any, + expected_count: int, + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + service = ModelProviderService() + provider_configuration = MagicMock() + provider_configuration.get_current_credentials.return_value = credentials + provider_configuration.get_model_schema.return_value = schema + monkeypatch.setattr(service, "_get_provider_configuration", MagicMock(return_value=provider_configuration)) + + # Act + result = service.get_model_parameter_rules(tenant_id="tenant-1", provider="openai", model="gpt-4o") + + # Assert + assert len(result) == expected_count + provider_configuration.get_current_credentials.assert_called_once_with(model_type=ModelType.LLM, model="gpt-4o") + if credentials: + provider_configuration.get_model_schema.assert_called_once_with( + model_type=ModelType.LLM, + model="gpt-4o", + credentials=credentials, + ) + else: + provider_configuration.get_model_schema.assert_not_called() + + +def test_get_default_model_of_model_type_should_return_response_when_manager_returns_model() -> None: + # Arrange + service, manager = _create_service_with_mocked_manager() + manager.get_default_model.return_value = SimpleNamespace( + model="gpt-4o", + model_type=ModelType.LLM, + provider=SimpleNamespace( + provider="openai", + label=I18nObject(en_US="OpenAI"), + icon_small=None, + supported_model_types=[ModelType.LLM], + ), + ) + + # Act + result = service.get_default_model_of_model_type(tenant_id="tenant-1", model_type=ModelType.LLM.value) + + # Assert + assert result is not None + assert result.model == "gpt-4o" + assert result.provider.provider == "openai" + manager.get_default_model.assert_called_once_with(tenant_id="tenant-1", model_type=ModelType.LLM) + + +def test_get_default_model_of_model_type_should_return_none_when_manager_returns_none() -> None: + # Arrange + service, manager = _create_service_with_mocked_manager() + manager.get_default_model.return_value = None + + # Act + result = service.get_default_model_of_model_type(tenant_id="tenant-1", model_type=ModelType.LLM.value) + + # Assert + assert result is None + + +def test_get_default_model_of_model_type_should_return_none_when_manager_raises_exception() -> None: + # Arrange + service, manager = _create_service_with_mocked_manager() + manager.get_default_model.side_effect = RuntimeError("boom") + + # Act + result = service.get_default_model_of_model_type(tenant_id="tenant-1", model_type=ModelType.LLM.value) + + # Assert + assert result is None + + +def test_update_default_model_of_model_type_should_delegate_to_provider_manager() -> None: + # Arrange + service, manager = _create_service_with_mocked_manager() + + # Act + service.update_default_model_of_model_type( + tenant_id="tenant-1", + model_type=ModelType.LLM.value, + provider="openai", + model="gpt-4o", + ) + + # Assert + manager.update_default_model_record.assert_called_once_with( + tenant_id="tenant-1", + model_type=ModelType.LLM, + provider="openai", + model="gpt-4o", + ) + + +def test_get_model_provider_icon_should_fetch_icon_bytes_from_factory(monkeypatch: pytest.MonkeyPatch) -> None: + # Arrange + service = ModelProviderService() + factory_instance = MagicMock() + factory_instance.get_provider_icon.return_value = (b"icon-bytes", "image/png") + factory_constructor = MagicMock(return_value=factory_instance) + monkeypatch.setattr(service_module, "create_plugin_model_provider_factory", factory_constructor) + + # Act + result = service.get_model_provider_icon( + tenant_id="tenant-1", + provider="openai", + icon_type="icon_small", + lang="en_US", + ) + + # Assert + factory_constructor.assert_called_once_with(tenant_id="tenant-1") + factory_instance.get_provider_icon.assert_called_once_with("openai", "icon_small", "en_US") + assert result == (b"icon-bytes", "image/png") + + +def test_switch_preferred_provider_should_convert_enum_and_delegate(monkeypatch: pytest.MonkeyPatch) -> None: + # Arrange + service = ModelProviderService() + provider_configuration = MagicMock() + monkeypatch.setattr(service, "_get_provider_configuration", MagicMock(return_value=provider_configuration)) + + # Act + service.switch_preferred_provider( + tenant_id="tenant-1", + provider="openai", + preferred_provider_type=ProviderType.SYSTEM.value, + ) + + # Assert + provider_configuration.switch_preferred_provider_type.assert_called_once_with(ProviderType.SYSTEM) + + +@pytest.mark.parametrize( + ("method_name", "provider_method_name"), + [ + ("enable_model", "enable_model"), + ("disable_model", "disable_model"), + ], +) +def test_model_enablement_methods_should_convert_model_type_and_delegate( + method_name: str, + provider_method_name: str, + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + service = ModelProviderService() + provider_configuration = MagicMock() + monkeypatch.setattr(service, "_get_provider_configuration", MagicMock(return_value=provider_configuration)) + + # Act + getattr(service, method_name)( + tenant_id="tenant-1", + provider="openai", + model="gpt-4o", + model_type=ModelType.LLM.value, + ) + + # Assert + getattr(provider_configuration, provider_method_name).assert_called_once_with( + model="gpt-4o", + model_type=ModelType.LLM, + ) diff --git a/api/tests/unit_tests/services/test_recommended_app_service.py b/api/tests/unit_tests/services/test_recommended_app_service.py index 12f4c0b982..12bc84db87 100644 --- a/api/tests/unit_tests/services/test_recommended_app_service.py +++ b/api/tests/unit_tests/services/test_recommended_app_service.py @@ -316,7 +316,7 @@ class TestRecommendedAppServiceGetDetail: mock_factory_class.get_recommend_app_factory.return_value = mock_factory # Act - result = RecommendedAppService.get_recommend_app_detail(app_id) + result = _recommendation_detail(RecommendedAppService.get_recommend_app_detail(app_id)) # Assert assert result == expected_detail @@ -346,7 +346,7 @@ class TestRecommendedAppServiceGetDetail: mock_factory_class.get_recommend_app_factory.return_value = mock_factory # Act - result = RecommendedAppService.get_recommend_app_detail(app_id) + result = _recommendation_detail(RecommendedAppService.get_recommend_app_detail(app_id)) # Assert assert result["name"] == f"App from {mode}" @@ -369,7 +369,7 @@ class TestRecommendedAppServiceGetDetail: mock_factory_class.get_recommend_app_factory.return_value = mock_factory # Act - result = RecommendedAppService.get_recommend_app_detail(app_id) + result = _recommendation_detail(RecommendedAppService.get_recommend_app_detail(app_id)) # Assert assert result is None @@ -392,7 +392,7 @@ class TestRecommendedAppServiceGetDetail: mock_factory_class.get_recommend_app_factory.return_value = mock_factory # Act - result = RecommendedAppService.get_recommend_app_detail(app_id) + result = _recommendation_detail(RecommendedAppService.get_recommend_app_detail(app_id)) # Assert assert result == {} @@ -432,9 +432,197 @@ class TestRecommendedAppServiceGetDetail: mock_factory_class.get_recommend_app_factory.return_value = mock_factory # Act - result = RecommendedAppService.get_recommend_app_detail(app_id) + result = _recommendation_detail(RecommendedAppService.get_recommend_app_detail(app_id)) # Assert assert result["model_config"] == complex_model_config assert len(result["workflows"]) == 2 assert len(result["tools"]) == 3 + + +# === Merged from test_recommended_app_service_additional.py === + + +from types import SimpleNamespace +from typing import Any, cast +from unittest.mock import MagicMock + +import pytest + +from services import recommended_app_service as service_module +from services.recommended_app_service import RecommendedAppService + + +def _recommendation_detail(result: dict[str, Any] | None) -> dict[str, Any]: + return cast(dict[str, Any], result) + + +@pytest.fixture +def mocked_db_session(monkeypatch: pytest.MonkeyPatch) -> MagicMock: + # Arrange + session = MagicMock() + monkeypatch.setattr(service_module, "db", SimpleNamespace(session=session)) + + # Assert + return session + + +def _mock_factory_for_apps( + monkeypatch: pytest.MonkeyPatch, + *, + mode: str, + result: dict[str, Any], + fallback_result: dict[str, Any] | None = None, +) -> tuple[MagicMock, MagicMock]: + retrieval_instance = MagicMock() + retrieval_instance.get_recommended_apps_and_categories.return_value = result + retrieval_factory = MagicMock(return_value=retrieval_instance) + monkeypatch.setattr(service_module.dify_config, "HOSTED_FETCH_APP_TEMPLATES_MODE", mode, raising=False) + monkeypatch.setattr( + service_module.RecommendAppRetrievalFactory, + "get_recommend_app_factory", + MagicMock(return_value=retrieval_factory), + ) + + builtin_instance = MagicMock() + if fallback_result is not None: + builtin_instance.fetch_recommended_apps_from_builtin.return_value = fallback_result + monkeypatch.setattr( + service_module.RecommendAppRetrievalFactory, + "get_buildin_recommend_app_retrieval", + MagicMock(return_value=builtin_instance), + ) + return retrieval_instance, builtin_instance + + +def test_get_recommended_apps_and_categories_should_not_query_trial_table_when_trial_feature_disabled( + monkeypatch: pytest.MonkeyPatch, + mocked_db_session: MagicMock, +) -> None: + # Arrange + expected = {"recommended_apps": [{"app_id": "app-1"}], "categories": ["all"]} + retrieval_instance, builtin_instance = _mock_factory_for_apps( + monkeypatch, + mode="remote", + result=expected, + ) + monkeypatch.setattr( + service_module.FeatureService, + "get_system_features", + MagicMock(return_value=SimpleNamespace(enable_trial_app=False)), + ) + + # Act + result = RecommendedAppService.get_recommended_apps_and_categories("en-US") + + # Assert + assert result == expected + retrieval_instance.get_recommended_apps_and_categories.assert_called_once_with("en-US") + builtin_instance.fetch_recommended_apps_from_builtin.assert_not_called() + mocked_db_session.scalar.assert_not_called() + + +def test_get_recommended_apps_and_categories_should_fallback_and_enrich_can_trial_when_trial_feature_enabled( + monkeypatch: pytest.MonkeyPatch, + mocked_db_session: MagicMock, +) -> None: + # Arrange + remote_result = {"recommended_apps": [], "categories": []} + fallback_result = {"recommended_apps": [{"app_id": "app-1"}, {"app_id": "app-2"}], "categories": ["all"]} + _, builtin_instance = _mock_factory_for_apps( + monkeypatch, + mode="remote", + result=remote_result, + fallback_result=fallback_result, + ) + monkeypatch.setattr( + service_module.FeatureService, + "get_system_features", + MagicMock(return_value=SimpleNamespace(enable_trial_app=True)), + ) + mocked_db_session.scalar.side_effect = [SimpleNamespace(id="trial-app"), None] + + # Act + result = RecommendedAppService.get_recommended_apps_and_categories("ja-JP") + + # Assert + builtin_instance.fetch_recommended_apps_from_builtin.assert_called_once_with("en-US") + assert result["recommended_apps"][0]["can_trial"] is True + assert result["recommended_apps"][1]["can_trial"] is False + assert mocked_db_session.scalar.call_count == 2 + + +@pytest.mark.parametrize( + ("trial_query_result", "expected_can_trial"), + [ + (SimpleNamespace(id="trial"), True), + (None, False), + ], +) +def test_get_recommend_app_detail_should_set_can_trial_when_trial_feature_enabled( + monkeypatch: pytest.MonkeyPatch, + mocked_db_session: MagicMock, + trial_query_result: Any, + expected_can_trial: bool, +) -> None: + # Arrange + detail = {"id": "app-1", "name": "Test App"} + retrieval_instance = MagicMock() + retrieval_instance.get_recommend_app_detail.return_value = detail + retrieval_factory = MagicMock(return_value=retrieval_instance) + monkeypatch.setattr(service_module.dify_config, "HOSTED_FETCH_APP_TEMPLATES_MODE", "remote", raising=False) + monkeypatch.setattr( + service_module.RecommendAppRetrievalFactory, + "get_recommend_app_factory", + MagicMock(return_value=retrieval_factory), + ) + monkeypatch.setattr( + service_module.FeatureService, + "get_system_features", + MagicMock(return_value=SimpleNamespace(enable_trial_app=True)), + ) + mocked_db_session.scalar.return_value = trial_query_result + + # Act + result = cast(dict[str, Any], RecommendedAppService.get_recommend_app_detail("app-1")) + + # Assert + assert result["id"] == "app-1" + assert result["can_trial"] is expected_can_trial + mocked_db_session.scalar.assert_called_once() + + +def test_add_trial_app_record_should_increment_count_when_existing_record_found( + mocked_db_session: MagicMock, +) -> None: + # Arrange + existing_record = SimpleNamespace(count=3) + mocked_db_session.scalar.return_value = existing_record + + # Act + RecommendedAppService.add_trial_app_record("app-1", "account-1") + + # Assert + assert existing_record.count == 4 + mocked_db_session.scalar.assert_called_once() + mocked_db_session.commit.assert_called_once() + mocked_db_session.add.assert_not_called() + + +def test_add_trial_app_record_should_create_new_record_when_no_existing_record( + mocked_db_session: MagicMock, +) -> None: + # Arrange + mocked_db_session.scalar.return_value = None + + # Act + RecommendedAppService.add_trial_app_record("app-2", "account-2") + + # Assert + mocked_db_session.scalar.assert_called_once() + mocked_db_session.add.assert_called_once() + added = mocked_db_session.add.call_args.args[0] + assert added.app_id == "app-2" + assert added.account_id == "account-2" + assert added.count == 1 + mocked_db_session.commit.assert_called_once() diff --git a/api/tests/unit_tests/services/test_schedule_service.py b/api/tests/unit_tests/services/test_schedule_service.py index e28965ea2c..2a78876da6 100644 --- a/api/tests/unit_tests/services/test_schedule_service.py +++ b/api/tests/unit_tests/services/test_schedule_service.py @@ -1,12 +1,15 @@ import unittest from datetime import UTC, datetime +from types import SimpleNamespace +from typing import Any, cast from unittest.mock import MagicMock, Mock, patch import pytest from sqlalchemy.orm import Session +from core.trigger.constants import TRIGGER_SCHEDULE_NODE_TYPE from core.workflow.nodes.trigger_schedule.entities import ScheduleConfig, SchedulePlanUpdate, VisualConfig -from core.workflow.nodes.trigger_schedule.exc import ScheduleConfigError +from core.workflow.nodes.trigger_schedule.exc import ScheduleConfigError, ScheduleNotFoundError from events.event_handlers.sync_workflow_schedule_when_app_published import ( sync_schedule_from_workflow, ) @@ -14,6 +17,8 @@ from libs.schedule_utils import calculate_next_run_at, convert_12h_to_24h from models.account import Account, TenantAccountJoin from models.trigger import WorkflowSchedulePlan from models.workflow import Workflow +from services.errors.account import AccountNotFoundError +from services.trigger import schedule_service as service_module from services.trigger.schedule_service import ScheduleService @@ -775,5 +780,158 @@ class TestSyncScheduleFromWorkflow(unittest.TestCase): mock_session.commit.assert_called_once() +@pytest.fixture +def session_mock() -> MagicMock: + return MagicMock(spec=Session) + + +def _workflow(**kwargs: Any) -> Workflow: + return cast(Workflow, SimpleNamespace(**kwargs)) + + +def test_update_schedule_should_update_only_node_id_without_recomputing_time( + session_mock: MagicMock, + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + schedule = MagicMock(spec=WorkflowSchedulePlan) + schedule.cron_expression = "0 10 * * *" + schedule.timezone = "UTC" + session_mock.get.return_value = schedule + + next_run_mock = MagicMock(return_value=datetime(2026, 1, 1, 10, 0, tzinfo=UTC)) + monkeypatch.setattr(service_module, "calculate_next_run_at", next_run_mock) + + # Act + result = ScheduleService.update_schedule( + session=session_mock, + schedule_id="schedule-1", + updates=SchedulePlanUpdate(node_id="node-new"), + ) + + # Assert + assert result is schedule + assert schedule.node_id == "node-new" + next_run_mock.assert_not_called() + session_mock.flush.assert_called_once() + + +def test_get_tenant_owner_should_raise_when_account_record_missing(session_mock: MagicMock) -> None: + # Arrange + join = SimpleNamespace(account_id="account-404") + session_mock.execute.return_value.scalar_one_or_none.return_value = join + session_mock.get.return_value = None + + # Act / Assert + with pytest.raises(AccountNotFoundError, match="Account not found: account-404"): + ScheduleService.get_tenant_owner(session=session_mock, tenant_id="tenant-1") + + +def test_get_tenant_owner_should_raise_when_no_owner_or_admin_found(session_mock: MagicMock) -> None: + # Arrange + session_mock.execute.return_value.scalar_one_or_none.side_effect = [None, None] + + # Act / Assert + with pytest.raises(AccountNotFoundError, match="Account not found for tenant: tenant-1"): + ScheduleService.get_tenant_owner(session=session_mock, tenant_id="tenant-1") + + +def test_update_next_run_at_should_raise_when_schedule_not_found(session_mock: MagicMock) -> None: + # Arrange + session_mock.get.return_value = None + + # Act / Assert + with pytest.raises(ScheduleNotFoundError, match="Schedule not found: schedule-1"): + ScheduleService.update_next_run_at(session=session_mock, schedule_id="schedule-1") + + +def test_to_schedule_config_should_build_from_cron_mode() -> None: + # Arrange + node_config: dict[str, Any] = { + "id": "node-1", + "data": { + "mode": "cron", + "cron_expression": "0 12 * * *", + "timezone": "Asia/Kolkata", + }, + } + + # Act + result = ScheduleService.to_schedule_config(node_config=node_config) + + # Assert + assert result.node_id == "node-1" + assert result.cron_expression == "0 12 * * *" + assert result.timezone == "Asia/Kolkata" + + +def test_to_schedule_config_should_raise_for_cron_mode_without_expression() -> None: + # Arrange + node_config = {"id": "node-1", "data": {"mode": "cron", "cron_expression": ""}} + + # Act / Assert + with pytest.raises(ScheduleConfigError, match="Cron expression is required for cron mode"): + ScheduleService.to_schedule_config(node_config=node_config) + + +def test_to_schedule_config_should_build_from_visual_mode(monkeypatch: pytest.MonkeyPatch) -> None: + # Arrange + node_config = { + "id": "node-1", + "data": { + "mode": "visual", + "frequency": "daily", + "visual_config": {"time": "9:30 AM"}, + "timezone": "UTC", + }, + } + monkeypatch.setattr(ScheduleService, "visual_to_cron", MagicMock(return_value="30 9 * * *")) + + # Act + result = ScheduleService.to_schedule_config(node_config=node_config) + + # Assert + assert result.cron_expression == "30 9 * * *" + + +def test_to_schedule_config_should_raise_for_invalid_mode() -> None: + # Arrange + node_config = {"id": "node-1", "data": {"mode": "manual"}} + + # Act / Assert + with pytest.raises(ScheduleConfigError, match="Invalid schedule mode: manual"): + ScheduleService.to_schedule_config(node_config=node_config) + + +def test_extract_schedule_config_should_raise_when_graph_is_empty() -> None: + # Arrange + workflow = _workflow(graph_dict={}) + + # Act / Assert + with pytest.raises(ScheduleConfigError, match="Workflow graph is empty"): + ScheduleService.extract_schedule_config(workflow=workflow) + + +def test_extract_schedule_config_should_raise_when_mode_invalid() -> None: + # Arrange + workflow = _workflow( + graph_dict={ + "nodes": [ + { + "id": "schedule-1", + "data": { + "type": TRIGGER_SCHEDULE_NODE_TYPE, + "mode": "invalid", + }, + } + ] + } + ) + + # Act / Assert + with pytest.raises(ScheduleConfigError, match="Invalid schedule mode: invalid"): + ScheduleService.extract_schedule_config(workflow=workflow) + + if __name__ == "__main__": unittest.main() diff --git a/api/tests/unit_tests/services/test_variable_truncator.py b/api/tests/unit_tests/services/test_variable_truncator.py index 9c23135225..27602bb1cc 100644 --- a/api/tests/unit_tests/services/test_variable_truncator.py +++ b/api/tests/unit_tests/services/test_variable_truncator.py @@ -12,6 +12,7 @@ This test suite covers all functionality of the current VariableTruncator includ import functools import json import uuid +from collections.abc import Mapping from typing import Any from uuid import uuid4 @@ -199,14 +200,14 @@ class TestArrayTruncation: def test_small_array_no_truncation(self, small_truncator: VariableTruncator): """Test that small arrays are not truncated.""" - small_array = [1, 2] + small_array: list[object] = [1, 2] result = small_truncator._truncate_array(small_array, 1000) assert result.value == small_array assert result.truncated is False def test_array_element_limit_truncation(self, small_truncator: VariableTruncator): """Test that arrays over element limit are truncated.""" - large_array = [1, 2, 3, 4, 5, 6] # Exceeds limit of 3 + large_array: list[object] = [1, 2, 3, 4, 5, 6] # Exceeds limit of 3 result = small_truncator._truncate_array(large_array, 1000) assert result.truncated is True @@ -215,7 +216,7 @@ class TestArrayTruncation: def test_array_size_budget_truncation(self, small_truncator: VariableTruncator): """Test array truncation due to size budget constraints.""" # Create array with strings that will exceed size budget - large_strings = ["very long string " * 5, "another long string " * 5] + large_strings: list[object] = ["very long string " * 5, "another long string " * 5] result = small_truncator._truncate_array(large_strings, 50) assert result.truncated is True @@ -276,10 +277,10 @@ class TestObjectTruncation: # Values should be truncated if they exist for key, value in result.value.items(): - if isinstance(value, str): - original_value = obj_with_long_values[key] - # Value should be same or smaller - assert len(value) <= len(original_value) + assert isinstance(value, str) + original_value = obj_with_long_values[key] + # Value should be same or smaller + assert len(value) <= len(original_value) def test_object_key_dropping(self, small_truncator): """Test object truncation where keys are dropped due to size constraints.""" @@ -506,10 +507,9 @@ class TestEdgeCases: truncator = VariableTruncator(string_length_limit=10) # Unicode characters - unicode_text = "🌍🚀🌍🚀🌍🚀🌍🚀🌍🚀" # Each emoji counts as 1 character + unicode_text = "你好世界你好世界你好世界" # Multi-byte UTF-8 characters result = truncator.truncate(StringSegment(value=unicode_text)) - if len(unicode_text) > 10: - assert result.truncated is True + assert result.truncated is True # Special JSON characters special_chars = '{"key": "value with \\"quotes\\" and \\n newlines"}' @@ -631,13 +631,12 @@ class TestIntegrationScenarios: result = truncator.truncate(segment) assert isinstance(result, TruncationResult) - # Should handle all data types appropriately - if result.truncated: - # Verify the result is smaller or equal than original - original_size = truncator.calculate_json_size(mixed_data) - if isinstance(result.result, ObjectSegment): - result_size = truncator.calculate_json_size(result.result.value) - assert result_size <= original_size + assert result.truncated is True + assert isinstance(result.result, ObjectSegment) + # Verify the result is smaller or equal than original + original_size = truncator.calculate_json_size(mixed_data) + result_size = truncator.calculate_json_size(result.result.value) + assert result_size <= original_size def test_file_and_array_file_variable_mapping(self, file): truncator = VariableTruncator(string_length_limit=30, array_element_limit=3, max_size_bytes=300) @@ -675,3 +674,229 @@ def test_dummy_variable_truncator_methods(): assert isinstance(result, TruncationResult) assert result.result == segment assert result.truncated is False + + +# === Merged from test_variable_truncator_additional.py === + + +from typing import Any + +import pytest +from graphon.nodes.variable_assigner.common.helpers import UpdatedVariable +from graphon.variables.segments import IntegerSegment, ObjectSegment, StringSegment +from graphon.variables.types import SegmentType + +from services import variable_truncator as truncator_module +from services.variable_truncator import BaseTruncator, TruncationResult, VariableTruncator + + +class _AbstractPassthrough(BaseTruncator): + def truncate(self, segment: Any) -> TruncationResult: + # Arrange / Act + return super().truncate(segment) # type: ignore[misc] + + def truncate_variable_mapping(self, v: Mapping[str, Any]) -> tuple[Mapping[str, Any], bool]: + # Arrange / Act + return super().truncate_variable_mapping(v) # type: ignore[misc] + + +def test_base_truncator_methods_should_execute_abstract_placeholders() -> None: + # Arrange + passthrough = _AbstractPassthrough() + + # Act + truncate_result = passthrough.truncate(StringSegment(value="x")) + mapping_result = passthrough.truncate_variable_mapping({"a": 1}) + + # Assert + assert truncate_result is None + assert mapping_result is None + + +def test_default_should_use_dify_config_limits(monkeypatch: pytest.MonkeyPatch) -> None: + # Arrange + monkeypatch.setattr(truncator_module.dify_config, "WORKFLOW_VARIABLE_TRUNCATION_MAX_SIZE", 111) + monkeypatch.setattr(truncator_module.dify_config, "WORKFLOW_VARIABLE_TRUNCATION_ARRAY_LENGTH", 7) + monkeypatch.setattr(truncator_module.dify_config, "WORKFLOW_VARIABLE_TRUNCATION_STRING_LENGTH", 33) + + # Act + truncator = VariableTruncator.default() + + # Assert + assert truncator._max_size_bytes == 111 + assert truncator._array_element_limit == 7 + assert truncator._string_length_limit == 33 + + +def test_truncate_variable_mapping_should_mark_over_budget_keys_with_ellipsis() -> None: + # Arrange + truncator = VariableTruncator(max_size_bytes=5) + mapping = {"very_long_key": "value"} + + # Act + result, truncated = truncator.truncate_variable_mapping(mapping) + + # Assert + assert result == {"very_long_key": "..."} + assert truncated is True + + +def test_truncate_variable_mapping_should_handle_segment_values() -> None: + # Arrange + truncator = VariableTruncator(max_size_bytes=100) + mapping = {"seg": StringSegment(value="hello")} + + # Act + result, truncated = truncator.truncate_variable_mapping(mapping) + + # Assert + assert isinstance(result["seg"], StringSegment) + assert result["seg"].value == "hello" + assert truncated is False + + +@pytest.mark.parametrize( + ("value", "expected"), + [ + (None, False), + (True, False), + (1, False), + (1.5, False), + ("x", True), + ({"k": "v"}, True), + ], +) +def test_json_value_needs_truncation_should_match_expected_rules(value: Any, expected: bool) -> None: + # Arrange + + # Act + result = VariableTruncator._json_value_needs_truncation(value) + + # Assert + assert result is expected + + +def test_truncate_should_use_string_fallback_when_truncated_value_size_exceeds_limit( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + truncator = VariableTruncator(max_size_bytes=10) + forced_result = truncator_module._PartResult( + value=StringSegment(value="this is too long"), + value_size=100, + truncated=True, + ) + monkeypatch.setattr(truncator, "_truncate_segment", lambda *_args, **_kwargs: forced_result) + + # Act + result = truncator.truncate(StringSegment(value="input")) + + # Assert + assert result.truncated is True + assert isinstance(result.result, StringSegment) + assert not result.result.value.startswith('"') + + +def test_truncate_segment_should_raise_assertion_for_unexpected_truncatable_segment( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + truncator = VariableTruncator() + monkeypatch.setattr(VariableTruncator, "_segment_need_truncation", lambda _segment: True) + + # Act / Assert + with pytest.raises(AssertionError): + truncator._truncate_segment(IntegerSegment(value=1), 10) + + +def test_calculate_json_size_should_unwrap_segment_values() -> None: + # Arrange + segment = StringSegment(value="abc") + + # Act + size = VariableTruncator.calculate_json_size(segment) + + # Assert + assert size == VariableTruncator.calculate_json_size("abc") + + +def test_calculate_json_size_should_handle_updated_variable_instances() -> None: + # Arrange + updated = UpdatedVariable(name="n", selector=["node", "var"], value_type=SegmentType.STRING, new_value="v") + + # Act + size = VariableTruncator.calculate_json_size(updated) + + # Assert + assert size > 0 + + +def test_maybe_qa_structure_should_validate_shape() -> None: + # Arrange + + # Act / Assert + assert VariableTruncator._maybe_qa_structure({"qa_chunks": []}) is True + assert VariableTruncator._maybe_qa_structure({"qa_chunks": "not-list"}) is False + assert VariableTruncator._maybe_qa_structure({}) is False + + +def test_maybe_parent_child_structure_should_validate_shape() -> None: + # Arrange + + # Act / Assert + assert VariableTruncator._maybe_parent_child_structure({"parent_mode": "full", "parent_child_chunks": []}) is True + assert VariableTruncator._maybe_parent_child_structure({"parent_mode": 1, "parent_child_chunks": []}) is False + assert ( + VariableTruncator._maybe_parent_child_structure({"parent_mode": "full", "parent_child_chunks": "bad"}) is False + ) + + +def test_truncate_object_should_truncate_segment_values_inside_object() -> None: + # Arrange + truncator = VariableTruncator(string_length_limit=8, max_size_bytes=30) + mapping = {"s": StringSegment(value="long-content")} + + # Act + result = truncator._truncate_object(mapping, 20) + + # Assert + assert result.truncated is True + assert isinstance(result.value["s"], StringSegment) + + +def test_truncate_json_primitives_should_handle_updated_variable_input() -> None: + # Arrange + truncator = VariableTruncator(max_size_bytes=100) + updated = UpdatedVariable(name="n", selector=["node", "var"], value_type=SegmentType.STRING, new_value="v") + + # Act + result = truncator._truncate_json_primitives(updated, 100) + + # Assert + assert isinstance(result.value, dict) + + +def test_truncate_json_primitives_should_raise_assertion_for_unsupported_value_type() -> None: + # Arrange + truncator = VariableTruncator() + + # Act / Assert + with pytest.raises(AssertionError): + truncator._truncate_json_primitives(object(), 100) # type: ignore[arg-type] + + +def test_truncate_should_apply_json_string_fallback_for_large_non_string_segment( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + truncator = VariableTruncator(max_size_bytes=10) + forced_segment = ObjectSegment(value={"k": "v"}) + forced_result = truncator_module._PartResult(value=forced_segment, value_size=100, truncated=True) + monkeypatch.setattr(truncator, "_truncate_segment", lambda *_args, **_kwargs: forced_result) + + # Act + result = truncator.truncate(ObjectSegment(value={"a": "b"})) + + # Assert + assert result.truncated is True + assert isinstance(result.result, StringSegment) diff --git a/api/tests/unit_tests/services/test_webhook_service.py b/api/tests/unit_tests/services/test_webhook_service.py index ffdcc046f9..78049182ad 100644 --- a/api/tests/unit_tests/services/test_webhook_service.py +++ b/api/tests/unit_tests/services/test_webhook_service.py @@ -559,3 +559,757 @@ class TestWebhookServiceUnit: result = _prepare_webhook_execution("test_webhook", is_debug=True) assert result == (mock_trigger, mock_workflow, mock_config, mock_data, None) + + +# === Merged from test_webhook_service_additional.py === + + +from types import SimpleNamespace +from typing import Any, cast +from unittest.mock import MagicMock + +import pytest +from flask import Flask +from graphon.variables.types import SegmentType +from werkzeug.datastructures import FileStorage +from werkzeug.exceptions import RequestEntityTooLarge + +from core.workflow.nodes.trigger_webhook.entities import ( + ContentType, + WebhookBodyParameter, + WebhookData, + WebhookParameter, +) +from models.enums import AppTriggerStatus +from models.model import App +from models.trigger import WorkflowWebhookTrigger +from models.workflow import Workflow +from services.errors.app import QuotaExceededError +from services.trigger import webhook_service as service_module +from services.trigger.webhook_service import WebhookService + + +class _FakeQuery: + def __init__(self, result: Any) -> None: + self._result = result + + def where(self, *args: Any, **kwargs: Any) -> "_FakeQuery": + return self + + def filter(self, *args: Any, **kwargs: Any) -> "_FakeQuery": + return self + + def order_by(self, *args: Any, **kwargs: Any) -> "_FakeQuery": + return self + + def first(self) -> Any: + return self._result + + +class _SessionContext: + def __init__(self, session: Any) -> None: + self._session = session + + def __enter__(self) -> Any: + return self._session + + def __exit__(self, exc_type: Any, exc: Any, tb: Any) -> bool: + return False + + +@pytest.fixture +def flask_app() -> Flask: + return Flask(__name__) + + +def _patch_session(monkeypatch: pytest.MonkeyPatch, session: Any) -> None: + monkeypatch.setattr(service_module, "db", SimpleNamespace(engine=MagicMock(), session=MagicMock())) + monkeypatch.setattr(service_module, "Session", lambda *args, **kwargs: _SessionContext(session)) + + +def _workflow_trigger(**kwargs: Any) -> WorkflowWebhookTrigger: + return cast(WorkflowWebhookTrigger, SimpleNamespace(**kwargs)) + + +def _workflow(**kwargs: Any) -> Workflow: + return cast(Workflow, SimpleNamespace(**kwargs)) + + +def _app(**kwargs: Any) -> App: + return cast(App, SimpleNamespace(**kwargs)) + + +def test_get_webhook_trigger_and_workflow_should_raise_when_webhook_not_found(monkeypatch: pytest.MonkeyPatch) -> None: + # Arrange + fake_session = MagicMock() + fake_session.query.return_value = _FakeQuery(None) + _patch_session(monkeypatch, fake_session) + + # Act / Assert + with pytest.raises(ValueError, match="Webhook not found"): + WebhookService.get_webhook_trigger_and_workflow("webhook-1") + + +def test_get_webhook_trigger_and_workflow_should_raise_when_app_trigger_not_found( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + webhook_trigger = SimpleNamespace(app_id="app-1", node_id="node-1") + fake_session = MagicMock() + fake_session.query.side_effect = [_FakeQuery(webhook_trigger), _FakeQuery(None)] + _patch_session(monkeypatch, fake_session) + + # Act / Assert + with pytest.raises(ValueError, match="App trigger not found"): + WebhookService.get_webhook_trigger_and_workflow("webhook-1") + + +def test_get_webhook_trigger_and_workflow_should_raise_when_app_trigger_rate_limited( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + webhook_trigger = SimpleNamespace(app_id="app-1", node_id="node-1") + app_trigger = SimpleNamespace(status=AppTriggerStatus.RATE_LIMITED) + fake_session = MagicMock() + fake_session.query.side_effect = [_FakeQuery(webhook_trigger), _FakeQuery(app_trigger)] + _patch_session(monkeypatch, fake_session) + + # Act / Assert + with pytest.raises(ValueError, match="rate limited"): + WebhookService.get_webhook_trigger_and_workflow("webhook-1") + + +def test_get_webhook_trigger_and_workflow_should_raise_when_app_trigger_disabled( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + webhook_trigger = SimpleNamespace(app_id="app-1", node_id="node-1") + app_trigger = SimpleNamespace(status=AppTriggerStatus.DISABLED) + fake_session = MagicMock() + fake_session.query.side_effect = [_FakeQuery(webhook_trigger), _FakeQuery(app_trigger)] + _patch_session(monkeypatch, fake_session) + + # Act / Assert + with pytest.raises(ValueError, match="disabled"): + WebhookService.get_webhook_trigger_and_workflow("webhook-1") + + +def test_get_webhook_trigger_and_workflow_should_raise_when_workflow_not_found(monkeypatch: pytest.MonkeyPatch) -> None: + # Arrange + webhook_trigger = SimpleNamespace(app_id="app-1", node_id="node-1") + app_trigger = SimpleNamespace(status=AppTriggerStatus.ENABLED) + fake_session = MagicMock() + fake_session.query.side_effect = [_FakeQuery(webhook_trigger), _FakeQuery(app_trigger), _FakeQuery(None)] + _patch_session(monkeypatch, fake_session) + + # Act / Assert + with pytest.raises(ValueError, match="Workflow not found"): + WebhookService.get_webhook_trigger_and_workflow("webhook-1") + + +def test_get_webhook_trigger_and_workflow_should_return_values_for_non_debug_mode( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + webhook_trigger = SimpleNamespace(app_id="app-1", node_id="node-1") + app_trigger = SimpleNamespace(status=AppTriggerStatus.ENABLED) + workflow = MagicMock() + workflow.get_node_config_by_id.return_value = {"data": {"key": "value"}} + + fake_session = MagicMock() + fake_session.query.side_effect = [_FakeQuery(webhook_trigger), _FakeQuery(app_trigger), _FakeQuery(workflow)] + _patch_session(monkeypatch, fake_session) + + # Act + got_trigger, got_workflow, got_node_config = WebhookService.get_webhook_trigger_and_workflow("webhook-1") + + # Assert + assert got_trigger is webhook_trigger + assert got_workflow is workflow + assert got_node_config == {"data": {"key": "value"}} + + +def test_get_webhook_trigger_and_workflow_should_return_values_for_debug_mode(monkeypatch: pytest.MonkeyPatch) -> None: + # Arrange + webhook_trigger = SimpleNamespace(app_id="app-1", node_id="node-1") + workflow = MagicMock() + workflow.get_node_config_by_id.return_value = {"data": {"mode": "debug"}} + + fake_session = MagicMock() + fake_session.query.side_effect = [_FakeQuery(webhook_trigger), _FakeQuery(workflow)] + _patch_session(monkeypatch, fake_session) + + # Act + got_trigger, got_workflow, got_node_config = WebhookService.get_webhook_trigger_and_workflow( + "webhook-1", is_debug=True + ) + + # Assert + assert got_trigger is webhook_trigger + assert got_workflow is workflow + assert got_node_config == {"data": {"mode": "debug"}} + + +def test_extract_webhook_data_should_use_text_fallback_for_unknown_content_type( + flask_app: Flask, + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + warning_mock = MagicMock() + monkeypatch.setattr(service_module.logger, "warning", warning_mock) + webhook_trigger = MagicMock() + + # Act + with flask_app.test_request_context( + "/webhook", + method="POST", + headers={"Content-Type": "application/vnd.custom"}, + data="plain content", + ): + result = WebhookService.extract_webhook_data(webhook_trigger) + + # Assert + assert result["body"] == {"raw": "plain content"} + warning_mock.assert_called_once() + + +def test_extract_webhook_data_should_raise_for_request_too_large( + flask_app: Flask, + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + monkeypatch.setattr(service_module.dify_config, "WEBHOOK_REQUEST_BODY_MAX_SIZE", 1) + + # Act / Assert + with flask_app.test_request_context("/webhook", method="POST", data="ab"): + with pytest.raises(RequestEntityTooLarge): + WebhookService.extract_webhook_data(MagicMock()) + + +def test_extract_octet_stream_body_should_return_none_when_empty_payload(flask_app: Flask) -> None: + # Arrange + webhook_trigger = MagicMock() + + # Act + with flask_app.test_request_context("/webhook", method="POST", data=b""): + body, files = WebhookService._extract_octet_stream_body(webhook_trigger) + + # Assert + assert body == {"raw": None} + assert files == {} + + +def test_extract_octet_stream_body_should_return_none_when_processing_raises( + flask_app: Flask, + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + webhook_trigger = MagicMock() + monkeypatch.setattr(WebhookService, "_detect_binary_mimetype", MagicMock(return_value="application/octet-stream")) + monkeypatch.setattr(WebhookService, "_create_file_from_binary", MagicMock(side_effect=RuntimeError("boom"))) + + # Act + with flask_app.test_request_context("/webhook", method="POST", data=b"abc"): + body, files = WebhookService._extract_octet_stream_body(webhook_trigger) + + # Assert + assert body == {"raw": None} + assert files == {} + + +def test_extract_text_body_should_return_empty_string_when_request_read_fails( + flask_app: Flask, + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + monkeypatch.setattr("flask.wrappers.Request.get_data", MagicMock(side_effect=RuntimeError("read error"))) + + # Act + with flask_app.test_request_context("/webhook", method="POST", data="abc"): + body, files = WebhookService._extract_text_body() + + # Assert + assert body == {"raw": ""} + assert files == {} + + +def test_detect_binary_mimetype_should_fallback_when_magic_raises(monkeypatch: pytest.MonkeyPatch) -> None: + # Arrange + fake_magic = MagicMock() + fake_magic.from_buffer.side_effect = RuntimeError("magic failed") + monkeypatch.setattr(service_module, "magic", fake_magic) + + # Act + result = WebhookService._detect_binary_mimetype(b"binary") + + # Assert + assert result == "application/octet-stream" + + +def test_process_file_uploads_should_use_octet_stream_fallback_when_mimetype_unknown( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + webhook_trigger = _workflow_trigger(created_by="user-1", tenant_id="tenant-1") + file_obj = MagicMock() + file_obj.to_dict.return_value = {"id": "f-1"} + monkeypatch.setattr(WebhookService, "_create_file_from_binary", MagicMock(return_value=file_obj)) + monkeypatch.setattr(service_module.mimetypes, "guess_type", MagicMock(return_value=(None, None))) + + uploaded = MagicMock() + uploaded.filename = "file.unknown" + uploaded.content_type = None + uploaded.read.return_value = b"content" + + # Act + result = WebhookService._process_file_uploads({"f": uploaded}, webhook_trigger) + + # Assert + assert result == {"f": {"id": "f-1"}} + + +def test_create_file_from_binary_should_call_tool_file_manager_and_file_factory( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + webhook_trigger = _workflow_trigger(created_by="user-1", tenant_id="tenant-1") + manager = MagicMock() + manager.create_file_by_raw.return_value = SimpleNamespace(id="tool-file-1") + monkeypatch.setattr(service_module, "ToolFileManager", MagicMock(return_value=manager)) + expected_file = MagicMock() + monkeypatch.setattr(service_module.file_factory, "build_from_mapping", MagicMock(return_value=expected_file)) + + # Act + result = WebhookService._create_file_from_binary(b"abc", "text/plain", webhook_trigger) + + # Assert + assert result is expected_file + manager.create_file_by_raw.assert_called_once() + + +@pytest.mark.parametrize( + ("raw_value", "param_type", "expected"), + [ + ("42", SegmentType.NUMBER, 42), + ("3.14", SegmentType.NUMBER, 3.14), + ("yes", SegmentType.BOOLEAN, True), + ("no", SegmentType.BOOLEAN, False), + ], +) +def test_convert_form_value_should_convert_supported_types( + raw_value: str, + param_type: str, + expected: Any, +) -> None: + # Arrange + + # Act + result = WebhookService._convert_form_value("param", raw_value, param_type) + + # Assert + assert result == expected + + +def test_convert_form_value_should_raise_for_unsupported_type() -> None: + # Arrange + + # Act / Assert + with pytest.raises(ValueError, match="Unsupported type"): + WebhookService._convert_form_value("p", "x", SegmentType.FILE) + + +def test_validate_json_value_should_return_original_for_unmapped_supported_segment_type( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + warning_mock = MagicMock() + monkeypatch.setattr(service_module.logger, "warning", warning_mock) + + # Act + result = WebhookService._validate_json_value("param", {"x": 1}, "unsupported-type") + + # Assert + assert result == {"x": 1} + warning_mock.assert_called_once() + + +def test_validate_and_convert_value_should_wrap_conversion_errors() -> None: + # Arrange + + # Act / Assert + with pytest.raises(ValueError, match="validation failed"): + WebhookService._validate_and_convert_value("param", "bad", SegmentType.NUMBER, is_form_data=True) + + +def test_process_parameters_should_raise_when_required_parameter_missing() -> None: + # Arrange + raw_params = {"optional": "x"} + config = [WebhookParameter(name="required_param", type=SegmentType.STRING, required=True)] + + # Act / Assert + with pytest.raises(ValueError, match="Required parameter missing"): + WebhookService._process_parameters(raw_params, config, is_form_data=True) + + +def test_process_parameters_should_include_unconfigured_parameters() -> None: + # Arrange + raw_params = {"known": "1", "unknown": "x"} + config = [WebhookParameter(name="known", type=SegmentType.NUMBER, required=False)] + + # Act + result = WebhookService._process_parameters(raw_params, config, is_form_data=True) + + # Assert + assert result == {"known": 1, "unknown": "x"} + + +def test_process_body_parameters_should_raise_when_required_text_raw_is_missing() -> None: + # Arrange + + # Act / Assert + with pytest.raises(ValueError, match="Required body content missing"): + WebhookService._process_body_parameters( + raw_body={"raw": ""}, + body_configs=[WebhookBodyParameter(name="raw", required=True)], + content_type=ContentType.TEXT, + ) + + +def test_process_body_parameters_should_skip_file_config_for_multipart_form_data() -> None: + # Arrange + raw_body = {"message": "hello", "extra": "x"} + body_configs = [ + WebhookBodyParameter(name="upload", type=SegmentType.FILE, required=True), + WebhookBodyParameter(name="message", type=SegmentType.STRING, required=True), + ] + + # Act + result = WebhookService._process_body_parameters(raw_body, body_configs, ContentType.FORM_DATA) + + # Assert + assert result == {"message": "hello", "extra": "x"} + + +def test_validate_required_headers_should_accept_sanitized_header_names() -> None: + # Arrange + headers = {"x_api_key": "123"} + configs = [WebhookParameter(name="x-api-key", required=True)] + + # Act + WebhookService._validate_required_headers(headers, configs) + + # Assert + assert True + + +def test_validate_required_headers_should_raise_when_required_header_missing() -> None: + # Arrange + headers = {"x-other": "123"} + configs = [WebhookParameter(name="x-api-key", required=True)] + + # Act / Assert + with pytest.raises(ValueError, match="Required header missing"): + WebhookService._validate_required_headers(headers, configs) + + +def test_validate_http_metadata_should_return_content_type_mismatch_error() -> None: + # Arrange + webhook_data = {"method": "POST", "headers": {"Content-Type": "application/json"}} + node_data = WebhookData(method="post", content_type=ContentType.TEXT) + + # Act + result = WebhookService._validate_http_metadata(webhook_data, node_data) + + # Assert + assert result["valid"] is False + assert "Content-type mismatch" in result["error"] + + +def test_extract_content_type_should_fallback_to_lowercase_header_key() -> None: + # Arrange + headers = {"content-type": "application/json; charset=utf-8"} + + # Act + result = WebhookService._extract_content_type(headers) + + # Assert + assert result == "application/json" + + +def test_build_workflow_inputs_should_include_expected_keys() -> None: + # Arrange + webhook_data = {"headers": {"h": "v"}, "query_params": {"q": 1}, "body": {"b": 2}} + + # Act + result = WebhookService.build_workflow_inputs(webhook_data) + + # Assert + assert result["webhook_data"] == webhook_data + assert result["webhook_headers"] == {"h": "v"} + assert result["webhook_query_params"] == {"q": 1} + assert result["webhook_body"] == {"b": 2} + + +def test_trigger_workflow_execution_should_trigger_async_workflow_successfully(monkeypatch: pytest.MonkeyPatch) -> None: + # Arrange + webhook_trigger = _workflow_trigger( + app_id="app-1", + node_id="node-1", + tenant_id="tenant-1", + webhook_id="webhook-1", + ) + workflow = _workflow(id="wf-1") + webhook_data = {"body": {"x": 1}} + + session = MagicMock() + _patch_session(monkeypatch, session) + + end_user = SimpleNamespace(id="end-user-1") + monkeypatch.setattr( + service_module.EndUserService, "get_or_create_end_user_by_type", MagicMock(return_value=end_user) + ) + quota_type = SimpleNamespace(TRIGGER=SimpleNamespace(consume=MagicMock())) + monkeypatch.setattr(service_module, "QuotaType", quota_type) + trigger_async_mock = MagicMock() + monkeypatch.setattr(service_module.AsyncWorkflowService, "trigger_workflow_async", trigger_async_mock) + + # Act + WebhookService.trigger_workflow_execution(webhook_trigger, webhook_data, workflow) + + # Assert + trigger_async_mock.assert_called_once() + + +def test_trigger_workflow_execution_should_mark_tenant_rate_limited_when_quota_exceeded( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + webhook_trigger = _workflow_trigger( + app_id="app-1", + node_id="node-1", + tenant_id="tenant-1", + webhook_id="webhook-1", + ) + workflow = _workflow(id="wf-1") + + session = MagicMock() + _patch_session(monkeypatch, session) + + monkeypatch.setattr( + service_module.EndUserService, + "get_or_create_end_user_by_type", + MagicMock(return_value=SimpleNamespace(id="end-user-1")), + ) + quota_type = SimpleNamespace( + TRIGGER=SimpleNamespace( + consume=MagicMock(side_effect=QuotaExceededError(feature="trigger", tenant_id="tenant-1", required=1)) + ) + ) + monkeypatch.setattr(service_module, "QuotaType", quota_type) + mark_rate_limited_mock = MagicMock() + monkeypatch.setattr(service_module.AppTriggerService, "mark_tenant_triggers_rate_limited", mark_rate_limited_mock) + + # Act / Assert + with pytest.raises(QuotaExceededError): + WebhookService.trigger_workflow_execution(webhook_trigger, {"body": {}}, workflow) + mark_rate_limited_mock.assert_called_once_with("tenant-1") + + +def test_trigger_workflow_execution_should_log_and_reraise_unexpected_errors(monkeypatch: pytest.MonkeyPatch) -> None: + # Arrange + webhook_trigger = _workflow_trigger( + app_id="app-1", + node_id="node-1", + tenant_id="tenant-1", + webhook_id="webhook-1", + ) + workflow = _workflow(id="wf-1") + + session = MagicMock() + _patch_session(monkeypatch, session) + + monkeypatch.setattr( + service_module.EndUserService, "get_or_create_end_user_by_type", MagicMock(side_effect=RuntimeError("boom")) + ) + logger_exception_mock = MagicMock() + monkeypatch.setattr(service_module.logger, "exception", logger_exception_mock) + + # Act / Assert + with pytest.raises(RuntimeError, match="boom"): + WebhookService.trigger_workflow_execution(webhook_trigger, {"body": {}}, workflow) + logger_exception_mock.assert_called_once() + + +def test_sync_webhook_relationships_should_raise_when_workflow_exceeds_node_limit() -> None: + # Arrange + app = _app(id="app-1", tenant_id="tenant-1", created_by="user-1") + workflow = _workflow( + walk_nodes=lambda _node_type: [ + (f"node-{i}", {}) for i in range(WebhookService.MAX_WEBHOOK_NODES_PER_WORKFLOW + 1) + ] + ) + + # Act / Assert + with pytest.raises(ValueError, match="maximum webhook node limit"): + WebhookService.sync_webhook_relationships(app, workflow) + + +def test_sync_webhook_relationships_should_raise_when_lock_not_acquired(monkeypatch: pytest.MonkeyPatch) -> None: + # Arrange + app = _app(id="app-1", tenant_id="tenant-1", created_by="user-1") + workflow = _workflow(walk_nodes=lambda _node_type: [("node-1", {})]) + + lock = MagicMock() + lock.acquire.return_value = False + monkeypatch.setattr(service_module.redis_client, "get", MagicMock(return_value=None)) + monkeypatch.setattr(service_module.redis_client, "lock", MagicMock(return_value=lock)) + + # Act / Assert + with pytest.raises(RuntimeError, match="Failed to acquire lock"): + WebhookService.sync_webhook_relationships(app, workflow) + + +def test_sync_webhook_relationships_should_create_missing_records_and_delete_stale_records( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + app = _app(id="app-1", tenant_id="tenant-1", created_by="user-1") + workflow = _workflow(walk_nodes=lambda _node_type: [("node-new", {})]) + + class _WorkflowWebhookTrigger: + app_id = "app_id" + tenant_id = "tenant_id" + webhook_id = "webhook_id" + node_id = "node_id" + + def __init__(self, app_id: str, tenant_id: str, node_id: str, webhook_id: str, created_by: str) -> None: + self.id = None + self.app_id = app_id + self.tenant_id = tenant_id + self.node_id = node_id + self.webhook_id = webhook_id + self.created_by = created_by + + class _Select: + def where(self, *args: Any, **kwargs: Any) -> "_Select": + return self + + class _Session: + def __init__(self) -> None: + self.added: list[Any] = [] + self.deleted: list[Any] = [] + self.commit_count = 0 + self.existing_records = [SimpleNamespace(node_id="node-stale")] + + def scalars(self, _stmt: Any) -> Any: + return SimpleNamespace(all=lambda: self.existing_records) + + def add(self, obj: Any) -> None: + self.added.append(obj) + + def flush(self) -> None: + for idx, obj in enumerate(self.added, start=1): + if obj.id is None: + obj.id = f"rec-{idx}" + + def commit(self) -> None: + self.commit_count += 1 + + def delete(self, obj: Any) -> None: + self.deleted.append(obj) + + lock = MagicMock() + lock.acquire.return_value = True + lock.release.return_value = None + + fake_session = _Session() + + monkeypatch.setattr(service_module, "WorkflowWebhookTrigger", _WorkflowWebhookTrigger) + monkeypatch.setattr(service_module, "select", MagicMock(return_value=_Select())) + monkeypatch.setattr(service_module.redis_client, "get", MagicMock(return_value=None)) + monkeypatch.setattr(service_module.redis_client, "lock", MagicMock(return_value=lock)) + redis_set_mock = MagicMock() + redis_delete_mock = MagicMock() + monkeypatch.setattr(service_module.redis_client, "set", redis_set_mock) + monkeypatch.setattr(service_module.redis_client, "delete", redis_delete_mock) + monkeypatch.setattr(WebhookService, "generate_webhook_id", MagicMock(return_value="generated-webhook-id")) + _patch_session(monkeypatch, fake_session) + + # Act + WebhookService.sync_webhook_relationships(app, workflow) + + # Assert + assert len(fake_session.added) == 1 + assert len(fake_session.deleted) == 1 + assert fake_session.commit_count == 2 + redis_set_mock.assert_called_once() + redis_delete_mock.assert_called_once() + lock.release.assert_called_once() + + +def test_sync_webhook_relationships_should_log_when_lock_release_fails(monkeypatch: pytest.MonkeyPatch) -> None: + # Arrange + app = _app(id="app-1", tenant_id="tenant-1", created_by="user-1") + workflow = _workflow(walk_nodes=lambda _node_type: []) + + class _Select: + def where(self, *args: Any, **kwargs: Any) -> "_Select": + return self + + class _Session: + def scalars(self, _stmt: Any) -> Any: + return SimpleNamespace(all=lambda: []) + + def commit(self) -> None: + return None + + lock = MagicMock() + lock.acquire.return_value = True + lock.release.side_effect = RuntimeError("release failed") + + logger_exception_mock = MagicMock() + + monkeypatch.setattr(service_module, "select", MagicMock(return_value=_Select())) + monkeypatch.setattr(service_module.redis_client, "get", MagicMock(return_value=None)) + monkeypatch.setattr(service_module.redis_client, "lock", MagicMock(return_value=lock)) + monkeypatch.setattr(service_module.logger, "exception", logger_exception_mock) + _patch_session(monkeypatch, _Session()) + + # Act + WebhookService.sync_webhook_relationships(app, workflow) + + # Assert + assert logger_exception_mock.call_count == 1 + + +def test_generate_webhook_response_should_fallback_when_response_body_is_not_json() -> None: + # Arrange + node_config = {"data": {"status_code": 200, "response_body": "{bad-json"}} + + # Act + body, status = WebhookService.generate_webhook_response(node_config) + + # Assert + assert status == 200 + assert "message" in body + + +def test_generate_webhook_id_should_return_24_character_identifier() -> None: + # Arrange + + # Act + webhook_id = WebhookService.generate_webhook_id() + + # Assert + assert isinstance(webhook_id, str) + assert len(webhook_id) == 24 + + +def test_sanitize_key_should_return_original_value_for_non_string_input() -> None: + # Arrange + + # Act + result = WebhookService._sanitize_key(123) # type: ignore[arg-type] + + # Assert + assert result == 123 diff --git a/api/tests/unit_tests/services/test_workflow_run_service_pause.py b/api/tests/unit_tests/services/test_workflow_run_service_pause.py index a62c9f4555..64b21317ab 100644 --- a/api/tests/unit_tests/services/test_workflow_run_service_pause.py +++ b/api/tests/unit_tests/services/test_workflow_run_service_pause.py @@ -176,3 +176,300 @@ class TestWorkflowRunService: service = WorkflowRunService(session_factory) assert service._session_factory == session_factory + + +# === Merged from test_workflow_run_service.py === + + +from types import SimpleNamespace +from typing import Any, cast +from unittest.mock import MagicMock + +import pytest + +from models import Account, App, EndUser, WorkflowRunTriggeredFrom +from services import workflow_run_service as service_module +from services.workflow_run_service import WorkflowRunService + + +@pytest.fixture +def repository_factory_mocks(monkeypatch: pytest.MonkeyPatch) -> tuple[MagicMock, MagicMock, Any]: + # Arrange + node_repo = MagicMock() + workflow_run_repo = MagicMock() + factory = SimpleNamespace( + create_api_workflow_node_execution_repository=MagicMock(return_value=node_repo), + create_api_workflow_run_repository=MagicMock(return_value=workflow_run_repo), + ) + monkeypatch.setattr(service_module, "DifyAPIRepositoryFactory", factory) + + # Assert + return node_repo, workflow_run_repo, factory + + +def _app_model(**kwargs: Any) -> App: + return cast(App, SimpleNamespace(**kwargs)) + + +def _account(**kwargs: Any) -> Account: + return cast(Account, SimpleNamespace(**kwargs)) + + +def _end_user(**kwargs: Any) -> EndUser: + return cast(EndUser, SimpleNamespace(**kwargs)) + + +def test___init___should_create_sessionmaker_from_db_engine_when_session_factory_missing( + monkeypatch: pytest.MonkeyPatch, + repository_factory_mocks: tuple[MagicMock, MagicMock, Any], +) -> None: + # Arrange + session_factory = MagicMock(name="session_factory") + sessionmaker_mock = MagicMock(return_value=session_factory) + monkeypatch.setattr(service_module, "sessionmaker", sessionmaker_mock) + monkeypatch.setattr(service_module, "db", SimpleNamespace(engine="db-engine")) + + # Act + service = WorkflowRunService() + + # Assert + sessionmaker_mock.assert_called_once_with(bind="db-engine", expire_on_commit=False) + assert service._session_factory is session_factory + + +def test___init___should_create_sessionmaker_when_engine_is_provided( + monkeypatch: pytest.MonkeyPatch, + repository_factory_mocks: tuple[MagicMock, MagicMock, Any], +) -> None: + # Arrange + class FakeEngine: + pass + + session_factory = MagicMock(name="session_factory") + sessionmaker_mock = MagicMock(return_value=session_factory) + monkeypatch.setattr(service_module, "Engine", FakeEngine) + monkeypatch.setattr(service_module, "sessionmaker", sessionmaker_mock) + engine = cast(Engine, FakeEngine()) + + # Act + service = WorkflowRunService(session_factory=engine) + + # Assert + sessionmaker_mock.assert_called_once_with(bind=engine, expire_on_commit=False) + assert service._session_factory is session_factory + + +def test___init___should_keep_provided_sessionmaker_and_create_repositories( + repository_factory_mocks: tuple[MagicMock, MagicMock, Any], +) -> None: + # Arrange + node_repo, workflow_run_repo, factory = repository_factory_mocks + session_factory = MagicMock(name="session_factory") + + # Act + service = WorkflowRunService(session_factory=session_factory) + + # Assert + assert service._session_factory is session_factory + assert service._node_execution_service_repo is node_repo + assert service._workflow_run_repo is workflow_run_repo + factory.create_api_workflow_node_execution_repository.assert_called_once_with(session_factory) + factory.create_api_workflow_run_repository.assert_called_once_with(session_factory) + + +def test_get_paginate_workflow_runs_should_forward_filters_and_parse_limit( + repository_factory_mocks: tuple[MagicMock, MagicMock, Any], +) -> None: + # Arrange + _, workflow_run_repo, _ = repository_factory_mocks + service = WorkflowRunService(session_factory=MagicMock(name="session_factory")) + app_model = _app_model(tenant_id="tenant-1", id="app-1") + expected = MagicMock(name="pagination") + workflow_run_repo.get_paginated_workflow_runs.return_value = expected + args = {"limit": "7", "last_id": "last-1", "status": "succeeded"} + + # Act + result = service.get_paginate_workflow_runs( + app_model=app_model, + args=args, + triggered_from=WorkflowRunTriggeredFrom.APP_RUN, + ) + + # Assert + assert result is expected + workflow_run_repo.get_paginated_workflow_runs.assert_called_once_with( + tenant_id="tenant-1", + app_id="app-1", + triggered_from=WorkflowRunTriggeredFrom.APP_RUN, + limit=7, + last_id="last-1", + status="succeeded", + ) + + +def test_get_paginate_advanced_chat_workflow_runs_should_attach_message_fields_when_message_exists( + repository_factory_mocks: tuple[MagicMock, MagicMock, Any], + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + service = WorkflowRunService(session_factory=MagicMock(name="session_factory")) + app_model = _app_model(tenant_id="tenant-1", id="app-1") + run_with_message = SimpleNamespace( + id="run-1", + status="running", + message=SimpleNamespace(id="msg-1", conversation_id="conv-1"), + ) + run_without_message = SimpleNamespace(id="run-2", status="succeeded", message=None) + pagination = SimpleNamespace(data=[run_with_message, run_without_message]) + monkeypatch.setattr(service, "get_paginate_workflow_runs", MagicMock(return_value=pagination)) + + # Act + result = service.get_paginate_advanced_chat_workflow_runs(app_model=app_model, args={"limit": "2"}) + + # Assert + assert result is pagination + assert len(result.data) == 2 + assert result.data[0].message_id == "msg-1" + assert result.data[0].conversation_id == "conv-1" + assert result.data[0].status == "running" + assert not hasattr(result.data[1], "message_id") + assert result.data[1].id == "run-2" + + +def test_get_workflow_run_should_delegate_to_repository_by_tenant_and_app( + repository_factory_mocks: tuple[MagicMock, MagicMock, Any], +) -> None: + # Arrange + _, workflow_run_repo, _ = repository_factory_mocks + service = WorkflowRunService(session_factory=MagicMock(name="session_factory")) + app_model = _app_model(tenant_id="tenant-1", id="app-1") + expected = MagicMock(name="workflow_run") + workflow_run_repo.get_workflow_run_by_id.return_value = expected + + # Act + result = service.get_workflow_run(app_model=app_model, run_id="run-1") + + # Assert + assert result is expected + workflow_run_repo.get_workflow_run_by_id.assert_called_once_with( + tenant_id="tenant-1", + app_id="app-1", + run_id="run-1", + ) + + +def test_get_workflow_runs_count_should_forward_optional_filters( + repository_factory_mocks: tuple[MagicMock, MagicMock, Any], +) -> None: + # Arrange + _, workflow_run_repo, _ = repository_factory_mocks + service = WorkflowRunService(session_factory=MagicMock(name="session_factory")) + app_model = _app_model(tenant_id="tenant-1", id="app-1") + expected = {"total": 3, "succeeded": 2} + workflow_run_repo.get_workflow_runs_count.return_value = expected + + # Act + result = service.get_workflow_runs_count( + app_model=app_model, + status="succeeded", + time_range="7d", + triggered_from=WorkflowRunTriggeredFrom.APP_RUN, + ) + + # Assert + assert result == expected + workflow_run_repo.get_workflow_runs_count.assert_called_once_with( + tenant_id="tenant-1", + app_id="app-1", + triggered_from=WorkflowRunTriggeredFrom.APP_RUN, + status="succeeded", + time_range="7d", + ) + + +def test_get_workflow_run_node_executions_should_return_empty_list_when_run_not_found( + repository_factory_mocks: tuple[MagicMock, MagicMock, Any], + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + service = WorkflowRunService(session_factory=MagicMock(name="session_factory")) + monkeypatch.setattr(service, "get_workflow_run", MagicMock(return_value=None)) + app_model = _app_model(id="app-1") + user = _account(current_tenant_id="tenant-1") + + # Act + result = service.get_workflow_run_node_executions(app_model=app_model, run_id="run-1", user=user) + + # Assert + assert result == [] + + +def test_get_workflow_run_node_executions_should_use_end_user_tenant_id( + repository_factory_mocks: tuple[MagicMock, MagicMock, Any], + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + node_repo, _, _ = repository_factory_mocks + service = WorkflowRunService(session_factory=MagicMock(name="session_factory")) + monkeypatch.setattr(service, "get_workflow_run", MagicMock(return_value=SimpleNamespace(id="run-1"))) + + class FakeEndUser: + def __init__(self, tenant_id: str) -> None: + self.tenant_id = tenant_id + + monkeypatch.setattr(service_module, "EndUser", FakeEndUser) + user = cast(EndUser, FakeEndUser(tenant_id="tenant-end-user")) + app_model = _app_model(id="app-1") + expected = [SimpleNamespace(id="exec-1")] + node_repo.get_executions_by_workflow_run.return_value = expected + + # Act + result = service.get_workflow_run_node_executions(app_model=app_model, run_id="run-1", user=user) + + # Assert + assert result == expected + node_repo.get_executions_by_workflow_run.assert_called_once_with( + tenant_id="tenant-end-user", + app_id="app-1", + workflow_run_id="run-1", + ) + + +def test_get_workflow_run_node_executions_should_use_account_current_tenant_id( + repository_factory_mocks: tuple[MagicMock, MagicMock, Any], + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + node_repo, _, _ = repository_factory_mocks + service = WorkflowRunService(session_factory=MagicMock(name="session_factory")) + monkeypatch.setattr(service, "get_workflow_run", MagicMock(return_value=SimpleNamespace(id="run-1"))) + app_model = _app_model(id="app-1") + user = _account(current_tenant_id="tenant-account") + expected = [SimpleNamespace(id="exec-1"), SimpleNamespace(id="exec-2")] + node_repo.get_executions_by_workflow_run.return_value = expected + + # Act + result = service.get_workflow_run_node_executions(app_model=app_model, run_id="run-1", user=user) + + # Assert + assert result == expected + node_repo.get_executions_by_workflow_run.assert_called_once_with( + tenant_id="tenant-account", + app_id="app-1", + workflow_run_id="run-1", + ) + + +def test_get_workflow_run_node_executions_should_raise_when_resolved_tenant_id_is_none( + repository_factory_mocks: tuple[MagicMock, MagicMock, Any], + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + service = WorkflowRunService(session_factory=MagicMock(name="session_factory")) + monkeypatch.setattr(service, "get_workflow_run", MagicMock(return_value=SimpleNamespace(id="run-1"))) + app_model = _app_model(id="app-1") + user = _account(current_tenant_id=None) + + # Act / Assert + with pytest.raises(ValueError, match="tenant_id cannot be None"): + service.get_workflow_run_node_executions(app_model=app_model, run_id="run-1", user=user) diff --git a/api/tests/unit_tests/services/workflow/test_workflow_converter_additional.py b/api/tests/unit_tests/services/workflow/test_workflow_converter_additional.py new file mode 100644 index 0000000000..2aaf3bdf1d --- /dev/null +++ b/api/tests/unit_tests/services/workflow/test_workflow_converter_additional.py @@ -0,0 +1,831 @@ +from __future__ import annotations + +import json +from types import SimpleNamespace +from typing import Any, cast +from unittest.mock import MagicMock + +import pytest + +from core.app.app_config.entities import ( + AdvancedChatMessageEntity, + AdvancedChatPromptTemplateEntity, + AdvancedCompletionPromptTemplateEntity, + DatasetEntity, + DatasetRetrieveConfigEntity, + ExternalDataVariableEntity, + ModelConfigEntity, + PromptTemplateEntity, +) +from core.helper import encrypter +from core.prompt.utils.prompt_template_parser import PromptTemplateParser +from models.api_based_extension import APIBasedExtension, APIBasedExtensionPoint +from models.model import Account, App, AppMode, AppModelConfig +from services.workflow import workflow_converter as converter_module +from services.workflow.workflow_converter import WorkflowConverter + +try: + from graphon.enums import BuiltinNodeTypes + from graphon.model_runtime.entities.llm_entities import LLMMode + from graphon.model_runtime.entities.message_entities import PromptMessageRole + from graphon.variables.input_entities import VariableEntity, VariableEntityType +except ModuleNotFoundError: + from dify_graph.enums import BuiltinNodeTypes + from dify_graph.model_runtime.entities.llm_entities import LLMMode + from dify_graph.model_runtime.entities.message_entities import PromptMessageRole + from dify_graph.variables.input_entities import VariableEntity, VariableEntityType + + +@pytest.fixture +def converter() -> WorkflowConverter: + return WorkflowConverter() + + +def _app_model(**kwargs: Any) -> App: + return cast(App, SimpleNamespace(**kwargs)) + + +def _account(**kwargs: Any) -> Account: + return cast(Account, SimpleNamespace(**kwargs)) + + +def _app_model_config(**kwargs: Any) -> AppModelConfig: + return cast(AppModelConfig, SimpleNamespace(**kwargs)) + + +def _build_start_graph() -> dict[str, Any]: + return { + "nodes": [ + { + "id": "start", + "position": None, + "data": {"type": BuiltinNodeTypes.START, "variables": [{"variable": "name"}, {"variable": "city"}]}, + } + ], + "edges": [], + } + + +def _build_model_config(mode: str | LLMMode) -> ModelConfigEntity: + return ModelConfigEntity(provider="openai", model="gpt-4", mode=mode, parameters={}, stop=[]) + + +@pytest.fixture +def default_variables() -> list[VariableEntity]: + return [ + VariableEntity(variable="text_input", label="text-input", type=VariableEntityType.TEXT_INPUT), + VariableEntity(variable="paragraph", label="paragraph", type=VariableEntityType.PARAGRAPH), + VariableEntity(variable="select", label="select", type=VariableEntityType.SELECT), + ] + + +def test__convert_to_start_node(default_variables: list[VariableEntity]) -> None: + result = WorkflowConverter()._convert_to_start_node(default_variables) + + assert result["id"] == "start" + assert result["data"]["type"] == BuiltinNodeTypes.START + assert result["data"]["variables"][0]["type"] == "text-input" + assert result["data"]["variables"][0]["variable"] == "text_input" + + +def test__convert_to_http_request_node_for_chatbot(default_variables: list[VariableEntity]) -> None: + app_model = MagicMock() + app_model.id = "app_id" + app_model.tenant_id = "tenant_id" + app_model.mode = AppMode.CHAT + + extension = APIBasedExtension( + tenant_id="tenant_id", + name="api-1", + api_key="encrypted_api_key", + api_endpoint="https://dify.ai", + ) + extension.id = "api_based_extension_id" + + workflow_converter = WorkflowConverter() + workflow_converter._get_api_based_extension = MagicMock(return_value=extension) + encrypter.decrypt_token = MagicMock(return_value="api_key") + + external_data_variables = [ + ExternalDataVariableEntity( + variable="external_variable", + type="api", + config={"api_based_extension_id": "api_based_extension_id"}, + ), + ] + + nodes, mapping = workflow_converter._convert_to_http_request_node( + app_model=app_model, + variables=default_variables, + external_data_variables=external_data_variables, + ) + + assert len(nodes) == 2 + assert nodes[0]["data"]["type"] == BuiltinNodeTypes.HTTP_REQUEST + assert nodes[1]["data"]["type"] == BuiltinNodeTypes.CODE + body = json.loads(nodes[0]["data"]["body"]["data"]) + assert body["point"] == APIBasedExtensionPoint.APP_EXTERNAL_DATA_TOOL_QUERY + assert body["params"]["query"] == "{{#sys.query#}}" + assert body["params"]["inputs"]["text_input"] == "{{#start.text_input#}}" + assert mapping == {"external_variable": "code_1"} + + +def test__convert_to_http_request_node_for_workflow_app(default_variables: list[VariableEntity]) -> None: + app_model = MagicMock() + app_model.id = "app_id" + app_model.tenant_id = "tenant_id" + app_model.mode = AppMode.WORKFLOW + + extension = APIBasedExtension( + tenant_id="tenant_id", + name="api-1", + api_key="encrypted_api_key", + api_endpoint="https://dify.ai", + ) + extension.id = "api_based_extension_id" + + workflow_converter = WorkflowConverter() + workflow_converter._get_api_based_extension = MagicMock(return_value=extension) + encrypter.decrypt_token = MagicMock(return_value="api_key") + + external_data_variables = [ + ExternalDataVariableEntity( + variable="external_variable", + type="api", + config={"api_based_extension_id": "api_based_extension_id"}, + ), + ] + + nodes, _ = workflow_converter._convert_to_http_request_node( + app_model=app_model, + variables=default_variables, + external_data_variables=external_data_variables, + ) + + body = json.loads(nodes[0]["data"]["body"]["data"]) + assert body["params"]["query"] == "" + + +def test__convert_to_knowledge_retrieval_node_for_chatbot() -> None: + dataset_config = DatasetEntity( + dataset_ids=["dataset_id_1", "dataset_id_2"], + retrieve_config=DatasetRetrieveConfigEntity( + retrieve_strategy=DatasetRetrieveConfigEntity.RetrieveStrategy.MULTIPLE, + top_k=5, + score_threshold=0.8, + reranking_model={"reranking_provider_name": "cohere", "reranking_model_name": "rerank-english-v2.0"}, + reranking_enabled=True, + ), + ) + model_config = ModelConfigEntity(provider="openai", model="gpt-4", mode="chat", parameters={}, stop=[]) + + node = WorkflowConverter()._convert_to_knowledge_retrieval_node( + new_app_mode=AppMode.ADVANCED_CHAT, + dataset_config=dataset_config, + model_config=model_config, + ) + + assert node is not None + assert node["data"]["query_variable_selector"] == ["sys", "query"] + assert node["data"]["multiple_retrieval_config"]["top_k"] == 5 + + +def test__convert_to_knowledge_retrieval_node_for_workflow_app() -> None: + dataset_config = DatasetEntity( + dataset_ids=["dataset_id_1", "dataset_id_2"], + retrieve_config=DatasetRetrieveConfigEntity( + query_variable="query", + retrieve_strategy=DatasetRetrieveConfigEntity.RetrieveStrategy.MULTIPLE, + top_k=5, + score_threshold=0.8, + reranking_model={"reranking_provider_name": "cohere", "reranking_model_name": "rerank-english-v2.0"}, + reranking_enabled=True, + ), + ) + model_config = ModelConfigEntity(provider="openai", model="gpt-4", mode="chat", parameters={}, stop=[]) + + node = WorkflowConverter()._convert_to_knowledge_retrieval_node( + new_app_mode=AppMode.WORKFLOW, + dataset_config=dataset_config, + model_config=model_config, + ) + + assert node is not None + assert node["data"]["query_variable_selector"] == ["start", "query"] + + +def test__convert_to_llm_node_for_chatbot_simple_chat_model(default_variables: list[VariableEntity]) -> None: + workflow_converter = WorkflowConverter() + graph = {"nodes": [workflow_converter._convert_to_start_node(default_variables)], "edges": []} + model_config = ModelConfigEntity(provider="openai", model="gpt-4", mode=LLMMode.CHAT.value, parameters={}, stop=[]) + prompt_template = PromptTemplateEntity( + prompt_type=PromptTemplateEntity.PromptType.SIMPLE, + simple_prompt_template="You are a helper for {{text_input}} and {{paragraph}}", + ) + + node = workflow_converter._convert_to_llm_node( + original_app_mode=AppMode.CHAT, + new_app_mode=AppMode.ADVANCED_CHAT, + model_config=model_config, + graph=graph, + prompt_template=prompt_template, + ) + + assert node["data"]["type"] == BuiltinNodeTypes.LLM + assert node["data"]["memory"] is not None + assert node["data"]["prompt_template"][0]["role"] == "user" + assert "{{#start.text_input#}}" in node["data"]["prompt_template"][0]["text"] + + +def test__convert_to_llm_node_for_chatbot_simple_chat_model_with_empty_template( + default_variables: list[VariableEntity], + monkeypatch: pytest.MonkeyPatch, +) -> None: + workflow_converter = WorkflowConverter() + graph = {"nodes": [workflow_converter._convert_to_start_node(default_variables)], "edges": []} + model_config = ModelConfigEntity(provider="openai", model="gpt-4", mode=LLMMode.CHAT.value, parameters={}, stop=[]) + prompt_template = PromptTemplateEntity( + prompt_type=PromptTemplateEntity.PromptType.SIMPLE, + simple_prompt_template="ignored", + ) + monkeypatch.setattr( + converter_module.SimplePromptTransform, + "get_prompt_template", + lambda self, **kwargs: {"prompt_template": PromptTemplateParser(""), "prompt_rules": {}}, + ) + + node = workflow_converter._convert_to_llm_node( + original_app_mode=AppMode.CHAT, + new_app_mode=AppMode.ADVANCED_CHAT, + model_config=model_config, + graph=graph, + prompt_template=prompt_template, + ) + + assert node["data"]["prompt_template"] == [] + + +def test__convert_to_llm_node_for_chatbot_advanced_chat_model(default_variables: list[VariableEntity]) -> None: + workflow_converter = WorkflowConverter() + graph = {"nodes": [workflow_converter._convert_to_start_node(default_variables)], "edges": []} + model_config = ModelConfigEntity(provider="openai", model="gpt-4", mode=LLMMode.CHAT.value, parameters={}, stop=[]) + prompt_template = PromptTemplateEntity( + prompt_type=PromptTemplateEntity.PromptType.ADVANCED, + advanced_chat_prompt_template=AdvancedChatPromptTemplateEntity( + messages=[AdvancedChatMessageEntity(text="Hello {{text_input}}", role=PromptMessageRole.USER)] + ), + ) + + node = workflow_converter._convert_to_llm_node( + original_app_mode=AppMode.CHAT, + new_app_mode=AppMode.ADVANCED_CHAT, + model_config=model_config, + graph=graph, + prompt_template=prompt_template, + ) + + assert isinstance(node["data"]["prompt_template"], list) + assert node["data"]["prompt_template"][0]["role"] == PromptMessageRole.USER.value + + +def test__convert_to_llm_node_for_chatbot_advanced_chat_model_without_template( + default_variables: list[VariableEntity], +) -> None: + workflow_converter = WorkflowConverter() + graph = {"nodes": [workflow_converter._convert_to_start_node(default_variables)], "edges": []} + model_config = ModelConfigEntity(provider="openai", model="gpt-4", mode=LLMMode.CHAT.value, parameters={}, stop=[]) + prompt_template = PromptTemplateEntity( + prompt_type=PromptTemplateEntity.PromptType.ADVANCED, + advanced_chat_prompt_template=None, + ) + + node = workflow_converter._convert_to_llm_node( + original_app_mode=AppMode.CHAT, + new_app_mode=AppMode.WORKFLOW, + model_config=model_config, + graph=graph, + prompt_template=prompt_template, + ) + + assert node["data"]["prompt_template"] == [] + assert node["data"]["memory"] is None + + +def test__convert_to_llm_node_for_workflow_advanced_completion_model(default_variables: list[VariableEntity]) -> None: + workflow_converter = WorkflowConverter() + graph = {"nodes": [workflow_converter._convert_to_start_node(default_variables)], "edges": []} + model_config = ModelConfigEntity( + provider="openai", + model="gpt-3.5-turbo-instruct", + mode=LLMMode.COMPLETION.value, + parameters={}, + stop=[], + ) + prompt_template = PromptTemplateEntity( + prompt_type=PromptTemplateEntity.PromptType.ADVANCED, + advanced_completion_prompt_template=AdvancedCompletionPromptTemplateEntity( + prompt="Hello {{text_input}} and {{#query#}}", + role_prefix=AdvancedCompletionPromptTemplateEntity.RolePrefixEntity(user="Human", assistant="Assistant"), + ), + ) + + node = workflow_converter._convert_to_llm_node( + original_app_mode=AppMode.COMPLETION, + new_app_mode=AppMode.ADVANCED_CHAT, + model_config=model_config, + graph=graph, + prompt_template=prompt_template, + ) + + assert node["data"]["prompt_template"]["text"].find("{{#sys.query#}}") != -1 + assert node["data"]["memory"]["role_prefix"]["user"] == "Human" + + +def test__convert_to_end_node() -> None: + node = WorkflowConverter()._convert_to_end_node() + assert node["id"] == "end" + assert node["data"]["type"] == BuiltinNodeTypes.END + + +def test__convert_to_answer_node() -> None: + node = WorkflowConverter()._convert_to_answer_node() + assert node["id"] == "answer" + assert node["data"]["type"] == BuiltinNodeTypes.ANSWER + + +def test_convert_to_workflow_should_raise_when_app_model_config_is_missing(converter: WorkflowConverter) -> None: + app_model = _app_model(app_model_config=None) + + with pytest.raises(ValueError, match="App model config is required"): + converter.convert_to_workflow( + app_model=app_model, + account=_account(id="account-1"), + name="new-app", + icon_type="emoji", + icon="robot", + icon_background="#fff", + ) + + +@pytest.mark.parametrize( + ("source_mode", "expected_mode"), + [ + (AppMode.CHAT, AppMode.ADVANCED_CHAT), + (AppMode.COMPLETION, AppMode.WORKFLOW), + ], +) +def test_convert_to_workflow_should_create_new_app_with_fallback_fields( + converter: WorkflowConverter, + monkeypatch: pytest.MonkeyPatch, + source_mode: AppMode, + expected_mode: AppMode, +) -> None: + class FakeApp: + def __init__(self) -> None: + self.id = "new-app-id" + + workflow = SimpleNamespace(app_id=None) + monkeypatch.setattr(converter, "convert_app_model_config_to_workflow", MagicMock(return_value=workflow)) + monkeypatch.setattr(converter_module, "App", FakeApp) + + db_session = SimpleNamespace(add=MagicMock(), flush=MagicMock(), commit=MagicMock()) + monkeypatch.setattr(converter_module, "db", SimpleNamespace(session=db_session)) + + send_mock = MagicMock() + monkeypatch.setattr(converter_module.app_was_created, "send", send_mock) + + account = _account(id="account-1") + app_model = _app_model( + tenant_id="tenant-1", + name="Source App", + mode=source_mode, + icon_type="emoji", + icon="sparkles", + icon_background="#123456", + enable_site=True, + enable_api=True, + api_rpm=10, + api_rph=100, + is_public=False, + app_model_config=_app_model_config(id="config-1"), + ) + + new_app = converter.convert_to_workflow( + app_model=app_model, + account=account, + name="", + icon_type="", + icon="", + icon_background="", + ) + + assert new_app.name == "Source App(workflow)" + assert new_app.mode == expected_mode + assert new_app.icon_type == "emoji" + assert new_app.icon == "sparkles" + assert new_app.icon_background == "#123456" + assert new_app.created_by == "account-1" + assert workflow.app_id == "new-app-id" + db_session.add.assert_called_once() + db_session.flush.assert_called_once() + db_session.commit.assert_called_once() + send_mock.assert_called_once_with(new_app, account=account) + + +def test_convert_app_model_config_to_workflow_should_build_advanced_chat_graph_and_features( + converter: WorkflowConverter, + monkeypatch: pytest.MonkeyPatch, +) -> None: + app_model = _app_model(id="app-1", tenant_id="tenant-1", mode=AppMode.CHAT) + app_config = SimpleNamespace( + variables=[SimpleNamespace(variable="name")], + external_data_variables=[SimpleNamespace(variable="ext")], + dataset=SimpleNamespace(id="dataset"), + model=SimpleNamespace(), + prompt_template=SimpleNamespace(), + additional_features=SimpleNamespace(file_upload=SimpleNamespace()), + app_model_config_dict={ + "opening_statement": "hello", + "suggested_questions": ["q1"], + "suggested_questions_after_answer": True, + "speech_to_text": True, + "text_to_speech": {"enabled": True}, + "file_upload": {"enabled": True}, + "sensitive_word_avoidance": {"enabled": True}, + "retriever_resource": {"enabled": True}, + }, + ) + + class FakeWorkflow: + VERSION_DRAFT = "draft" + + def __init__(self, **kwargs: Any) -> None: + self.__dict__.update(kwargs) + + monkeypatch.setattr(converter, "_get_new_app_mode", MagicMock(return_value=AppMode.ADVANCED_CHAT)) + monkeypatch.setattr(converter, "_convert_to_app_config", MagicMock(return_value=app_config)) + monkeypatch.setattr( + converter, + "_convert_to_start_node", + MagicMock( + return_value={"id": "start", "position": None, "data": {"type": BuiltinNodeTypes.START, "variables": []}} + ), + ) + monkeypatch.setattr( + converter, + "_convert_to_http_request_node", + MagicMock( + return_value=( + [{"id": "http", "position": None, "data": {"type": BuiltinNodeTypes.HTTP_REQUEST}}], + {"ext": "code_1"}, + ) + ), + ) + monkeypatch.setattr( + converter, + "_convert_to_knowledge_retrieval_node", + MagicMock( + return_value={"id": "knowledge", "position": None, "data": {"type": BuiltinNodeTypes.KNOWLEDGE_RETRIEVAL}} + ), + ) + monkeypatch.setattr( + converter, + "_convert_to_llm_node", + MagicMock(return_value={"id": "llm", "position": None, "data": {"type": BuiltinNodeTypes.LLM}}), + ) + monkeypatch.setattr( + converter, + "_convert_to_answer_node", + MagicMock(return_value={"id": "answer", "position": None, "data": {"type": BuiltinNodeTypes.ANSWER}}), + ) + monkeypatch.setattr(converter_module, "Workflow", FakeWorkflow) + + db_session = SimpleNamespace(add=MagicMock(), commit=MagicMock()) + monkeypatch.setattr(converter_module, "db", SimpleNamespace(session=db_session)) + + workflow = converter.convert_app_model_config_to_workflow( + app_model=app_model, + app_model_config=_app_model_config(id="cfg"), + account_id="account-1", + ) + + graph = json.loads(workflow.graph) + node_ids = [node["id"] for node in graph["nodes"]] + assert node_ids == ["start", "http", "knowledge", "llm", "answer"] + + features = json.loads(workflow.features) + assert "opening_statement" in features + assert "retriever_resource" in features + db_session.add.assert_called_once() + db_session.commit.assert_called_once() + + +def test_convert_app_model_config_to_workflow_should_build_workflow_mode_with_end_node( + converter: WorkflowConverter, + monkeypatch: pytest.MonkeyPatch, +) -> None: + app_model = _app_model(id="app-1", tenant_id="tenant-1", mode=AppMode.COMPLETION) + app_config = SimpleNamespace( + variables=[SimpleNamespace(variable="name")], + external_data_variables=[], + dataset=SimpleNamespace(id="dataset"), + model=SimpleNamespace(), + prompt_template=SimpleNamespace(), + additional_features=None, + app_model_config_dict={ + "text_to_speech": {"enabled": False}, + "file_upload": {"enabled": False}, + "sensitive_word_avoidance": {"enabled": False}, + }, + ) + + class FakeWorkflow: + VERSION_DRAFT = "draft" + + def __init__(self, **kwargs: Any) -> None: + self.__dict__.update(kwargs) + + monkeypatch.setattr(converter, "_get_new_app_mode", MagicMock(return_value=AppMode.WORKFLOW)) + monkeypatch.setattr(converter, "_convert_to_app_config", MagicMock(return_value=app_config)) + monkeypatch.setattr( + converter, + "_convert_to_start_node", + MagicMock( + return_value={"id": "start", "position": None, "data": {"type": BuiltinNodeTypes.START, "variables": []}} + ), + ) + monkeypatch.setattr(converter, "_convert_to_knowledge_retrieval_node", MagicMock(return_value=None)) + monkeypatch.setattr( + converter, + "_convert_to_llm_node", + MagicMock(return_value={"id": "llm", "position": None, "data": {"type": BuiltinNodeTypes.LLM}}), + ) + monkeypatch.setattr( + converter, + "_convert_to_end_node", + MagicMock(return_value={"id": "end", "position": None, "data": {"type": BuiltinNodeTypes.END}}), + ) + monkeypatch.setattr(converter_module, "Workflow", FakeWorkflow) + + db_session = SimpleNamespace(add=MagicMock(), commit=MagicMock()) + monkeypatch.setattr(converter_module, "db", SimpleNamespace(session=db_session)) + + workflow = converter.convert_app_model_config_to_workflow( + app_model=app_model, + app_model_config=_app_model_config(id="cfg"), + account_id="account-1", + ) + + graph = json.loads(workflow.graph) + node_ids = [node["id"] for node in graph["nodes"]] + assert node_ids == ["start", "llm", "end"] + + features = json.loads(workflow.features) + assert set(features.keys()) == {"text_to_speech", "file_upload", "sensitive_word_avoidance"} + + +def test_convert_to_app_config_should_route_to_correct_manager( + converter: WorkflowConverter, + monkeypatch: pytest.MonkeyPatch, +) -> None: + agent_result = SimpleNamespace(kind="agent") + chat_result = SimpleNamespace(kind="chat") + completion_result = SimpleNamespace(kind="completion") + monkeypatch.setattr( + converter_module.AgentChatAppConfigManager, "get_app_config", MagicMock(return_value=agent_result) + ) + monkeypatch.setattr(converter_module.ChatAppConfigManager, "get_app_config", MagicMock(return_value=chat_result)) + monkeypatch.setattr( + converter_module.CompletionAppConfigManager, + "get_app_config", + MagicMock(return_value=completion_result), + ) + + from_agent_mode = converter._convert_to_app_config( + app_model=_app_model(mode=AppMode.AGENT_CHAT, is_agent=False), + app_model_config=_app_model_config(id="cfg-1"), + ) + from_agent_flag = converter._convert_to_app_config( + app_model=_app_model(mode=AppMode.CHAT, is_agent=True), + app_model_config=_app_model_config(id="cfg-2"), + ) + from_chat_mode = converter._convert_to_app_config( + app_model=_app_model(mode=AppMode.CHAT, is_agent=False), + app_model_config=_app_model_config(id="cfg-3"), + ) + from_completion_mode = converter._convert_to_app_config( + app_model=_app_model(mode=AppMode.COMPLETION, is_agent=False), + app_model_config=_app_model_config(id="cfg-4"), + ) + + assert from_agent_mode is agent_result + assert from_agent_flag is agent_result + assert from_chat_mode is chat_result + assert from_completion_mode is completion_result + + +def test_convert_to_app_config_should_raise_for_invalid_app_mode(converter: WorkflowConverter) -> None: + app_model = _app_model(mode=AppMode.WORKFLOW, is_agent=False) + + with pytest.raises(ValueError, match="Invalid app mode"): + converter._convert_to_app_config(app_model=app_model, app_model_config=_app_model_config(id="cfg")) + + +def test_convert_to_http_request_node_should_skip_non_api_and_missing_extension_id( + converter: WorkflowConverter, +) -> None: + app_model = _app_model(id="app-1", tenant_id="tenant-1", mode=AppMode.CHAT) + external_data_variables = [ + ExternalDataVariableEntity(variable="skip_type", type="dataset", config={"api_based_extension_id": "x"}), + ExternalDataVariableEntity(variable="skip_config", type="api", config={}), + ] + + nodes, mapping = converter._convert_to_http_request_node( + app_model=app_model, + variables=[], + external_data_variables=external_data_variables, + ) + + assert nodes == [] + assert mapping == {} + + +def test_convert_to_knowledge_retrieval_node_should_return_none_for_workflow_without_query_variable( + converter: WorkflowConverter, +) -> None: + dataset_config = DatasetEntity( + dataset_ids=["ds-1"], + retrieve_config=DatasetRetrieveConfigEntity( + query_variable=None, + retrieve_strategy=DatasetRetrieveConfigEntity.RetrieveStrategy.MULTIPLE, + ), + ) + model_config = _build_model_config(mode=LLMMode.CHAT) + + node = converter._convert_to_knowledge_retrieval_node( + new_app_mode=AppMode.WORKFLOW, + dataset_config=dataset_config, + model_config=model_config, + ) + + assert node is None + + +def test_convert_to_llm_node_should_raise_when_simple_chat_template_missing( + converter: WorkflowConverter, +) -> None: + graph = _build_start_graph() + model_config = _build_model_config(mode=LLMMode.CHAT) + prompt_template = PromptTemplateEntity(prompt_type=PromptTemplateEntity.PromptType.SIMPLE) + + with pytest.raises(ValueError, match="Simple prompt template is required"): + converter._convert_to_llm_node( + original_app_mode=AppMode.CHAT, + new_app_mode=AppMode.ADVANCED_CHAT, + graph=graph, + model_config=model_config, + prompt_template=prompt_template, + ) + + +def test_convert_to_llm_node_should_raise_when_prompt_template_parser_type_is_invalid_for_chat( + converter: WorkflowConverter, + monkeypatch: pytest.MonkeyPatch, +) -> None: + graph = _build_start_graph() + model_config = _build_model_config(mode=LLMMode.CHAT) + prompt_template = PromptTemplateEntity( + prompt_type=PromptTemplateEntity.PromptType.SIMPLE, + simple_prompt_template="Hello {{name}}", + ) + monkeypatch.setattr( + converter_module.SimplePromptTransform, + "get_prompt_template", + lambda self, **kwargs: {"prompt_template": "invalid"}, + ) + + with pytest.raises(TypeError, match="Expected PromptTemplateParser"): + converter._convert_to_llm_node( + original_app_mode=AppMode.CHAT, + new_app_mode=AppMode.ADVANCED_CHAT, + graph=graph, + model_config=model_config, + prompt_template=prompt_template, + ) + + +def test_convert_to_llm_node_should_raise_when_simple_completion_template_missing( + converter: WorkflowConverter, +) -> None: + graph = _build_start_graph() + model_config = _build_model_config(mode=LLMMode.COMPLETION) + prompt_template = PromptTemplateEntity(prompt_type=PromptTemplateEntity.PromptType.SIMPLE) + + with pytest.raises(ValueError, match="Simple prompt template is required"): + converter._convert_to_llm_node( + original_app_mode=AppMode.COMPLETION, + new_app_mode=AppMode.WORKFLOW, + graph=graph, + model_config=model_config, + prompt_template=prompt_template, + ) + + +def test_convert_to_llm_node_should_raise_when_completion_prompt_rules_type_is_invalid( + converter: WorkflowConverter, + monkeypatch: pytest.MonkeyPatch, +) -> None: + graph = _build_start_graph() + model_config = _build_model_config(mode=LLMMode.COMPLETION) + prompt_template = PromptTemplateEntity( + prompt_type=PromptTemplateEntity.PromptType.SIMPLE, + simple_prompt_template="Hello {{name}}", + ) + monkeypatch.setattr( + converter_module.SimplePromptTransform, + "get_prompt_template", + lambda self, **kwargs: {"prompt_template": PromptTemplateParser("Hello {{name}}"), "prompt_rules": "invalid"}, + ) + + with pytest.raises(TypeError, match="Expected dict for prompt_rules"): + converter._convert_to_llm_node( + original_app_mode=AppMode.COMPLETION, + new_app_mode=AppMode.ADVANCED_CHAT, + graph=graph, + model_config=model_config, + prompt_template=prompt_template, + ) + + +def test_convert_to_llm_node_should_use_empty_text_for_advanced_completion_without_template( + converter: WorkflowConverter, +) -> None: + graph = _build_start_graph() + model_config = _build_model_config(mode=LLMMode.COMPLETION) + prompt_template = PromptTemplateEntity( + prompt_type=PromptTemplateEntity.PromptType.ADVANCED, + advanced_completion_prompt_template=None, + ) + + llm_node = converter._convert_to_llm_node( + original_app_mode=AppMode.COMPLETION, + new_app_mode=AppMode.WORKFLOW, + graph=graph, + model_config=model_config, + prompt_template=prompt_template, + ) + + assert llm_node["data"]["prompt_template"]["text"] == "" + assert llm_node["data"]["memory"] is None + + +def test_replace_template_variables_should_replace_start_and_external_references(converter: WorkflowConverter) -> None: + template = "Hello {{name}} from {{city}} with {{weather}}" + variables = [{"variable": "name"}, {"variable": "city"}] + external_mapping = {"weather": "code_1"} + + result = converter._replace_template_variables(template, variables, external_mapping) + + assert result == "Hello {{#start.name#}} from {{#start.city#}} with {{#code_1.result#}}" + + +def test_graph_helpers_should_create_edges_append_nodes_and_choose_mode(converter: WorkflowConverter) -> None: + graph = {"nodes": [{"id": "start", "position": None, "data": {"type": BuiltinNodeTypes.START}}], "edges": []} + node = {"id": "llm", "position": None, "data": {"type": BuiltinNodeTypes.LLM}} + + edge = converter._create_edge("start", "llm") + updated_graph = converter._append_node(graph, node) + workflow_mode = converter._get_new_app_mode(_app_model(mode=AppMode.COMPLETION)) + advanced_chat_mode = converter._get_new_app_mode(_app_model(mode=AppMode.CHAT)) + + assert edge == {"id": "start-llm", "source": "start", "target": "llm"} + assert updated_graph["nodes"][-1]["id"] == "llm" + assert updated_graph["edges"][-1]["source"] == "start" + assert workflow_mode == AppMode.WORKFLOW + assert advanced_chat_mode == AppMode.ADVANCED_CHAT + + +def test_get_api_based_extension_should_raise_when_extension_not_found( + converter: WorkflowConverter, + monkeypatch: pytest.MonkeyPatch, +) -> None: + db_session = SimpleNamespace(scalar=MagicMock(return_value=None)) + monkeypatch.setattr(converter_module, "db", SimpleNamespace(session=db_session)) + + with pytest.raises(ValueError, match="API Based Extension not found"): + converter._get_api_based_extension(tenant_id="tenant-1", api_based_extension_id="ext-1") + db_session.scalar.assert_called_once() + + +def test_get_api_based_extension_should_return_entity_when_found( + converter: WorkflowConverter, + monkeypatch: pytest.MonkeyPatch, +) -> None: + extension = SimpleNamespace(id="ext-1") + db_session = SimpleNamespace(scalar=MagicMock(return_value=extension)) + monkeypatch.setattr(converter_module, "db", SimpleNamespace(session=db_session)) + + result = converter._get_api_based_extension(tenant_id="tenant-1", api_based_extension_id="ext-1") + + assert result is extension + db_session.scalar.assert_called_once() diff --git a/api/tests/unit_tests/services/workflow/test_workflow_event_snapshot_service.py b/api/tests/unit_tests/services/workflow/test_workflow_event_snapshot_service.py index 077a7c27a2..b8b073f75c 100644 --- a/api/tests/unit_tests/services/workflow/test_workflow_event_snapshot_service.py +++ b/api/tests/unit_tests/services/workflow/test_workflow_event_snapshot_service.py @@ -1,10 +1,9 @@ -from __future__ import annotations - import json import queue from collections.abc import Sequence from dataclasses import dataclass from datetime import UTC, datetime +from itertools import cycle from threading import Event import pytest @@ -224,3 +223,577 @@ def test_resolve_task_id_priority(context_task_id, buffered_task_id, expected) - buffer_state.task_id_ready.set() task_id = _resolve_task_id(resumption_context, buffer_state, "run-1", wait_timeout=0.0) assert task_id == expected + + +# === Merged from test_workflow_event_snapshot_service_additional.py === + + +import json +import queue +from collections.abc import Mapping +from dataclasses import dataclass +from datetime import UTC, datetime +from threading import Event +from types import SimpleNamespace +from typing import Any, cast +from unittest.mock import MagicMock + +import pytest +from graphon.enums import WorkflowExecutionStatus +from graphon.runtime import GraphRuntimeState, VariablePool +from sqlalchemy.orm import Session, sessionmaker + +from core.app.app_config.entities import WorkflowUIBasedAppConfig +from core.app.entities.app_invoke_entities import InvokeFrom, WorkflowAppGenerateEntity +from core.app.entities.task_entities import StreamEvent +from core.app.layers.pause_state_persist_layer import WorkflowResumptionContext, _WorkflowGenerateEntityWrapper +from models.enums import CreatorUserRole +from models.model import AppMode +from models.workflow import WorkflowRun +from repositories.entities.workflow_pause import WorkflowPauseEntity +from services import workflow_event_snapshot_service as service_module +from services.workflow_event_snapshot_service import BufferState, MessageContext, build_workflow_event_stream + + +def _build_workflow_run_additional(status: WorkflowExecutionStatus = WorkflowExecutionStatus.RUNNING) -> WorkflowRun: + return WorkflowRun( + id="run-1", + tenant_id="tenant-1", + app_id="app-1", + workflow_id="workflow-1", + type="workflow", + triggered_from="app-run", + version="v1", + graph=None, + inputs=json.dumps({"query": "hello"}), + status=status, + outputs=json.dumps({}), + error=None, + elapsed_time=1.2, + total_tokens=5, + total_steps=2, + created_by_role=CreatorUserRole.END_USER, + created_by="user-1", + created_at=datetime(2024, 1, 1, tzinfo=UTC), + ) + + +def _build_resumption_context_additional(task_id: str) -> WorkflowResumptionContext: + app_config = WorkflowUIBasedAppConfig( + tenant_id="tenant-1", + app_id="app-1", + app_mode=AppMode.WORKFLOW, + workflow_id="workflow-1", + ) + generate_entity = WorkflowAppGenerateEntity( + task_id=task_id, + app_config=app_config, + inputs={}, + files=[], + user_id="user-1", + stream=True, + invoke_from=InvokeFrom.EXPLORE, + call_depth=0, + workflow_execution_id="run-1", + ) + runtime_state = GraphRuntimeState(variable_pool=VariablePool(), start_at=0.0) + runtime_state.outputs = {"answer": "ok"} + wrapper = _WorkflowGenerateEntityWrapper(entity=generate_entity) + return WorkflowResumptionContext( + generate_entity=wrapper, + serialized_graph_runtime_state=runtime_state.dumps(), + ) + + +class _SessionContext: + def __init__(self, session: Any) -> None: + self._session = session + + def __enter__(self) -> Any: + return self._session + + def __exit__(self, exc_type: Any, exc: Any, tb: Any) -> bool: + return False + + +class _SessionMaker: + def __init__(self, session: Any) -> None: + self._session = session + + def __call__(self) -> _SessionContext: + return _SessionContext(self._session) + + +class _SubscriptionContext: + def __init__(self, subscription: Any) -> None: + self._subscription = subscription + + def __enter__(self) -> Any: + return self._subscription + + def __exit__(self, exc_type: Any, exc: Any, tb: Any) -> bool: + return False + + +class _Topic: + def __init__(self, subscription: Any) -> None: + self._subscription = subscription + + def subscribe(self) -> _SubscriptionContext: + return _SubscriptionContext(self._subscription) + + +class _StaticSubscription: + def receive(self, timeout: int = 1) -> None: + return None + + +@dataclass(frozen=True) +class _PauseEntity(WorkflowPauseEntity): + state: bytes + + @property + def id(self) -> str: + return "pause-1" + + @property + def workflow_execution_id(self) -> str: + return "run-1" + + @property + def resumed_at(self) -> datetime | None: + return None + + @property + def paused_at(self) -> datetime: + return datetime(2024, 1, 1, tzinfo=UTC) + + def get_state(self) -> bytes: + return self.state + + def get_pause_reasons(self) -> list[Any]: + return [] + + +def test_get_message_context_should_return_none_when_no_message() -> None: + # Arrange + session = SimpleNamespace(scalar=MagicMock(return_value=None)) + session_maker = _SessionMaker(session) + + # Act + result = service_module._get_message_context(cast(sessionmaker[Session], session_maker), "run-1") + + # Assert + assert result is None + + +def test_get_message_context_should_default_created_at_to_zero_when_message_has_no_timestamp() -> None: + # Arrange + message = SimpleNamespace( + id="msg-1", + conversation_id="conv-1", + created_at=None, + answer="answer", + ) + session = SimpleNamespace(scalar=MagicMock(return_value=message)) + session_maker = _SessionMaker(session) + + # Act + result = service_module._get_message_context(cast(sessionmaker[Session], session_maker), "run-1") + + # Assert + assert result is not None + assert result.created_at == 0 + assert result.message_id == "msg-1" + assert result.conversation_id == "conv-1" + assert result.answer == "answer" + + +def test_load_resumption_context_should_return_none_when_pause_entity_missing() -> None: + # Arrange + + # Act + result = service_module._load_resumption_context(None) + + # Assert + assert result is None + + +def test_load_resumption_context_should_return_none_when_pause_entity_state_is_invalid() -> None: + # Arrange + pause_entity = _PauseEntity(state=b"not-a-valid-state") + + # Act + result = service_module._load_resumption_context(pause_entity) + + # Assert + assert result is None + + +def test_load_resumption_context_should_parse_valid_state_into_context() -> None: + # Arrange + context = _build_resumption_context_additional(task_id="task-ctx") + pause_entity = _PauseEntity(state=context.dumps().encode()) + + # Act + result = service_module._load_resumption_context(pause_entity) + + # Assert + assert result is not None + assert result.get_generate_entity().task_id == "task-ctx" + + +def test_resolve_task_id_should_return_workflow_run_id_when_buffer_state_is_missing() -> None: + # Arrange + + # Act + result = service_module._resolve_task_id( + resumption_context=None, + buffer_state=None, + workflow_run_id="run-1", + ) + + # Assert + assert result == "run-1" + + +@pytest.mark.parametrize( + ("payload", "expected"), + [ + (b'{"event":"node_started"}', {"event": "node_started"}), + (b"invalid-json", None), + (b"[]", None), + ], +) +def test_parse_event_message_should_parse_only_json_object( + payload: bytes, + expected: dict[str, Any] | None, +) -> None: + # Arrange + + # Act + result = service_module._parse_event_message(payload) + + # Assert + assert result == expected + + +def test_is_terminal_event_should_recognize_finished_and_optional_paused_events() -> None: + # Arrange + finished_event = {"event": StreamEvent.WORKFLOW_FINISHED.value} + paused_event = {"event": StreamEvent.WORKFLOW_PAUSED.value} + + # Act + is_finished = service_module._is_terminal_event(finished_event, include_paused=False) + paused_without_flag = service_module._is_terminal_event(paused_event, include_paused=False) + paused_with_flag = service_module._is_terminal_event(paused_event, include_paused=True) + + # Assert + assert is_finished is True + assert paused_without_flag is False + assert paused_with_flag is True + assert service_module._is_terminal_event(StreamEvent.PING.value, include_paused=True) is False + + +def test_apply_message_context_should_update_payload_when_context_exists() -> None: + # Arrange + payload: dict[str, Any] = {"event": "workflow_started"} + context = MessageContext(conversation_id="conv-1", message_id="msg-1", created_at=1700000000) + + # Act + service_module._apply_message_context(payload, context) + + # Assert + assert payload["conversation_id"] == "conv-1" + assert payload["message_id"] == "msg-1" + assert payload["created_at"] == 1700000000 + + +def test_start_buffering_should_capture_task_id_and_enqueue_event() -> None: + # Arrange + class Subscription: + def __init__(self) -> None: + self._calls = 0 + + def receive(self, timeout: int = 1) -> bytes | None: + self._calls += 1 + if self._calls == 1: + return b'{"event":"node_started","task_id":"task-1"}' + return None + + subscription = Subscription() + + # Act + buffer_state = service_module._start_buffering(subscription) + ready = buffer_state.task_id_ready.wait(timeout=1) + event = buffer_state.queue.get(timeout=1) + buffer_state.stop_event.set() + finished = buffer_state.done_event.wait(timeout=1) + + # Assert + assert ready is True + assert finished is True + assert buffer_state.task_id_hint == "task-1" + assert event["event"] == "node_started" + + +def test_start_buffering_should_drop_old_event_when_queue_is_full( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + class QueueWithSingleFull: + def __init__(self) -> None: + self._first_put = True + self.items: list[dict[str, Any]] = [{"event": "old"}] + + def put_nowait(self, item: dict[str, Any]) -> None: + if self._first_put: + self._first_put = False + raise queue.Full + self.items.append(item) + + def get_nowait(self) -> dict[str, Any]: + if not self.items: + raise queue.Empty + return self.items.pop(0) + + def empty(self) -> bool: + return len(self.items) == 0 + + fake_queue = QueueWithSingleFull() + monkeypatch.setattr(service_module.queue, "Queue", lambda maxsize=2048: fake_queue) + + class Subscription: + def __init__(self) -> None: + self._calls = 0 + + def receive(self, timeout: int = 1) -> bytes | None: + self._calls += 1 + if self._calls == 1: + return b'{"event":"node_started","task_id":"task-2"}' + return None + + subscription = Subscription() + + # Act + buffer_state = service_module._start_buffering(subscription) + ready = buffer_state.task_id_ready.wait(timeout=1) + buffer_state.stop_event.set() + finished = buffer_state.done_event.wait(timeout=1) + + # Assert + assert ready is True + assert finished is True + assert fake_queue.items[-1]["task_id"] == "task-2" + + +def test_start_buffering_should_set_done_event_when_subscription_raises() -> None: + # Arrange + class Subscription: + def receive(self, timeout: int = 1) -> bytes | None: + raise RuntimeError("subscription failure") + + subscription = Subscription() + + # Act + buffer_state = service_module._start_buffering(subscription) + finished = buffer_state.done_event.wait(timeout=1) + + # Assert + assert finished is True + + +def test_build_workflow_event_stream_should_emit_ping_and_terminal_snapshot_event( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + workflow_run = _build_workflow_run_additional(status=WorkflowExecutionStatus.RUNNING) + topic = _Topic(_StaticSubscription()) + workflow_run_repo = SimpleNamespace(get_workflow_pause=MagicMock()) + node_repo = SimpleNamespace(get_execution_snapshots_by_workflow_run=MagicMock(return_value=[])) + factory = SimpleNamespace( + create_api_workflow_run_repository=MagicMock(return_value=workflow_run_repo), + create_api_workflow_node_execution_repository=MagicMock(return_value=node_repo), + ) + monkeypatch.setattr(service_module, "DifyAPIRepositoryFactory", factory) + monkeypatch.setattr(service_module.MessageGenerator, "get_response_topic", MagicMock(return_value=topic)) + monkeypatch.setattr( + service_module, + "_get_message_context", + MagicMock(return_value=MessageContext("conv-1", "msg-1", 1700000000)), + ) + monkeypatch.setattr(service_module, "_load_resumption_context", MagicMock(return_value=None)) + buffer_state = BufferState( + queue=queue.Queue(), + stop_event=Event(), + done_event=Event(), + task_id_ready=Event(), + task_id_hint="task-1", + ) + monkeypatch.setattr(service_module, "_start_buffering", MagicMock(return_value=buffer_state)) + monkeypatch.setattr(service_module, "_resolve_task_id", MagicMock(return_value="task-1")) + monkeypatch.setattr( + service_module, + "_build_snapshot_events", + MagicMock(return_value=[{"event": StreamEvent.WORKFLOW_FINISHED.value, "task_id": "task-1"}]), + ) + + # Act + events = list( + build_workflow_event_stream( + app_mode=AppMode.ADVANCED_CHAT, + workflow_run=workflow_run, + tenant_id="tenant-1", + app_id="app-1", + session_maker=MagicMock(), + ) + ) + + # Assert + assert events[0] == StreamEvent.PING.value + finished_event = cast(Mapping[str, Any], events[1]) + assert finished_event["event"] == StreamEvent.WORKFLOW_FINISHED.value + assert buffer_state.stop_event.is_set() is True + node_repo.get_execution_snapshots_by_workflow_run.assert_called_once() + called_kwargs = node_repo.get_execution_snapshots_by_workflow_run.call_args.kwargs + assert called_kwargs["workflow_run_id"] == "run-1" + + +def test_build_workflow_event_stream_should_emit_periodic_ping_and_stop_after_idle_timeout( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + workflow_run = _build_workflow_run_additional(status=WorkflowExecutionStatus.RUNNING) + topic = _Topic(_StaticSubscription()) + workflow_run_repo = SimpleNamespace(get_workflow_pause=MagicMock()) + node_repo = SimpleNamespace(get_execution_snapshots_by_workflow_run=MagicMock(return_value=[])) + factory = SimpleNamespace( + create_api_workflow_run_repository=MagicMock(return_value=workflow_run_repo), + create_api_workflow_node_execution_repository=MagicMock(return_value=node_repo), + ) + monkeypatch.setattr(service_module, "DifyAPIRepositoryFactory", factory) + monkeypatch.setattr(service_module.MessageGenerator, "get_response_topic", MagicMock(return_value=topic)) + monkeypatch.setattr(service_module, "_load_resumption_context", MagicMock(return_value=None)) + monkeypatch.setattr(service_module, "_build_snapshot_events", MagicMock(return_value=[])) + monkeypatch.setattr(service_module, "_resolve_task_id", MagicMock(return_value="task-1")) + + class AlwaysEmptyQueue: + def empty(self) -> bool: + return False + + def get(self, timeout: int = 1) -> None: + raise queue.Empty + + buffer_state = BufferState( + queue=AlwaysEmptyQueue(), # type: ignore[arg-type] + stop_event=Event(), + done_event=Event(), + task_id_ready=Event(), + task_id_hint="task-1", + ) + monkeypatch.setattr(service_module, "_start_buffering", MagicMock(return_value=buffer_state)) + time_values = cycle([0.0, 6.0, 21.0, 26.0]) + monkeypatch.setattr(service_module.time, "time", lambda: next(time_values)) + + # Act + events = list( + build_workflow_event_stream( + app_mode=AppMode.WORKFLOW, + workflow_run=workflow_run, + tenant_id="tenant-1", + app_id="app-1", + session_maker=MagicMock(), + idle_timeout=20.0, + ping_interval=5.0, + ) + ) + + # Assert + assert events == [StreamEvent.PING.value, StreamEvent.PING.value] + assert buffer_state.stop_event.is_set() is True + + +def test_build_workflow_event_stream_should_exit_when_buffer_done_and_empty( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + workflow_run = _build_workflow_run_additional(status=WorkflowExecutionStatus.RUNNING) + topic = _Topic(_StaticSubscription()) + workflow_run_repo = SimpleNamespace(get_workflow_pause=MagicMock()) + node_repo = SimpleNamespace(get_execution_snapshots_by_workflow_run=MagicMock(return_value=[])) + factory = SimpleNamespace( + create_api_workflow_run_repository=MagicMock(return_value=workflow_run_repo), + create_api_workflow_node_execution_repository=MagicMock(return_value=node_repo), + ) + monkeypatch.setattr(service_module, "DifyAPIRepositoryFactory", factory) + monkeypatch.setattr(service_module.MessageGenerator, "get_response_topic", MagicMock(return_value=topic)) + monkeypatch.setattr(service_module, "_load_resumption_context", MagicMock(return_value=None)) + monkeypatch.setattr(service_module, "_build_snapshot_events", MagicMock(return_value=[])) + monkeypatch.setattr(service_module, "_resolve_task_id", MagicMock(return_value="task-1")) + buffer_state = BufferState( + queue=queue.Queue(), + stop_event=Event(), + done_event=Event(), + task_id_ready=Event(), + task_id_hint="task-1", + ) + buffer_state.done_event.set() + monkeypatch.setattr(service_module, "_start_buffering", MagicMock(return_value=buffer_state)) + + # Act + events = list( + build_workflow_event_stream( + app_mode=AppMode.WORKFLOW, + workflow_run=workflow_run, + tenant_id="tenant-1", + app_id="app-1", + session_maker=MagicMock(), + ) + ) + + # Assert + assert events == [StreamEvent.PING.value] + assert buffer_state.stop_event.is_set() is True + + +def test_build_workflow_event_stream_should_continue_when_pause_loading_fails( + monkeypatch: pytest.MonkeyPatch, +) -> None: + # Arrange + workflow_run = _build_workflow_run_additional(status=WorkflowExecutionStatus.PAUSED) + topic = _Topic(_StaticSubscription()) + workflow_run_repo = SimpleNamespace(get_workflow_pause=MagicMock(side_effect=RuntimeError("boom"))) + node_repo = SimpleNamespace(get_execution_snapshots_by_workflow_run=MagicMock(return_value=[])) + factory = SimpleNamespace( + create_api_workflow_run_repository=MagicMock(return_value=workflow_run_repo), + create_api_workflow_node_execution_repository=MagicMock(return_value=node_repo), + ) + monkeypatch.setattr(service_module, "DifyAPIRepositoryFactory", factory) + monkeypatch.setattr(service_module.MessageGenerator, "get_response_topic", MagicMock(return_value=topic)) + monkeypatch.setattr(service_module, "_load_resumption_context", MagicMock(return_value=None)) + monkeypatch.setattr(service_module, "_resolve_task_id", MagicMock(return_value="task-1")) + snapshot_builder = MagicMock(return_value=[{"event": StreamEvent.WORKFLOW_FINISHED.value}]) + monkeypatch.setattr(service_module, "_build_snapshot_events", snapshot_builder) + buffer_state = BufferState( + queue=queue.Queue(), + stop_event=Event(), + done_event=Event(), + task_id_ready=Event(), + task_id_hint="task-1", + ) + monkeypatch.setattr(service_module, "_start_buffering", MagicMock(return_value=buffer_state)) + + # Act + events = list( + build_workflow_event_stream( + app_mode=AppMode.WORKFLOW, + workflow_run=workflow_run, + tenant_id="tenant-1", + app_id="app-1", + session_maker=MagicMock(), + ) + ) + + # Assert + assert events[0] == StreamEvent.PING.value + assert snapshot_builder.call_args.kwargs["pause_entity"] is None diff --git a/api/tests/unit_tests/tasks/test_dataset_indexing_task.py b/api/tests/unit_tests/tasks/test_dataset_indexing_task.py index 0b189ebae2..34e474c921 100644 --- a/api/tests/unit_tests/tasks/test_dataset_indexing_task.py +++ b/api/tests/unit_tests/tasks/test_dataset_indexing_task.py @@ -10,6 +10,8 @@ This module tests the document indexing task functionality including: """ import uuid +from contextlib import nullcontext +from types import SimpleNamespace from unittest.mock import MagicMock, Mock, patch import pytest @@ -1113,13 +1115,17 @@ class TestAdvancedScenarios: _document_indexing_with_tenant_queue(tenant_id, dataset_id, document_ids, mock_task) # Assert - # Verify delete was called to clean up task key - mock_redis.delete.assert_called_once() + expected_task_key = f"tenant_document_indexing_task:{tenant_id}" - # Verify the correct key was deleted (contains tenant_id and "document_indexing") - delete_call_args = mock_redis.delete.call_args[0][0] - assert tenant_id in delete_call_args - assert "document_indexing" in delete_call_args + # Verify the task key for this tenant was deleted (do not assert call count; fixtures may be shared). + mock_redis.delete.assert_any_call(expected_task_key) + + deleted_keys = [delete_call.args[0] for delete_call in mock_redis.delete.call_args_list if delete_call.args] + assert expected_task_key in deleted_keys + + deleted_task_key = next(key for key in deleted_keys if key == expected_task_key) + assert tenant_id in deleted_task_key + assert "document_indexing" in deleted_task_key def test_billing_disabled_skips_limit_checks( self, dataset_id, document_ids, mock_db_session, mock_dataset, mock_indexing_runner, mock_feature_service @@ -1510,3 +1516,475 @@ class TestRobustness: # Verify the exception message assert "Feature service" in str(exc_info.value) or isinstance(exc_info.value, Exception) + + +class _SessionContext: + def __init__(self, session: MagicMock) -> None: + self._session = session + + def __enter__(self) -> MagicMock: + return self._session + + def __exit__(self, exc_type, exc, tb) -> None: # type: ignore[override] + return None + + +class TestDocumentIndexingTaskSummaryFlow: + """Additional coverage for summary and tenant queue branches.""" + + def test_should_return_when_dataset_missing(self, monkeypatch: pytest.MonkeyPatch) -> None: + """Test early return when dataset does not exist.""" + # Arrange + session = MagicMock() + dataset_query = MagicMock() + dataset_query.where.return_value = dataset_query + dataset_query.first.return_value = None + session.query.side_effect = lambda model: dataset_query + + create_session_mock = MagicMock(return_value=_SessionContext(session)) + monkeypatch.setattr("tasks.document_indexing_task.session_factory.create_session", create_session_mock) + features_mock = MagicMock() + monkeypatch.setattr("tasks.document_indexing_task.FeatureService.get_features", features_mock) + + # Act + _document_indexing("dataset-1", ["doc-1"]) + + # Assert + features_mock.assert_not_called() + + def test_should_mark_documents_error_when_batch_upload_limit_exceeded( + self, monkeypatch: pytest.MonkeyPatch + ) -> None: + """Test batch upload limit triggers error handling.""" + # Arrange + dataset = SimpleNamespace(id="dataset-1", tenant_id="tenant-1") + document = SimpleNamespace(id="doc-1", indexing_status=None, error=None, stopped_at=None) + + dataset_query = MagicMock() + dataset_query.where.return_value = dataset_query + dataset_query.first.return_value = dataset + + document_query = MagicMock() + document_query.where.return_value = document_query + document_query.first.return_value = document + + session = MagicMock() + session.query.side_effect = lambda model: dataset_query if model is Dataset else document_query + + monkeypatch.setattr( + "tasks.document_indexing_task.session_factory.create_session", + MagicMock(return_value=_SessionContext(session)), + ) + + features = SimpleNamespace( + billing=SimpleNamespace( + enabled=True, + subscription=SimpleNamespace(plan=CloudPlan.PROFESSIONAL), + ), + vector_space=SimpleNamespace(limit=0, size=0), + ) + monkeypatch.setattr( + "tasks.document_indexing_task.FeatureService.get_features", MagicMock(return_value=features) + ) + monkeypatch.setattr("tasks.document_indexing_task.dify_config.BATCH_UPLOAD_LIMIT", "1") + + # Act + _document_indexing("dataset-1", ["doc-1", "doc-2"]) + + # Assert + assert document.indexing_status == "error" + assert "batch upload limit" in document.error + session.commit.assert_called_once() + + def test_should_queue_summary_generation_for_completed_documents(self, monkeypatch: pytest.MonkeyPatch) -> None: + """Test summary generation is queued for eligible documents.""" + # Arrange + dataset = SimpleNamespace( + id="dataset-1", + tenant_id="tenant-1", + indexing_technique="high_quality", + summary_index_setting={"enable": True}, + ) + + doc_eligible = SimpleNamespace( + id="doc-1", + indexing_status="completed", + doc_form="text", + need_summary=True, + ) + doc_skip_form = SimpleNamespace( + id="doc-2", + indexing_status="completed", + doc_form="qa_model", + need_summary=True, + ) + doc_skip_status = SimpleNamespace( + id="doc-3", + indexing_status="processing", + doc_form="text", + need_summary=True, + ) + + dataset_query = MagicMock() + dataset_query.where.return_value = dataset_query + dataset_query.first.return_value = dataset + + phase1_docs = [SimpleNamespace(id="doc-1"), SimpleNamespace(id="doc-2"), SimpleNamespace(id="doc-3")] + phase1_document_query = MagicMock() + phase1_document_query.where.return_value = phase1_document_query + phase1_document_query.all.return_value = phase1_docs + + summary_document_query = MagicMock() + summary_document_query.where.return_value = summary_document_query + summary_document_query.all.return_value = [doc_eligible, doc_skip_form, doc_skip_status] + + session1 = MagicMock() + session2 = MagicMock() + session2.begin.return_value = nullcontext() + session3 = MagicMock() + + session1.query.side_effect = lambda model: dataset_query + session2.query.side_effect = lambda model: phase1_document_query + session3.query.side_effect = lambda model: summary_document_query if model is Document else dataset_query + + create_session_mock = MagicMock( + side_effect=[_SessionContext(session1), _SessionContext(session2), _SessionContext(session3)] + ) + monkeypatch.setattr("tasks.document_indexing_task.session_factory.create_session", create_session_mock) + + features = SimpleNamespace( + billing=SimpleNamespace(enabled=False), + vector_space=SimpleNamespace(limit=0, size=0), + ) + monkeypatch.setattr( + "tasks.document_indexing_task.FeatureService.get_features", MagicMock(return_value=features) + ) + + indexing_runner = MagicMock() + monkeypatch.setattr("tasks.document_indexing_task.IndexingRunner", MagicMock(return_value=indexing_runner)) + delay_mock = MagicMock() + monkeypatch.setattr("tasks.document_indexing_task.generate_summary_index_task.delay", delay_mock) + + # Act + _document_indexing("dataset-1", ["doc-1", "doc-2", "doc-3"]) + + # Assert + delay_mock.assert_called_once_with("dataset-1", "doc-1", None) + + def test_should_continue_when_summary_queue_fails(self, monkeypatch: pytest.MonkeyPatch) -> None: + """Test summary queueing errors are swallowed.""" + # Arrange + dataset = SimpleNamespace( + id="dataset-1", + tenant_id="tenant-1", + indexing_technique="high_quality", + summary_index_setting={"enable": True}, + ) + + doc_eligible = SimpleNamespace( + id="doc-1", + indexing_status="completed", + doc_form="text", + need_summary=True, + ) + + dataset_query = MagicMock() + dataset_query.where.return_value = dataset_query + dataset_query.first.return_value = dataset + + phase1_query = MagicMock() + phase1_query.where.return_value = phase1_query + phase1_query.all.return_value = [SimpleNamespace(id="doc-1")] + + summary_query = MagicMock() + summary_query.where.return_value = summary_query + summary_query.all.return_value = [doc_eligible] + + session1 = MagicMock() + session2 = MagicMock() + session2.begin.return_value = nullcontext() + session3 = MagicMock() + session1.query.side_effect = lambda model: dataset_query + session2.query.side_effect = lambda model: phase1_query + session3.query.side_effect = lambda model: summary_query if model is Document else dataset_query + + monkeypatch.setattr( + "tasks.document_indexing_task.session_factory.create_session", + MagicMock(side_effect=[_SessionContext(session1), _SessionContext(session2), _SessionContext(session3)]), + ) + + features = SimpleNamespace( + billing=SimpleNamespace(enabled=False), + vector_space=SimpleNamespace(limit=0, size=0), + ) + monkeypatch.setattr( + "tasks.document_indexing_task.FeatureService.get_features", MagicMock(return_value=features) + ) + + indexing_runner = MagicMock() + monkeypatch.setattr("tasks.document_indexing_task.IndexingRunner", MagicMock(return_value=indexing_runner)) + delay_mock = MagicMock(side_effect=Exception("boom")) + monkeypatch.setattr("tasks.document_indexing_task.generate_summary_index_task.delay", delay_mock) + + # Act + _document_indexing("dataset-1", ["doc-1"]) + + # Assert + delay_mock.assert_called_once_with("dataset-1", "doc-1", None) + + def test_should_return_when_dataset_missing_after_indexing(self, monkeypatch: pytest.MonkeyPatch) -> None: + """Test early return when dataset is missing after indexing.""" + # Arrange + dataset = SimpleNamespace(id="dataset-1", tenant_id="tenant-1") + dataset_query = MagicMock() + dataset_query.where.return_value = dataset_query + dataset_query.first.side_effect = [dataset, None] + + document_query = MagicMock() + document_query.where.return_value = document_query + document_query.all.return_value = [SimpleNamespace(id="doc-1")] + + session1 = MagicMock() + session2 = MagicMock() + session2.begin.return_value = nullcontext() + session3 = MagicMock() + session1.query.side_effect = lambda model: dataset_query + session2.query.side_effect = lambda model: document_query + session3.query.side_effect = lambda model: dataset_query + + monkeypatch.setattr( + "tasks.document_indexing_task.session_factory.create_session", + MagicMock(side_effect=[_SessionContext(session1), _SessionContext(session2), _SessionContext(session3)]), + ) + + features = SimpleNamespace( + billing=SimpleNamespace(enabled=False), + vector_space=SimpleNamespace(limit=0, size=0), + ) + monkeypatch.setattr( + "tasks.document_indexing_task.FeatureService.get_features", MagicMock(return_value=features) + ) + monkeypatch.setattr("tasks.document_indexing_task.IndexingRunner", MagicMock(return_value=MagicMock())) + + # Act + _document_indexing("dataset-1", ["doc-1"]) + + # Assert + session3.query.assert_called() + + def test_should_skip_summary_when_not_high_quality(self, monkeypatch: pytest.MonkeyPatch) -> None: + """Test summary generation skipped when indexing_technique is not high_quality.""" + # Arrange + dataset = SimpleNamespace( + id="dataset-1", + tenant_id="tenant-1", + indexing_technique="economy", + summary_index_setting={"enable": True}, + ) + dataset_query = MagicMock() + dataset_query.where.return_value = dataset_query + dataset_query.first.return_value = dataset + + document_query = MagicMock() + document_query.where.return_value = document_query + document_query.all.return_value = [SimpleNamespace(id="doc-1")] + + session1 = MagicMock() + session2 = MagicMock() + session2.begin.return_value = nullcontext() + session3 = MagicMock() + session1.query.side_effect = lambda model: dataset_query + session2.query.side_effect = lambda model: document_query + session3.query.side_effect = lambda model: dataset_query + + monkeypatch.setattr( + "tasks.document_indexing_task.session_factory.create_session", + MagicMock(side_effect=[_SessionContext(session1), _SessionContext(session2), _SessionContext(session3)]), + ) + + features = SimpleNamespace( + billing=SimpleNamespace(enabled=False), + vector_space=SimpleNamespace(limit=0, size=0), + ) + monkeypatch.setattr( + "tasks.document_indexing_task.FeatureService.get_features", MagicMock(return_value=features) + ) + monkeypatch.setattr("tasks.document_indexing_task.IndexingRunner", MagicMock(return_value=MagicMock())) + + delay_mock = MagicMock() + monkeypatch.setattr("tasks.document_indexing_task.generate_summary_index_task.delay", delay_mock) + + # Act + _document_indexing("dataset-1", ["doc-1"]) + + # Assert + delay_mock.assert_not_called() + + def test_should_skip_summary_generation_when_indexing_paused(self, monkeypatch: pytest.MonkeyPatch) -> None: + """Test summary generation is skipped when indexing is paused.""" + # Arrange + dataset = SimpleNamespace(id="dataset-1", tenant_id="tenant-1") + dataset_query = MagicMock() + dataset_query.where.return_value = dataset_query + dataset_query.first.return_value = dataset + + document_query = MagicMock() + document_query.where.return_value = document_query + document_query.all.return_value = [SimpleNamespace(id="doc-1")] + + session1 = MagicMock() + session2 = MagicMock() + session2.begin.return_value = nullcontext() + session1.query.side_effect = lambda model: dataset_query + session2.query.side_effect = lambda model: document_query + + create_session_mock = MagicMock(side_effect=[_SessionContext(session1), _SessionContext(session2)]) + monkeypatch.setattr("tasks.document_indexing_task.session_factory.create_session", create_session_mock) + + features = SimpleNamespace( + billing=SimpleNamespace(enabled=False), + vector_space=SimpleNamespace(limit=0, size=0), + ) + monkeypatch.setattr( + "tasks.document_indexing_task.FeatureService.get_features", MagicMock(return_value=features) + ) + + runner = MagicMock() + runner.run.side_effect = DocumentIsPausedError("paused") + monkeypatch.setattr("tasks.document_indexing_task.IndexingRunner", MagicMock(return_value=runner)) + delay_mock = MagicMock() + monkeypatch.setattr("tasks.document_indexing_task.generate_summary_index_task.delay", delay_mock) + + # Act + _document_indexing("dataset-1", ["doc-1"]) + + # Assert + delay_mock.assert_not_called() + + def test_should_handle_indexing_runner_exception(self, monkeypatch: pytest.MonkeyPatch) -> None: + """Test generic indexing runner exception is handled.""" + # Arrange + dataset = SimpleNamespace(id="dataset-1", tenant_id="tenant-1") + dataset_query = MagicMock() + dataset_query.where.return_value = dataset_query + dataset_query.first.return_value = dataset + + document_query = MagicMock() + document_query.where.return_value = document_query + document_query.all.return_value = [SimpleNamespace(id="doc-1")] + + session1 = MagicMock() + session2 = MagicMock() + session2.begin.return_value = nullcontext() + session1.query.side_effect = lambda model: dataset_query + session2.query.side_effect = lambda model: document_query + + monkeypatch.setattr( + "tasks.document_indexing_task.session_factory.create_session", + MagicMock(side_effect=[_SessionContext(session1), _SessionContext(session2)]), + ) + + features = SimpleNamespace( + billing=SimpleNamespace(enabled=False), + vector_space=SimpleNamespace(limit=0, size=0), + ) + monkeypatch.setattr( + "tasks.document_indexing_task.FeatureService.get_features", MagicMock(return_value=features) + ) + + runner = MagicMock() + runner.run.side_effect = RuntimeError("boom") + monkeypatch.setattr("tasks.document_indexing_task.IndexingRunner", MagicMock(return_value=runner)) + + delay_mock = MagicMock() + monkeypatch.setattr("tasks.document_indexing_task.generate_summary_index_task.delay", delay_mock) + + # Act + _document_indexing("dataset-1", ["doc-1"]) + + # Assert + delay_mock.assert_not_called() + + def test_should_log_missing_document_entry_in_summary_list(self, monkeypatch: pytest.MonkeyPatch) -> None: + """Test falsey document entries are handled in summary iteration.""" + + # Arrange + class _FalseyDocument: + def __init__(self, doc_id: str) -> None: + self.id = doc_id + + def __bool__(self) -> bool: + return False + + dataset = SimpleNamespace( + id="dataset-1", + tenant_id="tenant-1", + indexing_technique="high_quality", + summary_index_setting={"enable": True}, + ) + dataset_query = MagicMock() + dataset_query.where.return_value = dataset_query + dataset_query.first.return_value = dataset + + phase1_query = MagicMock() + phase1_query.where.return_value = phase1_query + phase1_query.all.return_value = [SimpleNamespace(id="doc-1")] + + summary_query = MagicMock() + summary_query.where.return_value = summary_query + summary_query.all.return_value = [_FalseyDocument("missing-doc")] + + session1 = MagicMock() + session2 = MagicMock() + session2.begin.return_value = nullcontext() + session3 = MagicMock() + session1.query.side_effect = lambda model: dataset_query + session2.query.side_effect = lambda model: phase1_query + session3.query.side_effect = lambda model: summary_query if model is Document else dataset_query + + monkeypatch.setattr( + "tasks.document_indexing_task.session_factory.create_session", + MagicMock(side_effect=[_SessionContext(session1), _SessionContext(session2), _SessionContext(session3)]), + ) + + features = SimpleNamespace( + billing=SimpleNamespace(enabled=False), + vector_space=SimpleNamespace(limit=0, size=0), + ) + monkeypatch.setattr( + "tasks.document_indexing_task.FeatureService.get_features", MagicMock(return_value=features) + ) + monkeypatch.setattr("tasks.document_indexing_task.IndexingRunner", MagicMock(return_value=MagicMock())) + + delay_mock = MagicMock() + monkeypatch.setattr("tasks.document_indexing_task.generate_summary_index_task.delay", delay_mock) + + # Act + _document_indexing("dataset-1", ["doc-1"]) + + # Assert + delay_mock.assert_not_called() + + def test_normal_document_indexing_task_should_delegate(self, monkeypatch: pytest.MonkeyPatch) -> None: + """Test normal indexing task delegates to tenant queue handler.""" + # Arrange + handler = MagicMock() + monkeypatch.setattr("tasks.document_indexing_task._document_indexing_with_tenant_queue", handler) + + # Act + normal_document_indexing_task("tenant-1", "dataset-1", ["doc-1"]) + + # Assert + handler.assert_called_once_with("tenant-1", "dataset-1", ["doc-1"], normal_document_indexing_task) + + def test_priority_document_indexing_task_should_delegate(self, monkeypatch: pytest.MonkeyPatch) -> None: + """Test priority indexing task delegates to tenant queue handler.""" + # Arrange + handler = MagicMock() + monkeypatch.setattr("tasks.document_indexing_task._document_indexing_with_tenant_queue", handler) + + # Act + priority_document_indexing_task("tenant-1", "dataset-1", ["doc-1"]) + + # Assert + handler.assert_called_once_with("tenant-1", "dataset-1", ["doc-1"], priority_document_indexing_task) From 318a3d03087e1102b856381fc004acb0d781bb5f Mon Sep 17 00:00:00 2001 From: 99 Date: Thu, 2 Apr 2026 17:36:58 +0800 Subject: [PATCH 03/29] refactor(api): tighten login and wrapper typing (#34447) --- .../console/app/workflow_draft_variable.py | 4 +- api/controllers/console/app/wraps.py | 54 +++++-- .../rag_pipeline_draft_variable.py | 5 +- api/controllers/service_api/wraps.py | 140 ++++++++---------- api/dify_app.py | 11 +- api/extensions/ext_login.py | 39 ++++- api/libs/login.py | 27 ++-- .../console/test_workspace_account.py | 2 +- .../console/test_workspace_members.py | 2 +- .../unit_tests/extensions/test_ext_login.py | 17 +++ api/tests/unit_tests/libs/test_login.py | 49 +++++- 11 files changed, 229 insertions(+), 121 deletions(-) create mode 100644 api/tests/unit_tests/extensions/test_ext_login.py diff --git a/api/controllers/console/app/workflow_draft_variable.py b/api/controllers/console/app/workflow_draft_variable.py index 366f145360..f6d076320c 100644 --- a/api/controllers/console/app/workflow_draft_variable.py +++ b/api/controllers/console/app/workflow_draft_variable.py @@ -193,7 +193,7 @@ workflow_draft_variable_list_model = console_ns.model( ) -def _api_prerequisite(f: Callable[..., Any]) -> Callable[..., Any]: +def _api_prerequisite[**P, R](f: Callable[P, R]) -> Callable[P, R | Response]: """Common prerequisites for all draft workflow variable APIs. It ensures the following conditions are satisfied: @@ -210,7 +210,7 @@ def _api_prerequisite(f: Callable[..., Any]) -> Callable[..., Any]: @edit_permission_required @get_app_model(mode=[AppMode.ADVANCED_CHAT, AppMode.WORKFLOW]) @wraps(f) - def wrapper(*args: Any, **kwargs: Any): + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R | Response: return f(*args, **kwargs) return wrapper diff --git a/api/controllers/console/app/wraps.py b/api/controllers/console/app/wraps.py index bd6f019eac..c9cf08072a 100644 --- a/api/controllers/console/app/wraps.py +++ b/api/controllers/console/app/wraps.py @@ -1,6 +1,6 @@ from collections.abc import Callable from functools import wraps -from typing import Any +from typing import overload from sqlalchemy import select @@ -23,14 +23,30 @@ def _load_app_model_with_trial(app_id: str) -> App | None: return app_model -def get_app_model( - view: Callable[..., Any] | None = None, +@overload +def get_app_model[**P, R]( + view: Callable[P, R], *, mode: AppMode | list[AppMode] | None = None, -) -> Callable[..., Any] | Callable[[Callable[..., Any]], Callable[..., Any]]: - def decorator(view_func: Callable[..., Any]) -> Callable[..., Any]: +) -> Callable[P, R]: ... + + +@overload +def get_app_model[**P, R]( + view: None = None, + *, + mode: AppMode | list[AppMode] | None = None, +) -> Callable[[Callable[P, R]], Callable[P, R]]: ... + + +def get_app_model[**P, R]( + view: Callable[P, R] | None = None, + *, + mode: AppMode | list[AppMode] | None = None, +) -> Callable[P, R] | Callable[[Callable[P, R]], Callable[P, R]]: + def decorator(view_func: Callable[P, R]) -> Callable[P, R]: @wraps(view_func) - def decorated_view(*args: Any, **kwargs: Any): + def decorated_view(*args: P.args, **kwargs: P.kwargs) -> R: if not kwargs.get("app_id"): raise ValueError("missing app_id in path parameters") @@ -68,14 +84,30 @@ def get_app_model( return decorator(view) -def get_app_model_with_trial( - view: Callable[..., Any] | None = None, +@overload +def get_app_model_with_trial[**P, R]( + view: Callable[P, R], *, mode: AppMode | list[AppMode] | None = None, -) -> Callable[..., Any] | Callable[[Callable[..., Any]], Callable[..., Any]]: - def decorator(view_func: Callable[..., Any]) -> Callable[..., Any]: +) -> Callable[P, R]: ... + + +@overload +def get_app_model_with_trial[**P, R]( + view: None = None, + *, + mode: AppMode | list[AppMode] | None = None, +) -> Callable[[Callable[P, R]], Callable[P, R]]: ... + + +def get_app_model_with_trial[**P, R]( + view: Callable[P, R] | None = None, + *, + mode: AppMode | list[AppMode] | None = None, +) -> Callable[P, R] | Callable[[Callable[P, R]], Callable[P, R]]: + def decorator(view_func: Callable[P, R]) -> Callable[P, R]: @wraps(view_func) - def decorated_view(*args: Any, **kwargs: Any): + def decorated_view(*args: P.args, **kwargs: P.kwargs) -> R: if not kwargs.get("app_id"): raise ValueError("missing app_id in path parameters") diff --git a/api/controllers/console/datasets/rag_pipeline/rag_pipeline_draft_variable.py b/api/controllers/console/datasets/rag_pipeline/rag_pipeline_draft_variable.py index d635dcb530..93feec0019 100644 --- a/api/controllers/console/datasets/rag_pipeline/rag_pipeline_draft_variable.py +++ b/api/controllers/console/datasets/rag_pipeline/rag_pipeline_draft_variable.py @@ -1,4 +1,5 @@ import logging +from collections.abc import Callable from typing import Any, NoReturn from flask import Response, request @@ -55,7 +56,7 @@ class WorkflowDraftVariablePatchPayload(BaseModel): register_schema_models(console_ns, WorkflowDraftVariablePatchPayload) -def _api_prerequisite(f): +def _api_prerequisite[**P, R](f: Callable[P, R]) -> Callable[P, R | Response]: """Common prerequisites for all draft workflow variable APIs. It ensures the following conditions are satisfied: @@ -70,7 +71,7 @@ def _api_prerequisite(f): @login_required @account_initialization_required @get_rag_pipeline - def wrapper(*args, **kwargs): + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R | Response: if not isinstance(current_user, Account) or not current_user.has_edit_permission: raise Forbidden() return f(*args, **kwargs) diff --git a/api/controllers/service_api/wraps.py b/api/controllers/service_api/wraps.py index 2dd916bb31..b9389ccc47 100644 --- a/api/controllers/service_api/wraps.py +++ b/api/controllers/service_api/wraps.py @@ -1,9 +1,10 @@ +import inspect import logging import time from collections.abc import Callable from enum import StrEnum, auto from functools import wraps -from typing import Any, cast, overload +from typing import cast, overload from flask import current_app, request from flask_login import user_logged_in @@ -230,94 +231,73 @@ def cloud_edition_billing_rate_limit_check[**P, R]( return interceptor -def validate_dataset_token( - view: Callable[..., Any] | None = None, -) -> Callable[..., Any] | Callable[[Callable[..., Any]], Callable[..., Any]]: - def decorator(view_func: Callable[..., Any]) -> Callable[..., Any]: - @wraps(view_func) - def decorated(*args: Any, **kwargs: Any) -> Any: - api_token = validate_and_get_api_token("dataset") +def validate_dataset_token[R](view: Callable[..., R]) -> Callable[..., R]: + positional_parameters = [ + parameter + for parameter in inspect.signature(view).parameters.values() + if parameter.kind in (inspect.Parameter.POSITIONAL_ONLY, inspect.Parameter.POSITIONAL_OR_KEYWORD) + ] + expects_bound_instance = bool(positional_parameters and positional_parameters[0].name in {"self", "cls"}) - # get url path dataset_id from positional args or kwargs - # Flask passes URL path parameters as positional arguments - dataset_id = None + @wraps(view) + def decorated(*args: object, **kwargs: object) -> R: + api_token = validate_and_get_api_token("dataset") - # First try to get from kwargs (explicit parameter) - dataset_id = kwargs.get("dataset_id") + # Flask may pass URL path parameters positionally, so inspect both kwargs and args. + dataset_id = kwargs.get("dataset_id") - # If not in kwargs, try to extract from positional args - if not dataset_id and args: - # For class methods: args[0] is self, args[1] is dataset_id (if exists) - # Check if first arg is likely a class instance (has __dict__ or __class__) - if len(args) > 1 and hasattr(args[0], "__dict__"): - # This is a class method, dataset_id should be in args[1] - potential_id = args[1] - # Validate it's a string-like UUID, not another object - try: - # Try to convert to string and check if it's a valid UUID format - str_id = str(potential_id) - # Basic check: UUIDs are 36 chars with hyphens - if len(str_id) == 36 and str_id.count("-") == 4: - dataset_id = str_id - except Exception: - logger.exception("Failed to parse dataset_id from class method args") - elif len(args) > 0: - # Not a class method, check if args[0] looks like a UUID - potential_id = args[0] - try: - str_id = str(potential_id) - if len(str_id) == 36 and str_id.count("-") == 4: - dataset_id = str_id - except Exception: - logger.exception("Failed to parse dataset_id from positional args") + if not dataset_id and args: + potential_id = args[0] + try: + str_id = str(potential_id) + if len(str_id) == 36 and str_id.count("-") == 4: + dataset_id = str_id + except Exception: + logger.exception("Failed to parse dataset_id from positional args") - # Validate dataset if dataset_id is provided - if dataset_id: - dataset_id = str(dataset_id) - dataset = db.session.scalar( - select(Dataset) - .where( - Dataset.id == dataset_id, - Dataset.tenant_id == api_token.tenant_id, - ) - .limit(1) + if dataset_id: + dataset_id = str(dataset_id) + dataset = db.session.scalar( + select(Dataset) + .where( + Dataset.id == dataset_id, + Dataset.tenant_id == api_token.tenant_id, ) - if not dataset: - raise NotFound("Dataset not found.") - if not dataset.enable_api: - raise Forbidden("Dataset api access is not enabled.") - tenant_account_join = db.session.execute( - select(Tenant, TenantAccountJoin) - .where(Tenant.id == api_token.tenant_id) - .where(TenantAccountJoin.tenant_id == Tenant.id) - .where(TenantAccountJoin.role.in_(["owner"])) - .where(Tenant.status == TenantStatus.NORMAL) - ).one_or_none() # TODO: only owner information is required, so only one is returned. - if tenant_account_join: - tenant, ta = tenant_account_join - account = db.session.get(Account, ta.account_id) - # Login admin - if account: - account.current_tenant = tenant - current_app.login_manager._update_request_context_with_user(account) # type: ignore - user_logged_in.send(current_app._get_current_object(), user=current_user) # type: ignore - else: - raise Unauthorized("Tenant owner account does not exist.") + .limit(1) + ) + if not dataset: + raise NotFound("Dataset not found.") + if not dataset.enable_api: + raise Forbidden("Dataset api access is not enabled.") + + tenant_account_join = db.session.execute( + select(Tenant, TenantAccountJoin) + .where(Tenant.id == api_token.tenant_id) + .where(TenantAccountJoin.tenant_id == Tenant.id) + .where(TenantAccountJoin.role.in_(["owner"])) + .where(Tenant.status == TenantStatus.NORMAL) + ).one_or_none() # TODO: only owner information is required, so only one is returned. + if tenant_account_join: + tenant, ta = tenant_account_join + account = db.session.get(Account, ta.account_id) + # Login admin + if account: + account.current_tenant = tenant + current_app.login_manager._update_request_context_with_user(account) # type: ignore + user_logged_in.send(current_app._get_current_object(), user=current_user) # type: ignore else: - raise Unauthorized("Tenant does not exist.") - if args and isinstance(args[0], Resource): - return view_func(args[0], api_token.tenant_id, *args[1:], **kwargs) + raise Unauthorized("Tenant owner account does not exist.") + else: + raise Unauthorized("Tenant does not exist.") - return view_func(api_token.tenant_id, *args, **kwargs) + if expects_bound_instance: + if not args: + raise TypeError("validate_dataset_token expected a bound resource instance.") + return view(args[0], api_token.tenant_id, *args[1:], **kwargs) - return decorated + return view(api_token.tenant_id, *args, **kwargs) - if view: - return decorator(view) - - # if view is None, it means that the decorator is used without parentheses - # use the decorator as a function for method_decorators - return decorator + return decorated def validate_and_get_api_token(scope: str | None = None): diff --git a/api/dify_app.py b/api/dify_app.py index d6deb8e007..bbe3f33787 100644 --- a/api/dify_app.py +++ b/api/dify_app.py @@ -1,5 +1,14 @@ +from __future__ import annotations + +from typing import TYPE_CHECKING + from flask import Flask +if TYPE_CHECKING: + from extensions.ext_login import DifyLoginManager + class DifyApp(Flask): - pass + """Flask application type with Dify-specific extension attributes.""" + + login_manager: DifyLoginManager diff --git a/api/extensions/ext_login.py b/api/extensions/ext_login.py index 02e50a90fc..bc59eaca63 100644 --- a/api/extensions/ext_login.py +++ b/api/extensions/ext_login.py @@ -1,7 +1,8 @@ import json +from typing import cast import flask_login -from flask import Response, request +from flask import Request, Response, request from flask_login import user_loaded_from_request, user_logged_in from sqlalchemy import select from werkzeug.exceptions import NotFound, Unauthorized @@ -16,13 +17,35 @@ from models import Account, Tenant, TenantAccountJoin from models.model import AppMCPServer, EndUser from services.account_service import AccountService -login_manager = flask_login.LoginManager() +type LoginUser = Account | EndUser + + +class DifyLoginManager(flask_login.LoginManager): + """Project-specific Flask-Login manager with a stable unauthorized contract. + + Dify registers `unauthorized_handler` below to always return a JSON `Response`. + Overriding this method lets callers rely on that narrower return type instead of + Flask-Login's broader callback contract. + """ + + def unauthorized(self) -> Response: + """Return the registered unauthorized handler result as a Flask `Response`.""" + return cast(Response, super().unauthorized()) + + def load_user_from_request_context(self) -> None: + """Populate Flask-Login's request-local user cache for the current request.""" + self._load_user() + + +login_manager = DifyLoginManager() # Flask-Login configuration @login_manager.request_loader -def load_user_from_request(request_from_flask_login): +def load_user_from_request(request_from_flask_login: Request) -> LoginUser | None: """Load user based on the request.""" + del request_from_flask_login + # Skip authentication for documentation endpoints if dify_config.SWAGGER_UI_ENABLED and request.path.endswith((dify_config.SWAGGER_UI_PATH, "/swagger.json")): return None @@ -100,10 +123,12 @@ def load_user_from_request(request_from_flask_login): raise NotFound("End user not found.") return end_user + return None + @user_logged_in.connect @user_loaded_from_request.connect -def on_user_logged_in(_sender, user): +def on_user_logged_in(_sender: object, user: LoginUser) -> None: """Called when a user logged in. Note: AccountService.load_logged_in_account will populate user.current_tenant_id @@ -114,8 +139,10 @@ def on_user_logged_in(_sender, user): @login_manager.unauthorized_handler -def unauthorized_handler(): +def unauthorized_handler() -> Response: """Handle unauthorized requests.""" + # Keep this as a concrete `Response`; `DifyLoginManager.unauthorized()` narrows + # Flask-Login's callback contract based on this override. return Response( json.dumps({"code": "unauthorized", "message": "Unauthorized."}), status=401, @@ -123,5 +150,5 @@ def unauthorized_handler(): ) -def init_app(app: DifyApp): +def init_app(app: DifyApp) -> None: login_manager.init_app(app) diff --git a/api/libs/login.py b/api/libs/login.py index 68a2050747..067597cb3c 100644 --- a/api/libs/login.py +++ b/api/libs/login.py @@ -2,19 +2,19 @@ from __future__ import annotations from collections.abc import Callable from functools import wraps -from typing import TYPE_CHECKING, Any +from typing import TYPE_CHECKING, Any, cast -from flask import current_app, g, has_request_context, request +from flask import Response, current_app, g, has_request_context, request from flask_login.config import EXEMPT_METHODS from werkzeug.local import LocalProxy from configs import dify_config +from dify_app import DifyApp +from extensions.ext_login import DifyLoginManager from libs.token import check_csrf_token from models import Account if TYPE_CHECKING: - from flask.typing import ResponseReturnValue - from models.model import EndUser @@ -29,7 +29,13 @@ def _resolve_current_user() -> EndUser | Account | None: return get_current_object() if callable(get_current_object) else user_proxy # type: ignore -def current_account_with_tenant(): +def _get_login_manager() -> DifyLoginManager: + """Return the project login manager with Dify's narrowed unauthorized contract.""" + app = cast(DifyApp, current_app) + return app.login_manager + + +def current_account_with_tenant() -> tuple[Account, str]: """ Resolve the underlying account for the current user proxy and ensure tenant context exists. Allows tests to supply plain Account mocks without the LocalProxy helper. @@ -42,7 +48,7 @@ def current_account_with_tenant(): return user, user.current_tenant_id -def login_required[**P, R](func: Callable[P, R]) -> Callable[P, R | ResponseReturnValue]: +def login_required[**P, R](func: Callable[P, R]) -> Callable[P, R | Response]: """ If you decorate a view with this, it will ensure that the current user is logged in and authenticated before calling the actual view. (If they are @@ -77,13 +83,16 @@ def login_required[**P, R](func: Callable[P, R]) -> Callable[P, R | ResponseRetu """ @wraps(func) - def decorated_view(*args: P.args, **kwargs: P.kwargs) -> R | ResponseReturnValue: + def decorated_view(*args: P.args, **kwargs: P.kwargs) -> R | Response: if request.method in EXEMPT_METHODS or dify_config.LOGIN_DISABLED: return current_app.ensure_sync(func)(*args, **kwargs) user = _resolve_current_user() if user is None or not user.is_authenticated: - return current_app.login_manager.unauthorized() # type: ignore + # `DifyLoginManager` guarantees that the registered unauthorized handler + # is surfaced here as a concrete Flask `Response`. + unauthorized_response: Response = _get_login_manager().unauthorized() + return unauthorized_response g._login_user = user # we put csrf validation here for less conflicts # TODO: maybe find a better place for it. @@ -96,7 +105,7 @@ def login_required[**P, R](func: Callable[P, R]) -> Callable[P, R | ResponseRetu def _get_user() -> EndUser | Account | None: if has_request_context(): if "_login_user" not in g: - current_app.login_manager._load_user() # type: ignore + _get_login_manager().load_user_from_request_context() return g._login_user diff --git a/api/tests/unit_tests/controllers/console/test_workspace_account.py b/api/tests/unit_tests/controllers/console/test_workspace_account.py index 9afc1c4166..7f9fe9cbf9 100644 --- a/api/tests/unit_tests/controllers/console/test_workspace_account.py +++ b/api/tests/unit_tests/controllers/console/test_workspace_account.py @@ -20,7 +20,7 @@ def app(): app = Flask(__name__) app.config["TESTING"] = True app.config["RESTX_MASK_HEADER"] = "X-Fields" - app.login_manager = SimpleNamespace(_load_user=lambda: None) + app.login_manager = SimpleNamespace(load_user_from_request_context=lambda: None) return app diff --git a/api/tests/unit_tests/controllers/console/test_workspace_members.py b/api/tests/unit_tests/controllers/console/test_workspace_members.py index 368892b922..239fec8430 100644 --- a/api/tests/unit_tests/controllers/console/test_workspace_members.py +++ b/api/tests/unit_tests/controllers/console/test_workspace_members.py @@ -12,7 +12,7 @@ from models.account import Account, TenantAccountRole def app(): flask_app = Flask(__name__) flask_app.config["TESTING"] = True - flask_app.login_manager = SimpleNamespace(_load_user=lambda: None) + flask_app.login_manager = SimpleNamespace(load_user_from_request_context=lambda: None) return flask_app diff --git a/api/tests/unit_tests/extensions/test_ext_login.py b/api/tests/unit_tests/extensions/test_ext_login.py new file mode 100644 index 0000000000..64abc19427 --- /dev/null +++ b/api/tests/unit_tests/extensions/test_ext_login.py @@ -0,0 +1,17 @@ +import json + +from flask import Response + +from extensions.ext_login import unauthorized_handler + + +def test_unauthorized_handler_returns_json_response() -> None: + response = unauthorized_handler() + + assert isinstance(response, Response) + assert response.status_code == 401 + assert response.content_type == "application/json" + assert json.loads(response.get_data(as_text=True)) == { + "code": "unauthorized", + "message": "Unauthorized.", + } diff --git a/api/tests/unit_tests/libs/test_login.py b/api/tests/unit_tests/libs/test_login.py index 0c9e73299b..2bf2212844 100644 --- a/api/tests/unit_tests/libs/test_login.py +++ b/api/tests/unit_tests/libs/test_login.py @@ -2,11 +2,12 @@ from types import SimpleNamespace from unittest.mock import MagicMock import pytest -from flask import Flask, g -from flask_login import LoginManager, UserMixin +from flask import Flask, Response, g +from flask_login import UserMixin from pytest_mock import MockerFixture import libs.login as login_module +from extensions.ext_login import DifyLoginManager from libs.login import current_user from models.account import Account @@ -39,9 +40,12 @@ def login_app(mocker: MockerFixture) -> Flask: app = Flask(__name__) app.config["TESTING"] = True - login_manager = LoginManager() + login_manager = DifyLoginManager() login_manager.init_app(app) - login_manager.unauthorized = mocker.Mock(name="unauthorized", return_value="Unauthorized") + login_manager.unauthorized = mocker.Mock( + name="unauthorized", + return_value=Response("Unauthorized", status=401, content_type="application/json"), + ) @login_manager.user_loader def load_user(_user_id: str): @@ -109,18 +113,43 @@ class TestLoginRequired: resolved_user: MockUser | None, description: str, ): - """Test that missing or unauthenticated users are redirected.""" + """Test that missing or unauthenticated users return the manager response.""" resolve_user = resolve_current_user(resolved_user) with login_app.test_request_context(): result = protected_view() - assert result == "Unauthorized", description + assert result is login_app.login_manager.unauthorized.return_value, description + assert isinstance(result, Response) + assert result.status_code == 401 resolve_user.assert_called_once_with() login_app.login_manager.unauthorized.assert_called_once_with() csrf_check.assert_not_called() + def test_unauthorized_access_propagates_response_object( + self, + login_app: Flask, + protected_view, + csrf_check: MagicMock, + resolve_current_user, + mocker: MockerFixture, + ) -> None: + """Test that unauthorized responses are propagated as Flask Response objects.""" + resolve_user = resolve_current_user(None) + response = Response("Unauthorized", status=401, content_type="application/json") + mocker.patch.object( + login_module, "_get_login_manager", return_value=SimpleNamespace(unauthorized=lambda: response) + ) + + with login_app.test_request_context(): + result = protected_view() + + assert result is response + assert isinstance(result, Response) + resolve_user.assert_called_once_with() + csrf_check.assert_not_called() + @pytest.mark.parametrize( ("method", "login_disabled"), [ @@ -168,10 +197,14 @@ class TestGetUser: """Test that _get_user loads user if not already in g.""" mock_user = MockUser("test_user") - def _load_user() -> None: + def load_user_from_request_context() -> None: g._login_user = mock_user - load_user = mocker.patch.object(login_app.login_manager, "_load_user", side_effect=_load_user) + load_user = mocker.patch.object( + login_app.login_manager, + "load_user_from_request_context", + side_effect=load_user_from_request_context, + ) with login_app.test_request_context(): user = login_module._get_user() From a3386da5d61ed22b6770687db2791584a8affdf0 Mon Sep 17 00:00:00 2001 From: Asuka Minato Date: Thu, 2 Apr 2026 18:48:46 +0900 Subject: [PATCH 04/29] ci: Update pyrefly version to 0.59.1 (#34452) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- api/pyproject.toml | 2 +- api/uv.lock | 40 ++++++++++++---------------------------- 2 files changed, 13 insertions(+), 29 deletions(-) diff --git a/api/pyproject.toml b/api/pyproject.toml index 863b61cad1..cbd9af151b 100644 --- a/api/pyproject.toml +++ b/api/pyproject.toml @@ -171,7 +171,7 @@ dev = [ "sseclient-py>=1.8.0", "pytest-timeout>=2.4.0", "pytest-xdist>=3.8.0", - "pyrefly>=0.57.1", + "pyrefly>=0.59.1", ] ############################################################ diff --git a/api/uv.lock b/api/uv.lock index 9381fabb40..d171483d37 100644 --- a/api/uv.lock +++ b/api/uv.lock @@ -53,23 +53,6 @@ dependencies = [ ] sdist = { url = "https://files.pythonhosted.org/packages/45/4a/064321452809dae953c1ed6e017504e72551a26b6f5708a5a80e4bf556ff/aiohttp-3.13.4.tar.gz", hash = "sha256:d97a6d09c66087890c2ab5d49069e1e570583f7ac0314ecf98294c1b6aaebd38", size = 7859748, upload-time = "2026-03-28T17:19:40.6Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/7e/cb94129302d78c46662b47f9897d642fd0b33bdfef4b73b20c6ced35aa4c/aiohttp-3.13.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8ea0c64d1bcbf201b285c2246c51a0c035ba3bbd306640007bc5844a3b4658c1", size = 760027, upload-time = "2026-03-28T17:15:33.022Z" }, - { url = "https://files.pythonhosted.org/packages/5e/cd/2db3c9397c3bd24216b203dd739945b04f8b87bb036c640da7ddb63c75ef/aiohttp-3.13.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6f742e1fa45c0ed522b00ede565e18f97e4cf8d1883a712ac42d0339dfb0cce7", size = 508325, upload-time = "2026-03-28T17:15:34.714Z" }, - { url = "https://files.pythonhosted.org/packages/36/a3/d28b2722ec13107f2e37a86b8a169897308bab6a3b9e071ecead9d67bd9b/aiohttp-3.13.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dcfb50ee25b3b7a1222a9123be1f9f89e56e67636b561441f0b304e25aaef8f", size = 502402, upload-time = "2026-03-28T17:15:36.409Z" }, - { url = "https://files.pythonhosted.org/packages/fa/d6/acd47b5f17c4430e555590990a4746efbcb2079909bb865516892bf85f37/aiohttp-3.13.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3262386c4ff370849863ea93b9ea60fd59c6cf56bf8f93beac625cf4d677c04d", size = 1771224, upload-time = "2026-03-28T17:15:38.223Z" }, - { url = "https://files.pythonhosted.org/packages/98/af/af6e20113ba6a48fd1cd9e5832c4851e7613ef50c7619acdaee6ec5f1aff/aiohttp-3.13.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:473bb5aa4218dd254e9ae4834f20e31f5a0083064ac0136a01a62ddbae2eaa42", size = 1731530, upload-time = "2026-03-28T17:15:39.988Z" }, - { url = "https://files.pythonhosted.org/packages/81/16/78a2f5d9c124ad05d5ce59a9af94214b6466c3491a25fb70760e98e9f762/aiohttp-3.13.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e56423766399b4c77b965f6aaab6c9546617b8994a956821cc507d00b91d978c", size = 1827925, upload-time = "2026-03-28T17:15:41.944Z" }, - { url = "https://files.pythonhosted.org/packages/2a/1f/79acf0974ced805e0e70027389fccbb7d728e6f30fcac725fb1071e63075/aiohttp-3.13.4-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8af249343fafd5ad90366a16d230fc265cf1149f26075dc9fe93cfd7c7173942", size = 1923579, upload-time = "2026-03-28T17:15:44.071Z" }, - { url = "https://files.pythonhosted.org/packages/af/53/29f9e2054ea6900413f3b4c3eb9d8331f60678ec855f13ba8714c47fd48d/aiohttp-3.13.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bc0a5cf4f10ef5a2c94fdde488734b582a3a7a000b131263e27c9295bd682d9", size = 1767655, upload-time = "2026-03-28T17:15:45.911Z" }, - { url = "https://files.pythonhosted.org/packages/f3/57/462fe1d3da08109ba4aa8590e7aed57c059af2a7e80ec21f4bac5cfe1094/aiohttp-3.13.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5c7ff1028e3c9fc5123a865ce17df1cb6424d180c503b8517afbe89aa566e6be", size = 1630439, upload-time = "2026-03-28T17:15:48.11Z" }, - { url = "https://files.pythonhosted.org/packages/d7/4b/4813344aacdb8127263e3eec343d24e973421143826364fa9fc847f6283f/aiohttp-3.13.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ba5cf98b5dcb9bddd857da6713a503fa6d341043258ca823f0f5ab7ab4a94ee8", size = 1745557, upload-time = "2026-03-28T17:15:50.13Z" }, - { url = "https://files.pythonhosted.org/packages/d4/01/1ef1adae1454341ec50a789f03cfafe4c4ac9c003f6a64515ecd32fe4210/aiohttp-3.13.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d85965d3ba21ee4999e83e992fecb86c4614d6920e40705501c0a1f80a583c12", size = 1741796, upload-time = "2026-03-28T17:15:52.351Z" }, - { url = "https://files.pythonhosted.org/packages/22/04/8cdd99af988d2aa6922714d957d21383c559835cbd43fbf5a47ddf2e0f05/aiohttp-3.13.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:49f0b18a9b05d79f6f37ddd567695943fcefb834ef480f17a4211987302b2dc7", size = 1805312, upload-time = "2026-03-28T17:15:54.407Z" }, - { url = "https://files.pythonhosted.org/packages/fb/7f/b48d5577338d4b25bbdbae35c75dbfd0493cb8886dc586fbfb2e90862239/aiohttp-3.13.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7f78cb080c86fbf765920e5f1ef35af3f24ec4314d6675d0a21eaf41f6f2679c", size = 1621751, upload-time = "2026-03-28T17:15:56.564Z" }, - { url = "https://files.pythonhosted.org/packages/bc/89/4eecad8c1858e6d0893c05929e22343e0ebe3aec29a8a399c65c3cc38311/aiohttp-3.13.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:67a3ec705534a614b68bbf1c70efa777a21c3da3895d1c44510a41f5a7ae0453", size = 1826073, upload-time = "2026-03-28T17:15:58.489Z" }, - { url = "https://files.pythonhosted.org/packages/f5/5c/9dc8293ed31b46c39c9c513ac7ca152b3c3d38e0ea111a530ad12001b827/aiohttp-3.13.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d6630ec917e85c5356b2295744c8a97d40f007f96a1c76bf1928dc2e27465393", size = 1760083, upload-time = "2026-03-28T17:16:00.677Z" }, - { url = "https://files.pythonhosted.org/packages/1e/19/8bbf6a4994205d96831f97b7d21a0feed120136e6267b5b22d229c6dc4dc/aiohttp-3.13.4-cp311-cp311-win32.whl", hash = "sha256:54049021bc626f53a5394c29e8c444f726ee5a14b6e89e0ad118315b1f90f5e3", size = 439690, upload-time = "2026-03-28T17:16:02.902Z" }, - { url = "https://files.pythonhosted.org/packages/0c/f5/ac409ecd1007528d15c3e8c3a57d34f334c70d76cfb7128a28cffdebd4c1/aiohttp-3.13.4-cp311-cp311-win_amd64.whl", hash = "sha256:c033f2bc964156030772d31cbf7e5defea181238ce1f87b9455b786de7d30145", size = 463824, upload-time = "2026-03-28T17:16:05.058Z" }, { url = "https://files.pythonhosted.org/packages/1e/bd/ede278648914cabbabfdf95e436679b5d4156e417896a9b9f4587169e376/aiohttp-3.13.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ee62d4471ce86b108b19c3364db4b91180d13fe3510144872d6bad5401957360", size = 752158, upload-time = "2026-03-28T17:16:06.901Z" }, { url = "https://files.pythonhosted.org/packages/90/de/581c053253c07b480b03785196ca5335e3c606a37dc73e95f6527f1591fe/aiohttp-3.13.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c0fd8f41b54b58636402eb493afd512c23580456f022c1ba2db0f810c959ed0d", size = 501037, upload-time = "2026-03-28T17:16:08.82Z" }, { url = "https://files.pythonhosted.org/packages/fa/f9/a5ede193c08f13cc42c0a5b50d1e246ecee9115e4cf6e900d8dbd8fd6acb/aiohttp-3.13.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4baa48ce49efd82d6b1a0be12d6a36b35e5594d1dd42f8bfba96ea9f8678b88c", size = 501556, upload-time = "2026-03-28T17:16:10.63Z" }, @@ -1586,7 +1569,7 @@ dev = [ { name = "lxml-stubs", specifier = "~=0.5.1" }, { name = "mypy", specifier = "~=1.19.1" }, { name = "pandas-stubs", specifier = "~=3.0.0" }, - { name = "pyrefly", specifier = ">=0.57.1" }, + { name = "pyrefly", specifier = ">=0.59.1" }, { name = "pytest", specifier = "~=9.0.2" }, { name = "pytest-benchmark", specifier = "~=5.2.3" }, { name = "pytest-cov", specifier = "~=7.1.0" }, @@ -4839,18 +4822,19 @@ wheels = [ [[package]] name = "pyrefly" -version = "0.57.1" +version = "0.59.1" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/c9/c1/c17211e5bbd2b90a24447484713da7cc2cee4e9455e57b87016ffc69d426/pyrefly-0.57.1.tar.gz", hash = "sha256:b05f6f5ee3a6a5d502ca19d84cb9ab62d67f05083819964a48c1510f2993efc6", size = 5310800, upload-time = "2026-03-18T18:42:35.614Z" } +sdist = { url = "https://files.pythonhosted.org/packages/d5/ce/7882c2af92b2ff6505fcd3430eff8048ece6c6254cc90bdc76ecee12dfab/pyrefly-0.59.1.tar.gz", hash = "sha256:bf1675b0c38d45df2c8f8618cbdfa261a1b92430d9d31eba16e0282b551e210f", size = 5475432, upload-time = "2026-04-01T22:04:04.11Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/58/8af37856c8d45b365ece635a6728a14b0356b08d1ff1ac601d7120def1e0/pyrefly-0.57.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:91974bfbe951eebf5a7bc959c1f3921f0371c789cad84761511d695e9ab2265f", size = 12681847, upload-time = "2026-03-18T18:42:10.963Z" }, - { url = "https://files.pythonhosted.org/packages/5f/d7/fae6dd9d0355fc5b8df7793f1423b7433ca8e10b698ea934c35f0e4e6522/pyrefly-0.57.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:808087298537c70f5e7cdccb5bbaad482e7e056e947c0adf00fb612cbace9fdc", size = 12219634, upload-time = "2026-03-18T18:42:13.469Z" }, - { url = "https://files.pythonhosted.org/packages/29/8f/9511ae460f0690e837b9ba0f7e5e192079e16ff9a9ba8a272450e81f11f8/pyrefly-0.57.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b01f454fa5539e070c0cba17ddec46b3d2107d571d519bd8eca8f3142ba02a6", size = 34947757, upload-time = "2026-03-18T18:42:17.152Z" }, - { url = "https://files.pythonhosted.org/packages/07/43/f053bf9c65218f70e6a49561e9942c7233f8c3e4da8d42e5fe2aae50b3d2/pyrefly-0.57.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02ad59ea722191f51635f23e37574662116b82ca9d814529f7cb5528f041f381", size = 37621018, upload-time = "2026-03-18T18:42:20.79Z" }, - { url = "https://files.pythonhosted.org/packages/0e/76/9cea46de01665bbc125e4f215340c9365c8d56cda6198ff238a563ea8e75/pyrefly-0.57.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:54bc0afe56776145e37733ff763e7e9679ee8a76c467b617dc3f227d4124a9e2", size = 40203649, upload-time = "2026-03-18T18:42:24.519Z" }, - { url = "https://files.pythonhosted.org/packages/fd/8b/2fb4a96d75e2a57df698a43e2970e441ba2704e3906cdc0386a055daa05a/pyrefly-0.57.1-py3-none-win32.whl", hash = "sha256:468e5839144b25bb0dce839bfc5fd879c9f38e68ebf5de561f30bed9ae19d8ca", size = 11732953, upload-time = "2026-03-18T18:42:27.379Z" }, - { url = "https://files.pythonhosted.org/packages/13/5a/4a197910fe2e9b102b15ae5e7687c45b7b5981275a11a564b41e185dd907/pyrefly-0.57.1-py3-none-win_amd64.whl", hash = "sha256:46db9c97093673c4fb7fab96d610e74d140661d54688a92d8e75ad885a56c141", size = 12537319, upload-time = "2026-03-18T18:42:30.196Z" }, - { url = "https://files.pythonhosted.org/packages/b5/c6/bc442874be1d9b63da1f9debb4f04b7d0c590a8dc4091921f3c288207242/pyrefly-0.57.1-py3-none-win_arm64.whl", hash = "sha256:feb1bbe3b0d8d5a70121dcdf1476e6a99cc056a26a49379a156f040729244dcb", size = 12013455, upload-time = "2026-03-18T18:42:32.928Z" }, + { url = "https://files.pythonhosted.org/packages/d0/10/04a0e05b08fc855b6fe38c3df549925fc3c2c6e750506870de7335d3e1f7/pyrefly-0.59.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:390db3cd14aa7e0268e847b60cd9ee18b04273eddfa38cf341ed3bb43f3fef2a", size = 12868133, upload-time = "2026-04-01T22:03:39.436Z" }, + { url = "https://files.pythonhosted.org/packages/c7/78/fa7be227c3e3fcacee501c1562278dd026186ffd1b5b5beb51d3941a3aed/pyrefly-0.59.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:d246d417b6187c1650d7f855f61c68fbfd6d6155dc846d4e4d273a3e6b5175cb", size = 12379325, upload-time = "2026-04-01T22:03:42.046Z" }, + { url = "https://files.pythonhosted.org/packages/bb/13/6828ce1c98171b5f8388f33c4b0b9ea2ab8c49abe0ef8d793c31e30a05cb/pyrefly-0.59.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:575ac67b04412dc651a7143d27e38a40fbdd3c831c714d5520d0e9d4c8631ab4", size = 35826408, upload-time = "2026-04-01T22:03:45.067Z" }, + { url = "https://files.pythonhosted.org/packages/23/56/79ed8ece9a7ecad0113c394a06a084107db3ad8f1fefe19e7ded43c51245/pyrefly-0.59.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:062e6262ce1064d59dcad81ac0499bb7a3ad501e9bc8a677a50dc630ff0bf862", size = 38532699, upload-time = "2026-04-01T22:03:48.376Z" }, + { url = "https://files.pythonhosted.org/packages/18/7d/ecc025e0f0e3f295b497f523cc19cefaa39e57abede8fc353d29445d174b/pyrefly-0.59.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:43ef4247f9e6f734feb93e1f2b75335b943629956e509f545cc9cdcccd76dd20", size = 36743570, upload-time = "2026-04-01T22:03:51.362Z" }, + { url = "https://files.pythonhosted.org/packages/2f/03/b1ce882ebcb87c673165c00451fbe4df17bf96ccfde18c75880dc87c5f5e/pyrefly-0.59.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:59a2d01723b84d042f4fa6ec871ffd52d0a7e83b0ea791c2e0bb0ff750abce56", size = 41236246, upload-time = "2026-04-01T22:03:54.361Z" }, + { url = "https://files.pythonhosted.org/packages/17/af/5e9c7afd510e7dd64a2204be0ed39e804089cbc4338675a28615c7176acb/pyrefly-0.59.1-py3-none-win32.whl", hash = "sha256:4ea70c780848f8376411e787643ae5d2d09da8a829362332b7b26d15ebcbaf56", size = 11884747, upload-time = "2026-04-01T22:03:56.776Z" }, + { url = "https://files.pythonhosted.org/packages/aa/c1/7db1077627453fd1068f0761f059a9512645c00c4c20acfb9f0c24ac02ec/pyrefly-0.59.1-py3-none-win_amd64.whl", hash = "sha256:67e6a08cfd129a0d2788d5e40a627f9860e0fe91a876238d93d5c63ff4af68ae", size = 12720608, upload-time = "2026-04-01T22:03:59.252Z" }, + { url = "https://files.pythonhosted.org/packages/07/16/4bb6e5fce5a9cf0992932d9435d964c33e507aaaf96fdfbb1be493078a4a/pyrefly-0.59.1-py3-none-win_arm64.whl", hash = "sha256:01179cb215cf079e8223a064f61a074f7079aa97ea705cbbc68af3d6713afd15", size = 12223158, upload-time = "2026-04-01T22:04:01.869Z" }, ] [[package]] From 894826771abf0543d76514d43f945c401006c8ac Mon Sep 17 00:00:00 2001 From: Stephen Zhou Date: Thu, 2 Apr 2026 19:45:19 +0800 Subject: [PATCH 05/29] chore: clean up useless tailwind reference (#34478) --- .../app/(appDetailLayout)/[appId]/style.module.css | 2 -- .../[datasetId]/documents/style.module.css | 2 -- .../app/configuration/base/var-highlight/style.module.css | 2 -- .../app/configuration/base/warning-mask/style.module.css | 2 -- .../app/configuration/config-prompt/style.module.css | 2 -- .../app/configuration/config/automatic/style.module.css | 2 -- .../app/configuration/ctrl-btn-group/style.module.css | 2 -- web/app/components/app/configuration/style.module.css | 2 -- web/app/components/base/app-icon-picker/style.module.css | 2 -- web/app/components/base/audio-btn/style.module.css | 2 -- .../components/base/chat/chat/loading-anim/style.module.css | 2 -- web/app/components/base/copy-feedback/style.module.css | 2 -- web/app/components/base/grid-mask/style.module.css | 2 -- web/app/components/base/image-gallery/style.module.css | 2 -- web/app/components/base/radio/style.module.css | 2 -- web/app/components/base/simple-pie-chart/index.module.css | 2 -- web/app/components/base/svg/style.module.css | 2 -- web/app/components/base/ui/scroll-area/index.module.css | 2 -- .../components/base/video-gallery/VideoPlayer.module.css | 2 -- web/app/components/base/voice-input/index.module.css | 2 -- web/app/components/billing/annotation-full/style.module.css | 2 -- .../components/billing/apps-full-in-dialog/style.module.css | 2 -- .../components/billing/plan-upgrade-modal/style.module.css | 2 -- web/app/components/billing/pricing/header.module.css | 2 -- web/app/components/billing/upgrade-btn/style.module.css | 2 -- .../components/billing/vector-space-full/style.module.css | 2 -- .../components/custom/custom-web-app-brand/style.module.css | 2 -- web/app/components/custom/style.module.css | 2 -- web/app/components/datasets/create/index.module.css | 2 -- web/app/components/develop/secret-key/style.module.css | 2 -- web/app/components/explore/app-list/style.module.css | 2 -- web/app/components/explore/sidebar/no-apps/style.module.css | 2 -- .../account-dropdown/workplace-selector/index.module.css | 2 -- .../account-setting/Integrations-page/index.module.css | 2 -- .../header/account-setting/language-page/index.module.css | 2 -- .../members-page/invited-modal/index.module.css | 2 -- .../provider-added-card/quota-panel.module.css | 2 -- web/app/components/header/index.module.css | 2 -- web/app/components/header/nav/index.module.css | 2 -- .../header/plugins-nav/downloading-icon.module.css | 2 -- .../plugins/reference-setting-modal/style.module.css | 2 -- .../workflow/nodes/_base/components/retry/style.module.css | 2 -- web/app/signin/page.module.css | 2 -- web/app/styles/markdown.css | 6 ++++-- 44 files changed, 4 insertions(+), 88 deletions(-) diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/style.module.css b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/style.module.css index 1f1aca2d11..45c7d197b4 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/style.module.css +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../../styles/globals.css"; - .app { flex-grow: 1; height: 0; diff --git a/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/documents/style.module.css b/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/documents/style.module.css index 955f5d593b..67a9fe3bf5 100644 --- a/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/documents/style.module.css +++ b/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/documents/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../styles/globals.css"; - .logTable td { padding: 7px 8px; box-sizing: border-box; diff --git a/web/app/components/app/configuration/base/var-highlight/style.module.css b/web/app/components/app/configuration/base/var-highlight/style.module.css index b7a66085ce..2bcef0dabb 100644 --- a/web/app/components/app/configuration/base/var-highlight/style.module.css +++ b/web/app/components/app/configuration/base/var-highlight/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../styles/globals.css"; - .item { background-color: rgba(21, 94, 239, 0.05); } diff --git a/web/app/components/app/configuration/base/warning-mask/style.module.css b/web/app/components/app/configuration/base/warning-mask/style.module.css index f922ec332f..a2c394de2a 100644 --- a/web/app/components/app/configuration/base/warning-mask/style.module.css +++ b/web/app/components/app/configuration/base/warning-mask/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../styles/globals.css"; - .mask { backdrop-filter: blur(2px); } diff --git a/web/app/components/app/configuration/config-prompt/style.module.css b/web/app/components/app/configuration/config-prompt/style.module.css index 3086441327..224d59d9c8 100644 --- a/web/app/components/app/configuration/config-prompt/style.module.css +++ b/web/app/components/app/configuration/config-prompt/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../../styles/globals.css"; - .gradientBorder { background: radial-gradient(circle at 100% 100%, #fcfcfd 0, #fcfcfd 10px, transparent 10px) 0% 0%/12px 12px no-repeat, radial-gradient(circle at 0 100%, #fcfcfd 0, #fcfcfd 10px, transparent 10px) 100% 0%/12px 12px no-repeat, diff --git a/web/app/components/app/configuration/config/automatic/style.module.css b/web/app/components/app/configuration/config/automatic/style.module.css index fb25784808..fa67b8519b 100644 --- a/web/app/components/app/configuration/config/automatic/style.module.css +++ b/web/app/components/app/configuration/config/automatic/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../styles/globals.css"; - .textGradient { background: linear-gradient(92deg, #2250F2 -29.55%, #0EBCF3 75.22%); -webkit-background-clip: text; diff --git a/web/app/components/app/configuration/ctrl-btn-group/style.module.css b/web/app/components/app/configuration/ctrl-btn-group/style.module.css index 0614d2775b..3e874868a9 100644 --- a/web/app/components/app/configuration/ctrl-btn-group/style.module.css +++ b/web/app/components/app/configuration/ctrl-btn-group/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../../styles/globals.css"; - .ctrlBtn { left: -16px; right: -16px; diff --git a/web/app/components/app/configuration/style.module.css b/web/app/components/app/configuration/style.module.css index 136d065215..01f2c93167 100644 --- a/web/app/components/app/configuration/style.module.css +++ b/web/app/components/app/configuration/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .advancedPromptMode { position: relative; } diff --git a/web/app/components/base/app-icon-picker/style.module.css b/web/app/components/base/app-icon-picker/style.module.css index c22ca04a66..5ec199a232 100644 --- a/web/app/components/base/app-icon-picker/style.module.css +++ b/web/app/components/base/app-icon-picker/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .container { display: flex; flex-direction: column; diff --git a/web/app/components/base/audio-btn/style.module.css b/web/app/components/base/audio-btn/style.module.css index 2a07ad0697..7e3175aa13 100644 --- a/web/app/components/base/audio-btn/style.module.css +++ b/web/app/components/base/audio-btn/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .playIcon { background-image: url(~@/app/components/develop/secret-key/assets/play.svg); background-position: center; diff --git a/web/app/components/base/chat/chat/loading-anim/style.module.css b/web/app/components/base/chat/chat/loading-anim/style.module.css index 1e1a87a312..d5a373df6f 100644 --- a/web/app/components/base/chat/chat/loading-anim/style.module.css +++ b/web/app/components/base/chat/chat/loading-anim/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../styles/globals.css"; - .dot-flashing { position: relative; animation: dot-flashing 1s infinite linear alternate; diff --git a/web/app/components/base/copy-feedback/style.module.css b/web/app/components/base/copy-feedback/style.module.css index 1335976835..83625d6189 100644 --- a/web/app/components/base/copy-feedback/style.module.css +++ b/web/app/components/base/copy-feedback/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .copyIcon { background-image: url(~@/app/components/develop/secret-key/assets/copy.svg); background-position: center; diff --git a/web/app/components/base/grid-mask/style.module.css b/web/app/components/base/grid-mask/style.module.css index 24d73a62af..e051271fab 100644 --- a/web/app/components/base/grid-mask/style.module.css +++ b/web/app/components/base/grid-mask/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .gridBg{ background-image: url(./Grid.svg); background-repeat: repeat; diff --git a/web/app/components/base/image-gallery/style.module.css b/web/app/components/base/image-gallery/style.module.css index 3cbe886b04..2e4c62e456 100644 --- a/web/app/components/base/image-gallery/style.module.css +++ b/web/app/components/base/image-gallery/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .item { max-height: 200px; margin-right: 8px; diff --git a/web/app/components/base/radio/style.module.css b/web/app/components/base/radio/style.module.css index 3ecf32f8d6..3e6bcdf418 100644 --- a/web/app/components/base/radio/style.module.css +++ b/web/app/components/base/radio/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .container { padding: 4px; border-radius: 4px; diff --git a/web/app/components/base/simple-pie-chart/index.module.css b/web/app/components/base/simple-pie-chart/index.module.css index 8ee0bdecf8..827b18d5f1 100644 --- a/web/app/components/base/simple-pie-chart/index.module.css +++ b/web/app/components/base/simple-pie-chart/index.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .simplePieChart { border-radius: 50%; box-shadow: 0 0 5px -3px rgb(from var(--simple-pie-chart-color) r g b / 0.1), 0.5px 0.5px 3px 0 rgb(from var(--simple-pie-chart-color) r g b / 0.3); diff --git a/web/app/components/base/svg/style.module.css b/web/app/components/base/svg/style.module.css index 885a9f8c3a..9258fe8ed3 100644 --- a/web/app/components/base/svg/style.module.css +++ b/web/app/components/base/svg/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .svgIcon { background-image: url(~@/app/components/develop/secret-key/assets/svg.svg); background-position: center; diff --git a/web/app/components/base/ui/scroll-area/index.module.css b/web/app/components/base/ui/scroll-area/index.module.css index 4b0cb17875..a81fd3d3c2 100644 --- a/web/app/components/base/ui/scroll-area/index.module.css +++ b/web/app/components/base/ui/scroll-area/index.module.css @@ -1,5 +1,3 @@ -@reference "../../../../styles/globals.css"; - .scrollbar::before, .scrollbar::after { content: ''; diff --git a/web/app/components/base/video-gallery/VideoPlayer.module.css b/web/app/components/base/video-gallery/VideoPlayer.module.css index c31499184f..04c4a367d6 100644 --- a/web/app/components/base/video-gallery/VideoPlayer.module.css +++ b/web/app/components/base/video-gallery/VideoPlayer.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .videoPlayer { position: relative; width: 100%; diff --git a/web/app/components/base/voice-input/index.module.css b/web/app/components/base/voice-input/index.module.css index 330d261af0..8286f9d9a9 100644 --- a/web/app/components/base/voice-input/index.module.css +++ b/web/app/components/base/voice-input/index.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .wrapper { background: linear-gradient(131deg, #2250F2 0%, #0EBCF3 100%); box-shadow: 0px 4px 6px -2px rgba(16, 24, 40, 0.03), 0px 12px 16px -4px rgba(16, 24, 40, 0.08); diff --git a/web/app/components/billing/annotation-full/style.module.css b/web/app/components/billing/annotation-full/style.module.css index 61a4406ae5..15bedd84ca 100644 --- a/web/app/components/billing/annotation-full/style.module.css +++ b/web/app/components/billing/annotation-full/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .textGradient { background: linear-gradient(92deg, #2250F2 -29.55%, #0EBCF3 75.22%); -webkit-background-clip: text; diff --git a/web/app/components/billing/apps-full-in-dialog/style.module.css b/web/app/components/billing/apps-full-in-dialog/style.module.css index 06c062be7d..1f68e665a6 100644 --- a/web/app/components/billing/apps-full-in-dialog/style.module.css +++ b/web/app/components/billing/apps-full-in-dialog/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .textGradient { background: linear-gradient(92deg, #0EBCF3 -29.55%, #2250F2 75.22%); -webkit-background-clip: text; diff --git a/web/app/components/billing/plan-upgrade-modal/style.module.css b/web/app/components/billing/plan-upgrade-modal/style.module.css index 3b6dbf27a5..50ad488388 100644 --- a/web/app/components/billing/plan-upgrade-modal/style.module.css +++ b/web/app/components/billing/plan-upgrade-modal/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .surface { border: 0.5px solid var(--color-components-panel-border, rgba(16, 24, 40, 0.08)); background: diff --git a/web/app/components/billing/pricing/header.module.css b/web/app/components/billing/pricing/header.module.css index 43deaea206..fc05646d86 100644 --- a/web/app/components/billing/pricing/header.module.css +++ b/web/app/components/billing/pricing/header.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .instrumentSerif { font-family: "Instrument Serif", serif; font-style: italic; diff --git a/web/app/components/billing/upgrade-btn/style.module.css b/web/app/components/billing/upgrade-btn/style.module.css index 6fbdb8b6c4..ab8c30ebd5 100644 --- a/web/app/components/billing/upgrade-btn/style.module.css +++ b/web/app/components/billing/upgrade-btn/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .upgradeBtn { background: linear-gradient(99deg, rgba(255, 255, 255, 0.12) 7.16%, rgba(255, 255, 255, 0.00) 85.47%), linear-gradient(280deg, #00B2FF 12.96%, #132BFF 90.95%); box-shadow: 0px 2px 4px -2px rgba(16, 24, 40, 0.06), 0px 4px 8px -2px rgba(0, 162, 253, 0.12); diff --git a/web/app/components/billing/vector-space-full/style.module.css b/web/app/components/billing/vector-space-full/style.module.css index 61a4406ae5..15bedd84ca 100644 --- a/web/app/components/billing/vector-space-full/style.module.css +++ b/web/app/components/billing/vector-space-full/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .textGradient { background: linear-gradient(92deg, #2250F2 -29.55%, #0EBCF3 75.22%); -webkit-background-clip: text; diff --git a/web/app/components/custom/custom-web-app-brand/style.module.css b/web/app/components/custom/custom-web-app-brand/style.module.css index e24f725c03..bdc7d7cfbf 100644 --- a/web/app/components/custom/custom-web-app-brand/style.module.css +++ b/web/app/components/custom/custom-web-app-brand/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .mask { background: linear-gradient(273deg, rgba(255, 255, 255, 0.00) 51.75%, rgba(255, 255, 255, 0.80) 115.32%); } diff --git a/web/app/components/custom/style.module.css b/web/app/components/custom/style.module.css index df955bd293..0a839f6387 100644 --- a/web/app/components/custom/style.module.css +++ b/web/app/components/custom/style.module.css @@ -1,5 +1,3 @@ -@reference "../../styles/globals.css"; - .textGradient { background: linear-gradient(92deg, #2250F2 -29.55%, #0EBCF3 75.22%); -webkit-background-clip: text; diff --git a/web/app/components/datasets/create/index.module.css b/web/app/components/datasets/create/index.module.css index 2e7e4f3a56..e69de29bb2 100644 --- a/web/app/components/datasets/create/index.module.css +++ b/web/app/components/datasets/create/index.module.css @@ -1,2 +0,0 @@ -@reference "../../../styles/globals.css"; - diff --git a/web/app/components/develop/secret-key/style.module.css b/web/app/components/develop/secret-key/style.module.css index b62ba4cf27..f13161c888 100644 --- a/web/app/components/develop/secret-key/style.module.css +++ b/web/app/components/develop/secret-key/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .customModal { max-width: 800px !important; max-height: calc(100vh - 80px); diff --git a/web/app/components/explore/app-list/style.module.css b/web/app/components/explore/app-list/style.module.css index ca83ab0fa2..241130a03d 100644 --- a/web/app/components/explore/app-list/style.module.css +++ b/web/app/components/explore/app-list/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .textGradient { background: linear-gradient(to right, rgba(16, 74, 225, 1) 0, rgba(0, 152, 238, 1) 100%); -webkit-background-clip: text; diff --git a/web/app/components/explore/sidebar/no-apps/style.module.css b/web/app/components/explore/sidebar/no-apps/style.module.css index 556774eb75..ad3787ce2b 100644 --- a/web/app/components/explore/sidebar/no-apps/style.module.css +++ b/web/app/components/explore/sidebar/no-apps/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../../styles/globals.css"; - .light { background-image: url('./no-web-apps-light.png'); } diff --git a/web/app/components/header/account-dropdown/workplace-selector/index.module.css b/web/app/components/header/account-dropdown/workplace-selector/index.module.css index 4b2257f427..c3184f7e18 100644 --- a/web/app/components/header/account-dropdown/workplace-selector/index.module.css +++ b/web/app/components/header/account-dropdown/workplace-selector/index.module.css @@ -1,5 +1,3 @@ -@reference "../../../../styles/globals.css"; - .popup { left: 4px; transform: translateX(-100%); diff --git a/web/app/components/header/account-setting/Integrations-page/index.module.css b/web/app/components/header/account-setting/Integrations-page/index.module.css index e7c70e8e02..7c2a883639 100644 --- a/web/app/components/header/account-setting/Integrations-page/index.module.css +++ b/web/app/components/header/account-setting/Integrations-page/index.module.css @@ -1,5 +1,3 @@ -@reference "../../../../styles/globals.css"; - .google-icon { background: url(../../assets/google.svg) center center no-repeat; background-size: 16px 16px; diff --git a/web/app/components/header/account-setting/language-page/index.module.css b/web/app/components/header/account-setting/language-page/index.module.css index e7c70e8e02..7c2a883639 100644 --- a/web/app/components/header/account-setting/language-page/index.module.css +++ b/web/app/components/header/account-setting/language-page/index.module.css @@ -1,5 +1,3 @@ -@reference "../../../../styles/globals.css"; - .google-icon { background: url(../../assets/google.svg) center center no-repeat; background-size: 16px 16px; diff --git a/web/app/components/header/account-setting/members-page/invited-modal/index.module.css b/web/app/components/header/account-setting/members-page/invited-modal/index.module.css index 37e23b1f79..96470439f0 100644 --- a/web/app/components/header/account-setting/members-page/invited-modal/index.module.css +++ b/web/app/components/header/account-setting/members-page/invited-modal/index.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../styles/globals.css"; - .modal { padding: 32px !important; width: 480px !important; diff --git a/web/app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.module.css b/web/app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.module.css index 9c106968ca..47d2c4cead 100644 --- a/web/app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.module.css +++ b/web/app/components/header/account-setting/model-provider-page/provider-added-card/quota-panel.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../styles/globals.css"; - .gridBg { background-size: 4px 4px; background-image: diff --git a/web/app/components/header/index.module.css b/web/app/components/header/index.module.css index 755433a799..9e23bc10a6 100644 --- a/web/app/components/header/index.module.css +++ b/web/app/components/header/index.module.css @@ -1,5 +1,3 @@ -@reference "../../styles/globals.css"; - .header-DEVELOPMENT { background: linear-gradient(180deg, rgba(253, 176, 34, 0.08) 0%, rgba(253, 176, 34, 0) 100%); border-top: 4px solid #FDB022; diff --git a/web/app/components/header/nav/index.module.css b/web/app/components/header/nav/index.module.css index 2e7e4f3a56..e69de29bb2 100644 --- a/web/app/components/header/nav/index.module.css +++ b/web/app/components/header/nav/index.module.css @@ -1,2 +0,0 @@ -@reference "../../../styles/globals.css"; - diff --git a/web/app/components/header/plugins-nav/downloading-icon.module.css b/web/app/components/header/plugins-nav/downloading-icon.module.css index 53b2cf5479..bbd6a35e4c 100644 --- a/web/app/components/header/plugins-nav/downloading-icon.module.css +++ b/web/app/components/header/plugins-nav/downloading-icon.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - @keyframes realistic-blink { 0% { fill: #37ff37; opacity: 0.4; } 15% { fill: #37ff37; opacity: 0.9; } diff --git a/web/app/components/plugins/reference-setting-modal/style.module.css b/web/app/components/plugins/reference-setting-modal/style.module.css index 61a4406ae5..15bedd84ca 100644 --- a/web/app/components/plugins/reference-setting-modal/style.module.css +++ b/web/app/components/plugins/reference-setting-modal/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../styles/globals.css"; - .textGradient { background: linear-gradient(92deg, #2250F2 -29.55%, #0EBCF3 75.22%); -webkit-background-clip: text; diff --git a/web/app/components/workflow/nodes/_base/components/retry/style.module.css b/web/app/components/workflow/nodes/_base/components/retry/style.module.css index 0e92485b68..2ce4e7b400 100644 --- a/web/app/components/workflow/nodes/_base/components/retry/style.module.css +++ b/web/app/components/workflow/nodes/_base/components/retry/style.module.css @@ -1,5 +1,3 @@ -@reference "../../../../../../styles/globals.css"; - .input::-webkit-inner-spin-button, .input::-webkit-outer-spin-button { -webkit-appearance: none; diff --git a/web/app/signin/page.module.css b/web/app/signin/page.module.css index ba89077ec0..e9759b23a8 100644 --- a/web/app/signin/page.module.css +++ b/web/app/signin/page.module.css @@ -1,5 +1,3 @@ -@reference "../styles/globals.css"; - .githubIcon { background: center/contain url('./assets/github.svg') no-repeat; } diff --git a/web/app/styles/markdown.css b/web/app/styles/markdown.css index 1ada6e49bd..45b3d4bad1 100644 --- a/web/app/styles/markdown.css +++ b/web/app/styles/markdown.css @@ -1,6 +1,5 @@ @import '../../themes/markdown-light.css'; @import '../../themes/markdown-dark.css'; -@reference "./globals.css"; .markdown-body { -ms-text-size-adjust: 100%; @@ -73,7 +72,6 @@ } .markdown-body abbr[title]:hover::after { - @apply shadow-xl shadow-shadow-shadow-5 rounded-md; position: absolute; bottom: 100%; left: 0; @@ -84,8 +82,12 @@ font-size: 12px; line-height: 1; color: var(--color-text-secondary); + border-radius: 0.375rem; border: 0.5px solid var(--color-components-panel-border); background-color: var(--color-components-tooltip-bg); + box-shadow: + 0px 8px 8px -4px var(--color-shadow-shadow-5), + 0px 20px 24px -4px var(--color-shadow-shadow-5); } .markdown-body b, From d243de26ec33477154af83f9f6edbb9b24022a98 Mon Sep 17 00:00:00 2001 From: Renzo <170978465+RenzoMXD@users.noreply.github.com> Date: Thu, 2 Apr 2026 14:34:38 +0200 Subject: [PATCH 06/29] refactor: select in metadata_service (#34479) --- api/services/metadata_service.py | 77 ++++++++++++------ .../unit_tests/services/dataset_metadata.py | 78 +++---------------- 2 files changed, 65 insertions(+), 90 deletions(-) diff --git a/api/services/metadata_service.py b/api/services/metadata_service.py index 12729278cc..672f309bac 100644 --- a/api/services/metadata_service.py +++ b/api/services/metadata_service.py @@ -1,6 +1,8 @@ import copy import logging +from sqlalchemy import delete, func, select + from core.rag.index_processor.constant.built_in_field import BuiltInField, MetadataDataSource from extensions.ext_database import db from extensions.ext_redis import redis_client @@ -25,10 +27,14 @@ class MetadataService: raise ValueError("Metadata name cannot exceed 255 characters.") current_user, current_tenant_id = current_account_with_tenant() # check if metadata name already exists - if ( - db.session.query(DatasetMetadata) - .filter_by(tenant_id=current_tenant_id, dataset_id=dataset_id, name=metadata_args.name) - .first() + if db.session.scalar( + select(DatasetMetadata) + .where( + DatasetMetadata.tenant_id == current_tenant_id, + DatasetMetadata.dataset_id == dataset_id, + DatasetMetadata.name == metadata_args.name, + ) + .limit(1) ): raise ValueError("Metadata name already exists.") for field in BuiltInField: @@ -54,10 +60,14 @@ class MetadataService: lock_key = f"dataset_metadata_lock_{dataset_id}" # check if metadata name already exists current_user, current_tenant_id = current_account_with_tenant() - if ( - db.session.query(DatasetMetadata) - .filter_by(tenant_id=current_tenant_id, dataset_id=dataset_id, name=name) - .first() + if db.session.scalar( + select(DatasetMetadata) + .where( + DatasetMetadata.tenant_id == current_tenant_id, + DatasetMetadata.dataset_id == dataset_id, + DatasetMetadata.name == name, + ) + .limit(1) ): raise ValueError("Metadata name already exists.") for field in BuiltInField: @@ -65,7 +75,11 @@ class MetadataService: raise ValueError("Metadata name already exists in Built-in fields.") try: MetadataService.knowledge_base_metadata_lock_check(dataset_id, None) - metadata = db.session.query(DatasetMetadata).filter_by(id=metadata_id, dataset_id=dataset_id).first() + metadata = db.session.scalar( + select(DatasetMetadata) + .where(DatasetMetadata.id == metadata_id, DatasetMetadata.dataset_id == dataset_id) + .limit(1) + ) if metadata is None: raise ValueError("Metadata not found.") old_name = metadata.name @@ -74,9 +88,9 @@ class MetadataService: metadata.updated_at = naive_utc_now() # update related documents - dataset_metadata_bindings = ( - db.session.query(DatasetMetadataBinding).filter_by(metadata_id=metadata_id).all() - ) + dataset_metadata_bindings = db.session.scalars( + select(DatasetMetadataBinding).where(DatasetMetadataBinding.metadata_id == metadata_id) + ).all() if dataset_metadata_bindings: document_ids = [binding.document_id for binding in dataset_metadata_bindings] documents = DocumentService.get_document_by_ids(document_ids) @@ -101,15 +115,19 @@ class MetadataService: lock_key = f"dataset_metadata_lock_{dataset_id}" try: MetadataService.knowledge_base_metadata_lock_check(dataset_id, None) - metadata = db.session.query(DatasetMetadata).filter_by(id=metadata_id, dataset_id=dataset_id).first() + metadata = db.session.scalar( + select(DatasetMetadata) + .where(DatasetMetadata.id == metadata_id, DatasetMetadata.dataset_id == dataset_id) + .limit(1) + ) if metadata is None: raise ValueError("Metadata not found.") db.session.delete(metadata) # deal related documents - dataset_metadata_bindings = ( - db.session.query(DatasetMetadataBinding).filter_by(metadata_id=metadata_id).all() - ) + dataset_metadata_bindings = db.session.scalars( + select(DatasetMetadataBinding).where(DatasetMetadataBinding.metadata_id == metadata_id) + ).all() if dataset_metadata_bindings: document_ids = [binding.document_id for binding in dataset_metadata_bindings] documents = DocumentService.get_document_by_ids(document_ids) @@ -224,16 +242,23 @@ class MetadataService: # deal metadata binding (in the same transaction as the doc_metadata update) if not operation.partial_update: - db.session.query(DatasetMetadataBinding).filter_by(document_id=operation.document_id).delete() + db.session.execute( + delete(DatasetMetadataBinding).where( + DatasetMetadataBinding.document_id == operation.document_id + ) + ) current_user, current_tenant_id = current_account_with_tenant() for metadata_value in operation.metadata_list: # check if binding already exists if operation.partial_update: - existing_binding = ( - db.session.query(DatasetMetadataBinding) - .filter_by(document_id=operation.document_id, metadata_id=metadata_value.id) - .first() + existing_binding = db.session.scalar( + select(DatasetMetadataBinding) + .where( + DatasetMetadataBinding.document_id == operation.document_id, + DatasetMetadataBinding.metadata_id == metadata_value.id, + ) + .limit(1) ) if existing_binding: continue @@ -275,9 +300,13 @@ class MetadataService: "id": item.get("id"), "name": item.get("name"), "type": item.get("type"), - "count": db.session.query(DatasetMetadataBinding) - .filter_by(metadata_id=item.get("id"), dataset_id=dataset.id) - .count(), + "count": db.session.scalar( + select(func.count(DatasetMetadataBinding.id)).where( + DatasetMetadataBinding.metadata_id == item.get("id"), + DatasetMetadataBinding.dataset_id == dataset.id, + ) + ) + or 0, } for item in dataset.doc_metadata or [] if item.get("id") != "built-in" diff --git a/api/tests/unit_tests/services/dataset_metadata.py b/api/tests/unit_tests/services/dataset_metadata.py index 5ba18d8dc0..b825a8686a 100644 --- a/api/tests/unit_tests/services/dataset_metadata.py +++ b/api/tests/unit_tests/services/dataset_metadata.py @@ -401,10 +401,7 @@ class TestMetadataServiceCreateMetadata: metadata_args = MetadataTestDataFactory.create_metadata_args_mock(name="category", metadata_type="string") # Mock query to return None (no existing metadata with same name) - mock_query = Mock() - mock_query.filter_by.return_value = mock_query - mock_query.first.return_value = None - mock_db_session.query.return_value = mock_query + mock_db_session.scalar.return_value = None # Mock BuiltInField enum iteration with patch("services.metadata_service.BuiltInField") as mock_builtin: @@ -417,10 +414,6 @@ class TestMetadataServiceCreateMetadata: assert result is not None assert isinstance(result, DatasetMetadata) - # Verify query was made to check for duplicates - mock_db_session.query.assert_called() - mock_query.filter_by.assert_called() - # Verify metadata was added and committed mock_db_session.add.assert_called_once() mock_db_session.commit.assert_called_once() @@ -468,10 +461,7 @@ class TestMetadataServiceCreateMetadata: # Mock existing metadata with same name existing_metadata = MetadataTestDataFactory.create_metadata_mock(name="category") - mock_query = Mock() - mock_query.filter_by.return_value = mock_query - mock_query.first.return_value = existing_metadata - mock_db_session.query.return_value = mock_query + mock_db_session.scalar.return_value = existing_metadata # Act & Assert with pytest.raises(ValueError, match="Metadata name already exists"): @@ -500,10 +490,7 @@ class TestMetadataServiceCreateMetadata: ) # Mock query to return None (no duplicate in database) - mock_query = Mock() - mock_query.filter_by.return_value = mock_query - mock_query.first.return_value = None - mock_db_session.query.return_value = mock_query + mock_db_session.scalar.return_value = None # Mock BuiltInField to include the conflicting name with patch("services.metadata_service.BuiltInField") as mock_builtin: @@ -597,27 +584,11 @@ class TestMetadataServiceUpdateMetadataName: existing_metadata = MetadataTestDataFactory.create_metadata_mock(metadata_id=metadata_id, name="category") - # Mock query for duplicate check (no duplicate) - mock_query = Mock() - mock_query.filter_by.return_value = mock_query - mock_query.first.return_value = None - mock_db_session.query.return_value = mock_query - - # Mock metadata retrieval - def query_side_effect(model): - if model == DatasetMetadata: - mock_meta_query = Mock() - mock_meta_query.filter_by.return_value = mock_meta_query - mock_meta_query.first.return_value = existing_metadata - return mock_meta_query - return mock_query - - mock_db_session.query.side_effect = query_side_effect + # Mock scalar calls: first for duplicate check (None), second for metadata retrieval + mock_db_session.scalar.side_effect = [None, existing_metadata] # Mock no metadata bindings (no documents to update) - mock_binding_query = Mock() - mock_binding_query.filter_by.return_value = mock_binding_query - mock_binding_query.all.return_value = [] + mock_db_session.scalars.return_value.all.return_value = [] # Mock BuiltInField enum with patch("services.metadata_service.BuiltInField") as mock_builtin: @@ -655,22 +626,8 @@ class TestMetadataServiceUpdateMetadataName: metadata_id = "non-existent-metadata" new_name = "updated_category" - # Mock query for duplicate check (no duplicate) - mock_query = Mock() - mock_query.filter_by.return_value = mock_query - mock_query.first.return_value = None - mock_db_session.query.return_value = mock_query - - # Mock metadata retrieval to return None - def query_side_effect(model): - if model == DatasetMetadata: - mock_meta_query = Mock() - mock_meta_query.filter_by.return_value = mock_meta_query - mock_meta_query.first.return_value = None # Not found - return mock_meta_query - return mock_query - - mock_db_session.query.side_effect = query_side_effect + # Mock scalar calls: first for duplicate check (None), second for metadata retrieval (None = not found) + mock_db_session.scalar.side_effect = [None, None] # Mock BuiltInField enum with patch("services.metadata_service.BuiltInField") as mock_builtin: @@ -746,15 +703,10 @@ class TestMetadataServiceDeleteMetadata: existing_metadata = MetadataTestDataFactory.create_metadata_mock(metadata_id=metadata_id, name="category") # Mock metadata retrieval - mock_query = Mock() - mock_query.filter_by.return_value = mock_query - mock_query.first.return_value = existing_metadata - mock_db_session.query.return_value = mock_query + mock_db_session.scalar.return_value = existing_metadata # Mock no metadata bindings (no documents to update) - mock_binding_query = Mock() - mock_binding_query.filter_by.return_value = mock_binding_query - mock_binding_query.all.return_value = [] + mock_db_session.scalars.return_value.all.return_value = [] # Act result = MetadataService.delete_metadata(dataset_id, metadata_id) @@ -788,10 +740,7 @@ class TestMetadataServiceDeleteMetadata: metadata_id = "non-existent-metadata" # Mock metadata retrieval to return None - mock_query = Mock() - mock_query.filter_by.return_value = mock_query - mock_query.first.return_value = None - mock_db_session.query.return_value = mock_query + mock_db_session.scalar.return_value = None # Act & Assert with pytest.raises(ValueError, match="Metadata not found"): @@ -1013,10 +962,7 @@ class TestMetadataServiceGetDatasetMetadatas: ) # Mock usage count queries - mock_query = Mock() - mock_query.filter_by.return_value = mock_query - mock_query.count.return_value = 5 # 5 documents use this metadata - mock_db_session.query.return_value = mock_query + mock_db_session.scalar.return_value = 5 # 5 documents use this metadata # Act result = MetadataService.get_dataset_metadatas(dataset) From dbfb474eab3aaaf1b2e5131a4af06e9b73c27531 Mon Sep 17 00:00:00 2001 From: Renzo <170978465+RenzoMXD@users.noreply.github.com> Date: Thu, 2 Apr 2026 14:35:04 +0200 Subject: [PATCH 07/29] refactor: select in workflow_tools_manage_service (#34477) --- .../tools/workflow_tools_manage_service.py | 58 ++++++++++--------- 1 file changed, 31 insertions(+), 27 deletions(-) diff --git a/api/services/tools/workflow_tools_manage_service.py b/api/services/tools/workflow_tools_manage_service.py index fb6b5bea24..dc0b281e15 100644 --- a/api/services/tools/workflow_tools_manage_service.py +++ b/api/services/tools/workflow_tools_manage_service.py @@ -3,7 +3,7 @@ import logging from datetime import datetime from graphon.model_runtime.utils.encoders import jsonable_encoder -from sqlalchemy import or_, select +from sqlalchemy import delete, or_, select from sqlalchemy.orm import Session from core.tools.__base.tool_provider import ToolProviderController @@ -42,20 +42,22 @@ class WorkflowToolManageService: labels: list[str] | None = None, ): # check if the name is unique - existing_workflow_tool_provider = ( - db.session.query(WorkflowToolProvider) + existing_workflow_tool_provider = db.session.scalar( + select(WorkflowToolProvider) .where( WorkflowToolProvider.tenant_id == tenant_id, # name or app_id or_(WorkflowToolProvider.name == name, WorkflowToolProvider.app_id == workflow_app_id), ) - .first() + .limit(1) ) if existing_workflow_tool_provider is not None: raise ValueError(f"Tool with name {name} or app_id {workflow_app_id} already exists") - app: App | None = db.session.query(App).where(App.id == workflow_app_id, App.tenant_id == tenant_id).first() + app: App | None = db.session.scalar( + select(App).where(App.id == workflow_app_id, App.tenant_id == tenant_id).limit(1) + ) if app is None: raise ValueError(f"App {workflow_app_id} not found") @@ -122,30 +124,30 @@ class WorkflowToolManageService: :return: the updated tool """ # check if the name is unique - existing_workflow_tool_provider = ( - db.session.query(WorkflowToolProvider) + existing_workflow_tool_provider = db.session.scalar( + select(WorkflowToolProvider) .where( WorkflowToolProvider.tenant_id == tenant_id, WorkflowToolProvider.name == name, WorkflowToolProvider.id != workflow_tool_id, ) - .first() + .limit(1) ) if existing_workflow_tool_provider is not None: raise ValueError(f"Tool with name {name} already exists") - workflow_tool_provider: WorkflowToolProvider | None = ( - db.session.query(WorkflowToolProvider) + workflow_tool_provider: WorkflowToolProvider | None = db.session.scalar( + select(WorkflowToolProvider) .where(WorkflowToolProvider.tenant_id == tenant_id, WorkflowToolProvider.id == workflow_tool_id) - .first() + .limit(1) ) if workflow_tool_provider is None: raise ValueError(f"Tool {workflow_tool_id} not found") - app: App | None = ( - db.session.query(App).where(App.id == workflow_tool_provider.app_id, App.tenant_id == tenant_id).first() + app: App | None = db.session.scalar( + select(App).where(App.id == workflow_tool_provider.app_id, App.tenant_id == tenant_id).limit(1) ) if app is None: @@ -234,9 +236,11 @@ class WorkflowToolManageService: :param tenant_id: the tenant id :param workflow_tool_id: the workflow tool id """ - db.session.query(WorkflowToolProvider).where( - WorkflowToolProvider.tenant_id == tenant_id, WorkflowToolProvider.id == workflow_tool_id - ).delete() + db.session.execute( + delete(WorkflowToolProvider).where( + WorkflowToolProvider.tenant_id == tenant_id, WorkflowToolProvider.id == workflow_tool_id + ) + ) db.session.commit() @@ -251,10 +255,10 @@ class WorkflowToolManageService: :param workflow_tool_id: the workflow tool id :return: the tool """ - db_tool: WorkflowToolProvider | None = ( - db.session.query(WorkflowToolProvider) + db_tool: WorkflowToolProvider | None = db.session.scalar( + select(WorkflowToolProvider) .where(WorkflowToolProvider.tenant_id == tenant_id, WorkflowToolProvider.id == workflow_tool_id) - .first() + .limit(1) ) return cls._get_workflow_tool(tenant_id, db_tool) @@ -267,10 +271,10 @@ class WorkflowToolManageService: :param workflow_app_id: the workflow app id :return: the tool """ - db_tool: WorkflowToolProvider | None = ( - db.session.query(WorkflowToolProvider) + db_tool: WorkflowToolProvider | None = db.session.scalar( + select(WorkflowToolProvider) .where(WorkflowToolProvider.tenant_id == tenant_id, WorkflowToolProvider.app_id == workflow_app_id) - .first() + .limit(1) ) return cls._get_workflow_tool(tenant_id, db_tool) @@ -284,8 +288,8 @@ class WorkflowToolManageService: if db_tool is None: raise ValueError("Tool not found") - workflow_app: App | None = ( - db.session.query(App).where(App.id == db_tool.app_id, App.tenant_id == db_tool.tenant_id).first() + workflow_app: App | None = db.session.scalar( + select(App).where(App.id == db_tool.app_id, App.tenant_id == db_tool.tenant_id).limit(1) ) if workflow_app is None: @@ -331,10 +335,10 @@ class WorkflowToolManageService: :param workflow_tool_id: the workflow tool id :return: the list of tools """ - db_tool: WorkflowToolProvider | None = ( - db.session.query(WorkflowToolProvider) + db_tool: WorkflowToolProvider | None = db.session.scalar( + select(WorkflowToolProvider) .where(WorkflowToolProvider.tenant_id == tenant_id, WorkflowToolProvider.id == workflow_tool_id) - .first() + .limit(1) ) if db_tool is None: From 2e29ac2829f2177803de0436b9cda34e2609d619 Mon Sep 17 00:00:00 2001 From: lif <1835304752@qq.com> Date: Thu, 2 Apr 2026 20:36:21 +0800 Subject: [PATCH 08/29] fix: remove redundant cast in MCP base session (#34461) Signed-off-by: majiayu000 <1835304752@qq.com> --- api/core/mcp/session/base_session.py | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/api/core/mcp/session/base_session.py b/api/core/mcp/session/base_session.py index e50fd42198..0b3aa79838 100644 --- a/api/core/mcp/session/base_session.py +++ b/api/core/mcp/session/base_session.py @@ -4,7 +4,7 @@ from collections.abc import Callable from concurrent.futures import Future, ThreadPoolExecutor, TimeoutError from datetime import timedelta from types import TracebackType -from typing import Any, Self, cast +from typing import Any, Self from httpx import HTTPStatusError from pydantic import BaseModel @@ -338,12 +338,11 @@ class BaseSession[ validated_request = self._receive_request_type.model_validate( message.message.root.model_dump(by_alias=True, mode="json", exclude_none=True) ) - validated_request = cast(ReceiveRequestT, validated_request) responder = RequestResponder[ReceiveRequestT, SendResultT]( request_id=message.message.root.id, request_meta=validated_request.root.params.meta if validated_request.root.params else None, - request=validated_request, + request=validated_request, # type: ignore[arg-type] # mypy can't narrow constrained TypeVar from model_validate session=self, on_complete=lambda r: self._in_flight.pop(r.request_id, None), ) @@ -359,15 +358,14 @@ class BaseSession[ notification = self._receive_notification_type.model_validate( message.message.root.model_dump(by_alias=True, mode="json", exclude_none=True) ) - notification = cast(ReceiveNotificationT, notification) # Handle cancellation notifications if isinstance(notification.root, CancelledNotification): cancelled_id = notification.root.params.requestId if cancelled_id in self._in_flight: self._in_flight[cancelled_id].cancel() else: - self._received_notification(notification) - self._handle_incoming(notification) + self._received_notification(notification) # type: ignore[arg-type] + self._handle_incoming(notification) # type: ignore[arg-type] except Exception as e: # For other validation errors, log and continue logger.warning("Failed to validate notification: %s. Message was: %s", e, message.message.root) From 985b41c40bf33408c7ff63b17fbda4777c77f4be Mon Sep 17 00:00:00 2001 From: Tim Ren <137012659+xr843@users.noreply.github.com> Date: Thu, 2 Apr 2026 21:17:02 +0800 Subject: [PATCH 09/29] fix(security): add tenant_id validation to prevent IDOR in data source binding (#34456) Co-authored-by: Claude Opus 4.6 (1M context) --- api/controllers/console/datasets/data_source.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/api/controllers/console/datasets/data_source.py b/api/controllers/console/datasets/data_source.py index ac14349045..e623722b23 100644 --- a/api/controllers/console/datasets/data_source.py +++ b/api/controllers/console/datasets/data_source.py @@ -158,10 +158,11 @@ class DataSourceApi(Resource): @login_required @account_initialization_required def patch(self, binding_id, action: Literal["enable", "disable"]): + _, current_tenant_id = current_account_with_tenant() binding_id = str(binding_id) with sessionmaker(db.engine, expire_on_commit=False).begin() as session: data_source_binding = session.execute( - select(DataSourceOauthBinding).filter_by(id=binding_id) + select(DataSourceOauthBinding).filter_by(id=binding_id, tenant_id=current_tenant_id) ).scalar_one_or_none() if data_source_binding is None: raise NotFound("Data source binding not found.") From 36e840cd87e8de78ed306d8a5851c734afa352df Mon Sep 17 00:00:00 2001 From: Stephen Zhou Date: Thu, 2 Apr 2026 23:03:42 +0800 Subject: [PATCH 10/29] chore: knip fix (#34481) Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> --- .vite-hooks/pre-commit | 6 + .../(appDetailLayout)/[appId]/layout-main.tsx | 2 +- .../[appId]/overview/card-view.tsx | 2 +- .../[appId]/overview/chart-view.tsx | 2 +- .../[datasetId]/documents/style.module.css | 9 - .../[datasetId]/layout-main.tsx | 2 +- web/app/account/(commonLayout)/avatar.tsx | 4 - .../components/app-sidebar/app-info/index.tsx | 2 +- web/app/components/app-sidebar/basic.tsx | 2 +- web/app/components/app-sidebar/index.tsx | 2 +- web/app/components/app/annotation/type.ts | 2 - .../app/app-publisher/suggested-action.tsx | 2 +- .../base/feature-panel/index.tsx | 2 +- .../configuration/base/group-name/index.tsx | 2 +- .../base/operation-btn/index.tsx | 2 +- .../base/var-highlight/index.tsx | 2 +- .../warning-mask/cannot-query-dataset.tsx | 2 +- .../base/warning-mask/formatting-changed.tsx | 2 +- .../base/warning-mask/has-not-set-api.tsx | 2 +- .../configuration/base/warning-mask/index.tsx | 2 +- .../config-prompt/confirm-add-var/index.tsx | 2 +- .../config-prompt/simple-prompt-input.tsx | 2 +- .../config-var/config-modal/config.ts | 7 - .../config-var/config-modal/index.tsx | 2 +- .../config-var/config-select/index.tsx | 2 +- .../configuration/config-var/modal-foot.tsx | 2 +- .../config-var/select-type-item/index.tsx | 2 +- .../config/agent/prompt-editor.tsx | 152 ----------- .../config/automatic/automatic-btn.tsx | 2 +- .../config/automatic/get-automatic-res.tsx | 2 +- .../code-generator/get-code-generator-res.tsx | 2 +- .../configuration/ctrl-btn-group/index.tsx | 2 +- .../dataset-config/select-dataset/index.tsx | 2 +- .../debug-with-multiple-model/context.ts | 2 - .../app/configuration/style.module.css | 14 - .../app/configuration/tools/index.tsx | 204 --------------- .../app/create-app-dialog/app-card/index.tsx | 2 +- .../app/create-from-dsl-modal/uploader.tsx | 2 +- web/app/components/app/log/index.tsx | 2 +- .../apikey-info-panel.test-utils.tsx | 10 +- web/app/components/app/overview/app-chart.tsx | 6 +- .../app/overview/settings/index.tsx | 2 +- .../components/app/overview/trigger-card.tsx | 2 +- .../app/text-generate/item/index.tsx | 8 +- .../saved-items/no-data/index.tsx | 2 +- .../components/app/type-selector/index.tsx | 2 +- web/app/components/apps/app-card.tsx | 2 +- web/app/components/apps/new-app-card.tsx | 2 +- .../base/agent-log-modal/detail.tsx | 2 +- web/app/components/base/amplitude/index.ts | 2 +- web/app/components/base/answer-icon/index.tsx | 2 +- web/app/components/base/app-icon/index.tsx | 2 +- .../auto-height-textarea/style.module.scss | 0 web/app/components/base/avatar/index.tsx | 12 +- web/app/components/base/block-input/index.tsx | 2 +- .../base/chat/chat-with-history/index.tsx | 2 +- .../sidebar/rename-modal.tsx | 2 +- web/app/components/base/chat/chat/context.ts | 2 - .../base/chat/chat/loading-anim/index.tsx | 2 +- web/app/components/base/chat/chat/type.ts | 11 - .../chat/embedded-chatbot/header/index.tsx | 2 +- web/app/components/base/chat/types.ts | 30 +-- .../components/base/checkbox-list/index.tsx | 4 +- .../calendar/days-of-week.tsx | 2 - .../base/date-and-time-picker/utils/dayjs.ts | 2 +- web/app/components/base/divider/index.tsx | 2 +- .../components/base/file-uploader/index.ts | 4 +- .../base/form/form-scenarios/demo/types.ts | 2 - web/app/components/base/form/index.tsx | 4 +- web/app/components/base/form/types.ts | 2 - web/app/components/base/ga/index.tsx | 8 +- web/app/components/base/icons/IconBase.tsx | 2 +- .../base/icons/src/image/llm/index.ts | 9 - .../base/icons/src/public/billing/index.ts | 9 +- .../base/icons/src/public/common/index.ts | 13 +- .../public/knowledge/dataset-card/index.ts | 2 +- .../base/icons/src/public/knowledge/index.ts | 2 - .../base/icons/src/public/llm/index.ts | 46 +--- .../base/icons/src/public/model/index.ts | 1 - .../base/icons/src/public/other/index.ts | 2 +- .../base/icons/src/public/plugins/index.ts | 7 - .../base/icons/src/public/thought/index.ts | 4 - .../base/icons/src/vender/knowledge/index.ts | 2 +- .../vender/line/alertsAndFeedback/index.ts | 2 - .../icons/src/vender/line/arrows/index.ts | 4 +- .../src/vender/line/communication/index.ts | 4 +- .../src/vender/line/development/index.ts | 12 - .../icons/src/vender/line/editor/index.ts | 7 - .../base/icons/src/vender/line/files/index.ts | 7 +- .../vender/line/financeAndECommerce/index.ts | 5 +- .../icons/src/vender/line/general/index.ts | 25 +- .../icons/src/vender/line/layout/index.ts | 3 - .../src/vender/line/mediaAndDevices/index.ts | 4 - .../icons/src/vender/line/others/index.ts | 4 +- .../icons/src/vender/line/shapes/index.ts | 1 - .../base/icons/src/vender/line/time/index.ts | 2 - .../base/icons/src/vender/line/users/index.ts | 2 - .../icons/src/vender/line/weather/index.ts | 1 - .../base/icons/src/vender/other/index.ts | 1 - .../vender/solid/FinanceAndECommerce/index.ts | 1 - .../icons/src/vender/solid/arrows/index.ts | 2 - .../src/vender/solid/communication/index.ts | 8 +- .../src/vender/solid/development/index.ts | 10 +- .../icons/src/vender/solid/editor/index.ts | 4 - .../icons/src/vender/solid/education/index.ts | 2 +- .../icons/src/vender/solid/files/index.ts | 2 +- .../icons/src/vender/solid/general/index.ts | 10 +- .../icons/src/vender/solid/layout/index.ts | 1 - .../src/vender/solid/mediaAndDevices/index.ts | 11 +- .../icons/src/vender/solid/shapes/index.ts | 2 - .../icons/src/vender/solid/users/index.ts | 3 - .../base/icons/src/vender/workflow/index.ts | 2 +- web/app/components/base/icons/utils.ts | 2 +- .../base/inline-delete-confirm/index.tsx | 2 +- .../components/base/input-with-copy/index.tsx | 2 +- .../components/base/markdown-blocks/index.ts | 2 +- .../markdown-with-directive-schema.ts | 4 +- web/app/components/base/node-status/index.tsx | 2 +- .../components/base/pagination/pagination.tsx | 6 +- .../base/portal-to-follow-elem/index.tsx | 4 +- .../components/base/premium-badge/index.tsx | 1 - .../components/base/prompt-editor/hooks.ts | 10 +- .../plugins/context-block/node.tsx | 2 +- .../plugins/current-block/node.tsx | 2 +- .../plugins/error-message-block/node.tsx | 2 +- .../plugins/history-block/index.tsx | 7 - .../plugins/hitl-input-block/index.tsx | 5 - .../plugins/hitl-input-block/node.tsx | 2 +- .../plugins/last-run-block/node.tsx | 2 +- .../plugins/query-block/index.tsx | 5 - .../plugins/query-block/node.tsx | 2 +- .../plugins/request-url-block/node.tsx | 2 +- .../plugins/workflow-variable-block/index.tsx | 10 +- .../plugins/workflow-variable-block/node.tsx | 2 +- .../base/radio/component/group/index.tsx | 2 +- web/app/components/base/select/index.tsx | 2 +- web/app/components/base/sort/index.tsx | 2 +- web/app/components/base/tag/index.tsx | 2 +- .../components/base/text-generation/types.ts | 30 --- web/app/components/base/textarea/index.tsx | 2 +- web/app/components/base/theme-switcher.tsx | 2 +- .../components/base/timezone-label/index.tsx | 2 +- web/app/components/base/tooltip/content.tsx | 2 +- web/app/components/base/tooltip/index.tsx | 2 +- .../components/base/ui/context-menu/index.tsx | 24 +- .../base/ui/dropdown-menu/index.tsx | 1 - .../components/base/ui/number-field/index.tsx | 4 +- .../components/base/ui/scroll-area/index.tsx | 23 +- web/app/components/base/ui/select/index.tsx | 5 +- web/app/components/base/ui/slider/index.tsx | 2 +- web/app/components/base/ui/toast/index.tsx | 16 +- web/app/components/base/ui/tooltip/index.tsx | 2 +- web/app/components/base/zendesk/utils.ts | 2 +- web/app/components/billing/type.ts | 21 -- .../billing/upgrade-btn/style.module.css | 9 - .../custom-web-app-brand/style.module.css | 3 - web/app/components/datasets/chunk.tsx | 6 +- .../image-uploader-in-chunk/index.tsx | 2 +- .../index.tsx | 2 +- .../datasets/common/image-uploader/store.tsx | 2 +- .../hooks/use-dsl-import.ts | 4 +- .../create-from-dsl-modal/uploader.tsx | 2 +- .../create/embedding-process/index.module.css | 91 ------- .../file-uploader/hooks/use-file-upload.ts | 4 +- .../create/file-uploader/index.module.css | 133 ---------- .../datasets/create/index.module.css | 0 .../datasets/create/step-one/hooks/index.ts | 1 - .../step-one/hooks/use-preview-state.ts | 6 +- .../create/step-three/index.module.css | 77 ------ .../datasets/create/step-two/hooks/index.ts | 6 +- .../step-two/hooks/use-document-creation.ts | 5 +- .../step-two/hooks/use-indexing-config.ts | 4 +- .../step-two/hooks/use-indexing-estimate.ts | 4 +- .../step-two/hooks/use-preview-state.ts | 4 +- .../step-two/hooks/use-segmentation-state.ts | 4 +- .../document-list/components/index.ts | 2 - .../components/document-list/index.tsx | 3 - .../data-source/local-file/constants.ts | 1 - .../local-file/hooks/use-local-file-upload.ts | 2 +- .../data-source/local-file/index.tsx | 2 +- .../data-source/website-crawl/index.tsx | 2 +- .../detail/batch-modal/csv-uploader.tsx | 2 +- .../documents/detail/batch-modal/index.tsx | 2 +- .../documents/detail/completed/hooks/index.ts | 5 - .../completed/hooks/use-child-segment-data.ts | 4 +- .../detail/completed/hooks/use-modal-state.ts | 6 +- .../completed/hooks/use-search-filter.ts | 8 +- .../completed/hooks/use-segment-list-data.ts | 4 +- .../completed/hooks/use-segment-selection.ts | 2 +- .../documents/detail/embedding/hooks/index.ts | 7 +- .../embedding/hooks/use-embedding-status.ts | 2 - .../detail/embedding/style.module.css | 61 ----- .../documents/detail/segment-add/index.tsx | 2 +- .../formatted-text/flavours/shared.tsx | 8 +- .../datasets/formatted-text/formatted.tsx | 2 +- .../datasets/hit-testing/components/mask.tsx | 2 +- .../components/datasets/preview/container.tsx | 2 +- .../components/datasets/preview/header.tsx | 2 +- .../settings/permission-selector/index.tsx | 2 +- .../components/devtools/react-grab/loader.tsx | 17 -- web/app/components/explore/category.tsx | 2 +- .../explore/item-operation/index.tsx | 2 +- .../explore/sidebar/app-nav-item/index.tsx | 2 +- .../actions/commands/command-bus.ts | 2 +- .../goto-anything/actions/commands/index.ts | 12 +- .../goto-anything/actions/commands/slash.tsx | 4 +- .../components/goto-anything/actions/index.ts | 1 - .../goto-anything/components/empty-state.tsx | 4 +- .../goto-anything/components/footer.tsx | 2 +- .../goto-anything/components/index.ts | 7 - .../goto-anything/components/result-item.tsx | 2 +- .../goto-anything/components/result-list.tsx | 2 +- .../goto-anything/components/search-input.tsx | 2 +- .../components/goto-anything/hooks/index.ts | 4 - .../hooks/use-goto-anything-modal.ts | 2 +- .../hooks/use-goto-anything-navigation.ts | 4 +- .../hooks/use-goto-anything-results.ts | 6 +- .../hooks/use-goto-anything-search.ts | 2 +- .../account-dropdown/menu-item-content.tsx | 2 +- .../workplace-selector/index.module.css | 5 - .../key-validator/declarations.ts | 8 - .../account-setting/key-validator/index.tsx | 2 +- .../language-page/index.module.css | 24 -- .../invite-modal/role-selector.tsx | 2 +- .../members-page/invited-modal/index.tsx | 2 +- .../model-provider-page/declarations.ts | 25 -- .../derive-model-status.ts | 2 +- .../model-provider-page/model-auth/index.tsx | 2 +- .../agent-model-trigger.tsx | 2 +- .../derive-trigger-status.ts | 3 - .../provider-added-card/cooldown-timer.tsx | 2 +- .../provider-added-card/model-list-item.tsx | 2 +- .../model-load-balancing-configs.tsx | 2 +- .../model-provider-page/status-mapping.ts | 9 - .../components/header/nav/index.module.css | 0 web/app/components/plugins/card/index.tsx | 2 +- .../components/plugins/marketplace/types.ts | 19 -- .../detail-header/hooks/index.ts | 2 +- .../hooks/use-detail-header-state.ts | 4 +- .../model-selector/index.tsx | 2 +- .../create/components/modal-steps.tsx | 8 +- .../create/hooks/use-common-modal-state.ts | 2 +- .../subscription-list/index.tsx | 1 - .../tool-selector/components/index.ts | 1 - .../tool-selector/hooks/index.ts | 1 - .../hooks/use-tool-selector-state.ts | 4 +- .../components/plugins/plugin-page/context.ts | 2 +- .../plugin-tasks/components/plugin-item.tsx | 2 +- .../components/plugin-section.tsx | 2 +- .../components/task-status-indicator.tsx | 2 +- .../reference-setting-modal/style.module.css | 7 - web/app/components/plugins/types.ts | 35 --- .../components/rag-pipeline/store/index.ts | 1 - .../share/text-generation/index.tsx | 2 +- .../share/text-generation/no-data/index.tsx | 2 +- .../share/text-generation/result/index.tsx | 2 +- .../run-batch/csv-download/index.tsx | 2 +- .../run-batch/csv-reader/index.tsx | 2 +- .../share/text-generation/run-batch/index.tsx | 2 +- .../run-batch/res-download/index.tsx | 2 +- .../share/text-generation/run-once/index.tsx | 2 +- .../tools/mcp/hooks/use-mcp-modal-form.ts | 4 +- .../components/tools/mcp/mcp-server-modal.tsx | 2 +- .../components/tools/mcp/mcp-service-card.tsx | 2 +- web/app/components/tools/mcp/modal.tsx | 4 +- web/app/components/tools/types.ts | 5 - .../hooks/use-workflow-run-utils.ts | 8 +- .../store/workflow/workflow-slice.ts | 1 - .../components/workflow/__tests__/fixtures.ts | 55 +--- .../workflow/__tests__/workflow-test-env.tsx | 2 +- .../workflow/block-selector/hooks.ts | 13 +- .../workflow/block-selector/tabs.tsx | 2 +- .../workflow/block-selector/types.ts | 59 ----- web/app/components/workflow/context.tsx | 2 +- .../components/workflow/header/undo-redo.tsx | 2 +- .../components/workflow/hooks-store/store.ts | 4 - web/app/components/workflow/hooks/index.ts | 1 - .../hooks/use-node-plugin-installation.ts | 2 +- .../workflow/hooks/use-nodes-layout.ts | 96 ------- .../_base/components/add-variable-popup.tsx | 4 +- .../components/agent-strategy-selector.tsx | 2 +- .../nodes/_base/components/agent-strategy.tsx | 2 +- .../components/before-run-form/panel-wrap.tsx | 2 +- .../components/form-input-item.helpers.ts | 2 +- .../workflow/nodes/_base/components/group.tsx | 4 +- .../components/mcp-tool-availability.tsx | 2 +- .../nodes/_base/components/retry/hooks.ts | 15 -- .../nodes/_base/components/retry/utils.ts | 1 - .../nodes/_base/components/setting-item.tsx | 2 +- .../components/switch-plugin-version.tsx | 2 +- .../nodes/_base/components/variable/utils.ts | 2 +- .../nodes/_base/hooks/use-resize-panel.ts | 2 +- .../components/workflow/nodes/_base/types.ts | 13 - .../nodes/agent/components/model-bar.tsx | 2 +- .../components/workflow/nodes/agent/panel.tsx | 2 +- .../workflow/nodes/agent/use-config.ts | 2 +- .../components/workflow/nodes/answer/utils.ts | 5 - .../components/var-list/use-var-list.ts | 39 --- .../workflow/nodes/assigner/utils.ts | 10 - .../components/workflow/nodes/code/utils.ts | 3 - .../components/workflow/nodes/constants.ts | 2 - .../workflow/nodes/data-source/types.ts | 3 - .../components/workflow/nodes/end/utils.ts | 5 - .../workflow/nodes/if-else/utils.ts | 4 +- web/app/components/workflow/nodes/index.tsx | 2 +- .../metadata/condition-list/utils.ts | 6 +- .../nodes/knowledge-retrieval/utils.ts | 4 - .../json-schema-generator/prompt-editor.tsx | 2 +- .../visual-editor/context.tsx | 2 +- .../components/workflow/nodes/llm/utils.ts | 31 +-- .../components/workflow/nodes/loop/types.ts | 1 - .../components/workflow/nodes/loop/utils.ts | 25 +- .../nodes/question-classifier/utils.ts | 3 - .../components/workflow/nodes/start/utils.ts | 5 - .../nodes/template-transform/utils.ts | 5 - .../components/workflow/nodes/tool/utils.ts | 5 - .../hooks/use-trigger-auth-flow.ts | 174 ------------- .../workflow/nodes/trigger-plugin/types.ts | 2 +- .../utils/execution-time-calculator.ts | 8 +- .../workflow/nodes/trigger-webhook/types.ts | 8 - .../trigger-webhook/use-config.helpers.ts | 2 +- .../utils/parameter-type-utils.ts | 4 +- .../trigger-webhook/utils/raw-variable.ts | 2 +- .../components/add-variable/index.tsx | 2 +- .../components/var-list/use-var-list.ts | 34 --- .../workflow/nodes/variable-assigner/utils.ts | 4 - .../components/workflow/operator/index.tsx | 2 +- .../components/variable-modal.sections.tsx | 2 +- .../components/variable-modal.tsx | 2 +- .../conversation-variable-modal.tsx | 2 +- .../panel/env-panel/variable-modal.tsx | 2 +- web/app/components/workflow/run/index.tsx | 2 +- web/app/components/workflow/types.ts | 11 - .../workflow/utils/gen-node-meta-data.ts | 2 +- .../workflow/utils/node-navigation.ts | 2 +- .../workflow/utils/plugin-install-check.ts | 4 +- web/app/components/workflow/utils/trigger.ts | 2 +- .../workflow/variable-inspect/listening.tsx | 2 +- .../workflow/workflow-history-store.tsx | 4 +- .../education-apply/verify-state-modal.tsx | 2 +- web/context/app-context-provider.tsx | 2 +- web/context/datasets-context.ts | 21 -- web/context/event-emitter.ts | 2 - .../external-knowledge-api-context.tsx | 2 +- web/context/global-public-context.tsx | 2 +- web/context/mitt-context.ts | 6 +- web/context/modal-context-provider.tsx | 2 - web/context/modal-context.ts | 2 - web/context/provider-context.ts | 2 - web/context/workspace-context.ts | 4 +- web/contract/console/explore.ts | 8 +- web/contract/console/notification.ts | 4 +- web/contract/router.ts | 2 - web/eslint-suppressions.json | 242 +++++------------- web/hooks/use-mitt.ts | 8 +- web/hooks/use-moderate.ts | 49 ---- web/hooks/use-pay.tsx | 8 +- web/i18n-config/language.ts | 6 - web/knip.config.ts | 23 +- web/models/app.ts | 12 +- web/models/common.ts | 73 ------ web/models/datasets.ts | 31 --- web/models/debug.ts | 84 ------ web/models/log.ts | 11 - web/models/pipeline.ts | 11 +- web/models/share.ts | 2 - web/plugins/dev-proxy/server.ts | 4 +- web/plugins/eslint/namespaces.js | 4 +- web/plugins/vite/inject-target.ts | 2 +- web/plugins/vite/react-grab-open-file.ts | 92 ------- web/scripts/analyze-component.js | 2 +- web/service/apps.ts | 65 +---- web/service/base.ts | 15 +- web/service/datasets.ts | 73 +----- web/service/debug.ts | 17 +- web/service/knowledge/use-dataset.ts | 9 - web/service/knowledge/use-document.ts | 2 +- web/service/knowledge/use-hit-testing.ts | 21 +- web/service/knowledge/use-metadata.ts | 4 +- web/service/plugins.ts | 31 --- web/service/share.ts | 4 - web/service/tools.ts | 8 - web/service/use-apps.ts | 12 - web/service/use-common.ts | 37 --- web/service/use-oauth.ts | 4 +- web/service/use-pipeline.ts | 45 +--- web/service/use-plugins-auth.ts | 9 - web/service/use-plugins.ts | 82 +----- web/service/use-share.ts | 2 +- web/service/use-strategy.ts | 4 - web/service/use-tools.ts | 66 ----- web/service/use-triggers.ts | 33 +-- web/service/use-workflow.ts | 1 - web/service/webapp-auth.ts | 4 +- web/service/workflow-payload.ts | 193 -------------- web/test/i18n-mock.ts | 6 +- web/types/app.ts | 36 --- web/types/doc-paths.ts | 2 +- web/types/pipeline.tsx | 6 - web/types/workflow.ts | 10 - web/utils/download.ts | 2 +- web/utils/encryption.ts | 2 +- web/utils/var.ts | 2 +- 403 files changed, 475 insertions(+), 3679 deletions(-) delete mode 100644 web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/documents/style.module.css delete mode 100644 web/app/components/app/configuration/config/agent/prompt-editor.tsx delete mode 100644 web/app/components/app/configuration/style.module.css delete mode 100644 web/app/components/app/configuration/tools/index.tsx delete mode 100644 web/app/components/base/auto-height-textarea/style.module.scss delete mode 100644 web/app/components/base/icons/src/image/llm/index.ts delete mode 100644 web/app/components/base/icons/src/public/model/index.ts delete mode 100644 web/app/components/base/icons/src/public/plugins/index.ts delete mode 100644 web/app/components/base/icons/src/vender/line/shapes/index.ts delete mode 100644 web/app/components/base/icons/src/vender/line/users/index.ts delete mode 100644 web/app/components/base/icons/src/vender/line/weather/index.ts delete mode 100644 web/app/components/base/icons/src/vender/solid/layout/index.ts delete mode 100644 web/app/components/billing/upgrade-btn/style.module.css delete mode 100644 web/app/components/custom/custom-web-app-brand/style.module.css delete mode 100644 web/app/components/datasets/create/embedding-process/index.module.css delete mode 100644 web/app/components/datasets/create/file-uploader/index.module.css delete mode 100644 web/app/components/datasets/create/index.module.css delete mode 100644 web/app/components/datasets/create/step-three/index.module.css delete mode 100644 web/app/components/datasets/documents/components/document-list/index.tsx delete mode 100644 web/app/components/datasets/documents/detail/embedding/style.module.css delete mode 100644 web/app/components/devtools/react-grab/loader.tsx delete mode 100644 web/app/components/header/account-dropdown/workplace-selector/index.module.css delete mode 100644 web/app/components/header/account-setting/language-page/index.module.css delete mode 100644 web/app/components/header/account-setting/model-provider-page/status-mapping.ts delete mode 100644 web/app/components/header/nav/index.module.css delete mode 100644 web/app/components/plugins/reference-setting-modal/style.module.css delete mode 100644 web/app/components/workflow/hooks/use-nodes-layout.ts delete mode 100644 web/app/components/workflow/nodes/_base/components/retry/utils.ts delete mode 100644 web/app/components/workflow/nodes/answer/utils.ts delete mode 100644 web/app/components/workflow/nodes/assigner/components/var-list/use-var-list.ts delete mode 100644 web/app/components/workflow/nodes/code/utils.ts delete mode 100644 web/app/components/workflow/nodes/end/utils.ts delete mode 100644 web/app/components/workflow/nodes/question-classifier/utils.ts delete mode 100644 web/app/components/workflow/nodes/start/utils.ts delete mode 100644 web/app/components/workflow/nodes/template-transform/utils.ts delete mode 100644 web/app/components/workflow/nodes/tool/utils.ts delete mode 100644 web/app/components/workflow/nodes/trigger-plugin/hooks/use-trigger-auth-flow.ts delete mode 100644 web/app/components/workflow/nodes/variable-assigner/components/var-list/use-var-list.ts delete mode 100644 web/context/datasets-context.ts delete mode 100644 web/hooks/use-moderate.ts delete mode 100644 web/plugins/vite/react-grab-open-file.ts delete mode 100644 web/service/workflow-payload.ts diff --git a/.vite-hooks/pre-commit b/.vite-hooks/pre-commit index 54e09f80d6..a4b5531ab1 100755 --- a/.vite-hooks/pre-commit +++ b/.vite-hooks/pre-commit @@ -89,6 +89,12 @@ if $web_modified; then echo "No staged TypeScript changes detected, skipping type-check:tsgo" fi + echo "Running knip" + if ! pnpm run knip; then + echo "Knip check failed. Please run 'pnpm run knip' to fix the errors." + exit 1 + fi + echo "Running unit tests check" modified_files=$(git diff --cached --name-only -- utils | grep -v '\.spec\.ts$' || true) diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout-main.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout-main.tsx index 0c87fd1a4d..d3f15bdf46 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout-main.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/layout-main.tsx @@ -35,7 +35,7 @@ const TagManagementModal = dynamic(() => import('@/app/components/base/tag-manag ssr: false, }) -export type IAppDetailLayoutProps = { +type IAppDetailLayoutProps = { children: React.ReactNode appId: string } diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/card-view.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/card-view.tsx index 26373bd42a..fb2edf0102 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/card-view.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/card-view.tsx @@ -25,7 +25,7 @@ import { useAppWorkflow } from '@/service/use-workflow' import { AppModeEnum } from '@/types/app' import { asyncRunSafe } from '@/utils' -export type ICardViewProps = { +type ICardViewProps = { appId: string isInPanel?: boolean className?: string diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/chart-view.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/chart-view.tsx index b6e902f456..0d33de2972 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/chart-view.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/chart-view.tsx @@ -27,7 +27,7 @@ const TIME_PERIOD_MAPPING: { value: number, name: TimePeriodName }[] = [ const queryDateFormat = 'YYYY-MM-DD HH:mm' -export type IChartViewProps = { +type IChartViewProps = { appId: string headerRight: React.ReactNode } diff --git a/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/documents/style.module.css b/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/documents/style.module.css deleted file mode 100644 index 67a9fe3bf5..0000000000 --- a/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/documents/style.module.css +++ /dev/null @@ -1,9 +0,0 @@ -.logTable td { - padding: 7px 8px; - box-sizing: border-box; - max-width: 200px; -} - -.pagination li { - list-style: none; -} diff --git a/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout-main.tsx b/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout-main.tsx index 730b76ee19..092e47278f 100644 --- a/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout-main.tsx +++ b/web/app/(commonLayout)/datasets/(datasetDetailLayout)/[datasetId]/layout-main.tsx @@ -26,7 +26,7 @@ import { usePathname } from '@/next/navigation' import { useDatasetDetail, useDatasetRelatedApps } from '@/service/knowledge/use-dataset' import { cn } from '@/utils/classnames' -export type IAppDetailLayoutProps = { +type IAppDetailLayoutProps = { children: React.ReactNode datasetId: string } diff --git a/web/app/account/(commonLayout)/avatar.tsx b/web/app/account/(commonLayout)/avatar.tsx index 5461ce739c..36a510cf63 100644 --- a/web/app/account/(commonLayout)/avatar.tsx +++ b/web/app/account/(commonLayout)/avatar.tsx @@ -13,10 +13,6 @@ import { useProviderContext } from '@/context/provider-context' import { useRouter } from '@/next/navigation' import { useLogout, useUserProfile } from '@/service/use-common' -export type IAppSelector = { - isMobile: boolean -} - export default function AppSelector() { const router = useRouter() const { t } = useTranslation() diff --git a/web/app/components/app-sidebar/app-info/index.tsx b/web/app/components/app-sidebar/app-info/index.tsx index 2530add2dc..a0628ec786 100644 --- a/web/app/components/app-sidebar/app-info/index.tsx +++ b/web/app/components/app-sidebar/app-info/index.tsx @@ -5,7 +5,7 @@ import AppInfoModals from './app-info-modals' import AppInfoTrigger from './app-info-trigger' import { useAppInfoActions } from './use-app-info-actions' -export type IAppInfoProps = { +type IAppInfoProps = { expand: boolean onlyShowDetail?: boolean openState?: boolean diff --git a/web/app/components/app-sidebar/basic.tsx b/web/app/components/app-sidebar/basic.tsx index 24746aa687..29a08f8a01 100644 --- a/web/app/components/app-sidebar/basic.tsx +++ b/web/app/components/app-sidebar/basic.tsx @@ -7,7 +7,7 @@ import { import Tooltip from '@/app/components/base/tooltip' import AppIcon from '../base/app-icon' -export type IAppBasicProps = { +type IAppBasicProps = { iconType?: 'app' | 'api' | 'dataset' | 'webapp' | 'notion' icon?: string icon_background?: string | null diff --git a/web/app/components/app-sidebar/index.tsx b/web/app/components/app-sidebar/index.tsx index bbf71c6cf9..f86cd617e3 100644 --- a/web/app/components/app-sidebar/index.tsx +++ b/web/app/components/app-sidebar/index.tsx @@ -17,7 +17,7 @@ import DatasetSidebarDropdown from './dataset-sidebar-dropdown' import NavLink from './nav-link' import ToggleButton from './toggle-button' -export type IAppDetailNavProps = { +type IAppDetailNavProps = { iconType?: 'app' | 'dataset' navigation: Array<{ name: string diff --git a/web/app/components/app/annotation/type.ts b/web/app/components/app/annotation/type.ts index e2f2264f07..076ef8f9bd 100644 --- a/web/app/components/app/annotation/type.ts +++ b/web/app/components/app/annotation/type.ts @@ -39,7 +39,5 @@ export enum AnnotationEnableStatus { } export enum JobStatus { - waiting = 'waiting', - processing = 'processing', completed = 'completed', } diff --git a/web/app/components/app/app-publisher/suggested-action.tsx b/web/app/components/app/app-publisher/suggested-action.tsx index 71ddceec01..56879d8fea 100644 --- a/web/app/components/app/app-publisher/suggested-action.tsx +++ b/web/app/components/app/app-publisher/suggested-action.tsx @@ -2,7 +2,7 @@ import type { HTMLProps, PropsWithChildren } from 'react' import { RiArrowRightUpLine } from '@remixicon/react' import { cn } from '@/utils/classnames' -export type SuggestedActionProps = PropsWithChildren & { +type SuggestedActionProps = PropsWithChildren & { icon?: React.ReactNode link?: string disabled?: boolean diff --git a/web/app/components/app/configuration/base/feature-panel/index.tsx b/web/app/components/app/configuration/base/feature-panel/index.tsx index 7f337c1572..77ee7bc8dd 100644 --- a/web/app/components/app/configuration/base/feature-panel/index.tsx +++ b/web/app/components/app/configuration/base/feature-panel/index.tsx @@ -3,7 +3,7 @@ import type { FC, ReactNode } from 'react' import * as React from 'react' import { cn } from '@/utils/classnames' -export type IFeaturePanelProps = { +type IFeaturePanelProps = { className?: string headerIcon?: ReactNode title: ReactNode diff --git a/web/app/components/app/configuration/base/group-name/index.tsx b/web/app/components/app/configuration/base/group-name/index.tsx index b21b0c5825..210ba4ca87 100644 --- a/web/app/components/app/configuration/base/group-name/index.tsx +++ b/web/app/components/app/configuration/base/group-name/index.tsx @@ -2,7 +2,7 @@ import type { FC } from 'react' import * as React from 'react' -export type IGroupNameProps = { +type IGroupNameProps = { name: string } diff --git a/web/app/components/app/configuration/base/operation-btn/index.tsx b/web/app/components/app/configuration/base/operation-btn/index.tsx index d33b632071..e3bdfd01ba 100644 --- a/web/app/components/app/configuration/base/operation-btn/index.tsx +++ b/web/app/components/app/configuration/base/operation-btn/index.tsx @@ -9,7 +9,7 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import { cn } from '@/utils/classnames' -export type IOperationBtnProps = { +type IOperationBtnProps = { className?: string type: 'add' | 'edit' actionName?: string diff --git a/web/app/components/app/configuration/base/var-highlight/index.tsx b/web/app/components/app/configuration/base/var-highlight/index.tsx index 697007d0b0..fda58f0b65 100644 --- a/web/app/components/app/configuration/base/var-highlight/index.tsx +++ b/web/app/components/app/configuration/base/var-highlight/index.tsx @@ -4,7 +4,7 @@ import * as React from 'react' import s from './style.module.css' -export type IVarHighlightProps = { +type IVarHighlightProps = { name: string className?: string } diff --git a/web/app/components/app/configuration/base/warning-mask/cannot-query-dataset.tsx b/web/app/components/app/configuration/base/warning-mask/cannot-query-dataset.tsx index 791230566b..d5fbd9e78f 100644 --- a/web/app/components/app/configuration/base/warning-mask/cannot-query-dataset.tsx +++ b/web/app/components/app/configuration/base/warning-mask/cannot-query-dataset.tsx @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' import WarningMask from '.' -export type IFormattingChangedProps = { +type IFormattingChangedProps = { onConfirm: () => void } diff --git a/web/app/components/app/configuration/base/warning-mask/formatting-changed.tsx b/web/app/components/app/configuration/base/warning-mask/formatting-changed.tsx index 1fe7b9c182..56ccae5ade 100644 --- a/web/app/components/app/configuration/base/warning-mask/formatting-changed.tsx +++ b/web/app/components/app/configuration/base/warning-mask/formatting-changed.tsx @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' import WarningMask from '.' -export type IFormattingChangedProps = { +type IFormattingChangedProps = { onConfirm: () => void onCancel: () => void } diff --git a/web/app/components/app/configuration/base/warning-mask/has-not-set-api.tsx b/web/app/components/app/configuration/base/warning-mask/has-not-set-api.tsx index 06c81a9f95..25587c5e58 100644 --- a/web/app/components/app/configuration/base/warning-mask/has-not-set-api.tsx +++ b/web/app/components/app/configuration/base/warning-mask/has-not-set-api.tsx @@ -3,7 +3,7 @@ import type { FC } from 'react' import * as React from 'react' import { useTranslation } from 'react-i18next' -export type IHasNotSetAPIProps = { +type IHasNotSetAPIProps = { onSetting: () => void } diff --git a/web/app/components/app/configuration/base/warning-mask/index.tsx b/web/app/components/app/configuration/base/warning-mask/index.tsx index 6d6aeceb97..5275f022cb 100644 --- a/web/app/components/app/configuration/base/warning-mask/index.tsx +++ b/web/app/components/app/configuration/base/warning-mask/index.tsx @@ -4,7 +4,7 @@ import * as React from 'react' import s from './style.module.css' -export type IWarningMaskProps = { +type IWarningMaskProps = { title: string description: string footer: React.ReactNode diff --git a/web/app/components/app/configuration/config-prompt/confirm-add-var/index.tsx b/web/app/components/app/configuration/config-prompt/confirm-add-var/index.tsx index c2f0cb000a..47d9aaa4d2 100644 --- a/web/app/components/app/configuration/config-prompt/confirm-add-var/index.tsx +++ b/web/app/components/app/configuration/config-prompt/confirm-add-var/index.tsx @@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' import VarHighlight from '../../base/var-highlight' -export type IConfirmAddVarProps = { +type IConfirmAddVarProps = { varNameArr: string[] onConfirm: () => void onCancel: () => void diff --git a/web/app/components/app/configuration/config-prompt/simple-prompt-input.tsx b/web/app/components/app/configuration/config-prompt/simple-prompt-input.tsx index e5f1556cc5..da1949af60 100644 --- a/web/app/components/app/configuration/config-prompt/simple-prompt-input.tsx +++ b/web/app/components/app/configuration/config-prompt/simple-prompt-input.tsx @@ -33,7 +33,7 @@ import { getNewVar, getVars } from '@/utils/var' import ConfirmAddVar from './confirm-add-var' import PromptEditorHeightResizeWrap from './prompt-editor-height-resize-wrap' -export type ISimplePromptInput = { +type ISimplePromptInput = { mode: AppModeEnum promptTemplate: string promptVariables: PromptVariable[] diff --git a/web/app/components/app/configuration/config-var/config-modal/config.ts b/web/app/components/app/configuration/config-var/config-modal/config.ts index 6586c2fd54..e03464d453 100644 --- a/web/app/components/app/configuration/config-var/config-modal/config.ts +++ b/web/app/components/app/configuration/config-var/config-modal/config.ts @@ -1,10 +1,3 @@ -export const jsonObjectWrap = { - type: 'object', - properties: {}, - required: [], - additionalProperties: true, -} - export const jsonConfigPlaceHolder = JSON.stringify( { type: 'object', diff --git a/web/app/components/app/configuration/config-var/config-modal/index.tsx b/web/app/components/app/configuration/config-var/config-modal/index.tsx index 31b936f3e4..3495494676 100644 --- a/web/app/components/app/configuration/config-var/config-modal/index.tsx +++ b/web/app/components/app/configuration/config-var/config-modal/index.tsx @@ -52,7 +52,7 @@ const normalizeSelectDefaultValue = (inputVar: InputVar) => { return inputVar } -export type IConfigModalProps = { +type IConfigModalProps = { isCreate?: boolean payload?: InputVar isShow: boolean diff --git a/web/app/components/app/configuration/config-var/config-select/index.tsx b/web/app/components/app/configuration/config-var/config-select/index.tsx index 847d530375..6a5b12c417 100644 --- a/web/app/components/app/configuration/config-var/config-select/index.tsx +++ b/web/app/components/app/configuration/config-var/config-select/index.tsx @@ -8,7 +8,7 @@ import { ReactSortable } from 'react-sortablejs' import { cn } from '@/utils/classnames' export type Options = string[] -export type IConfigSelectProps = { +type IConfigSelectProps = { options: Options onChange: (options: Options) => void } diff --git a/web/app/components/app/configuration/config-var/modal-foot.tsx b/web/app/components/app/configuration/config-var/modal-foot.tsx index fbb00b72bf..1fcaebbc0d 100644 --- a/web/app/components/app/configuration/config-var/modal-foot.tsx +++ b/web/app/components/app/configuration/config-var/modal-foot.tsx @@ -4,7 +4,7 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' -export type IModalFootProps = { +type IModalFootProps = { onConfirm: () => void onCancel: () => void } diff --git a/web/app/components/app/configuration/config-var/select-type-item/index.tsx b/web/app/components/app/configuration/config-var/select-type-item/index.tsx index e6ae34664f..7385dfd4c8 100644 --- a/web/app/components/app/configuration/config-var/select-type-item/index.tsx +++ b/web/app/components/app/configuration/config-var/select-type-item/index.tsx @@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next' import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon' import { cn } from '@/utils/classnames' -export type ISelectTypeItemProps = { +type ISelectTypeItemProps = { type: InputVarType selected: boolean onClick: () => void diff --git a/web/app/components/app/configuration/config/agent/prompt-editor.tsx b/web/app/components/app/configuration/config/agent/prompt-editor.tsx deleted file mode 100644 index e807c21518..0000000000 --- a/web/app/components/app/configuration/config/agent/prompt-editor.tsx +++ /dev/null @@ -1,152 +0,0 @@ -'use client' -import type { FC } from 'react' -import type { ExternalDataTool } from '@/models/common' -import copy from 'copy-to-clipboard' -import { noop } from 'es-toolkit/function' -import * as React from 'react' -import { useTranslation } from 'react-i18next' -import { useContext } from 'use-context-selector' -import s from '@/app/components/app/configuration/config-prompt/style.module.css' -import { - Copy, - CopyCheck, -} from '@/app/components/base/icons/src/vender/line/files' -import PromptEditor from '@/app/components/base/prompt-editor' -import { toast } from '@/app/components/base/ui/toast' -import ConfigContext from '@/context/debug-configuration' -import { useModalContext } from '@/context/modal-context' -import { cn } from '@/utils/classnames' - -type Props = { - className?: string - type: 'first-prompt' | 'next-iteration' - value: string - onChange: (value: string) => void -} - -const Editor: FC = ({ - className, - type, - value, - onChange, -}) => { - const { t } = useTranslation() - - const [isCopied, setIsCopied] = React.useState(false) - const { - modelConfig, - hasSetBlockStatus, - dataSets, - showSelectDataSet, - externalDataToolsConfig, - setExternalDataToolsConfig, - } = useContext(ConfigContext) - const promptVariables = modelConfig.configs.prompt_variables - const { setShowExternalDataToolModal } = useModalContext() - const isFirstPrompt = type === 'first-prompt' - const editorHeight = isFirstPrompt ? 'h-[336px]' : 'h-[52px]' - - const handleOpenExternalDataToolModal = () => { - setShowExternalDataToolModal({ - payload: {}, - onSaveCallback: (newExternalDataTool?: ExternalDataTool) => { - if (!newExternalDataTool) - return - setExternalDataToolsConfig([...externalDataToolsConfig, newExternalDataTool]) - }, - onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => { - for (let i = 0; i < promptVariables.length; i++) { - if (promptVariables[i].key === newExternalDataTool.variable) { - toast.error(t('varKeyError.keyAlreadyExists', { ns: 'appDebug', key: promptVariables[i].key })) - return false - } - } - - for (let i = 0; i < externalDataToolsConfig.length; i++) { - if (externalDataToolsConfig[i].variable === newExternalDataTool.variable) { - toast.error(t('varKeyError.keyAlreadyExists', { ns: 'appDebug', key: externalDataToolsConfig[i].variable })) - return false - } - } - - return true - }, - }) - } - return ( -
-
-
-
{t(`agent.${isFirstPrompt ? 'firstPrompt' : 'nextIteration'}`, { ns: 'appDebug' })}
-
- {!isCopied - ? ( - { - copy(value) - setIsCopied(true) - }} - /> - ) - : ( - - )} -
-
-
- ({ - id: item.id, - name: item.name, - type: item.data_source_type, - })), - onAddContext: showSelectDataSet, - }} - variableBlock={{ - show: true, - variables: modelConfig.configs.prompt_variables.filter(item => item.key && item.key.trim() && item.name && item.name.trim()).map(item => ({ - name: item.name, - value: item.key, - })), - }} - externalToolBlock={{ - show: true, - externalTools: externalDataToolsConfig.map(item => ({ - name: item.label!, - variableName: item.variable!, - icon: item.icon, - icon_background: item.icon_background, - })), - onAddExternalTool: handleOpenExternalDataToolModal, - }} - historyBlock={{ - show: false, - selectable: false, - history: { - user: '', - assistant: '', - }, - onEditRole: noop, - }} - queryBlock={{ - show: false, - selectable: false, - }} - onChange={onChange} - onBlur={noop} - /> -
-
-
{value.length}
-
-
-
- ) -} -export default React.memo(Editor) diff --git a/web/app/components/app/configuration/config/automatic/automatic-btn.tsx b/web/app/components/app/configuration/config/automatic/automatic-btn.tsx index 49d9bc4cc1..7999ba87af 100644 --- a/web/app/components/app/configuration/config/automatic/automatic-btn.tsx +++ b/web/app/components/app/configuration/config/automatic/automatic-btn.tsx @@ -7,7 +7,7 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' -export type IAutomaticBtnProps = { +type IAutomaticBtnProps = { onClick: () => void } const AutomaticBtn: FC = ({ diff --git a/web/app/components/app/configuration/config/automatic/get-automatic-res.tsx b/web/app/components/app/configuration/config/automatic/get-automatic-res.tsx index a2ca99a9d0..d2522e875e 100644 --- a/web/app/components/app/configuration/config/automatic/get-automatic-res.tsx +++ b/web/app/components/app/configuration/config/automatic/get-automatic-res.tsx @@ -43,7 +43,7 @@ import useGenData from './use-gen-data' const i18nPrefix = 'generate' -export type IGetAutomaticResProps = { +type IGetAutomaticResProps = { mode: AppModeEnum isShow: boolean onClose: () => void diff --git a/web/app/components/app/configuration/config/code-generator/get-code-generator-res.tsx b/web/app/components/app/configuration/config/code-generator/get-code-generator-res.tsx index 4c7971dc1d..2d6b3efb3d 100644 --- a/web/app/components/app/configuration/config/code-generator/get-code-generator-res.tsx +++ b/web/app/components/app/configuration/config/code-generator/get-code-generator-res.tsx @@ -31,7 +31,7 @@ import { GeneratorType } from '../automatic/types' import useGenData from '../automatic/use-gen-data' const i18nPrefix = 'generate' -export type IGetCodeGeneratorResProps = { +type IGetCodeGeneratorResProps = { flowId: string nodeId: string currentCode?: string diff --git a/web/app/components/app/configuration/ctrl-btn-group/index.tsx b/web/app/components/app/configuration/ctrl-btn-group/index.tsx index ff8576cc43..53a07a9b1d 100644 --- a/web/app/components/app/configuration/ctrl-btn-group/index.tsx +++ b/web/app/components/app/configuration/ctrl-btn-group/index.tsx @@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' import s from './style.module.css' -export type IContrlBtnGroupProps = { +type IContrlBtnGroupProps = { onSave: () => void onReset: () => void } diff --git a/web/app/components/app/configuration/dataset-config/select-dataset/index.tsx b/web/app/components/app/configuration/dataset-config/select-dataset/index.tsx index dd69774b2b..5fc594dc6b 100644 --- a/web/app/components/app/configuration/dataset-config/select-dataset/index.tsx +++ b/web/app/components/app/configuration/dataset-config/select-dataset/index.tsx @@ -17,7 +17,7 @@ import Link from '@/next/link' import { useInfiniteDatasets } from '@/service/knowledge/use-dataset' import { cn } from '@/utils/classnames' -export type ISelectDataSetProps = { +type ISelectDataSetProps = { isShow: boolean onClose: () => void selectedIds: string[] diff --git a/web/app/components/app/configuration/debug/debug-with-multiple-model/context.ts b/web/app/components/app/configuration/debug/debug-with-multiple-model/context.ts index e3ad06f1b9..9e76067234 100644 --- a/web/app/components/app/configuration/debug/debug-with-multiple-model/context.ts +++ b/web/app/components/app/configuration/debug/debug-with-multiple-model/context.ts @@ -18,5 +18,3 @@ export const DebugWithMultipleModelContext = createContext useContext(DebugWithMultipleModelContext) - -export default DebugWithMultipleModelContext diff --git a/web/app/components/app/configuration/style.module.css b/web/app/components/app/configuration/style.module.css deleted file mode 100644 index 01f2c93167..0000000000 --- a/web/app/components/app/configuration/style.module.css +++ /dev/null @@ -1,14 +0,0 @@ -.advancedPromptMode { - position: relative; -} - -.advancedPromptMode::before { - content: ''; - position: absolute; - bottom: 0; - left: -1px; - width: 100%; - height: 3px; - background-color: rgba(68, 76, 231, 0.18); - transform: skewX(-30deg); -} diff --git a/web/app/components/app/configuration/tools/index.tsx b/web/app/components/app/configuration/tools/index.tsx deleted file mode 100644 index 2b4511a0c6..0000000000 --- a/web/app/components/app/configuration/tools/index.tsx +++ /dev/null @@ -1,204 +0,0 @@ -import type { ExternalDataTool } from '@/models/common' -import { - RiAddLine, - RiArrowDownSLine, - RiDeleteBinLine, -} from '@remixicon/react' -import copy from 'copy-to-clipboard' -import { useState } from 'react' -import { useTranslation } from 'react-i18next' -import { useContext } from 'use-context-selector' -import AppIcon from '@/app/components/base/app-icon' -import { - Settings01, -} from '@/app/components/base/icons/src/vender/line/general' -import { Tool03 } from '@/app/components/base/icons/src/vender/solid/general' -import Switch from '@/app/components/base/switch' -import { toast } from '@/app/components/base/ui/toast' -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from '@/app/components/base/ui/tooltip' -import ConfigContext from '@/context/debug-configuration' -import { useModalContext } from '@/context/modal-context' - -const Tools = () => { - const { t } = useTranslation() - const { setShowExternalDataToolModal } = useModalContext() - const { - externalDataToolsConfig, - setExternalDataToolsConfig, - modelConfig, - } = useContext(ConfigContext) - const [expanded, setExpanded] = useState(true) - const [copied, setCopied] = useState(false) - - const handleSaveExternalDataToolModal = (externalDataTool: ExternalDataTool, index: number) => { - if (index > -1) { - setExternalDataToolsConfig([ - ...externalDataToolsConfig.slice(0, index), - externalDataTool, - ...externalDataToolsConfig.slice(index + 1), - ]) - } - else { - setExternalDataToolsConfig([...externalDataToolsConfig, externalDataTool]) - } - } - const handleValidateBeforeSaveExternalDataToolModal = (newExternalDataTool: ExternalDataTool, index: number) => { - const promptVariables = modelConfig?.configs?.prompt_variables || [] - for (let i = 0; i < promptVariables.length; i++) { - if (promptVariables[i].key === newExternalDataTool.variable) { - toast.error(t('varKeyError.keyAlreadyExists', { ns: 'appDebug', key: promptVariables[i].key })) - return false - } - } - - let existedExternalDataTools = [] - if (index > -1) { - existedExternalDataTools = [ - ...externalDataToolsConfig.slice(0, index), - ...externalDataToolsConfig.slice(index + 1), - ] - } - else { - existedExternalDataTools = [...externalDataToolsConfig] - } - - for (let i = 0; i < existedExternalDataTools.length; i++) { - if (existedExternalDataTools[i].variable === newExternalDataTool.variable) { - toast.error(t('varKeyError.keyAlreadyExists', { ns: 'appDebug', key: existedExternalDataTools[i].variable })) - return false - } - } - - return true - } - const handleOpenExternalDataToolModal = (payload: ExternalDataTool, index: number) => { - setShowExternalDataToolModal({ - payload, - onSaveCallback: (externalDataTool?: ExternalDataTool) => { - if (!externalDataTool) - return - handleSaveExternalDataToolModal(externalDataTool, index) - }, - onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => handleValidateBeforeSaveExternalDataToolModal(newExternalDataTool, index), - }) - } - - return ( -
-
-
-
setExpanded(v => !v)} - > - { - externalDataToolsConfig.length - ? - : - } - { - !!externalDataToolsConfig.length && ( - - ) - } -
-
- {t('feature.tools.title', { ns: 'appDebug' })} -
- - } /> - -
- {t('feature.tools.tips', { ns: 'appDebug' })} -
-
-
-
- { - !expanded && !!externalDataToolsConfig.length && ( - <> -
{t('feature.tools.toolsInUse', { ns: 'appDebug', count: externalDataToolsConfig.length })}
-
- - ) - } -
handleOpenExternalDataToolModal({}, -1)} - > - - {t('operation.add', { ns: 'common' })} -
-
- { - expanded && !!externalDataToolsConfig.length && ( -
- { - externalDataToolsConfig.map((item, index: number) => ( -
-
- -
{item.label}
- - { - copy(item.variable || '') - setCopied(true) - }} - > - {item.variable} -
- )} - /> - - {copied ? t('copied', { ns: 'appApi' }) : `${item.variable}, ${t('copy', { ns: 'appApi' })}`} - - -
-
handleOpenExternalDataToolModal(item, index)} - > - -
-
setExternalDataToolsConfig([...externalDataToolsConfig.slice(0, index), ...externalDataToolsConfig.slice(index + 1)])} - > - -
-
- handleSaveExternalDataToolModal({ ...item, enabled }, index)} - /> -
- )) - } -
- ) - } -
- ) -} - -export default Tools diff --git a/web/app/components/app/create-app-dialog/app-card/index.tsx b/web/app/components/app/create-app-dialog/app-card/index.tsx index 8afb5cbf4b..f0633288fd 100644 --- a/web/app/components/app/create-app-dialog/app-card/index.tsx +++ b/web/app/components/app/create-app-dialog/app-card/index.tsx @@ -12,7 +12,7 @@ import { useGlobalPublicStore } from '@/context/global-public-context' import { cn } from '@/utils/classnames' import { AppTypeIcon, AppTypeLabel } from '../../type-selector' -export type AppCardProps = { +type AppCardProps = { app: App canCreate: boolean onCreate: () => void diff --git a/web/app/components/app/create-from-dsl-modal/uploader.tsx b/web/app/components/app/create-from-dsl-modal/uploader.tsx index e376d04a9f..7480da4b5f 100644 --- a/web/app/components/app/create-from-dsl-modal/uploader.tsx +++ b/web/app/components/app/create-from-dsl-modal/uploader.tsx @@ -13,7 +13,7 @@ import { toast } from '@/app/components/base/ui/toast' import { cn } from '@/utils/classnames' import { formatFileSize } from '@/utils/format' -export type Props = { +type Props = { file: File | undefined updateFile: (file?: File) => void className?: string diff --git a/web/app/components/app/log/index.tsx b/web/app/components/app/log/index.tsx index 59f454f754..c30cf6cf51 100644 --- a/web/app/components/app/log/index.tsx +++ b/web/app/components/app/log/index.tsx @@ -17,7 +17,7 @@ import EmptyElement from './empty-element' import Filter, { TIME_PERIOD_MAPPING } from './filter' import List from './list' -export type ILogsProps = { +type ILogsProps = { appDetail: App } diff --git a/web/app/components/app/overview/apikey-info-panel/apikey-info-panel.test-utils.tsx b/web/app/components/app/overview/apikey-info-panel/apikey-info-panel.test-utils.tsx index 54763907df..4bab54b711 100644 --- a/web/app/components/app/overview/apikey-info-panel/apikey-info-panel.test-utils.tsx +++ b/web/app/components/app/overview/apikey-info-panel/apikey-info-panel.test-utils.tsx @@ -72,17 +72,17 @@ const defaultModalContext: ModalContextState = { setShowTriggerEventsLimitModal: noop, } -export type MockOverrides = { +type MockOverrides = { providerContext?: Partial modalContext?: Partial } -export type APIKeyInfoPanelRenderOptions = { +type APIKeyInfoPanelRenderOptions = { mockOverrides?: MockOverrides } & Omit // Setup function to configure mocks -export function setupMocks(overrides: MockOverrides = {}) { +function setupMocks(overrides: MockOverrides = {}) { mockUseProviderContext.mockReturnValue({ ...defaultProviderContext, ...overrides.providerContext, @@ -95,7 +95,7 @@ export function setupMocks(overrides: MockOverrides = {}) { } // Custom render function -export function renderAPIKeyInfoPanel(options: APIKeyInfoPanelRenderOptions = {}) { +function renderAPIKeyInfoPanel(options: APIKeyInfoPanelRenderOptions = {}) { const { mockOverrides, ...renderOptions } = options setupMocks(mockOverrides) @@ -210,4 +210,4 @@ export function clearAllMocks() { } // Export mock functions for external access -export { defaultModalContext, mockUseModalContext, mockUseProviderContext } +export { defaultModalContext, mockUseModalContext } diff --git a/web/app/components/app/overview/app-chart.tsx b/web/app/components/app/overview/app-chart.tsx index 028753d41c..7ea94024ff 100644 --- a/web/app/components/app/overview/app-chart.tsx +++ b/web/app/components/app/overview/app-chart.tsx @@ -102,12 +102,12 @@ export type PeriodParamsWithTimeRange = { query?: TimeRange } -export type IBizChartProps = { +type IBizChartProps = { period: PeriodParams id: string } -export type IChartProps = { +type IChartProps = { className?: string basicInfo: { title: string, explanation: string, timePeriod: string } valueKey?: string @@ -508,5 +508,3 @@ export const AvgUserInteractions: FC = ({ id, period }) => { /> ) } - -export default Chart diff --git a/web/app/components/app/overview/settings/index.tsx b/web/app/components/app/overview/settings/index.tsx index db880839c9..cd50e7f8ee 100644 --- a/web/app/components/app/overview/settings/index.tsx +++ b/web/app/components/app/overview/settings/index.tsx @@ -29,7 +29,7 @@ import Link from '@/next/link' import { AppModeEnum } from '@/types/app' import { cn } from '@/utils/classnames' -export type ISettingsModalProps = { +type ISettingsModalProps = { isChat: boolean appInfo: AppDetailResponse & Partial isShow: boolean diff --git a/web/app/components/app/overview/trigger-card.tsx b/web/app/components/app/overview/trigger-card.tsx index 11f08cf994..53301a353a 100644 --- a/web/app/components/app/overview/trigger-card.tsx +++ b/web/app/components/app/overview/trigger-card.tsx @@ -22,7 +22,7 @@ import { import { useAllTriggerPlugins } from '@/service/use-triggers' import { canFindTool } from '@/utils' -export type ITriggerCardProps = { +type ITriggerCardProps = { appInfo: AppDetailResponse & Partial onToggleResult?: (err: Error | null, message?: I18nKeysByPrefix<'common', 'actionMsg.'>) => void } diff --git a/web/app/components/app/text-generate/item/index.tsx b/web/app/components/app/text-generate/item/index.tsx index 62f1e5752e..88599a5ef1 100644 --- a/web/app/components/app/text-generate/item/index.tsx +++ b/web/app/components/app/text-generate/item/index.tsx @@ -38,7 +38,7 @@ import ResultTab from './result-tab' const MAX_DEPTH = 3 -export type IGenerationItemProps = { +type IGenerationItemProps = { isWorkflow?: boolean workflowProcessData?: WorkflowProcess className?: string @@ -67,12 +67,6 @@ export type IGenerationItemProps = { inSidePanel?: boolean } -export const copyIcon = ( - - - -) - const GenerationItem: FC = ({ isWorkflow, workflowProcessData, diff --git a/web/app/components/app/text-generate/saved-items/no-data/index.tsx b/web/app/components/app/text-generate/saved-items/no-data/index.tsx index e73a1db1df..c6596c8ec3 100644 --- a/web/app/components/app/text-generate/saved-items/no-data/index.tsx +++ b/web/app/components/app/text-generate/saved-items/no-data/index.tsx @@ -8,7 +8,7 @@ import * as React from 'react' import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' -export type INoDataProps = { +type INoDataProps = { onStartCreateContent: () => void } diff --git a/web/app/components/app/type-selector/index.tsx b/web/app/components/app/type-selector/index.tsx index 2b0923a6a0..cb4db155d4 100644 --- a/web/app/components/app/type-selector/index.tsx +++ b/web/app/components/app/type-selector/index.tsx @@ -11,7 +11,7 @@ import { import { AppModeEnum } from '@/types/app' import { cn } from '@/utils/classnames' -export type AppSelectorProps = { +type AppSelectorProps = { value: Array onChange: (value: AppSelectorProps['value']) => void } diff --git a/web/app/components/apps/app-card.tsx b/web/app/components/apps/app-card.tsx index 079e8fa8bc..7227e412e7 100644 --- a/web/app/components/apps/app-card.tsx +++ b/web/app/components/apps/app-card.tsx @@ -62,7 +62,7 @@ const AccessControl = dynamic(() => import('@/app/components/app/app-access-cont ssr: false, }) -export type AppCardProps = { +type AppCardProps = { app: App onRefresh?: () => void } diff --git a/web/app/components/apps/new-app-card.tsx b/web/app/components/apps/new-app-card.tsx index 7741190b8c..31a374f6f7 100644 --- a/web/app/components/apps/new-app-card.tsx +++ b/web/app/components/apps/new-app-card.tsx @@ -25,7 +25,7 @@ const CreateFromDSLModal = dynamic(() => import('@/app/components/app/create-fro ssr: false, }) -export type CreateAppCardProps = { +type CreateAppCardProps = { className?: string isLoading?: boolean onSuccess?: () => void diff --git a/web/app/components/base/agent-log-modal/detail.tsx b/web/app/components/base/agent-log-modal/detail.tsx index 6550b305f8..45f34c9711 100644 --- a/web/app/components/base/agent-log-modal/detail.tsx +++ b/web/app/components/base/agent-log-modal/detail.tsx @@ -15,7 +15,7 @@ import { cn } from '@/utils/classnames' import ResultPanel from './result' import TracingPanel from './tracing' -export type AgentLogDetailProps = { +type AgentLogDetailProps = { activeTab?: 'DETAIL' | 'TRACING' conversationID: string log: IChatItem diff --git a/web/app/components/base/amplitude/index.ts b/web/app/components/base/amplitude/index.ts index 44cbf728e2..21152d1220 100644 --- a/web/app/components/base/amplitude/index.ts +++ b/web/app/components/base/amplitude/index.ts @@ -1,2 +1,2 @@ export { default } from './lazy-amplitude-provider' -export { resetUser, setUserId, setUserProperties, trackEvent } from './utils' +export { setUserId, setUserProperties, trackEvent } from './utils' diff --git a/web/app/components/base/answer-icon/index.tsx b/web/app/components/base/answer-icon/index.tsx index 56e932ad71..1ae1b4f076 100644 --- a/web/app/components/base/answer-icon/index.tsx +++ b/web/app/components/base/answer-icon/index.tsx @@ -8,7 +8,7 @@ import { cn } from '@/utils/classnames' init({ data }) -export type AnswerIconProps = { +type AnswerIconProps = { iconType?: AppIconType | null icon?: string | null background?: string | null diff --git a/web/app/components/base/app-icon/index.tsx b/web/app/components/base/app-icon/index.tsx index b3fe5f3c4f..d4eaeb69d9 100644 --- a/web/app/components/base/app-icon/index.tsx +++ b/web/app/components/base/app-icon/index.tsx @@ -12,7 +12,7 @@ import { cn } from '@/utils/classnames' init({ data }) -export type AppIconProps = { +type AppIconProps = { size?: 'xs' | 'tiny' | 'small' | 'medium' | 'large' | 'xl' | 'xxl' rounded?: boolean iconType?: AppIconType | null diff --git a/web/app/components/base/auto-height-textarea/style.module.scss b/web/app/components/base/auto-height-textarea/style.module.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/app/components/base/avatar/index.tsx b/web/app/components/base/avatar/index.tsx index f53e1f8985..885022dded 100644 --- a/web/app/components/base/avatar/index.tsx +++ b/web/app/components/base/avatar/index.tsx @@ -24,11 +24,11 @@ export type AvatarProps = { onLoadingStatusChange?: (status: ImageLoadingStatus) => void } -export type AvatarRootProps = React.ComponentPropsWithRef & { +type AvatarRootProps = React.ComponentPropsWithRef & { size?: AvatarSize } -export function AvatarRoot({ +function AvatarRoot({ size = 'md', className, ...props @@ -45,9 +45,9 @@ export function AvatarRoot({ ) } -export type AvatarImageProps = React.ComponentPropsWithRef +type AvatarImageProps = React.ComponentPropsWithRef -export function AvatarImage({ +function AvatarImage({ className, ...props }: AvatarImageProps) { @@ -59,11 +59,11 @@ export function AvatarImage({ ) } -export type AvatarFallbackProps = React.ComponentPropsWithRef & { +type AvatarFallbackProps = React.ComponentPropsWithRef & { size?: AvatarSize } -export function AvatarFallback({ +function AvatarFallback({ size = 'md', className, ...props diff --git a/web/app/components/base/block-input/index.tsx b/web/app/components/base/block-input/index.tsx index 2a917306cd..cf832d9f94 100644 --- a/web/app/components/base/block-input/index.tsx +++ b/web/app/components/base/block-input/index.tsx @@ -29,7 +29,7 @@ export const getInputKeys = (value: string) => { return res } -export type IBlockInputProps = { +type IBlockInputProps = { value: string className?: string // wrapper class highLightClassName?: string // class for the highlighted text default is text-blue-500 diff --git a/web/app/components/base/chat/chat-with-history/index.tsx b/web/app/components/base/chat/chat-with-history/index.tsx index a645775965..562502a573 100644 --- a/web/app/components/base/chat/chat-with-history/index.tsx +++ b/web/app/components/base/chat/chat-with-history/index.tsx @@ -97,7 +97,7 @@ const ChatWithHistory: FC = ({ ) } -export type ChatWithHistoryWrapProps = { +type ChatWithHistoryWrapProps = { installedAppInfo?: InstalledApp className?: string } diff --git a/web/app/components/base/chat/chat-with-history/sidebar/rename-modal.tsx b/web/app/components/base/chat/chat-with-history/sidebar/rename-modal.tsx index 66a5ad6a36..e66ca351f2 100644 --- a/web/app/components/base/chat/chat-with-history/sidebar/rename-modal.tsx +++ b/web/app/components/base/chat/chat-with-history/sidebar/rename-modal.tsx @@ -7,7 +7,7 @@ import Button from '@/app/components/base/button' import Input from '@/app/components/base/input' import Modal from '@/app/components/base/modal' -export type IRenameModalProps = { +type IRenameModalProps = { isShow: boolean saveLoading: boolean name: string diff --git a/web/app/components/base/chat/chat/context.ts b/web/app/components/base/chat/chat/context.ts index ff0bd26336..c4fbf9dd3e 100644 --- a/web/app/components/base/chat/chat/context.ts +++ b/web/app/components/base/chat/chat/context.ts @@ -26,5 +26,3 @@ export const ChatContext = createContext({ }) export const useChatContext = () => useContext(ChatContext) - -export default ChatContext diff --git a/web/app/components/base/chat/chat/loading-anim/index.tsx b/web/app/components/base/chat/chat/loading-anim/index.tsx index 74cc3444de..6ba37288e7 100644 --- a/web/app/components/base/chat/chat/loading-anim/index.tsx +++ b/web/app/components/base/chat/chat/loading-anim/index.tsx @@ -4,7 +4,7 @@ import * as React from 'react' import { cn } from '@/utils/classnames' import s from './style.module.css' -export type ILoadingAnimProps = { +type ILoadingAnimProps = { type: 'text' | 'avatar' } diff --git a/web/app/components/base/chat/chat/type.ts b/web/app/components/base/chat/chat/type.ts index 7bd4de5b05..6ddb4f958e 100644 --- a/web/app/components/base/chat/chat/type.ts +++ b/web/app/components/base/chat/chat/type.ts @@ -29,8 +29,6 @@ export type SubmitAnnotationFunc = ( content: string, ) => Promise -export type DisplayScene = 'web' | 'console' - export type ToolInfoInThought = { name: string label: string @@ -151,15 +149,6 @@ export type MessageReplace = { conversation_id: string } -export type AnnotationReply = { - id: string - task_id: string - answer: string - conversation_id: string - annotation_id: string - annotation_author_name: string -} - export type InputForm = { type: InputVarType label: string diff --git a/web/app/components/base/chat/embedded-chatbot/header/index.tsx b/web/app/components/base/chat/embedded-chatbot/header/index.tsx index 9cca48b42a..7b1fb46fa0 100644 --- a/web/app/components/base/chat/embedded-chatbot/header/index.tsx +++ b/web/app/components/base/chat/embedded-chatbot/header/index.tsx @@ -16,7 +16,7 @@ import { } from '../context' import { CssTransform } from '../theme/utils' -export type IHeaderProps = { +type IHeaderProps = { isMobile?: boolean allowResetChat?: boolean customerIcon?: React.ReactNode diff --git a/web/app/components/base/chat/types.ts b/web/app/components/base/chat/types.ts index 1502a32e92..341dd3c689 100644 --- a/web/app/components/base/chat/types.ts +++ b/web/app/components/base/chat/types.ts @@ -3,42 +3,16 @@ import type { FileEntity } from '@/app/components/base/file-uploader/types' import type { WorkflowRunningStatus } from '@/app/components/workflow/types' import type { ModelConfig, - VisionSettings, } from '@/types/app' import type { HumanInputFilledFormData, HumanInputFormData, NodeTracing } from '@/types/workflow' export type { Inputs, - PromptVariable, + } from '@/models/debug' -export type { VisionFile } from '@/types/app' + export { TransferMethod } from '@/types/app' -export type UserInputForm = { - default: string - label: string - required: boolean - variable: string -} - -export type UserInputFormTextInput = { - 'text-input': UserInputForm & { - max_length: number - } -} - -export type UserInputFormSelect = { - select: UserInputForm & { - options: string[] - } -} - -export type UserInputFormParagraph = { - paragraph: UserInputForm -} - -export type VisionConfig = VisionSettings - export type EnableType = { enabled: boolean } diff --git a/web/app/components/base/checkbox-list/index.tsx b/web/app/components/base/checkbox-list/index.tsx index 6eda2aebd0..5fb5ca6028 100644 --- a/web/app/components/base/checkbox-list/index.tsx +++ b/web/app/components/base/checkbox-list/index.tsx @@ -9,13 +9,13 @@ import SearchMenu from '@/assets/search-menu.svg' import { cn } from '@/utils/classnames' import Button from '../button' -export type CheckboxListOption = { +type CheckboxListOption = { label: string value: string disabled?: boolean } -export type CheckboxListProps = { +type CheckboxListProps = { title?: string label?: string description?: string diff --git a/web/app/components/base/date-and-time-picker/calendar/days-of-week.tsx b/web/app/components/base/date-and-time-picker/calendar/days-of-week.tsx index ac14d49ead..46670b27b3 100644 --- a/web/app/components/base/date-and-time-picker/calendar/days-of-week.tsx +++ b/web/app/components/base/date-and-time-picker/calendar/days-of-week.tsx @@ -17,5 +17,3 @@ export const DaysOfWeek = () => {
) } - -export default React.memo(DaysOfWeek) diff --git a/web/app/components/base/date-and-time-picker/utils/dayjs.ts b/web/app/components/base/date-and-time-picker/utils/dayjs.ts index f1c77ecc57..3e20e51cf3 100644 --- a/web/app/components/base/date-and-time-picker/utils/dayjs.ts +++ b/web/app/components/base/date-and-time-picker/utils/dayjs.ts @@ -126,7 +126,7 @@ export const convertTimezoneToOffsetStr = (timezone?: string) => { export const isDayjsObject = (value: unknown): value is Dayjs => dayjs.isDayjs(value) -export type ToDayjsOptions = { +type ToDayjsOptions = { timezone?: string format?: string formats?: string[] diff --git a/web/app/components/base/divider/index.tsx b/web/app/components/base/divider/index.tsx index d3693e9ffd..b096844079 100644 --- a/web/app/components/base/divider/index.tsx +++ b/web/app/components/base/divider/index.tsx @@ -21,7 +21,7 @@ const dividerVariants = cva('', { }, }) -export type DividerProps = { +type DividerProps = { className?: string style?: CSSProperties } & VariantProps diff --git a/web/app/components/base/file-uploader/index.ts b/web/app/components/base/file-uploader/index.ts index 1ab4fdae3b..5f27f61d90 100644 --- a/web/app/components/base/file-uploader/index.ts +++ b/web/app/components/base/file-uploader/index.ts @@ -1,7 +1,7 @@ export { default as FileTypeIcon } from './file-type-icon' export { default as FileUploaderInAttachmentWrapper } from './file-uploader-in-attachment' -export { default as FileItemInAttachment } from './file-uploader-in-attachment/file-item' + export { default as FileUploaderInChatInput } from './file-uploader-in-chat-input' -export { default as FileItem } from './file-uploader-in-chat-input/file-item' + export { FileListInChatInput } from './file-uploader-in-chat-input/file-list' export { FileList } from './file-uploader-in-chat-input/file-list' diff --git a/web/app/components/base/form/form-scenarios/demo/types.ts b/web/app/components/base/form/form-scenarios/demo/types.ts index 91ab1c7747..a8aa18b27d 100644 --- a/web/app/components/base/form/form-scenarios/demo/types.ts +++ b/web/app/components/base/form/form-scenarios/demo/types.ts @@ -30,5 +30,3 @@ export const UserSchema = z.object({ preferredContactMethod: ContactMethod, }), }) - -export type User = z.infer diff --git a/web/app/components/base/form/index.tsx b/web/app/components/base/form/index.tsx index 6c60826c32..663b7f1fe8 100644 --- a/web/app/components/base/form/index.tsx +++ b/web/app/components/base/form/index.tsx @@ -14,9 +14,11 @@ import UploadMethodField from './components/field/upload-method' import VariableOrConstantInputField from './components/field/variable-selector' import Actions from './components/form/actions' -export const { fieldContext, useFieldContext, formContext, useFormContext } +const { fieldContext, useFieldContext, formContext, useFormContext } = createFormHookContexts() +export { formContext, useFieldContext, useFormContext } + export const { useAppForm, withForm } = createFormHook({ fieldComponents: { TextField, diff --git a/web/app/components/base/form/types.ts b/web/app/components/base/form/types.ts index a2b434f3cf..4b83b9e4c9 100644 --- a/web/app/components/base/form/types.ts +++ b/web/app/components/base/form/types.ts @@ -82,8 +82,6 @@ export type FormSchema = { } } -export type FormValues = Record - export type GetValuesOptions = { needTransformWhenSecretFieldIsPristine?: boolean needCheckValidatedValues?: boolean diff --git a/web/app/components/base/ga/index.tsx b/web/app/components/base/ga/index.tsx index 3e19afd974..79783c75cc 100644 --- a/web/app/components/base/ga/index.tsx +++ b/web/app/components/base/ga/index.tsx @@ -9,16 +9,16 @@ export enum GaType { webapp = 'webapp', } -export const GA_MEASUREMENT_ID_ADMIN = 'G-DM9497FN4V' -export const GA_MEASUREMENT_ID_WEBAPP = 'G-2MFWXK7WYT' -export const COOKIEYES_SCRIPT_SRC = 'https://cdn-cookieyes.com/client_data/2a645945fcae53f8e025a2b1/script.js' +const GA_MEASUREMENT_ID_ADMIN = 'G-DM9497FN4V' +const GA_MEASUREMENT_ID_WEBAPP = 'G-2MFWXK7WYT' +const COOKIEYES_SCRIPT_SRC = 'https://cdn-cookieyes.com/client_data/2a645945fcae53f8e025a2b1/script.js' const gaIdMaps = { [GaType.admin]: GA_MEASUREMENT_ID_ADMIN, [GaType.webapp]: GA_MEASUREMENT_ID_WEBAPP, } -export type IGAProps = { +type IGAProps = { gaType: GaType } diff --git a/web/app/components/base/icons/IconBase.tsx b/web/app/components/base/icons/IconBase.tsx index 13ab7c816b..2de0f3239e 100644 --- a/web/app/components/base/icons/IconBase.tsx +++ b/web/app/components/base/icons/IconBase.tsx @@ -6,7 +6,7 @@ export type IconData = { icon: AbstractNode } -export type IconBaseProps = { +type IconBaseProps = { data: IconData className?: string onClick?: React.MouseEventHandler diff --git a/web/app/components/base/icons/src/image/llm/index.ts b/web/app/components/base/icons/src/image/llm/index.ts deleted file mode 100644 index 1b7f8c48eb..0000000000 --- a/web/app/components/base/icons/src/image/llm/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -export { default as BaichuanTextCn } from './BaichuanTextCn' -export { default as Minimax } from './Minimax' -export { default as MinimaxText } from './MinimaxText' -export { default as Tongyi } from './Tongyi' -export { default as TongyiText } from './TongyiText' -export { default as TongyiTextCn } from './TongyiTextCn' -export { default as Wxyy } from './Wxyy' -export { default as WxyyText } from './WxyyText' -export { default as WxyyTextCn } from './WxyyTextCn' diff --git a/web/app/components/base/icons/src/public/billing/index.ts b/web/app/components/base/icons/src/public/billing/index.ts index bd8fdc10dd..c80933b0db 100644 --- a/web/app/components/base/icons/src/public/billing/index.ts +++ b/web/app/components/base/icons/src/public/billing/index.ts @@ -1,12 +1,5 @@ -export { default as ArCube1 } from './ArCube1' -export { default as Asterisk } from './Asterisk' export { default as AwsMarketplaceDark } from './AwsMarketplaceDark' export { default as AwsMarketplaceLight } from './AwsMarketplaceLight' export { default as Azure } from './Azure' -export { default as Buildings } from './Buildings' -export { default as Diamond } from './Diamond' + export { default as GoogleCloud } from './GoogleCloud' -export { default as Group2 } from './Group2' -export { default as Keyframe } from './Keyframe' -export { default as Sparkles } from './Sparkles' -export { default as SparklesSoft } from './SparklesSoft' diff --git a/web/app/components/base/icons/src/public/common/index.ts b/web/app/components/base/icons/src/public/common/index.ts index c19ab569fa..894570bc8f 100644 --- a/web/app/components/base/icons/src/public/common/index.ts +++ b/web/app/components/base/icons/src/public/common/index.ts @@ -1,16 +1,9 @@ -export { default as D } from './D' -export { default as DiagonalDividingLine } from './DiagonalDividingLine' -export { default as Dify } from './Dify' -export { default as Gdpr } from './Gdpr' export { default as Github } from './Github' export { default as Highlight } from './Highlight' -export { default as Iso } from './Iso' + export { default as Line3 } from './Line3' -export { default as Lock } from './Lock' -export { default as MessageChatSquare } from './MessageChatSquare' -export { default as MultiPathRetrieval } from './MultiPathRetrieval' + export { default as Notion } from './Notion' -export { default as NTo1Retrieval } from './NTo1Retrieval' -export { default as Soc2 } from './Soc2' + export { default as SparklesSoft } from './SparklesSoft' export { default as SparklesSoftAccent } from './SparklesSoftAccent' diff --git a/web/app/components/base/icons/src/public/knowledge/dataset-card/index.ts b/web/app/components/base/icons/src/public/knowledge/dataset-card/index.ts index 9f45717e73..50d6bac1ed 100644 --- a/web/app/components/base/icons/src/public/knowledge/dataset-card/index.ts +++ b/web/app/components/base/icons/src/public/knowledge/dataset-card/index.ts @@ -1,5 +1,5 @@ export { default as ExternalKnowledgeBase } from './ExternalKnowledgeBase' export { default as General } from './General' -export { default as Graph } from './Graph' + export { default as ParentChild } from './ParentChild' export { default as Qa } from './Qa' diff --git a/web/app/components/base/icons/src/public/knowledge/index.ts b/web/app/components/base/icons/src/public/knowledge/index.ts index 4acde1663b..c0d35e9ef3 100644 --- a/web/app/components/base/icons/src/public/knowledge/index.ts +++ b/web/app/components/base/icons/src/public/knowledge/index.ts @@ -1,8 +1,6 @@ -export { default as File } from './File' export { default as OptionCardEffectBlue } from './OptionCardEffectBlue' export { default as OptionCardEffectBlueLight } from './OptionCardEffectBlueLight' export { default as OptionCardEffectOrange } from './OptionCardEffectOrange' export { default as OptionCardEffectPurple } from './OptionCardEffectPurple' export { default as OptionCardEffectTeal } from './OptionCardEffectTeal' export { default as SelectionMod } from './SelectionMod' -export { default as Watercrawl } from './Watercrawl' diff --git a/web/app/components/base/icons/src/public/llm/index.ts b/web/app/components/base/icons/src/public/llm/index.ts index 0c5cef4a36..6b77aefe51 100644 --- a/web/app/components/base/icons/src/public/llm/index.ts +++ b/web/app/components/base/icons/src/public/llm/index.ts @@ -1,50 +1,14 @@ -export { default as Anthropic } from './Anthropic' export { default as AnthropicDark } from './AnthropicDark' export { default as AnthropicLight } from './AnthropicLight' export { default as AnthropicShortLight } from './AnthropicShortLight' -export { default as AnthropicText } from './AnthropicText' -export { default as Azureai } from './Azureai' -export { default as AzureaiText } from './AzureaiText' -export { default as AzureOpenaiService } from './AzureOpenaiService' -export { default as AzureOpenaiServiceText } from './AzureOpenaiServiceText' -export { default as Baichuan } from './Baichuan' -export { default as BaichuanText } from './BaichuanText' -export { default as Chatglm } from './Chatglm' -export { default as ChatglmText } from './ChatglmText' -export { default as Cohere } from './Cohere' -export { default as CohereText } from './CohereText' + export { default as Deepseek } from './Deepseek' export { default as Gemini } from './Gemini' -export { default as Gpt3 } from './Gpt3' -export { default as Gpt4 } from './Gpt4' + export { default as Grok } from './Grok' -export { default as Huggingface } from './Huggingface' -export { default as HuggingfaceText } from './HuggingfaceText' -export { default as HuggingfaceTextHub } from './HuggingfaceTextHub' -export { default as IflytekSpark } from './IflytekSpark' -export { default as IflytekSparkText } from './IflytekSparkText' -export { default as IflytekSparkTextCn } from './IflytekSparkTextCn' -export { default as Jina } from './Jina' -export { default as JinaText } from './JinaText' -export { default as Localai } from './Localai' -export { default as LocalaiText } from './LocalaiText' -export { default as Microsoft } from './Microsoft' -export { default as OpenaiBlack } from './OpenaiBlack' -export { default as OpenaiBlue } from './OpenaiBlue' -export { default as OpenaiGreen } from './OpenaiGreen' + export { default as OpenaiSmall } from './OpenaiSmall' -export { default as OpenaiTeal } from './OpenaiTeal' -export { default as OpenaiText } from './OpenaiText' -export { default as OpenaiTransparent } from './OpenaiTransparent' -export { default as OpenaiViolet } from './OpenaiViolet' + export { default as OpenaiYellow } from './OpenaiYellow' -export { default as Openllm } from './Openllm' -export { default as OpenllmText } from './OpenllmText' -export { default as Replicate } from './Replicate' -export { default as ReplicateText } from './ReplicateText' + export { default as Tongyi } from './Tongyi' -export { default as XorbitsInference } from './XorbitsInference' -export { default as XorbitsInferenceText } from './XorbitsInferenceText' -export { default as Zhipuai } from './Zhipuai' -export { default as ZhipuaiText } from './ZhipuaiText' -export { default as ZhipuaiTextCn } from './ZhipuaiTextCn' diff --git a/web/app/components/base/icons/src/public/model/index.ts b/web/app/components/base/icons/src/public/model/index.ts deleted file mode 100644 index 719a6f0309..0000000000 --- a/web/app/components/base/icons/src/public/model/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Checked } from './Checked' diff --git a/web/app/components/base/icons/src/public/other/index.ts b/web/app/components/base/icons/src/public/other/index.ts index 10987368fb..a8f91dd98b 100644 --- a/web/app/components/base/icons/src/public/other/index.ts +++ b/web/app/components/base/icons/src/public/other/index.ts @@ -1,5 +1,5 @@ export { default as DefaultToolIcon } from './DefaultToolIcon' -export { default as Icon3Dots } from './Icon3Dots' + export { default as Message3Fill } from './Message3Fill' export { default as RowStruct } from './RowStruct' export { default as Slack } from './Slack' diff --git a/web/app/components/base/icons/src/public/plugins/index.ts b/web/app/components/base/icons/src/public/plugins/index.ts deleted file mode 100644 index 87dc37167c..0000000000 --- a/web/app/components/base/icons/src/public/plugins/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export { default as Google } from './Google' -export { default as PartnerDark } from './PartnerDark' -export { default as PartnerLight } from './PartnerLight' -export { default as VerifiedDark } from './VerifiedDark' -export { default as VerifiedLight } from './VerifiedLight' -export { default as WebReader } from './WebReader' -export { default as Wikipedia } from './Wikipedia' diff --git a/web/app/components/base/icons/src/public/thought/index.ts b/web/app/components/base/icons/src/public/thought/index.ts index 8a45489dbf..10f5e3f5c3 100644 --- a/web/app/components/base/icons/src/public/thought/index.ts +++ b/web/app/components/base/icons/src/public/thought/index.ts @@ -1,5 +1 @@ -export { default as DataSet } from './DataSet' export { default as Loading } from './Loading' -export { default as Search } from './Search' -export { default as ThoughtList } from './ThoughtList' -export { default as WebReader } from './WebReader' diff --git a/web/app/components/base/icons/src/vender/knowledge/index.ts b/web/app/components/base/icons/src/vender/knowledge/index.ts index 44055c4975..99a4f26ed5 100644 --- a/web/app/components/base/icons/src/vender/knowledge/index.ts +++ b/web/app/components/base/icons/src/vender/knowledge/index.ts @@ -3,7 +3,7 @@ export { default as ApiAggregate } from './ApiAggregate' export { default as ArrowShape } from './ArrowShape' export { default as Chunk } from './Chunk' export { default as Collapse } from './Collapse' -export { default as Divider } from './Divider' + export { default as Economic } from './Economic' export { default as FullTextSearch } from './FullTextSearch' export { default as GeneralChunk } from './GeneralChunk' diff --git a/web/app/components/base/icons/src/vender/line/alertsAndFeedback/index.ts b/web/app/components/base/icons/src/vender/line/alertsAndFeedback/index.ts index 4e721d70eb..27f8709bed 100644 --- a/web/app/components/base/icons/src/vender/line/alertsAndFeedback/index.ts +++ b/web/app/components/base/icons/src/vender/line/alertsAndFeedback/index.ts @@ -1,4 +1,2 @@ -export { default as AlertTriangle } from './AlertTriangle' -export { default as ThumbsDown } from './ThumbsDown' export { default as ThumbsUp } from './ThumbsUp' export { default as Warning } from './Warning' diff --git a/web/app/components/base/icons/src/vender/line/arrows/index.ts b/web/app/components/base/icons/src/vender/line/arrows/index.ts index 174c69bd95..b27efc2e9c 100644 --- a/web/app/components/base/icons/src/vender/line/arrows/index.ts +++ b/web/app/components/base/icons/src/vender/line/arrows/index.ts @@ -3,7 +3,5 @@ export { default as ArrowUpRight } from './ArrowUpRight' export { default as ChevronDownDouble } from './ChevronDownDouble' export { default as ChevronRight } from './ChevronRight' export { default as ChevronSelectorVertical } from './ChevronSelectorVertical' -export { default as IconR } from './IconR' + export { default as RefreshCcw01 } from './RefreshCcw01' -export { default as RefreshCw05 } from './RefreshCw05' -export { default as ReverseLeft } from './ReverseLeft' diff --git a/web/app/components/base/icons/src/vender/line/communication/index.ts b/web/app/components/base/icons/src/vender/line/communication/index.ts index a6844c2b69..45a762a1dd 100644 --- a/web/app/components/base/icons/src/vender/line/communication/index.ts +++ b/web/app/components/base/icons/src/vender/line/communication/index.ts @@ -1,6 +1,4 @@ -export { default as AiText } from './AiText' -export { default as ChatBot } from './ChatBot' export { default as ChatBotSlim } from './ChatBotSlim' -export { default as CuteRobot } from './CuteRobot' + export { default as MessageCheckRemove } from './MessageCheckRemove' export { default as MessageFastPlus } from './MessageFastPlus' diff --git a/web/app/components/base/icons/src/vender/line/development/index.ts b/web/app/components/base/icons/src/vender/line/development/index.ts index 93bb1956bb..7c3c48aa5e 100644 --- a/web/app/components/base/icons/src/vender/line/development/index.ts +++ b/web/app/components/base/icons/src/vender/line/development/index.ts @@ -1,14 +1,2 @@ -export { default as ArtificialBrain } from './ArtificialBrain' -export { default as BarChartSquare02 } from './BarChartSquare02' export { default as BracketsX } from './BracketsX' export { default as CodeBrowser } from './CodeBrowser' -export { default as Container } from './Container' -export { default as Database01 } from './Database01' -export { default as Database03 } from './Database03' -export { default as FileHeart02 } from './FileHeart02' -export { default as GitBranch01 } from './GitBranch01' -export { default as PromptEngineering } from './PromptEngineering' -export { default as PuzzlePiece01 } from './PuzzlePiece01' -export { default as TerminalSquare } from './TerminalSquare' -export { default as Variable } from './Variable' -export { default as Webhooks } from './Webhooks' diff --git a/web/app/components/base/icons/src/vender/line/editor/index.ts b/web/app/components/base/icons/src/vender/line/editor/index.ts index b31c42e390..c968aa814c 100644 --- a/web/app/components/base/icons/src/vender/line/editor/index.ts +++ b/web/app/components/base/icons/src/vender/line/editor/index.ts @@ -1,8 +1 @@ -export { default as AlignLeft } from './AlignLeft' -export { default as BezierCurve03 } from './BezierCurve03' -export { default as Collapse } from './Collapse' -export { default as Colors } from './Colors' export { default as ImageIndentLeft } from './ImageIndentLeft' -export { default as LeftIndent02 } from './LeftIndent02' -export { default as LetterSpacing01 } from './LetterSpacing01' -export { default as TypeSquare } from './TypeSquare' diff --git a/web/app/components/base/icons/src/vender/line/files/index.ts b/web/app/components/base/icons/src/vender/line/files/index.ts index 8455f7b56a..afdc65cb24 100644 --- a/web/app/components/base/icons/src/vender/line/files/index.ts +++ b/web/app/components/base/icons/src/vender/line/files/index.ts @@ -1,11 +1,10 @@ export { default as Copy } from './Copy' export { default as CopyCheck } from './CopyCheck' -export { default as File02 } from './File02' + export { default as FileArrow01 } from './FileArrow01' -export { default as FileCheck02 } from './FileCheck02' + export { default as FileDownload02 } from './FileDownload02' export { default as FilePlus01 } from './FilePlus01' export { default as FilePlus02 } from './FilePlus02' -export { default as FileText } from './FileText' -export { default as FileUpload } from './FileUpload' + export { default as Folder } from './Folder' diff --git a/web/app/components/base/icons/src/vender/line/financeAndECommerce/index.ts b/web/app/components/base/icons/src/vender/line/financeAndECommerce/index.ts index 8a98a4612c..736eeca453 100644 --- a/web/app/components/base/icons/src/vender/line/financeAndECommerce/index.ts +++ b/web/app/components/base/icons/src/vender/line/financeAndECommerce/index.ts @@ -1,7 +1,6 @@ export { default as Balance } from './Balance' -export { default as CoinsStacked01 } from './CoinsStacked01' + export { default as CreditsCoin } from './CreditsCoin' -export { default as GoldCoin } from './GoldCoin' -export { default as ReceiptList } from './ReceiptList' + export { default as Tag01 } from './Tag01' export { default as Tag03 } from './Tag03' diff --git a/web/app/components/base/icons/src/vender/line/general/index.ts b/web/app/components/base/icons/src/vender/line/general/index.ts index 2409367264..33f67f01a5 100644 --- a/web/app/components/base/icons/src/vender/line/general/index.ts +++ b/web/app/components/base/icons/src/vender/line/general/index.ts @@ -1,30 +1,19 @@ -export { default as AtSign } from './AtSign' -export { default as Bookmark } from './Bookmark' export { default as Check } from './Check' -export { default as CheckDone01 } from './CheckDone01' -export { default as ChecklistSquare } from './ChecklistSquare' + export { default as CodeAssistant } from './CodeAssistant' -export { default as DotsGrid } from './DotsGrid' -export { default as Edit02 } from './Edit02' -export { default as Edit04 } from './Edit04' -export { default as Edit05 } from './Edit05' -export { default as Hash02 } from './Hash02' -export { default as InfoCircle } from './InfoCircle' + export { default as Link03 } from './Link03' export { default as LinkExternal02 } from './LinkExternal02' -export { default as LogIn04 } from './LogIn04' + export { default as LogOut01 } from './LogOut01' -export { default as LogOut04 } from './LogOut04' + export { default as MagicEdit } from './MagicEdit' -export { default as Menu01 } from './Menu01' -export { default as Pin01 } from './Pin01' + export { default as Pin02 } from './Pin02' export { default as Plus02 } from './Plus02' -export { default as Refresh } from './Refresh' + export { default as SearchMenu } from './SearchMenu' export { default as Settings01 } from './Settings01' export { default as Settings04 } from './Settings04' -export { default as Target04 } from './Target04' -export { default as Upload03 } from './Upload03' -export { default as UploadCloud01 } from './UploadCloud01' + export { default as X } from './X' diff --git a/web/app/components/base/icons/src/vender/line/layout/index.ts b/web/app/components/base/icons/src/vender/line/layout/index.ts index 7c12b1f58f..a6aa205faa 100644 --- a/web/app/components/base/icons/src/vender/line/layout/index.ts +++ b/web/app/components/base/icons/src/vender/line/layout/index.ts @@ -1,4 +1 @@ -export { default as AlignLeft01 } from './AlignLeft01' -export { default as AlignRight01 } from './AlignRight01' -export { default as Grid01 } from './Grid01' export { default as LayoutGrid02 } from './LayoutGrid02' diff --git a/web/app/components/base/icons/src/vender/line/mediaAndDevices/index.ts b/web/app/components/base/icons/src/vender/line/mediaAndDevices/index.ts index 163c433ac8..35052d6564 100644 --- a/web/app/components/base/icons/src/vender/line/mediaAndDevices/index.ts +++ b/web/app/components/base/icons/src/vender/line/mediaAndDevices/index.ts @@ -1,6 +1,2 @@ -export { default as Microphone01 } from './Microphone01' -export { default as PlayCircle } from './PlayCircle' -export { default as SlidersH } from './SlidersH' -export { default as Speaker } from './Speaker' export { default as Stop } from './Stop' export { default as StopCircle } from './StopCircle' diff --git a/web/app/components/base/icons/src/vender/line/others/index.ts b/web/app/components/base/icons/src/vender/line/others/index.ts index 99db66b397..0425327c6c 100644 --- a/web/app/components/base/icons/src/vender/line/others/index.ts +++ b/web/app/components/base/icons/src/vender/line/others/index.ts @@ -1,10 +1,8 @@ export { default as BubbleX } from './BubbleX' -export { default as Colors } from './Colors' + export { default as DragHandle } from './DragHandle' export { default as Env } from './Env' export { default as GlobalVariable } from './GlobalVariable' export { default as Icon3Dots } from './Icon3Dots' export { default as LongArrowLeft } from './LongArrowLeft' export { default as LongArrowRight } from './LongArrowRight' -export { default as SearchMenu } from './SearchMenu' -export { default as Tools } from './Tools' diff --git a/web/app/components/base/icons/src/vender/line/shapes/index.ts b/web/app/components/base/icons/src/vender/line/shapes/index.ts deleted file mode 100644 index daf43bcaf7..0000000000 --- a/web/app/components/base/icons/src/vender/line/shapes/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as CubeOutline } from './CubeOutline' diff --git a/web/app/components/base/icons/src/vender/line/time/index.ts b/web/app/components/base/icons/src/vender/line/time/index.ts index 7fd91f2b2e..2187814bbf 100644 --- a/web/app/components/base/icons/src/vender/line/time/index.ts +++ b/web/app/components/base/icons/src/vender/line/time/index.ts @@ -1,4 +1,2 @@ export { default as ClockFastForward } from './ClockFastForward' export { default as ClockPlay } from './ClockPlay' -export { default as ClockPlaySlim } from './ClockPlaySlim' -export { default as ClockRefresh } from './ClockRefresh' diff --git a/web/app/components/base/icons/src/vender/line/users/index.ts b/web/app/components/base/icons/src/vender/line/users/index.ts deleted file mode 100644 index 9f8a35152f..0000000000 --- a/web/app/components/base/icons/src/vender/line/users/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export { default as User01 } from './User01' -export { default as Users01 } from './Users01' diff --git a/web/app/components/base/icons/src/vender/line/weather/index.ts b/web/app/components/base/icons/src/vender/line/weather/index.ts deleted file mode 100644 index 1a68bce765..0000000000 --- a/web/app/components/base/icons/src/vender/line/weather/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Stars02 } from './Stars02' diff --git a/web/app/components/base/icons/src/vender/other/index.ts b/web/app/components/base/icons/src/vender/other/index.ts index 0ca5f22bcf..493bac1931 100644 --- a/web/app/components/base/icons/src/vender/other/index.ts +++ b/web/app/components/base/icons/src/vender/other/index.ts @@ -1,4 +1,3 @@ -export { default as AnthropicText } from './AnthropicText' export { default as Generator } from './Generator' export { default as Group } from './Group' export { default as HourglassShape } from './HourglassShape' diff --git a/web/app/components/base/icons/src/vender/solid/FinanceAndECommerce/index.ts b/web/app/components/base/icons/src/vender/solid/FinanceAndECommerce/index.ts index 777fe96845..7770962bfa 100644 --- a/web/app/components/base/icons/src/vender/solid/FinanceAndECommerce/index.ts +++ b/web/app/components/base/icons/src/vender/solid/FinanceAndECommerce/index.ts @@ -1,2 +1 @@ -export { default as GoldCoin } from './GoldCoin' export { default as Scales02 } from './Scales02' diff --git a/web/app/components/base/icons/src/vender/solid/arrows/index.ts b/web/app/components/base/icons/src/vender/solid/arrows/index.ts index 58ce9aa8ac..d89a969bd4 100644 --- a/web/app/components/base/icons/src/vender/solid/arrows/index.ts +++ b/web/app/components/base/icons/src/vender/solid/arrows/index.ts @@ -1,5 +1,3 @@ export { default as ArrowDownDoubleLine } from './ArrowDownDoubleLine' export { default as ArrowDownRoundFill } from './ArrowDownRoundFill' export { default as ArrowUpDoubleLine } from './ArrowUpDoubleLine' -export { default as ChevronDown } from './ChevronDown' -export { default as HighPriority } from './HighPriority' diff --git a/web/app/components/base/icons/src/vender/solid/communication/index.ts b/web/app/components/base/icons/src/vender/solid/communication/index.ts index 7d2a3a5a95..2da1ac57e8 100644 --- a/web/app/components/base/icons/src/vender/solid/communication/index.ts +++ b/web/app/components/base/icons/src/vender/solid/communication/index.ts @@ -1,12 +1,8 @@ -export { default as AiText } from './AiText' export { default as BubbleTextMod } from './BubbleTextMod' export { default as ChatBot } from './ChatBot' export { default as CuteRobot } from './CuteRobot' -export { default as EditList } from './EditList' + export { default as ListSparkle } from './ListSparkle' export { default as Logic } from './Logic' -export { default as MessageDotsCircle } from './MessageDotsCircle' + export { default as MessageFast } from './MessageFast' -export { default as MessageHeartCircle } from './MessageHeartCircle' -export { default as MessageSmileSquare } from './MessageSmileSquare' -export { default as Send03 } from './Send03' diff --git a/web/app/components/base/icons/src/vender/solid/development/index.ts b/web/app/components/base/icons/src/vender/solid/development/index.ts index f67d854beb..25eb3d2736 100644 --- a/web/app/components/base/icons/src/vender/solid/development/index.ts +++ b/web/app/components/base/icons/src/vender/solid/development/index.ts @@ -1,13 +1,5 @@ export { default as ApiConnection } from './ApiConnection' export { default as ApiConnectionMod } from './ApiConnectionMod' -export { default as BarChartSquare02 } from './BarChartSquare02' -export { default as Container } from './Container' -export { default as Database02 } from './Database02' -export { default as Database03 } from './Database03' -export { default as FileHeart02 } from './FileHeart02' -export { default as PatternRecognition } from './PatternRecognition' -export { default as PromptEngineering } from './PromptEngineering' -export { default as PuzzlePiece01 } from './PuzzlePiece01' -export { default as Semantic } from './Semantic' + export { default as TerminalSquare } from './TerminalSquare' export { default as Variable02 } from './Variable02' diff --git a/web/app/components/base/icons/src/vender/solid/editor/index.ts b/web/app/components/base/icons/src/vender/solid/editor/index.ts index 6b1a0a1afa..8b6debe736 100644 --- a/web/app/components/base/icons/src/vender/solid/editor/index.ts +++ b/web/app/components/base/icons/src/vender/solid/editor/index.ts @@ -1,5 +1 @@ export { default as Brush01 } from './Brush01' -export { default as Citations } from './Citations' -export { default as Colors } from './Colors' -export { default as Paragraph } from './Paragraph' -export { default as TypeSquare } from './TypeSquare' diff --git a/web/app/components/base/icons/src/vender/solid/education/index.ts b/web/app/components/base/icons/src/vender/solid/education/index.ts index 2c8a3b6046..e67b631335 100644 --- a/web/app/components/base/icons/src/vender/solid/education/index.ts +++ b/web/app/components/base/icons/src/vender/solid/education/index.ts @@ -1,4 +1,4 @@ export { default as Beaker02 } from './Beaker02' export { default as BubbleText } from './BubbleText' -export { default as Heart02 } from './Heart02' + export { default as Unblur } from './Unblur' diff --git a/web/app/components/base/icons/src/vender/solid/files/index.ts b/web/app/components/base/icons/src/vender/solid/files/index.ts index fa93cd68dc..7677ba6761 100644 --- a/web/app/components/base/icons/src/vender/solid/files/index.ts +++ b/web/app/components/base/icons/src/vender/solid/files/index.ts @@ -1,4 +1,4 @@ export { default as File05 } from './File05' -export { default as FileSearch02 } from './FileSearch02' + export { default as FileZip } from './FileZip' export { default as Folder } from './Folder' diff --git a/web/app/components/base/icons/src/vender/solid/general/index.ts b/web/app/components/base/icons/src/vender/solid/general/index.ts index 4c4dd9a437..273fb7e876 100644 --- a/web/app/components/base/icons/src/vender/solid/general/index.ts +++ b/web/app/components/base/icons/src/vender/solid/general/index.ts @@ -1,18 +1,14 @@ -export { default as AnswerTriangle } from './AnswerTriangle' export { default as ArrowDownRoundFill } from './ArrowDownRoundFill' export { default as CheckCircle } from './CheckCircle' -export { default as CheckDone01 } from './CheckDone01' + export { default as Download02 } from './Download02' export { default as Edit03 } from './Edit03' -export { default as Edit04 } from './Edit04' + export { default as Eye } from './Eye' export { default as Github } from './Github' export { default as MessageClockCircle } from './MessageClockCircle' -export { default as PlusCircle } from './PlusCircle' -export { default as QuestionTriangle } from './QuestionTriangle' -export { default as SearchMd } from './SearchMd' + export { default as Target04 } from './Target04' export { default as Tool03 } from './Tool03' export { default as XCircle } from './XCircle' export { default as ZapFast } from './ZapFast' -export { default as ZapNarrow } from './ZapNarrow' diff --git a/web/app/components/base/icons/src/vender/solid/layout/index.ts b/web/app/components/base/icons/src/vender/solid/layout/index.ts deleted file mode 100644 index 73a2513d51..0000000000 --- a/web/app/components/base/icons/src/vender/solid/layout/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { default as Grid01 } from './Grid01' diff --git a/web/app/components/base/icons/src/vender/solid/mediaAndDevices/index.ts b/web/app/components/base/icons/src/vender/solid/mediaAndDevices/index.ts index 7c313fecfb..7d1bf786e9 100644 --- a/web/app/components/base/icons/src/vender/solid/mediaAndDevices/index.ts +++ b/web/app/components/base/icons/src/vender/solid/mediaAndDevices/index.ts @@ -1,12 +1,3 @@ -export { default as AudioSupportIcon } from './AudioSupportIcon' -export { default as DocumentSupportIcon } from './DocumentSupportIcon' export { default as MagicBox } from './MagicBox' -export { default as MagicEyes } from './MagicEyes' -export { default as MagicWand } from './MagicWand' -export { default as Microphone01 } from './Microphone01' -export { default as Play } from './Play' -export { default as Robot } from './Robot' -export { default as Sliders02 } from './Sliders02' -export { default as Speaker } from './Speaker' + export { default as StopCircle } from './StopCircle' -export { default as VideoSupportIcon } from './VideoSupportIcon' diff --git a/web/app/components/base/icons/src/vender/solid/shapes/index.ts b/web/app/components/base/icons/src/vender/solid/shapes/index.ts index 2768e3949a..f25784ab02 100644 --- a/web/app/components/base/icons/src/vender/solid/shapes/index.ts +++ b/web/app/components/base/icons/src/vender/solid/shapes/index.ts @@ -1,3 +1 @@ export { default as Corner } from './Corner' -export { default as Star04 } from './Star04' -export { default as Star06 } from './Star06' diff --git a/web/app/components/base/icons/src/vender/solid/users/index.ts b/web/app/components/base/icons/src/vender/solid/users/index.ts index 4c969bffd7..1691fc8401 100644 --- a/web/app/components/base/icons/src/vender/solid/users/index.ts +++ b/web/app/components/base/icons/src/vender/solid/users/index.ts @@ -1,4 +1 @@ -export { default as User01 } from './User01' export { default as UserEdit02 } from './UserEdit02' -export { default as Users01 } from './Users01' -export { default as UsersPlus } from './UsersPlus' diff --git a/web/app/components/base/icons/src/vender/workflow/index.ts b/web/app/components/base/icons/src/vender/workflow/index.ts index c21e865a09..c2511d3816 100644 --- a/web/app/components/base/icons/src/vender/workflow/index.ts +++ b/web/app/components/base/icons/src/vender/workflow/index.ts @@ -13,7 +13,7 @@ export { default as Http } from './Http' export { default as HumanInLoop } from './HumanInLoop' export { default as IfElse } from './IfElse' export { default as Iteration } from './Iteration' -export { default as IterationStart } from './IterationStart' + export { default as Jinja } from './Jinja' export { default as KnowledgeBase } from './KnowledgeBase' export { default as KnowledgeRetrieval } from './KnowledgeRetrieval' diff --git a/web/app/components/base/icons/utils.ts b/web/app/components/base/icons/utils.ts index 9a15a0816d..51a1d70568 100644 --- a/web/app/components/base/icons/utils.ts +++ b/web/app/components/base/icons/utils.ts @@ -8,7 +8,7 @@ export type AbstractNode = { children?: AbstractNode[] } -export type Attrs = { +type Attrs = { [key: string]: string | undefined } diff --git a/web/app/components/base/inline-delete-confirm/index.tsx b/web/app/components/base/inline-delete-confirm/index.tsx index 529dec479d..a0e3b8eb96 100644 --- a/web/app/components/base/inline-delete-confirm/index.tsx +++ b/web/app/components/base/inline-delete-confirm/index.tsx @@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next' import Button from '@/app/components/base/button' import { cn } from '@/utils/classnames' -export type InlineDeleteConfirmProps = { +type InlineDeleteConfirmProps = { title?: string confirmText?: string cancelText?: string diff --git a/web/app/components/base/input-with-copy/index.tsx b/web/app/components/base/input-with-copy/index.tsx index 7c2177d5d2..e85a7bd6f4 100644 --- a/web/app/components/base/input-with-copy/index.tsx +++ b/web/app/components/base/input-with-copy/index.tsx @@ -7,7 +7,7 @@ import { cn } from '@/utils/classnames' import ActionButton from '../action-button' import Tooltip from '../tooltip' -export type InputWithCopyProps = { +type InputWithCopyProps = { showCopyButton?: boolean copyValue?: string // Value to copy, defaults to input value onCopy?: (value: string) => void // Callback when copy is triggered diff --git a/web/app/components/base/markdown-blocks/index.ts b/web/app/components/base/markdown-blocks/index.ts index 73c9fdf13f..10e98c9ad9 100644 --- a/web/app/components/base/markdown-blocks/index.ts +++ b/web/app/components/base/markdown-blocks/index.ts @@ -6,7 +6,7 @@ export { default as AudioBlock } from './audio-block' // Assuming these are also standalone components in this directory intended for Markdown rendering export { default as MarkdownButton } from './button' -export { default as CodeBlock } from './code-block' + export { default as MarkdownForm } from './form' export { default as Img } from './img' export { default as Link } from './link' diff --git a/web/app/components/base/markdown-with-directive/components/markdown-with-directive-schema.ts b/web/app/components/base/markdown-with-directive/components/markdown-with-directive-schema.ts index 5e31a7afa9..4e721b214e 100644 --- a/web/app/components/base/markdown-with-directive/components/markdown-with-directive-schema.ts +++ b/web/app/components/base/markdown-with-directive/components/markdown-with-directive-schema.ts @@ -15,12 +15,12 @@ export const withIconCardItemPropsSchema = z.object({ ), }).strict() -export const directivePropsSchemas = { +const directivePropsSchemas = { withiconcardlist: withIconCardListPropsSchema, withiconcarditem: withIconCardItemPropsSchema, } as const -export type DirectiveName = keyof typeof directivePropsSchemas +type DirectiveName = keyof typeof directivePropsSchemas function isDirectiveName(name: string): name is DirectiveName { return Object.hasOwn(directivePropsSchemas, name) diff --git a/web/app/components/base/node-status/index.tsx b/web/app/components/base/node-status/index.tsx index 3c39fa1fb3..1616f350b0 100644 --- a/web/app/components/base/node-status/index.tsx +++ b/web/app/components/base/node-status/index.tsx @@ -32,7 +32,7 @@ const StatusIconMap: Record = React.createContext(defaultState) -export const PrevButton = ({ +const PrevButton = ({ className, children, dataTestId, @@ -61,7 +61,7 @@ export const PrevButton = ({ ) } -export const NextButton = ({ +const NextButton = ({ className, children, dataTestId, @@ -117,7 +117,7 @@ const TruncableElement = ({ prev }: ITruncableElementProps) => { : null } -export const PageButton = ({ +const PageButton = ({ as = , className, dataTestIdActive, diff --git a/web/app/components/base/portal-to-follow-elem/index.tsx b/web/app/components/base/portal-to-follow-elem/index.tsx index 7d4f6baa9b..932eceee2b 100644 --- a/web/app/components/base/portal-to-follow-elem/index.tsx +++ b/web/app/components/base/portal-to-follow-elem/index.tsx @@ -46,7 +46,7 @@ export type PortalToFollowElemOptions = { } /** @deprecated Use semantic overlay primitives instead. See #32767. */ -export function usePortalToFollowElem({ +function usePortalToFollowElem({ placement = 'bottom', open: controlledOpen, offset: offsetValue = 0, @@ -114,7 +114,7 @@ type ContextType = ReturnType | null const PortalToFollowElemContext = React.createContext(null) -export function usePortalToFollowElemContext() { +function usePortalToFollowElemContext() { const context = React.useContext(PortalToFollowElemContext) if (context == null) diff --git a/web/app/components/base/premium-badge/index.tsx b/web/app/components/base/premium-badge/index.tsx index 297e05fe42..1ffff2f7a9 100644 --- a/web/app/components/base/premium-badge/index.tsx +++ b/web/app/components/base/premium-badge/index.tsx @@ -66,4 +66,3 @@ const PremiumBadge: React.FC = ({ PremiumBadge.displayName = 'PremiumBadge' export default PremiumBadge -export { PremiumBadge, PremiumBadgeVariants } diff --git a/web/app/components/base/prompt-editor/hooks.ts b/web/app/components/base/prompt-editor/hooks.ts index 6984d30ee8..49fc6a8eb0 100644 --- a/web/app/components/base/prompt-editor/hooks.ts +++ b/web/app/components/base/prompt-editor/hooks.ts @@ -35,7 +35,7 @@ import { DELETE_QUERY_BLOCK_COMMAND } from './plugins/query-block' import { $isQueryBlockNode } from './plugins/query-block/node' import { registerLexicalTextEntity } from './utils' -export type UseSelectOrDeleteHandler = (nodeKey: string, command?: LexicalCommand) => [RefObject, boolean] +type UseSelectOrDeleteHandler = (nodeKey: string, command?: LexicalCommand) => [RefObject, boolean] export const useSelectOrDelete: UseSelectOrDeleteHandler = (nodeKey: string, command?: LexicalCommand) => { const ref = useRef(null) const [editor] = useLexicalComposerContext() @@ -110,7 +110,7 @@ export const useSelectOrDelete: UseSelectOrDeleteHandler = (nodeKey: string, com return [ref, isSelected] } -export type UseTriggerHandler = () => [RefObject, boolean, Dispatch>] +type UseTriggerHandler = () => [RefObject, boolean, Dispatch>] export const useTrigger: UseTriggerHandler = () => { const triggerRef = useRef(null) const [open, setOpen] = useState(false) @@ -145,16 +145,16 @@ export function useLexicalTextEntity( }, [createNode, editor, getMatch, targetNode]) } -export type MenuTextMatch = { +type MenuTextMatch = { leadOffset: number matchingString: string replaceableString: string } -export type TriggerFn = ( +type TriggerFn = ( text: string, editor: LexicalEditor, ) => MenuTextMatch | null -export const PUNCTUATION = '\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%\'"~=<>_:;' +const PUNCTUATION = '\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%\'"~=<>_:;' export function useBasicTypeaheadTriggerMatch( trigger: string, { minLength = 1, maxLength = 75 }: { minLength?: number, maxLength?: number }, diff --git a/web/app/components/base/prompt-editor/plugins/context-block/node.tsx b/web/app/components/base/prompt-editor/plugins/context-block/node.tsx index 231a72ca14..958415d843 100644 --- a/web/app/components/base/prompt-editor/plugins/context-block/node.tsx +++ b/web/app/components/base/prompt-editor/plugins/context-block/node.tsx @@ -3,7 +3,7 @@ import type { Dataset } from './index' import { DecoratorNode } from 'lexical' import ContextBlockComponent from './component' -export type SerializedNode = SerializedLexicalNode & { datasets: Dataset[], onAddContext: () => void, canNotAddContext: boolean } +type SerializedNode = SerializedLexicalNode & { datasets: Dataset[], onAddContext: () => void, canNotAddContext: boolean } export class ContextBlockNode extends DecoratorNode { __datasets: Dataset[] diff --git a/web/app/components/base/prompt-editor/plugins/current-block/node.tsx b/web/app/components/base/prompt-editor/plugins/current-block/node.tsx index 554bf1a2e9..916e3b5169 100644 --- a/web/app/components/base/prompt-editor/plugins/current-block/node.tsx +++ b/web/app/components/base/prompt-editor/plugins/current-block/node.tsx @@ -3,7 +3,7 @@ import type { GeneratorType } from '@/app/components/app/configuration/config/au import { DecoratorNode } from 'lexical' import CurrentBlockComponent from './component' -export type SerializedNode = SerializedLexicalNode & { generatorType: GeneratorType } +type SerializedNode = SerializedLexicalNode & { generatorType: GeneratorType } export class CurrentBlockNode extends DecoratorNode { __generatorType: GeneratorType diff --git a/web/app/components/base/prompt-editor/plugins/error-message-block/node.tsx b/web/app/components/base/prompt-editor/plugins/error-message-block/node.tsx index b8042e5e54..d253cf7ff3 100644 --- a/web/app/components/base/prompt-editor/plugins/error-message-block/node.tsx +++ b/web/app/components/base/prompt-editor/plugins/error-message-block/node.tsx @@ -2,7 +2,7 @@ import type { LexicalNode, NodeKey, SerializedLexicalNode } from 'lexical' import { DecoratorNode } from 'lexical' import ErrorMessageBlockComponent from './component' -export type SerializedNode = SerializedLexicalNode +type SerializedNode = SerializedLexicalNode export class ErrorMessageBlockNode extends DecoratorNode { static getType(): string { diff --git a/web/app/components/base/prompt-editor/plugins/history-block/index.tsx b/web/app/components/base/prompt-editor/plugins/history-block/index.tsx index a1d788c8cd..f6fd01f0d9 100644 --- a/web/app/components/base/prompt-editor/plugins/history-block/index.tsx +++ b/web/app/components/base/prompt-editor/plugins/history-block/index.tsx @@ -24,13 +24,6 @@ export type RoleName = { assistant: string } -export type HistoryBlockProps = { - roleName: RoleName - onEditRole: () => void - onInsert?: () => void - onDelete?: () => void -} - const HistoryBlock = memo(({ history = { user: '', assistant: '' }, onEditRole = noop, diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/index.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/index.tsx index 49b0e3d150..2c10fdbd5a 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/index.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/index.tsx @@ -22,11 +22,6 @@ import { export const INSERT_HITL_INPUT_BLOCK_COMMAND = createCommand('INSERT_HITL_INPUT_BLOCK_COMMAND') export const DELETE_HITL_INPUT_BLOCK_COMMAND = createCommand('DELETE_HITL_INPUT_BLOCK_COMMAND') export const UPDATE_WORKFLOW_NODES_MAP = createCommand('UPDATE_WORKFLOW_NODES_MAP') - -export type HITLInputProps = { - onInsert?: () => void - onDelete?: () => void -} const HITLInputBlock = memo(({ onInsert, onDelete, diff --git a/web/app/components/base/prompt-editor/plugins/hitl-input-block/node.tsx b/web/app/components/base/prompt-editor/plugins/hitl-input-block/node.tsx index bf3c44acf3..9f2d25b446 100644 --- a/web/app/components/base/prompt-editor/plugins/hitl-input-block/node.tsx +++ b/web/app/components/base/prompt-editor/plugins/hitl-input-block/node.tsx @@ -21,7 +21,7 @@ export type HITLNodeProps = { readonly?: boolean } -export type SerializedNode = SerializedLexicalNode & HITLNodeProps +type SerializedNode = SerializedLexicalNode & HITLNodeProps export class HITLInputNode extends DecoratorNode { __variableName: string diff --git a/web/app/components/base/prompt-editor/plugins/last-run-block/node.tsx b/web/app/components/base/prompt-editor/plugins/last-run-block/node.tsx index 5f61c3138b..0606adbe2e 100644 --- a/web/app/components/base/prompt-editor/plugins/last-run-block/node.tsx +++ b/web/app/components/base/prompt-editor/plugins/last-run-block/node.tsx @@ -2,7 +2,7 @@ import type { LexicalNode, NodeKey, SerializedLexicalNode } from 'lexical' import { DecoratorNode } from 'lexical' import LastRunBlockComponent from './component' -export type SerializedNode = SerializedLexicalNode +type SerializedNode = SerializedLexicalNode export class LastRunBlockNode extends DecoratorNode { static getType(): string { diff --git a/web/app/components/base/prompt-editor/plugins/query-block/index.tsx b/web/app/components/base/prompt-editor/plugins/query-block/index.tsx index d5953d16c4..adabf0bc6e 100644 --- a/web/app/components/base/prompt-editor/plugins/query-block/index.tsx +++ b/web/app/components/base/prompt-editor/plugins/query-block/index.tsx @@ -17,11 +17,6 @@ import { export const INSERT_QUERY_BLOCK_COMMAND = createCommand('INSERT_QUERY_BLOCK_COMMAND') export const DELETE_QUERY_BLOCK_COMMAND = createCommand('DELETE_QUERY_BLOCK_COMMAND') - -export type QueryBlockProps = { - onInsert?: () => void - onDelete?: () => void -} const QueryBlock = memo(({ onInsert, onDelete, diff --git a/web/app/components/base/prompt-editor/plugins/query-block/node.tsx b/web/app/components/base/prompt-editor/plugins/query-block/node.tsx index fc560451dd..519d6bab92 100644 --- a/web/app/components/base/prompt-editor/plugins/query-block/node.tsx +++ b/web/app/components/base/prompt-editor/plugins/query-block/node.tsx @@ -2,7 +2,7 @@ import type { LexicalNode, SerializedLexicalNode } from 'lexical' import { DecoratorNode } from 'lexical' import QueryBlockComponent from './component' -export type SerializedNode = SerializedLexicalNode +type SerializedNode = SerializedLexicalNode export class QueryBlockNode extends DecoratorNode { static getType(): string { diff --git a/web/app/components/base/prompt-editor/plugins/request-url-block/node.tsx b/web/app/components/base/prompt-editor/plugins/request-url-block/node.tsx index b1e74aa3a6..b24e653bbc 100644 --- a/web/app/components/base/prompt-editor/plugins/request-url-block/node.tsx +++ b/web/app/components/base/prompt-editor/plugins/request-url-block/node.tsx @@ -2,7 +2,7 @@ import type { LexicalNode, SerializedLexicalNode } from 'lexical' import { DecoratorNode } from 'lexical' import RequestURLBlockComponent from './component' -export type SerializedNode = SerializedLexicalNode +type SerializedNode = SerializedLexicalNode export class RequestURLBlockNode extends DecoratorNode { static getType(): string { diff --git a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/index.tsx b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/index.tsx index c8cac64d19..dfbd238dbf 100644 --- a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/index.tsx +++ b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/index.tsx @@ -1,5 +1,4 @@ -import type { GetVarType, WorkflowVariableBlockType } from '../../types' -import type { Node } from '@/app/components/workflow/types' +import type { WorkflowVariableBlockType } from '../../types' import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext' import { mergeRegister } from '@lexical/utils' import { @@ -19,13 +18,6 @@ import { export const INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND = createCommand('INSERT_WORKFLOW_VARIABLE_BLOCK_COMMAND') export const DELETE_WORKFLOW_VARIABLE_BLOCK_COMMAND = createCommand('DELETE_WORKFLOW_VARIABLE_BLOCK_COMMAND') export const UPDATE_WORKFLOW_NODES_MAP = createCommand('UPDATE_WORKFLOW_NODES_MAP') - -export type WorkflowVariableBlockProps = { - getWorkflowNode: (nodeId: string) => Node - onInsert?: () => void - onDelete?: () => void - getVarType: GetVarType -} const WorkflowVariableBlock = memo(({ workflowNodesMap, onInsert, diff --git a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/node.tsx b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/node.tsx index a241e75233..743937d8a6 100644 --- a/web/app/components/base/prompt-editor/plugins/workflow-variable-block/node.tsx +++ b/web/app/components/base/prompt-editor/plugins/workflow-variable-block/node.tsx @@ -6,7 +6,7 @@ import WorkflowVariableBlockComponent from './component' export type WorkflowNodesMap = WorkflowVariableBlockType['workflowNodesMap'] -export type SerializedNode = SerializedLexicalNode & { +type SerializedNode = SerializedLexicalNode & { variables: string[] workflowNodesMap: WorkflowNodesMap getVarType?: GetVarType diff --git a/web/app/components/base/radio/component/group/index.tsx b/web/app/components/base/radio/component/group/index.tsx index 53ccd5e833..aff9e5e3c6 100644 --- a/web/app/components/base/radio/component/group/index.tsx +++ b/web/app/components/base/radio/component/group/index.tsx @@ -3,7 +3,7 @@ import { cn } from '@/utils/classnames' import RadioGroupContext from '../../context' import s from '../../style.module.css' -export type TRadioGroupProps = { +type TRadioGroupProps = { children?: ReactNode | ReactNode[] value?: string | number | boolean className?: string diff --git a/web/app/components/base/select/index.tsx b/web/app/components/base/select/index.tsx index 2cfdcf74bc..70ed726c38 100644 --- a/web/app/components/base/select/index.tsx +++ b/web/app/components/base/select/index.tsx @@ -37,7 +37,7 @@ export type Item = { extra?: React.ReactNode } & Record -export type ISelectProps = { +type ISelectProps = { className?: string wrapperClassName?: string renderTrigger?: (value: Item | null, isOpen: boolean) => React.JSX.Element | null diff --git a/web/app/components/base/sort/index.tsx b/web/app/components/base/sort/index.tsx index 69562e2f3e..901d353ec2 100644 --- a/web/app/components/base/sort/index.tsx +++ b/web/app/components/base/sort/index.tsx @@ -9,7 +9,7 @@ import { } from '@/app/components/base/portal-to-follow-elem' import { cn } from '@/utils/classnames' -export type Item = { +type Item = { value: number | string name: string } & Record diff --git a/web/app/components/base/tag/index.tsx b/web/app/components/base/tag/index.tsx index 21e2a9c982..dee85c998c 100644 --- a/web/app/components/base/tag/index.tsx +++ b/web/app/components/base/tag/index.tsx @@ -1,7 +1,7 @@ import * as React from 'react' import { cn } from '@/utils/classnames' -export type ITagProps = { +type ITagProps = { children: string | React.ReactNode color?: keyof typeof COLOR_MAP className?: string diff --git a/web/app/components/base/text-generation/types.ts b/web/app/components/base/text-generation/types.ts index d7c03ab3eb..62a401c3cb 100644 --- a/web/app/components/base/text-generation/types.ts +++ b/web/app/components/base/text-generation/types.ts @@ -2,41 +2,11 @@ import type { ExternalDataTool } from '@/models/common' import type { ModelConfig, VisionFile, - VisionSettings, } from '@/types/app' export type { VisionFile } from '@/types/app' export { TransferMethod } from '@/types/app' -export type UserInputForm = { - default: string - label: string - required: boolean - variable: string -} - -export type UserInputFormTextInput = { - 'text-input': UserInputForm & { - max_length: number - } -} - -export type UserInputFormSelect = { - select: UserInputForm & { - options: string[] - } -} - -export type UserInputFormParagraph = { - paragraph: UserInputForm -} - -export type VisionConfig = VisionSettings - -export type EnableType = { - enabled: boolean -} - export type TextGenerationConfig = Omit & { external_data_tools: ExternalDataTool[] } diff --git a/web/app/components/base/textarea/index.tsx b/web/app/components/base/textarea/index.tsx index 73c6865903..d991acb28b 100644 --- a/web/app/components/base/textarea/index.tsx +++ b/web/app/components/base/textarea/index.tsx @@ -58,4 +58,4 @@ const Textarea = React.forwardRef( Textarea.displayName = 'Textarea' export default Textarea -export { Textarea, textareaVariants } +export { textareaVariants } diff --git a/web/app/components/base/theme-switcher.tsx b/web/app/components/base/theme-switcher.tsx index 91fb5ff2c9..a6b6972210 100644 --- a/web/app/components/base/theme-switcher.tsx +++ b/web/app/components/base/theme-switcher.tsx @@ -2,7 +2,7 @@ import { useTheme } from 'next-themes' import { cn } from '@/utils/classnames' -export type Theme = 'light' | 'dark' | 'system' +type Theme = 'light' | 'dark' | 'system' export default function ThemeSwitcher() { const { theme, setTheme } = useTheme() diff --git a/web/app/components/base/timezone-label/index.tsx b/web/app/components/base/timezone-label/index.tsx index bb4355f338..385e4c782a 100644 --- a/web/app/components/base/timezone-label/index.tsx +++ b/web/app/components/base/timezone-label/index.tsx @@ -3,7 +3,7 @@ import { useMemo } from 'react' import { convertTimezoneToOffsetStr } from '@/app/components/base/date-and-time-picker/utils/dayjs' import { cn } from '@/utils/classnames' -export type TimezoneLabelProps = { +type TimezoneLabelProps = { /** IANA timezone identifier (e.g., 'Asia/Shanghai', 'America/New_York') */ timezone: string /** Additional CSS classes to apply */ diff --git a/web/app/components/base/tooltip/content.tsx b/web/app/components/base/tooltip/content.tsx index a5a31a2a5c..191ee933f1 100644 --- a/web/app/components/base/tooltip/content.tsx +++ b/web/app/components/base/tooltip/content.tsx @@ -1,6 +1,6 @@ import type { FC, PropsWithChildren, ReactNode } from 'react' -export type ToolTipContentProps = { +type ToolTipContentProps = { title?: ReactNode action?: ReactNode } & PropsWithChildren diff --git a/web/app/components/base/tooltip/index.tsx b/web/app/components/base/tooltip/index.tsx index 1588c99812..da373dea83 100644 --- a/web/app/components/base/tooltip/index.tsx +++ b/web/app/components/base/tooltip/index.tsx @@ -14,7 +14,7 @@ import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigge import { cn } from '@/utils/classnames' import { tooltipManager } from './TooltipManager' -export type TooltipProps = { +type TooltipProps = { position?: Placement triggerMethod?: 'hover' | 'click' triggerClassName?: string diff --git a/web/app/components/base/ui/context-menu/index.tsx b/web/app/components/base/ui/context-menu/index.tsx index 5a0f580ca4..4e164b08b9 100644 --- a/web/app/components/base/ui/context-menu/index.tsx +++ b/web/app/components/base/ui/context-menu/index.tsx @@ -17,8 +17,6 @@ import { cn } from '@/utils/classnames' export const ContextMenu = BaseContextMenu.Root export const ContextMenuTrigger = BaseContextMenu.Trigger -export const ContextMenuPortal = BaseContextMenu.Portal -export const ContextMenuBackdrop = BaseContextMenu.Backdrop export const ContextMenuSub = BaseContextMenu.SubmenuRoot export const ContextMenuGroup = BaseContextMenu.Group export const ContextMenuRadioGroup = BaseContextMenu.RadioGroup @@ -175,26 +173,6 @@ export function ContextMenuCheckboxItem({ ) } -type ContextMenuIndicatorProps = Omit, 'children'> & { - children?: React.ReactNode -} - -export function ContextMenuItemIndicator({ - className, - children, - ...props -}: ContextMenuIndicatorProps) { - return ( - - {children ?? } - - ) -} - export function ContextMenuCheckboxItemIndicator({ className, ...props @@ -239,7 +217,7 @@ export function ContextMenuSubTrigger({ {...props} > {children} - + ) } diff --git a/web/app/components/base/ui/dropdown-menu/index.tsx b/web/app/components/base/ui/dropdown-menu/index.tsx index 13c2dab626..5db5833fd7 100644 --- a/web/app/components/base/ui/dropdown-menu/index.tsx +++ b/web/app/components/base/ui/dropdown-menu/index.tsx @@ -15,7 +15,6 @@ import { parsePlacement } from '@/app/components/base/ui/placement' import { cn } from '@/utils/classnames' export const DropdownMenu = Menu.Root -export const DropdownMenuPortal = Menu.Portal export const DropdownMenuTrigger = Menu.Trigger export const DropdownMenuSub = Menu.SubmenuRoot export const DropdownMenuGroup = Menu.Group diff --git a/web/app/components/base/ui/number-field/index.tsx b/web/app/components/base/ui/number-field/index.tsx index ac2ae0c7c6..924250ca22 100644 --- a/web/app/components/base/ui/number-field/index.tsx +++ b/web/app/components/base/ui/number-field/index.tsx @@ -113,7 +113,7 @@ export function NumberFieldUnit({ ) } -export const numberFieldControlsVariants = cva( +const numberFieldControlsVariants = cva( 'flex shrink-0 flex-col items-stretch border-l border-divider-subtle bg-transparent text-text-tertiary', ) @@ -131,7 +131,7 @@ export function NumberFieldControls({ ) } -export const numberFieldControlButtonVariants = cva( +const numberFieldControlButtonVariants = cva( [ 'flex touch-manipulation select-none items-center justify-center px-1.5 text-text-tertiary outline-hidden transition-colors', 'hover:bg-components-input-bg-hover focus-visible:bg-components-input-bg-hover', diff --git a/web/app/components/base/ui/scroll-area/index.tsx b/web/app/components/base/ui/scroll-area/index.tsx index 195f9b4e81..053d9e684a 100644 --- a/web/app/components/base/ui/scroll-area/index.tsx +++ b/web/app/components/base/ui/scroll-area/index.tsx @@ -6,18 +6,17 @@ import { cn } from '@/utils/classnames' import styles from './index.module.css' export const ScrollAreaRoot = BaseScrollArea.Root -export type ScrollAreaRootProps = React.ComponentPropsWithRef +type ScrollAreaRootProps = React.ComponentPropsWithRef export const ScrollAreaContent = BaseScrollArea.Content -export type ScrollAreaContentProps = React.ComponentPropsWithRef -export type ScrollAreaSlotClassNames = { +type ScrollAreaSlotClassNames = { viewport?: string content?: string scrollbar?: string } -export type ScrollAreaProps = Omit & { +type ScrollAreaProps = Omit & { children: React.ReactNode orientation?: 'vertical' | 'horizontal' slotClassNames?: ScrollAreaSlotClassNames @@ -25,7 +24,7 @@ export type ScrollAreaProps = Omit & { labelledBy?: string } -export const scrollAreaScrollbarClassName = cn( +const scrollAreaScrollbarClassName = cn( styles.scrollbar, 'flex touch-none select-none overflow-clip p-1 opacity-100 transition-opacity motion-reduce:transition-none', 'pointer-events-none data-hovering:pointer-events-auto', @@ -34,20 +33,20 @@ export const scrollAreaScrollbarClassName = cn( 'data-[orientation=horizontal]:absolute data-[orientation=horizontal]:inset-x-0 data-[orientation=horizontal]:h-3 data-[orientation=horizontal]:items-center', ) -export const scrollAreaThumbClassName = cn( +const scrollAreaThumbClassName = cn( 'shrink-0 radius-xs bg-state-base-handle transition-[background-color] motion-reduce:transition-none', 'data-[orientation=vertical]:w-1', 'data-[orientation=horizontal]:h-1', ) -export const scrollAreaViewportClassName = cn( +const scrollAreaViewportClassName = cn( 'size-full min-h-0 min-w-0 outline-hidden', 'focus-visible:ring-1 focus-visible:ring-inset focus-visible:ring-components-input-border-hover', ) -export const scrollAreaCornerClassName = 'bg-transparent' +const scrollAreaCornerClassName = 'bg-transparent' -export type ScrollAreaViewportProps = React.ComponentPropsWithRef +type ScrollAreaViewportProps = React.ComponentPropsWithRef export function ScrollAreaViewport({ className, @@ -61,7 +60,7 @@ export function ScrollAreaViewport({ ) } -export type ScrollAreaScrollbarProps = React.ComponentPropsWithRef +type ScrollAreaScrollbarProps = React.ComponentPropsWithRef export function ScrollAreaScrollbar({ className, @@ -75,7 +74,7 @@ export function ScrollAreaScrollbar({ ) } -export type ScrollAreaThumbProps = React.ComponentPropsWithRef +type ScrollAreaThumbProps = React.ComponentPropsWithRef export function ScrollAreaThumb({ className, @@ -89,7 +88,7 @@ export function ScrollAreaThumb({ ) } -export type ScrollAreaCornerProps = React.ComponentPropsWithRef +type ScrollAreaCornerProps = React.ComponentPropsWithRef export function ScrollAreaCorner({ className, diff --git a/web/app/components/base/ui/select/index.tsx b/web/app/components/base/ui/select/index.tsx index 83dfe817dc..b9441b2d6b 100644 --- a/web/app/components/base/ui/select/index.tsx +++ b/web/app/components/base/ui/select/index.tsx @@ -10,11 +10,8 @@ import { cn } from '@/utils/classnames' export const Select = BaseSelect.Root export const SelectValue = BaseSelect.Value -export const SelectGroup = BaseSelect.Group -export const SelectGroupLabel = BaseSelect.GroupLabel -export const SelectSeparator = BaseSelect.Separator -export const selectTriggerVariants = cva( +const selectTriggerVariants = cva( '', { variants: { diff --git a/web/app/components/base/ui/slider/index.tsx b/web/app/components/base/ui/slider/index.tsx index d44f553254..b0a8c2f376 100644 --- a/web/app/components/base/ui/slider/index.tsx +++ b/web/app/components/base/ui/slider/index.tsx @@ -24,7 +24,7 @@ type UncontrolledSliderProps = SliderBaseProps & { defaultValue?: number } -export type SliderProps = ControlledSliderProps | UncontrolledSliderProps +type SliderProps = ControlledSliderProps | UncontrolledSliderProps const sliderRootClassName = 'group/slider relative inline-flex w-full data-disabled:opacity-30' const sliderControlClassName = cn( diff --git a/web/app/components/base/ui/toast/index.tsx b/web/app/components/base/ui/toast/index.tsx index 0307e14dbc..abb71d371e 100644 --- a/web/app/components/base/ui/toast/index.tsx +++ b/web/app/components/base/ui/toast/index.tsx @@ -35,28 +35,28 @@ const TOAST_TONE_STYLES = { }, } satisfies Record -export type ToastType = keyof typeof TOAST_TONE_STYLES +type ToastType = keyof typeof TOAST_TONE_STYLES -export type ToastAddOptions = Omit, 'data' | 'positionerProps' | 'type'> & { +type ToastAddOptions = Omit, 'data' | 'positionerProps' | 'type'> & { type?: ToastType } -export type ToastUpdateOptions = Omit, 'data' | 'positionerProps' | 'type'> & { +type ToastUpdateOptions = Omit, 'data' | 'positionerProps' | 'type'> & { type?: ToastType } -export type ToastOptions = Omit -export type TypedToastOptions = Omit +type ToastOptions = Omit +type TypedToastOptions = Omit type ToastPromiseResultOption = string | ToastUpdateOptions | ((value: Value) => string | ToastUpdateOptions) -export type ToastPromiseOptions = { +type ToastPromiseOptions = { loading: string | ToastUpdateOptions success: ToastPromiseResultOption error: ToastPromiseResultOption } -export type ToastHostProps = { +type ToastHostProps = { timeout?: number limit?: number } @@ -65,7 +65,7 @@ type ToastDismiss = (toastId?: string) => void type ToastCall = (title: ReactNode, options?: ToastOptions) => string type TypedToastCall = (title: ReactNode, options?: TypedToastOptions) => string -export type ToastApi = { +type ToastApi = { (title: ReactNode, options?: ToastOptions): string success: TypedToastCall error: TypedToastCall diff --git a/web/app/components/base/ui/tooltip/index.tsx b/web/app/components/base/ui/tooltip/index.tsx index b100c594c6..693a61ca1f 100644 --- a/web/app/components/base/ui/tooltip/index.tsx +++ b/web/app/components/base/ui/tooltip/index.tsx @@ -8,7 +8,7 @@ import { cn } from '@/utils/classnames' type TooltipContentVariant = 'default' | 'plain' -export type TooltipContentProps = { +type TooltipContentProps = { children: React.ReactNode placement?: Placement sideOffset?: number diff --git a/web/app/components/base/zendesk/utils.ts b/web/app/components/base/zendesk/utils.ts index 961f4b96f6..35f3da7411 100644 --- a/web/app/components/base/zendesk/utils.ts +++ b/web/app/components/base/zendesk/utils.ts @@ -1,6 +1,6 @@ import { IS_CE_EDITION } from '@/config' -export type ConversationField = { +type ConversationField = { id: string value: any } diff --git a/web/app/components/billing/type.ts b/web/app/components/billing/type.ts index e3eb8b6799..15eda0bbf6 100644 --- a/web/app/components/billing/type.ts +++ b/web/app/components/billing/type.ts @@ -37,22 +37,6 @@ export enum SelfHostedPlan { enterprise = 'enterprise', } -export type SelfHostedPlanInfo = { - level: number - price: number - modelProviders: string - teamWorkspace: number - teamMembers: number - buildApps: number - documents: number - vectorSpace: string - documentsRequestQuota: number - documentProcessingPriority: Priority - logHistory: number - messageRequest: number - annotatedResponse: number -} - export type UsagePlanInfo = Pick & { vectorSpace: number } export type UsageResetInfo = { @@ -121,11 +105,6 @@ export type CurrentPlanInfoBackend = { human_input_email_delivery_enabled: boolean } -export type SubscriptionItem = { - plan: Plan - url: string -} - export type SubscriptionUrlsBackend = { url: string } diff --git a/web/app/components/billing/upgrade-btn/style.module.css b/web/app/components/billing/upgrade-btn/style.module.css deleted file mode 100644 index ab8c30ebd5..0000000000 --- a/web/app/components/billing/upgrade-btn/style.module.css +++ /dev/null @@ -1,9 +0,0 @@ -.upgradeBtn { - background: linear-gradient(99deg, rgba(255, 255, 255, 0.12) 7.16%, rgba(255, 255, 255, 0.00) 85.47%), linear-gradient(280deg, #00B2FF 12.96%, #132BFF 90.95%); - box-shadow: 0px 2px 4px -2px rgba(16, 24, 40, 0.06), 0px 4px 8px -2px rgba(0, 162, 253, 0.12); - -} -.upgradeBtn:hover { - background: linear-gradient(99deg, rgba(255, 255, 255, 0.12) 7.16%, rgba(255, 255, 255, 0.00) 85.47%), linear-gradient(280deg, #02C2FF 12.96%, #001AFF 90.95%); - box-shadow: 0px 4px 6px -2px rgba(16, 18, 40, 0.08), 0px 12px 16px -4px rgba(0, 209, 255, 0.08); -} diff --git a/web/app/components/custom/custom-web-app-brand/style.module.css b/web/app/components/custom/custom-web-app-brand/style.module.css deleted file mode 100644 index bdc7d7cfbf..0000000000 --- a/web/app/components/custom/custom-web-app-brand/style.module.css +++ /dev/null @@ -1,3 +0,0 @@ -.mask { - background: linear-gradient(273deg, rgba(255, 255, 255, 0.00) 51.75%, rgba(255, 255, 255, 0.80) 115.32%); -} diff --git a/web/app/components/datasets/chunk.tsx b/web/app/components/datasets/chunk.tsx index 74184c8d07..e0d820a4f3 100644 --- a/web/app/components/datasets/chunk.tsx +++ b/web/app/components/datasets/chunk.tsx @@ -2,7 +2,7 @@ import type { FC, PropsWithChildren } from 'react' import type { QA } from '@/models/datasets' import { SelectionMod } from '../base/icons/src/public/knowledge' -export type ChunkLabelProps = { +type ChunkLabelProps = { label: string characterCount: number } @@ -27,7 +27,7 @@ export const ChunkLabel: FC = (props) => { ) } -export type ChunkContainerProps = ChunkLabelProps & PropsWithChildren +type ChunkContainerProps = ChunkLabelProps & PropsWithChildren export const ChunkContainer: FC = (props) => { const { label, characterCount, children } = props @@ -41,7 +41,7 @@ export const ChunkContainer: FC = (props) => { ) } -export type QAPreviewProps = { +type QAPreviewProps = { qa: QA } diff --git a/web/app/components/datasets/common/image-uploader/image-uploader-in-chunk/index.tsx b/web/app/components/datasets/common/image-uploader/image-uploader-in-chunk/index.tsx index 17ff348c64..ba2ede9f08 100644 --- a/web/app/components/datasets/common/image-uploader/image-uploader-in-chunk/index.tsx +++ b/web/app/components/datasets/common/image-uploader/image-uploader-in-chunk/index.tsx @@ -72,7 +72,7 @@ const ImageUploaderInChunk = ({ ) } -export type ImageUploaderInChunkWrapperProps = { +type ImageUploaderInChunkWrapperProps = { value?: FileEntity[] onChange: (files: FileEntity[]) => void } & ImageUploaderInChunkProps diff --git a/web/app/components/datasets/common/image-uploader/image-uploader-in-retrieval-testing/index.tsx b/web/app/components/datasets/common/image-uploader/image-uploader-in-retrieval-testing/index.tsx index 5f395f3e54..0c4da5a7e4 100644 --- a/web/app/components/datasets/common/image-uploader/image-uploader-in-retrieval-testing/index.tsx +++ b/web/app/components/datasets/common/image-uploader/image-uploader-in-retrieval-testing/index.tsx @@ -110,7 +110,7 @@ const ImageUploaderInRetrievalTesting = ({ ) } -export type ImageUploaderInRetrievalTestingWrapperProps = { +type ImageUploaderInRetrievalTestingWrapperProps = { value?: FileEntity[] onChange: (files: FileEntity[]) => void } & ImageUploaderInRetrievalTestingProps diff --git a/web/app/components/datasets/common/image-uploader/store.tsx b/web/app/components/datasets/common/image-uploader/store.tsx index 93470190a4..45c338d8bc 100644 --- a/web/app/components/datasets/common/image-uploader/store.tsx +++ b/web/app/components/datasets/common/image-uploader/store.tsx @@ -30,7 +30,7 @@ export const createFileStore = ( } type FileStore = ReturnType -export const FileContext = createContext(null) +const FileContext = createContext(null) export function useFileStoreWithSelector(selector: (state: Shape) => T): T { const store = useContext(FileContext) 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 19023ccfe3..992d0526be 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 @@ -12,13 +12,13 @@ export enum CreateFromDSLModalTab { FROM_FILE = 'from-file', FROM_URL = 'from-url', } -export type UseDSLImportOptions = { +type UseDSLImportOptions = { activeTab?: CreateFromDSLModalTab dslUrl?: string onSuccess?: () => void onClose?: () => void } -export type DSLVersions = { +type DSLVersions = { importedVersion: string systemVersion: string } diff --git a/web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/uploader.tsx b/web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/uploader.tsx index 74a51d488a..7089c8293a 100644 --- a/web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/uploader.tsx +++ b/web/app/components/datasets/create-from-pipeline/create-options/create-from-dsl-modal/uploader.tsx @@ -9,7 +9,7 @@ import { toast } from '@/app/components/base/ui/toast' import { cn } from '@/utils/classnames' import { formatFileSize } from '@/utils/format' -export type Props = { +type Props = { file: File | undefined updateFile: (file?: File) => void className?: string diff --git a/web/app/components/datasets/create/embedding-process/index.module.css b/web/app/components/datasets/create/embedding-process/index.module.css deleted file mode 100644 index 74251cacd2..0000000000 --- a/web/app/components/datasets/create/embedding-process/index.module.css +++ /dev/null @@ -1,91 +0,0 @@ -@reference "../../../../styles/globals.css"; - -.progressContainer { - @apply relative pb-4 w-full; - border-bottom: 0.5px solid #EAECF0; -} -.sourceItem { - position: relative; - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 4px; - padding: 0 4px; - height: 24px; - background: #EFF4FF; - border-radius: 6px; - overflow: hidden; -} - -.sourceItem .info .name { - font-weight: 500; - font-size: 12px; - line-height: 18px; - color: #101828; -} -.sourceItem.success .info .name { - color: #05603A; -} -.sourceItem .percent { - font-weight: 500; - font-size: 12px; - line-height: 18px; - color: #344054; - z-index: 1; -} -.sourceItem .error { - color: #D92D20; -} -.sourceItem .success { - color: #05603A; -} - -.commonIcon { - @apply w-3 h-3 mr-1 inline-block align-middle; -} -.highIcon { - mask-image: url(../assets/star.svg); - @apply bg-orange-500; -} -.economyIcon { - background-color: #444ce7; - mask-image: url(../assets/normal.svg); -} -.tokens { - @apply text-xs font-medium px-1; -} -.price { - color: #f79009; - @apply text-xs font-medium; -} - -.unknownFileIcon { - background-image: url(../assets/unknown.svg); -} -.csv { - background-image: url(../assets/csv.svg); -} -.docx { - background-image: url(../assets/docx.svg); -} -.xlsx, -.xls { - background-image: url(../assets/xlsx.svg); -} -.pdf { - background-image: url(../assets/pdf.svg); -} -.html, -.htm { - background-image: url(../assets/html.svg); -} -.md, -.markdown { - background-image: url(../assets/md.svg); -} -.txt { - background-image: url(../assets/txt.svg); -} -.json { - background-image: url(../assets/json.svg); -} diff --git a/web/app/components/datasets/create/file-uploader/hooks/use-file-upload.ts b/web/app/components/datasets/create/file-uploader/hooks/use-file-upload.ts index a202d85b61..05827d0a9e 100644 --- a/web/app/components/datasets/create/file-uploader/hooks/use-file-upload.ts +++ b/web/app/components/datasets/create/file-uploader/hooks/use-file-upload.ts @@ -19,7 +19,7 @@ export type FileUploadConfig = { file_upload_limit: number } -export type UseFileUploadOptions = { +type UseFileUploadOptions = { fileList: FileItem[] prepareFileList: (files: FileItem[]) => void onFileUpdate: (fileItem: FileItem, progress: number, list: FileItem[]) => void @@ -33,7 +33,7 @@ export type UseFileUploadOptions = { allowedExtensions?: string[] } -export type UseFileUploadReturn = { +type UseFileUploadReturn = { // Refs dropRef: RefObject dragRef: RefObject diff --git a/web/app/components/datasets/create/file-uploader/index.module.css b/web/app/components/datasets/create/file-uploader/index.module.css deleted file mode 100644 index a75274594d..0000000000 --- a/web/app/components/datasets/create/file-uploader/index.module.css +++ /dev/null @@ -1,133 +0,0 @@ -@reference "../../../../styles/globals.css"; - -.file { - @apply box-border relative flex items-center justify-between; - padding: 8px 12px 8px 8px; - max-width: 640px; - height: 40px; - background: #ffffff; - border: 0.5px solid #EAECF0; - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); - border-radius: 8px; - overflow: hidden; - cursor: pointer; -} - -.progressbar { - position: absolute; - top: 0; - left: 0; - height: 100%; - background-color: #F2F4F7; -} - -.file.uploading, -.file.uploading:hover { - background: #FCFCFD; - border: 0.5px solid #EAECF0; -} - -.file.active { - background: #F5F8FF; - border: 1px solid #D1E0FF; - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); -} - -.file:hover { - background: #F5F8FF; - border: 1px solid #D1E0FF; - box-shadow: 0px 4px 8px -2px rgba(16, 24, 40, 0.1), 0px 2px 4px -2px rgba(16, 24, 40, 0.06); -} - -.fileIcon { - @apply shrink-0 w-6 h-6 mr-2 bg-center bg-no-repeat; - background-image: url(../assets/unknown.svg); - background-size: 24px; -} - -.fileIcon.csv { - background-image: url(../assets/csv.svg); -} - -.fileIcon.doc { - background-image: url(../assets/doc.svg); -} - -.fileIcon.docx { - background-image: url(../assets/docx.svg); -} - -.fileIcon.xlsx, -.fileIcon.xls { - background-image: url(../assets/xlsx.svg); -} - -.fileIcon.pdf { - background-image: url(../assets/pdf.svg); -} - -.fileIcon.html, -.fileIcon.htm { - background-image: url(../assets/html.svg); -} - -.fileIcon.md, -.fileIcon.markdown { - background-image: url(../assets/md.svg); -} - -.fileIcon.txt { - background-image: url(../assets/txt.svg); -} - -.fileIcon.json { - background-image: url(../assets/json.svg); -} - -.fileInfo { - @apply grow flex items-center; - z-index: 1; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -} - -.filename { - font-weight: 500; - font-size: 13px; - line-height: 18px; - color: #1D2939; -} - -.size { - @apply ml-3; - font-weight: 400; - font-size: 12px; - line-height: 18px; - color: #667085; -} - -.actionWrapper { - @apply flex items-center shrink-0; - z-index: 1; -} - -.actionWrapper .percent { - font-weight: 400; - font-size: 13px; - line-height: 18px; - color: #344054; -} - -.actionWrapper .remove { - display: none; - width: 24px; - height: 24px; - background: center no-repeat url(../assets/trash.svg); - background-size: 16px; - cursor: pointer; -} - -.file:hover .actionWrapper .remove { - display: block; -} diff --git a/web/app/components/datasets/create/index.module.css b/web/app/components/datasets/create/index.module.css deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/web/app/components/datasets/create/step-one/hooks/index.ts b/web/app/components/datasets/create/step-one/hooks/index.ts index bae5ce4fce..bccd40e542 100644 --- a/web/app/components/datasets/create/step-one/hooks/index.ts +++ b/web/app/components/datasets/create/step-one/hooks/index.ts @@ -1,2 +1 @@ export { default as usePreviewState } from './use-preview-state' -export type { PreviewActions, PreviewState, UsePreviewStateReturn } from './use-preview-state' diff --git a/web/app/components/datasets/create/step-one/hooks/use-preview-state.ts b/web/app/components/datasets/create/step-one/hooks/use-preview-state.ts index 3984947ab1..79249fd84d 100644 --- a/web/app/components/datasets/create/step-one/hooks/use-preview-state.ts +++ b/web/app/components/datasets/create/step-one/hooks/use-preview-state.ts @@ -4,13 +4,13 @@ import type { NotionPage } from '@/models/common' import type { CrawlResultItem } from '@/models/datasets' import { useCallback, useState } from 'react' -export type PreviewState = { +type PreviewState = { currentFile: File | undefined currentNotionPage: NotionPage | undefined currentWebsite: CrawlResultItem | undefined } -export type PreviewActions = { +type PreviewActions = { showFilePreview: (file: File) => void hideFilePreview: () => void showNotionPagePreview: (page: NotionPage) => void @@ -19,7 +19,7 @@ export type PreviewActions = { hideWebsitePreview: () => void } -export type UsePreviewStateReturn = PreviewState & PreviewActions +type UsePreviewStateReturn = PreviewState & PreviewActions /** * Custom hook for managing preview state across different data source types. diff --git a/web/app/components/datasets/create/step-three/index.module.css b/web/app/components/datasets/create/step-three/index.module.css deleted file mode 100644 index 221c77bb05..0000000000 --- a/web/app/components/datasets/create/step-three/index.module.css +++ /dev/null @@ -1,77 +0,0 @@ -@reference "../../../../styles/globals.css"; - -.creationInfo { - padding-top: 42px; -} -.creationInfo .title { - @apply mb-2; - font-weight: 500; - font-size: 20px; - line-height: 30px; - color: #101828; -} -.creationInfo .content { - margin-bottom: 44px; - font-weight: 400; - font-size: 14px; - line-height: 20px; - color: #667085; -} -.creationInfo .label { - @apply mb-2; - font-weight: 500; - font-size: 14px; - line-height: 20px; - color: #101828; -} -.datasetName { - padding: 8px 12px; - background: #F9FAFB; - border-radius: 8px; - font-weight: 400; - font-size: 14px; - line-height: 20px; - color: #101828; - word-break: break-all; -} - -.dividerLine { - margin: 24px 0; - height: 1px; - background-color: #eaecf0; -} - -.sideTip { - @apply flex flex-col items-center shrink-0 ; - padding-top: 108px; - width: 524px; - border-left: 0.5px solid #F2F4F7; -} -.tipCard { - @apply flex flex-col items-start p-6; - width: 320px; - background-color: #F9FAFB; - box-shadow: 0px 1px 2px rgba(16, 24, 40, 0.05); - border-radius: 12px; -} -.tipCard .icon { - width: 32px; - height: 32px; - border: 1px solid #EAECF0; - border-radius: 6px; - background: center no-repeat url(../assets/book-open-01.svg); - background-size: 16px; -} -.tipCard .title { - margin: 12px 0; - font-weight: 500; - font-size: 16px; - line-height: 24px; - color: #344054; -} -.tipCard .content { - font-weight: 400; - font-size: 14px; - line-height: 20px; - color: #344054; -} diff --git a/web/app/components/datasets/create/step-two/hooks/index.ts b/web/app/components/datasets/create/step-two/hooks/index.ts index f16daaaea5..b216ead2e6 100644 --- a/web/app/components/datasets/create/step-two/hooks/index.ts +++ b/web/app/components/datasets/create/step-two/hooks/index.ts @@ -1,14 +1,10 @@ export { useDocumentCreation } from './use-document-creation' -export type { DocumentCreation, ValidationParams } from './use-document-creation' export { IndexingType, useIndexingConfig } from './use-indexing-config' -export type { IndexingConfig } from './use-indexing-config' export { useIndexingEstimate } from './use-indexing-estimate' -export type { IndexingEstimate } from './use-indexing-estimate' export { usePreviewState } from './use-preview-state' -export type { PreviewState } from './use-preview-state' export { DEFAULT_MAXIMUM_CHUNK_LENGTH, DEFAULT_OVERLAP, DEFAULT_SEGMENT_IDENTIFIER, defaultParentChildConfig, MAXIMUM_CHUNK_TOKEN_LENGTH, useSegmentationState } from './use-segmentation-state' -export type { ParentChildConfig, SegmentationState } from './use-segmentation-state' +export type { ParentChildConfig } from './use-segmentation-state' diff --git a/web/app/components/datasets/create/step-two/hooks/use-document-creation.ts b/web/app/components/datasets/create/step-two/hooks/use-document-creation.ts index eb1994276c..1c80a188e5 100644 --- a/web/app/components/datasets/create/step-two/hooks/use-document-creation.ts +++ b/web/app/components/datasets/create/step-two/hooks/use-document-creation.ts @@ -14,7 +14,7 @@ import { useInvalidDatasetList } from '@/service/knowledge/use-dataset' import { IndexingType } from './use-indexing-config' import { MAXIMUM_CHUNK_TOKEN_LENGTH } from './use-segmentation-state' -export type UseDocumentCreationOptions = { +type UseDocumentCreationOptions = { datasetId?: string isSetting?: boolean documentDetail?: FullDocumentDetail @@ -34,7 +34,7 @@ export type UseDocumentCreationOptions = { onSave?: () => void mutateDatasetRes?: () => void } -export type ValidationParams = { +type ValidationParams = { segmentationType: string maxChunkLength: number limitMaxChunkLength: number @@ -197,4 +197,3 @@ export const useDocumentCreation = (options: UseDocumentCreationOptions) => { validatePreviewParams, } } -export type DocumentCreation = ReturnType 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 97fc9c260f..a8dd5f2217 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 @@ -23,7 +23,7 @@ const DEFAULT_RETRIEVAL_CONFIG: RetrievalConfig = { score_threshold: 0.5, } -export type UseIndexingConfigOptions = { +type UseIndexingConfigOptions = { initialIndexType?: IndexingType initialEmbeddingModel?: DefaultModel initialRetrievalConfig?: RetrievalConfig @@ -139,5 +139,3 @@ export const useIndexingConfig = (options: UseIndexingConfigOptions) => { showMultiModalTip, } } - -export type IndexingConfig = ReturnType diff --git a/web/app/components/datasets/create/step-two/hooks/use-indexing-estimate.ts b/web/app/components/datasets/create/step-two/hooks/use-indexing-estimate.ts index cc5a2bcf33..ea14ef2c99 100644 --- a/web/app/components/datasets/create/step-two/hooks/use-indexing-estimate.ts +++ b/web/app/components/datasets/create/step-two/hooks/use-indexing-estimate.ts @@ -10,7 +10,7 @@ import { useFetchFileIndexingEstimateForWeb, } from '@/service/knowledge/use-create-dataset' -export type UseIndexingEstimateOptions = { +type UseIndexingEstimateOptions = { dataSourceType: DataSourceType datasetId?: string // Document settings @@ -119,5 +119,3 @@ export const useIndexingEstimate = (options: UseIndexingEstimateOptions) => { reset: currentMutation.reset, } } - -export type IndexingEstimate = ReturnType diff --git a/web/app/components/datasets/create/step-two/hooks/use-preview-state.ts b/web/app/components/datasets/create/step-two/hooks/use-preview-state.ts index 94171c5947..8ac1b7904d 100644 --- a/web/app/components/datasets/create/step-two/hooks/use-preview-state.ts +++ b/web/app/components/datasets/create/step-two/hooks/use-preview-state.ts @@ -3,7 +3,7 @@ import type { CrawlResultItem, CustomFile, DocumentItem, FullDocumentDetail } fr import { useCallback, useState } from 'react' import { DataSourceType } from '@/models/datasets' -export type UsePreviewStateOptions = { +type UsePreviewStateOptions = { dataSourceType: DataSourceType files: CustomFile[] notionPages: NotionPage[] @@ -123,5 +123,3 @@ export const usePreviewState = (options: UsePreviewStateOptions) => { handlePreviewChange, } } - -export type PreviewState = ReturnType diff --git a/web/app/components/datasets/create/step-two/hooks/use-segmentation-state.ts b/web/app/components/datasets/create/step-two/hooks/use-segmentation-state.ts index abef8a98cb..cdd2f61c0c 100644 --- a/web/app/components/datasets/create/step-two/hooks/use-segmentation-state.ts +++ b/web/app/components/datasets/create/step-two/hooks/use-segmentation-state.ts @@ -35,7 +35,7 @@ export const defaultParentChildConfig: ParentChildConfig = { }, } -export type UseSegmentationStateOptions = { +type UseSegmentationStateOptions = { initialSegmentationType?: ProcessMode initialSummaryIndexSetting?: SummaryIndexSettingType } @@ -230,5 +230,3 @@ export const useSegmentationState = (options: UseSegmentationStateOptions = {}) getProcessRule, } } - -export type SegmentationState = ReturnType diff --git a/web/app/components/datasets/documents/components/document-list/components/index.ts b/web/app/components/datasets/documents/components/document-list/components/index.ts index 377f64a27f..9a279e410f 100644 --- a/web/app/components/datasets/documents/components/document-list/components/index.ts +++ b/web/app/components/datasets/documents/components/document-list/components/index.ts @@ -1,4 +1,2 @@ -export { default as DocumentSourceIcon } from './document-source-icon' export { default as DocumentTableRow } from './document-table-row' export { default as SortHeader } from './sort-header' -export { renderTdValue } from './utils' diff --git a/web/app/components/datasets/documents/components/document-list/index.tsx b/web/app/components/datasets/documents/components/document-list/index.tsx deleted file mode 100644 index 46fd7a02d5..0000000000 --- a/web/app/components/datasets/documents/components/document-list/index.tsx +++ /dev/null @@ -1,3 +0,0 @@ -// Re-export from parent for backwards compatibility -export { default } from '../list' -export { renderTdValue } from './components' diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/constants.ts b/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/constants.ts index cda2dae868..5714f4d899 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/constants.ts +++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/constants.ts @@ -1,3 +1,2 @@ export const PROGRESS_NOT_STARTED = -1 export const PROGRESS_ERROR = -2 -export const PROGRESS_COMPLETE = 100 diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/hooks/use-local-file-upload.ts b/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/hooks/use-local-file-upload.ts index 1f7c9ecfed..667010f661 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/hooks/use-local-file-upload.ts +++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/hooks/use-local-file-upload.ts @@ -4,7 +4,7 @@ import { useCallback, useRef } from 'react' import { useFileUpload } from '@/app/components/datasets/create/file-uploader/hooks/use-file-upload' import { useDataSourceStore, useDataSourceStoreWithSelector } from '../../store' -export type UseLocalFileUploadOptions = { +type UseLocalFileUploadOptions = { allowedExtensions: string[] supportBatchUpload?: boolean } diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/index.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/index.tsx index cb3632ba9d..93a48f6be7 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/index.tsx +++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/local-file/index.tsx @@ -3,7 +3,7 @@ import FileListItem from './components/file-list-item' import UploadDropzone from './components/upload-dropzone' import { useLocalFileUpload } from './hooks/use-local-file-upload' -export type LocalFileProps = { +type LocalFileProps = { allowedExtensions: string[] supportBatchUpload?: boolean } diff --git a/web/app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/index.tsx b/web/app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/index.tsx index b0f25d94b7..fc56e05b43 100644 --- a/web/app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/index.tsx +++ b/web/app/components/datasets/documents/create-from-pipeline/data-source/website-crawl/index.tsx @@ -31,7 +31,7 @@ import Options from './base/options' const I18N_PREFIX = 'stepOne.website' -export type WebsiteCrawlProps = { +type WebsiteCrawlProps = { nodeId: string nodeData: DataSourceNodeType onCredentialChange: (credentialId: string) => void diff --git a/web/app/components/datasets/documents/detail/batch-modal/csv-uploader.tsx b/web/app/components/datasets/documents/detail/batch-modal/csv-uploader.tsx index 2e85dad26a..7382d1abd1 100644 --- a/web/app/components/datasets/documents/detail/batch-modal/csv-uploader.tsx +++ b/web/app/components/datasets/documents/detail/batch-modal/csv-uploader.tsx @@ -16,7 +16,7 @@ import { useFileUploadConfig } from '@/service/use-common' import { Theme } from '@/types/app' import { cn } from '@/utils/classnames' -export type Props = { +type Props = { file: FileItem | undefined updateFile: (file?: FileItem) => void } diff --git a/web/app/components/datasets/documents/detail/batch-modal/index.tsx b/web/app/components/datasets/documents/detail/batch-modal/index.tsx index 1fc006831e..ff43f5f67d 100644 --- a/web/app/components/datasets/documents/detail/batch-modal/index.tsx +++ b/web/app/components/datasets/documents/detail/batch-modal/index.tsx @@ -11,7 +11,7 @@ import Modal from '@/app/components/base/modal' import CSVDownloader from './csv-downloader' import CSVUploader from './csv-uploader' -export type IBatchModalProps = { +type IBatchModalProps = { isShow: boolean docForm: ChunkingMode onCancel: () => void diff --git a/web/app/components/datasets/documents/detail/completed/hooks/index.ts b/web/app/components/datasets/documents/detail/completed/hooks/index.ts index 858b448563..1a6ed8bd0e 100644 --- a/web/app/components/datasets/documents/detail/completed/hooks/index.ts +++ b/web/app/components/datasets/documents/detail/completed/hooks/index.ts @@ -1,14 +1,9 @@ export { useChildSegmentData } from './use-child-segment-data' -export type { UseChildSegmentDataReturn } from './use-child-segment-data' export { useModalState } from './use-modal-state' -export type { CurrChildChunkType, CurrSegmentType, UseModalStateReturn } from './use-modal-state' export { useSearchFilter } from './use-search-filter' -export type { UseSearchFilterReturn } from './use-search-filter' export { useSegmentListData } from './use-segment-list-data' -export type { UseSegmentListDataReturn } from './use-segment-list-data' export { useSegmentSelection } from './use-segment-selection' -export type { UseSegmentSelectionReturn } from './use-segment-selection' diff --git a/web/app/components/datasets/documents/detail/completed/hooks/use-child-segment-data.ts b/web/app/components/datasets/documents/detail/completed/hooks/use-child-segment-data.ts index 50a22fc71f..fab8b16019 100644 --- a/web/app/components/datasets/documents/detail/completed/hooks/use-child-segment-data.ts +++ b/web/app/components/datasets/documents/detail/completed/hooks/use-child-segment-data.ts @@ -8,7 +8,7 @@ import { useChildSegmentList, useChildSegmentListKey, useDeleteChildSegment, use import { useInvalid } from '@/service/use-base' import { useDocumentContext } from '../../context' -export type UseChildSegmentDataOptions = { +type UseChildSegmentDataOptions = { searchValue: string currentPage: number limit: number @@ -19,7 +19,7 @@ export type UseChildSegmentDataOptions = { refreshChunkListDataWithDetailChanged: () => void updateSegmentInCache: (segmentId: string, updater: (seg: SegmentDetailModel) => SegmentDetailModel) => void } -export type UseChildSegmentDataReturn = { +type UseChildSegmentDataReturn = { childSegments: ChildChunkDetail[] isLoadingChildSegmentList: boolean childChunkListData: ReturnType['data'] diff --git a/web/app/components/datasets/documents/detail/completed/hooks/use-modal-state.ts b/web/app/components/datasets/documents/detail/completed/hooks/use-modal-state.ts index ecb45ac1ee..fa314bec25 100644 --- a/web/app/components/datasets/documents/detail/completed/hooks/use-modal-state.ts +++ b/web/app/components/datasets/documents/detail/completed/hooks/use-modal-state.ts @@ -1,18 +1,18 @@ import type { ChildChunkDetail, SegmentDetailModel } from '@/models/datasets' import { useCallback, useState } from 'react' -export type CurrSegmentType = { +type CurrSegmentType = { segInfo?: SegmentDetailModel showModal: boolean isEditMode?: boolean } -export type CurrChildChunkType = { +type CurrChildChunkType = { childChunkInfo?: ChildChunkDetail showModal: boolean } -export type UseModalStateReturn = { +type UseModalStateReturn = { // Segment detail modal currSegment: CurrSegmentType onClickCard: (detail: SegmentDetailModel, isEditMode?: boolean) => void diff --git a/web/app/components/datasets/documents/detail/completed/hooks/use-search-filter.ts b/web/app/components/datasets/documents/detail/completed/hooks/use-search-filter.ts index e7fafa692d..310e326fc1 100644 --- a/web/app/components/datasets/documents/detail/completed/hooks/use-search-filter.ts +++ b/web/app/components/datasets/documents/detail/completed/hooks/use-search-filter.ts @@ -3,13 +3,7 @@ import { useDebounceFn } from 'ahooks' import { useCallback, useMemo, useRef, useState } from 'react' import { useTranslation } from 'react-i18next' -export type SearchFilterState = { - inputValue: string - searchValue: string - selectedStatus: boolean | 'all' -} - -export type UseSearchFilterReturn = { +type UseSearchFilterReturn = { inputValue: string searchValue: string selectedStatus: boolean | 'all' diff --git a/web/app/components/datasets/documents/detail/completed/hooks/use-segment-list-data.ts b/web/app/components/datasets/documents/detail/completed/hooks/use-segment-list-data.ts index fb5db4497e..3a3c486070 100644 --- a/web/app/components/datasets/documents/detail/completed/hooks/use-segment-list-data.ts +++ b/web/app/components/datasets/documents/detail/completed/hooks/use-segment-list-data.ts @@ -14,7 +14,7 @@ import { useDocumentContext } from '../../context' import { ProcessStatus } from '../../segment-add' const DEFAULT_LIMIT = 10 -export type UseSegmentListDataOptions = { +type UseSegmentListDataOptions = { searchValue: string selectedStatus: boolean | 'all' selectedSegmentIds: string[] @@ -24,7 +24,7 @@ export type UseSegmentListDataOptions = { onCloseSegmentDetail: () => void clearSelection: () => void } -export type UseSegmentListDataReturn = { +type UseSegmentListDataReturn = { segments: SegmentDetailModel[] isLoadingSegmentList: boolean segmentListData: ReturnType['data'] diff --git a/web/app/components/datasets/documents/detail/completed/hooks/use-segment-selection.ts b/web/app/components/datasets/documents/detail/completed/hooks/use-segment-selection.ts index b1adeedaf4..e0fb0b036f 100644 --- a/web/app/components/datasets/documents/detail/completed/hooks/use-segment-selection.ts +++ b/web/app/components/datasets/documents/detail/completed/hooks/use-segment-selection.ts @@ -1,7 +1,7 @@ import type { SegmentDetailModel } from '@/models/datasets' import { useCallback, useMemo, useState } from 'react' -export type UseSegmentSelectionReturn = { +type UseSegmentSelectionReturn = { selectedSegmentIds: string[] isAllSelected: boolean isSomeSelected: boolean diff --git a/web/app/components/datasets/documents/detail/embedding/hooks/index.ts b/web/app/components/datasets/documents/detail/embedding/hooks/index.ts index 603c16dda5..2d0c4fa25e 100644 --- a/web/app/components/datasets/documents/detail/embedding/hooks/index.ts +++ b/web/app/components/datasets/documents/detail/embedding/hooks/index.ts @@ -1,10 +1,7 @@ export { - calculatePercent, - isEmbeddingStatus, - isTerminalStatus, + useEmbeddingStatus, - useInvalidateEmbeddingStatus, + usePauseIndexing, useResumeIndexing, } from './use-embedding-status' -export type { EmbeddingStatusType } from './use-embedding-status' diff --git a/web/app/components/datasets/documents/detail/embedding/hooks/use-embedding-status.ts b/web/app/components/datasets/documents/detail/embedding/hooks/use-embedding-status.ts index e55cd8f9aa..5f9314e695 100644 --- a/web/app/components/datasets/documents/detail/embedding/hooks/use-embedding-status.ts +++ b/web/app/components/datasets/documents/detail/embedding/hooks/use-embedding-status.ts @@ -10,8 +10,6 @@ import { const NAME_SPACE = 'embedding' -export type EmbeddingStatusType = 'indexing' | 'splitting' | 'parsing' | 'cleaning' | 'completed' | 'paused' | 'error' | 'waiting' | '' - const EMBEDDING_STATUSES = ['indexing', 'splitting', 'parsing', 'cleaning'] as const const TERMINAL_STATUSES = ['completed', 'error', 'paused'] as const diff --git a/web/app/components/datasets/documents/detail/embedding/style.module.css b/web/app/components/datasets/documents/detail/embedding/style.module.css deleted file mode 100644 index a60a583ebe..0000000000 --- a/web/app/components/datasets/documents/detail/embedding/style.module.css +++ /dev/null @@ -1,61 +0,0 @@ -@reference "../../../../../styles/globals.css"; - -.progressBar { - @apply absolute top-0 h-4; -} -.barPaused { - background: linear-gradient( - 270deg, - rgba(208, 213, 221, 0.8) -2.21%, - rgba(208, 213, 221, 0.5) 100% - ); -} -.barProcessing { - background: linear-gradient( - 90deg, - rgba(41, 112, 255, 0.9) 0%, - rgba(21, 94, 239, 0.9) 100% - ); -} -.opBtn { - @apply !h-6 !w-fit !px-2 !py-1 !text-xs !text-gray-700 rounded-md; -} -.opIcon { - @apply mr-1 stroke-current text-gray-700 w-3 h-3; -} -.progressContainer { - @apply relative flex mb-2 h-4 rounded-md w-full; -} -.progressBgItem { - @apply flex-1 border-r border-r-white first:rounded-l-md; -} -.progressBgItem:nth-last-child(2) { - @apply rounded-r-md; -} -.progressData { - @apply w-full flex items-center text-xs text-gray-700; -} -.previewTip { - @apply pb-1 pt-12 text-gray-900 text-sm font-medium; -} -.embeddingStatus { - @apply flex items-center justify-between text-gray-900 font-medium text-base mb-3; -} -.commonIcon { - @apply w-3 h-3 mr-1 inline-block align-middle; -} -.highIcon { - mask-image: url(../../assets/star.svg); - @apply bg-orange-500; -} -.economyIcon { - background-color: #444ce7; - mask-image: url(../../assets/normal.svg); -} -.tokens { - @apply text-xs font-medium px-1; -} -.price { - color: #f79009; - @apply text-xs font-medium; -} diff --git a/web/app/components/datasets/documents/detail/segment-add/index.tsx b/web/app/components/datasets/documents/detail/segment-add/index.tsx index 0abfda328b..dbd9f0b5e5 100644 --- a/web/app/components/datasets/documents/detail/segment-add/index.tsx +++ b/web/app/components/datasets/documents/detail/segment-add/index.tsx @@ -17,7 +17,7 @@ import { Plan } from '@/app/components/billing/type' import { useProviderContext } from '@/context/provider-context' import { cn } from '@/utils/classnames' -export type ISegmentAddProps = { +type ISegmentAddProps = { importStatus: ProcessStatus | string | undefined clearProcessStatus: () => void showNewSegmentModal: () => void diff --git a/web/app/components/datasets/formatted-text/flavours/shared.tsx b/web/app/components/datasets/formatted-text/flavours/shared.tsx index 77637f4bb2..4f68177ea3 100644 --- a/web/app/components/datasets/formatted-text/flavours/shared.tsx +++ b/web/app/components/datasets/formatted-text/flavours/shared.tsx @@ -3,7 +3,7 @@ import { cn } from '@/utils/classnames' const baseStyle = 'py-[3px]' -export type SliceContainerProps = ComponentProps<'span'> +type SliceContainerProps = ComponentProps<'span'> export const SliceContainer: FC = ( { @@ -22,7 +22,7 @@ export const SliceContainer: FC = ( } SliceContainer.displayName = 'SliceContainer' -export type SliceLabelProps = ComponentProps<'span'> & { labelInnerClassName?: string } +type SliceLabelProps = ComponentProps<'span'> & { labelInnerClassName?: string } export const SliceLabel: FC = ( { @@ -45,7 +45,7 @@ export const SliceLabel: FC = ( } SliceLabel.displayName = 'SliceLabel' -export type SliceContentProps = ComponentProps<'span'> +type SliceContentProps = ComponentProps<'span'> export const SliceContent: FC = ( { @@ -66,7 +66,7 @@ export const SliceContent: FC = ( } SliceContent.displayName = 'SliceContent' -export type SliceDividerProps = ComponentProps<'span'> +type SliceDividerProps = ComponentProps<'span'> export const SliceDivider: FC = ( { diff --git a/web/app/components/datasets/formatted-text/formatted.tsx b/web/app/components/datasets/formatted-text/formatted.tsx index 0c1aad6d21..21036ac6f3 100644 --- a/web/app/components/datasets/formatted-text/formatted.tsx +++ b/web/app/components/datasets/formatted-text/formatted.tsx @@ -1,7 +1,7 @@ import type { ComponentProps, FC } from 'react' import { cn } from '@/utils/classnames' -export type FormattedTextProps = ComponentProps<'p'> +type FormattedTextProps = ComponentProps<'p'> export const FormattedText: FC = (props) => { const { className, ...rest } = props diff --git a/web/app/components/datasets/hit-testing/components/mask.tsx b/web/app/components/datasets/hit-testing/components/mask.tsx index 4568bce5a9..4510e38430 100644 --- a/web/app/components/datasets/hit-testing/components/mask.tsx +++ b/web/app/components/datasets/hit-testing/components/mask.tsx @@ -5,7 +5,7 @@ type MaskProps = { className?: string } -export const Mask = ({ +const Mask = ({ className, }: MaskProps) => { return ( diff --git a/web/app/components/datasets/preview/container.tsx b/web/app/components/datasets/preview/container.tsx index 9bba6054a9..ed63bbc8c5 100644 --- a/web/app/components/datasets/preview/container.tsx +++ b/web/app/components/datasets/preview/container.tsx @@ -1,7 +1,7 @@ import type { ComponentProps, FC, ReactNode } from 'react' import { cn } from '@/utils/classnames' -export type PreviewContainerProps = ComponentProps<'div'> & { +type PreviewContainerProps = ComponentProps<'div'> & { header: ReactNode mainClassName?: string ref?: React.Ref diff --git a/web/app/components/datasets/preview/header.tsx b/web/app/components/datasets/preview/header.tsx index 0124d03e88..2da4e497a4 100644 --- a/web/app/components/datasets/preview/header.tsx +++ b/web/app/components/datasets/preview/header.tsx @@ -1,7 +1,7 @@ import type { ComponentProps, FC } from 'react' import { cn } from '@/utils/classnames' -export type PreviewHeaderProps = Omit, 'title'> & { +type PreviewHeaderProps = Omit, 'title'> & { title: string } diff --git a/web/app/components/datasets/settings/permission-selector/index.tsx b/web/app/components/datasets/settings/permission-selector/index.tsx index 5afb56f0a9..a83beffbb4 100644 --- a/web/app/components/datasets/settings/permission-selector/index.tsx +++ b/web/app/components/datasets/settings/permission-selector/index.tsx @@ -17,7 +17,7 @@ import { cn } from '@/utils/classnames' import MemberItem from './member-item' import Item from './permission-item' -export type RoleSelectorProps = { +type RoleSelectorProps = { disabled?: boolean permission?: DatasetPermission value: string[] diff --git a/web/app/components/devtools/react-grab/loader.tsx b/web/app/components/devtools/react-grab/loader.tsx deleted file mode 100644 index 4ee9ad1236..0000000000 --- a/web/app/components/devtools/react-grab/loader.tsx +++ /dev/null @@ -1,17 +0,0 @@ -import { IS_DEV } from '@/config' -import Script from '@/next/script' - -export function ReactGrabLoader() { - if (!IS_DEV) - return null - - return ( - <> -