Merge branch 'main' into chore/workflow-last-run

pull/21823/head
zxhlyh 11 months ago
commit 5308776757

@ -47,15 +47,17 @@ jobs:
- name: Run Unit tests - name: Run Unit tests
run: | run: |
uv run --project api bash dev/pytest/pytest_unit_tests.sh uv run --project api bash dev/pytest/pytest_unit_tests.sh
- name: Coverage Summary
run: |
set -x
# Extract coverage percentage and create a summary # Extract coverage percentage and create a summary
TOTAL_COVERAGE=$(python -c 'import json; print(json.load(open("coverage.json"))["totals"]["percent_covered_display"])') TOTAL_COVERAGE=$(python -c 'import json; print(json.load(open("coverage.json"))["totals"]["percent_covered_display"])')
# Create a detailed coverage summary # Create a detailed coverage summary
echo "### Test Coverage Summary :test_tube:" >> $GITHUB_STEP_SUMMARY echo "### Test Coverage Summary :test_tube:" >> $GITHUB_STEP_SUMMARY
echo "Total Coverage: ${TOTAL_COVERAGE}%" >> $GITHUB_STEP_SUMMARY echo "Total Coverage: ${TOTAL_COVERAGE}%" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY uv run --project api coverage report --format=markdown >> $GITHUB_STEP_SUMMARY
uv run --project api coverage report >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
- name: Run dify config tests - name: Run dify config tests
run: uv run --project api dev/pytest/pytest_config_tests.py run: uv run --project api dev/pytest/pytest_config_tests.py

1
.gitignore vendored

@ -214,3 +214,4 @@ mise.toml
# AI Assistant # AI Assistant
.roo/ .roo/
api/.env.backup

@ -1,8 +1,11 @@
import logging import logging
from pathlib import Path
from typing import Any from typing import Any
from pydantic.fields import FieldInfo from pydantic.fields import FieldInfo
from pydantic_settings import BaseSettings, PydanticBaseSettingsSource, SettingsConfigDict from pydantic_settings import BaseSettings, PydanticBaseSettingsSource, SettingsConfigDict, TomlConfigSettingsSource
from libs.file_utils import search_file_upwards
from .deploy import DeploymentConfig from .deploy import DeploymentConfig
from .enterprise import EnterpriseFeatureConfig from .enterprise import EnterpriseFeatureConfig
@ -99,4 +102,12 @@ class DifyConfig(
RemoteSettingsSourceFactory(settings_cls), RemoteSettingsSourceFactory(settings_cls),
dotenv_settings, dotenv_settings,
file_secret_settings, file_secret_settings,
TomlConfigSettingsSource(
settings_cls=settings_cls,
toml_file=search_file_upwards(
base_dir_path=Path(__file__).parent,
target_file_name="pyproject.toml",
max_search_parent_depth=2,
),
),
) )

@ -1,8 +1,9 @@
from pydantic import Field from pydantic import Field
from pydantic_settings import BaseSettings
from configs.packaging.pyproject import PyProjectConfig, PyProjectTomlConfig
class PackagingInfo(BaseSettings):
class PackagingInfo(PyProjectTomlConfig):
""" """
Packaging build information Packaging build information
""" """

@ -0,0 +1,17 @@
from pydantic import BaseModel, Field
from pydantic_settings import BaseSettings
class PyProjectConfig(BaseModel):
version: str = Field(description="Dify version", default="")
class PyProjectTomlConfig(BaseSettings):
"""
configs in api/pyproject.toml
"""
project: PyProjectConfig = Field(
description="configs in the project section of pyproject.toml",
default=PyProjectConfig(),
)

@ -41,7 +41,7 @@ class OAuthDataSource(Resource):
if not internal_secret: if not internal_secret:
return ({"error": "Internal secret is not set"},) return ({"error": "Internal secret is not set"},)
oauth_provider.save_internal_access_token(internal_secret) oauth_provider.save_internal_access_token(internal_secret)
return {"data": ""} return {"data": "internal"}
else: else:
auth_url = oauth_provider.get_authorization_url() auth_url = oauth_provider.get_authorization_url()
return {"data": auth_url}, 200 return {"data": auth_url}, 200

@ -18,7 +18,7 @@ class VersionApi(Resource):
check_update_url = dify_config.CHECK_UPDATE_URL check_update_url = dify_config.CHECK_UPDATE_URL
result = { result = {
"version": dify_config.CURRENT_VERSION, "version": dify_config.project.version,
"release_date": "", "release_date": "",
"release_notes": "", "release_notes": "",
"can_auto_update": False, "can_auto_update": False,

@ -9,7 +9,7 @@ class IndexApi(Resource):
return { return {
"welcome": "Dify OpenAPI", "welcome": "Dify OpenAPI",
"api_version": "v1", "api_version": "v1",
"server_version": dify_config.CURRENT_VERSION, "server_version": dify_config.project.version,
} }

@ -219,6 +219,9 @@ class WorkflowAppGenerator(BaseAppGenerator):
# new thread with request context and contextvars # new thread with request context and contextvars
context = contextvars.copy_context() context = contextvars.copy_context()
# release database connection, because the following new thread operations may take a long time
db.session.close()
worker_thread = threading.Thread( worker_thread = threading.Thread(
target=self._generate_worker, target=self._generate_worker,
kwargs={ kwargs={

@ -83,6 +83,7 @@ class LangFuseDataTrace(BaseTraceInstance):
metadata=metadata, metadata=metadata,
session_id=trace_info.conversation_id, session_id=trace_info.conversation_id,
tags=["message", "workflow"], tags=["message", "workflow"],
version=trace_info.workflow_run_version,
) )
self.add_trace(langfuse_trace_data=trace_data) self.add_trace(langfuse_trace_data=trace_data)
workflow_span_data = LangfuseSpan( workflow_span_data = LangfuseSpan(
@ -108,6 +109,7 @@ class LangFuseDataTrace(BaseTraceInstance):
metadata=metadata, metadata=metadata,
session_id=trace_info.conversation_id, session_id=trace_info.conversation_id,
tags=["workflow"], tags=["workflow"],
version=trace_info.workflow_run_version,
) )
self.add_trace(langfuse_trace_data=trace_data) self.add_trace(langfuse_trace_data=trace_data)
@ -172,37 +174,7 @@ class LangFuseDataTrace(BaseTraceInstance):
} }
) )
# add span # add generation span
if trace_info.message_id:
span_data = LangfuseSpan(
id=node_execution_id,
name=node_type,
input=inputs,
output=outputs,
trace_id=trace_id,
start_time=created_at,
end_time=finished_at,
metadata=metadata,
level=(LevelEnum.DEFAULT if status == "succeeded" else LevelEnum.ERROR),
status_message=trace_info.error or "",
parent_observation_id=trace_info.workflow_run_id,
)
else:
span_data = LangfuseSpan(
id=node_execution_id,
name=node_type,
input=inputs,
output=outputs,
trace_id=trace_id,
start_time=created_at,
end_time=finished_at,
metadata=metadata,
level=(LevelEnum.DEFAULT if status == "succeeded" else LevelEnum.ERROR),
status_message=trace_info.error or "",
)
self.add_span(langfuse_span_data=span_data)
if process_data and process_data.get("model_mode") == "chat": if process_data and process_data.get("model_mode") == "chat":
total_token = metadata.get("total_tokens", 0) total_token = metadata.get("total_tokens", 0)
prompt_tokens = 0 prompt_tokens = 0
@ -226,10 +198,10 @@ class LangFuseDataTrace(BaseTraceInstance):
) )
node_generation_data = LangfuseGeneration( node_generation_data = LangfuseGeneration(
name="llm", id=node_execution_id,
name=node_name,
trace_id=trace_id, trace_id=trace_id,
model=process_data.get("model_name"), model=process_data.get("model_name"),
parent_observation_id=node_execution_id,
start_time=created_at, start_time=created_at,
end_time=finished_at, end_time=finished_at,
input=inputs, input=inputs,
@ -237,11 +209,30 @@ class LangFuseDataTrace(BaseTraceInstance):
metadata=metadata, metadata=metadata,
level=(LevelEnum.DEFAULT if status == "succeeded" else LevelEnum.ERROR), level=(LevelEnum.DEFAULT if status == "succeeded" else LevelEnum.ERROR),
status_message=trace_info.error or "", status_message=trace_info.error or "",
parent_observation_id=trace_info.workflow_run_id if trace_info.message_id else None,
usage=generation_usage, usage=generation_usage,
) )
self.add_generation(langfuse_generation_data=node_generation_data) self.add_generation(langfuse_generation_data=node_generation_data)
# add normal span
else:
span_data = LangfuseSpan(
id=node_execution_id,
name=node_name,
input=inputs,
output=outputs,
trace_id=trace_id,
start_time=created_at,
end_time=finished_at,
metadata=metadata,
level=(LevelEnum.DEFAULT if status == "succeeded" else LevelEnum.ERROR),
status_message=trace_info.error or "",
parent_observation_id=trace_info.workflow_run_id if trace_info.message_id else None,
)
self.add_span(langfuse_span_data=span_data)
def message_trace(self, trace_info: MessageTraceInfo, **kwargs): def message_trace(self, trace_info: MessageTraceInfo, **kwargs):
# get message file data # get message file data
file_list = trace_info.file_list file_list = trace_info.file_list
@ -284,7 +275,7 @@ class LangFuseDataTrace(BaseTraceInstance):
) )
self.add_trace(langfuse_trace_data=trace_data) self.add_trace(langfuse_trace_data=trace_data)
# start add span # add generation
generation_usage = GenerationUsage( generation_usage = GenerationUsage(
input=trace_info.message_tokens, input=trace_info.message_tokens,
output=trace_info.answer_tokens, output=trace_info.answer_tokens,

@ -42,4 +42,4 @@ class DynamicSelectClient(BasePluginClient):
for options in response: for options in response:
return options return options
raise ValueError("Plugin service returned no options") raise ValueError(f"Plugin service returned no options for parameter '{parameter}' in provider '{provider}'")

@ -4,6 +4,7 @@ from typing import Any, Optional
from core.helper.code_executor.code_executor import CodeExecutor, CodeLanguage from core.helper.code_executor.code_executor import CodeExecutor, CodeLanguage
from core.tools.builtin_tool.tool import BuiltinTool from core.tools.builtin_tool.tool import BuiltinTool
from core.tools.entities.tool_entities import ToolInvokeMessage from core.tools.entities.tool_entities import ToolInvokeMessage
from core.tools.errors import ToolInvokeError
class SimpleCode(BuiltinTool): class SimpleCode(BuiltinTool):
@ -25,6 +26,8 @@ class SimpleCode(BuiltinTool):
if language not in {CodeLanguage.PYTHON3, CodeLanguage.JAVASCRIPT}: if language not in {CodeLanguage.PYTHON3, CodeLanguage.JAVASCRIPT}:
raise ValueError(f"Only python3 and javascript are supported, not {language}") raise ValueError(f"Only python3 and javascript are supported, not {language}")
result = CodeExecutor.execute_code(language, "", code) try:
result = CodeExecutor.execute_code(language, "", code)
yield self.create_text_message(result) yield self.create_text_message(result)
except Exception as e:
raise ToolInvokeError(str(e))

@ -158,7 +158,10 @@ class AgentNode(ToolNode):
# variable_pool.convert_template expects a string template, # variable_pool.convert_template expects a string template,
# but if passing a dict, convert to JSON string first before rendering # but if passing a dict, convert to JSON string first before rendering
try: try:
parameter_value = json.dumps(agent_input.value, ensure_ascii=False) if not isinstance(agent_input.value, str):
parameter_value = json.dumps(agent_input.value, ensure_ascii=False)
else:
parameter_value = str(agent_input.value)
except TypeError: except TypeError:
parameter_value = str(agent_input.value) parameter_value = str(agent_input.value)
segment_group = variable_pool.convert_template(parameter_value) segment_group = variable_pool.convert_template(parameter_value)
@ -166,7 +169,8 @@ class AgentNode(ToolNode):
# variable_pool.convert_template returns a string, # variable_pool.convert_template returns a string,
# so we need to convert it back to a dictionary # so we need to convert it back to a dictionary
try: try:
parameter_value = json.loads(parameter_value) if not isinstance(agent_input.value, str):
parameter_value = json.loads(parameter_value)
except json.JSONDecodeError: except json.JSONDecodeError:
parameter_value = parameter_value parameter_value = parameter_value
else: else:

@ -167,7 +167,9 @@ class ToolNode(BaseNode[ToolNodeData]):
if tool_input.type == "variable": if tool_input.type == "variable":
variable = variable_pool.get(tool_input.value) variable = variable_pool.get(tool_input.value)
if variable is None: if variable is None:
raise ToolParameterError(f"Variable {tool_input.value} does not exist") if parameter.required:
raise ToolParameterError(f"Variable {tool_input.value} does not exist")
continue
parameter_value = variable.value parameter_value = variable.value
elif tool_input.type in {"mixed", "constant"}: elif tool_input.type in {"mixed", "constant"}:
segment_group = variable_pool.convert_template(str(tool_input.value)) segment_group = variable_pool.convert_template(str(tool_input.value))

@ -12,14 +12,14 @@ def init_app(app: DifyApp):
@app.after_request @app.after_request
def after_request(response): def after_request(response):
"""Add Version headers to the response.""" """Add Version headers to the response."""
response.headers.add("X-Version", dify_config.CURRENT_VERSION) response.headers.add("X-Version", dify_config.project.version)
response.headers.add("X-Env", dify_config.DEPLOY_ENV) response.headers.add("X-Env", dify_config.DEPLOY_ENV)
return response return response
@app.route("/health") @app.route("/health")
def health(): def health():
return Response( return Response(
json.dumps({"pid": os.getpid(), "status": "ok", "version": dify_config.CURRENT_VERSION}), json.dumps({"pid": os.getpid(), "status": "ok", "version": dify_config.project.version}),
status=200, status=200,
content_type="application/json", content_type="application/json",
) )

@ -49,7 +49,7 @@ def init_app(app: DifyApp):
logging.getLogger().addHandler(exception_handler) logging.getLogger().addHandler(exception_handler)
def init_flask_instrumentor(app: DifyApp): def init_flask_instrumentor(app: DifyApp):
meter = get_meter("http_metrics", version=dify_config.CURRENT_VERSION) meter = get_meter("http_metrics", version=dify_config.project.version)
_http_response_counter = meter.create_counter( _http_response_counter = meter.create_counter(
"http.server.response.count", "http.server.response.count",
description="Total number of HTTP responses by status code, method and target", description="Total number of HTTP responses by status code, method and target",
@ -163,7 +163,7 @@ def init_app(app: DifyApp):
resource = Resource( resource = Resource(
attributes={ attributes={
ResourceAttributes.SERVICE_NAME: dify_config.APPLICATION_NAME, ResourceAttributes.SERVICE_NAME: dify_config.APPLICATION_NAME,
ResourceAttributes.SERVICE_VERSION: f"dify-{dify_config.CURRENT_VERSION}-{dify_config.COMMIT_SHA}", ResourceAttributes.SERVICE_VERSION: f"dify-{dify_config.project.version}-{dify_config.COMMIT_SHA}",
ResourceAttributes.PROCESS_PID: os.getpid(), ResourceAttributes.PROCESS_PID: os.getpid(),
ResourceAttributes.DEPLOYMENT_ENVIRONMENT: f"{dify_config.DEPLOY_ENV}-{dify_config.EDITION}", ResourceAttributes.DEPLOYMENT_ENVIRONMENT: f"{dify_config.DEPLOY_ENV}-{dify_config.EDITION}",
ResourceAttributes.HOST_NAME: socket.gethostname(), ResourceAttributes.HOST_NAME: socket.gethostname(),

@ -35,6 +35,6 @@ def init_app(app: DifyApp):
traces_sample_rate=dify_config.SENTRY_TRACES_SAMPLE_RATE, traces_sample_rate=dify_config.SENTRY_TRACES_SAMPLE_RATE,
profiles_sample_rate=dify_config.SENTRY_PROFILES_SAMPLE_RATE, profiles_sample_rate=dify_config.SENTRY_PROFILES_SAMPLE_RATE,
environment=dify_config.DEPLOY_ENV, environment=dify_config.DEPLOY_ENV,
release=f"dify-{dify_config.CURRENT_VERSION}-{dify_config.COMMIT_SHA}", release=f"dify-{dify_config.project.version}-{dify_config.COMMIT_SHA}",
before_send=before_send, before_send=before_send,
) )

@ -0,0 +1,30 @@
from pathlib import Path
def search_file_upwards(
base_dir_path: Path,
target_file_name: str,
max_search_parent_depth: int,
) -> Path:
"""
Find a target file in the current directory or its parent directories up to a specified depth.
:param base_dir_path: Starting directory path to search from.
:param target_file_name: Name of the file to search for.
:param max_search_parent_depth: Maximum number of parent directories to search upwards.
:return: Path of the file if found, otherwise None.
"""
current_path = base_dir_path.resolve()
for _ in range(max_search_parent_depth):
candidate_path = current_path / target_file_name
if candidate_path.is_file():
return candidate_path
parent_path = current_path.parent
if parent_path == current_path: # reached the root directory
break
else:
current_path = parent_path
raise ValueError(
f"File '{target_file_name}' not found in the directory '{base_dir_path.resolve()}' or its parent directories"
f" in depth of {max_search_parent_depth}."
)

@ -140,7 +140,7 @@ class Dataset(Base):
def word_count(self): def word_count(self):
return ( return (
db.session.query(Document) db.session.query(Document)
.with_entities(func.coalesce(func.sum(Document.word_count))) .with_entities(func.coalesce(func.sum(Document.word_count), 0))
.filter(Document.dataset_id == self.id) .filter(Document.dataset_id == self.id)
.scalar() .scalar()
) )
@ -448,7 +448,7 @@ class Document(Base):
def hit_count(self): def hit_count(self):
return ( return (
db.session.query(DocumentSegment) db.session.query(DocumentSegment)
.with_entities(func.coalesce(func.sum(DocumentSegment.hit_count))) .with_entities(func.coalesce(func.sum(DocumentSegment.hit_count), 0))
.filter(DocumentSegment.document_id == self.id) .filter(DocumentSegment.document_id == self.id)
.scalar() .scalar()
) )

@ -676,7 +676,7 @@ class Conversation(Base):
if isinstance(value, dict) and value.get("dify_model_identity") == FILE_MODEL_IDENTITY: if isinstance(value, dict) and value.get("dify_model_identity") == FILE_MODEL_IDENTITY:
if value["transfer_method"] == FileTransferMethod.TOOL_FILE: if value["transfer_method"] == FileTransferMethod.TOOL_FILE:
value["tool_file_id"] = value["related_id"] value["tool_file_id"] = value["related_id"]
elif value["transfer_method"] == FileTransferMethod.LOCAL_FILE: elif value["transfer_method"] in [FileTransferMethod.LOCAL_FILE, FileTransferMethod.REMOTE_URL]:
value["upload_file_id"] = value["related_id"] value["upload_file_id"] = value["related_id"]
inputs[key] = file_factory.build_from_mapping(mapping=value, tenant_id=value["tenant_id"]) inputs[key] = file_factory.build_from_mapping(mapping=value, tenant_id=value["tenant_id"])
elif isinstance(value, list) and all( elif isinstance(value, list) and all(
@ -686,7 +686,7 @@ class Conversation(Base):
for item in value: for item in value:
if item["transfer_method"] == FileTransferMethod.TOOL_FILE: if item["transfer_method"] == FileTransferMethod.TOOL_FILE:
item["tool_file_id"] = item["related_id"] item["tool_file_id"] = item["related_id"]
elif item["transfer_method"] == FileTransferMethod.LOCAL_FILE: elif item["transfer_method"] in [FileTransferMethod.LOCAL_FILE, FileTransferMethod.REMOTE_URL]:
item["upload_file_id"] = item["related_id"] item["upload_file_id"] = item["related_id"]
inputs[key].append(file_factory.build_from_mapping(mapping=item, tenant_id=item["tenant_id"])) inputs[key].append(file_factory.build_from_mapping(mapping=item, tenant_id=item["tenant_id"]))
@ -946,7 +946,7 @@ class Message(Base):
if isinstance(value, dict) and value.get("dify_model_identity") == FILE_MODEL_IDENTITY: if isinstance(value, dict) and value.get("dify_model_identity") == FILE_MODEL_IDENTITY:
if value["transfer_method"] == FileTransferMethod.TOOL_FILE: if value["transfer_method"] == FileTransferMethod.TOOL_FILE:
value["tool_file_id"] = value["related_id"] value["tool_file_id"] = value["related_id"]
elif value["transfer_method"] == FileTransferMethod.LOCAL_FILE: elif value["transfer_method"] in [FileTransferMethod.LOCAL_FILE, FileTransferMethod.REMOTE_URL]:
value["upload_file_id"] = value["related_id"] value["upload_file_id"] = value["related_id"]
inputs[key] = file_factory.build_from_mapping(mapping=value, tenant_id=value["tenant_id"]) inputs[key] = file_factory.build_from_mapping(mapping=value, tenant_id=value["tenant_id"])
elif isinstance(value, list) and all( elif isinstance(value, list) and all(
@ -956,7 +956,7 @@ class Message(Base):
for item in value: for item in value:
if item["transfer_method"] == FileTransferMethod.TOOL_FILE: if item["transfer_method"] == FileTransferMethod.TOOL_FILE:
item["tool_file_id"] = item["related_id"] item["tool_file_id"] = item["related_id"]
elif item["transfer_method"] == FileTransferMethod.LOCAL_FILE: elif item["transfer_method"] in [FileTransferMethod.LOCAL_FILE, FileTransferMethod.REMOTE_URL]:
item["upload_file_id"] = item["related_id"] item["upload_file_id"] = item["related_id"]
inputs[key].append(file_factory.build_from_mapping(mapping=item, tenant_id=item["tenant_id"])) inputs[key].append(file_factory.build_from_mapping(mapping=item, tenant_id=item["tenant_id"]))
return inputs return inputs

@ -1,6 +1,6 @@
[project] [project]
name = "dify-api" name = "dify-api"
dynamic = ["version"] version = "1.5.1"
requires-python = ">=3.11,<3.13" requires-python = ">=3.11,<3.13"
dependencies = [ dependencies = [

@ -889,7 +889,7 @@ class RegisterService:
TenantService.create_owner_tenant_if_not_exist(account=account, is_setup=True) TenantService.create_owner_tenant_if_not_exist(account=account, is_setup=True)
dify_setup = DifySetup(version=dify_config.CURRENT_VERSION) dify_setup = DifySetup(version=dify_config.project.version)
db.session.add(dify_setup) db.session.add(dify_setup)
db.session.commit() db.session.commit()
except Exception as e: except Exception as e:

File diff suppressed because it is too large Load Diff

@ -7,4 +7,4 @@ cd "$SCRIPT_DIR/.."
# run mypy checks # run mypy checks
uv run --directory api --dev --with pip \ uv run --directory api --dev --with pip \
python -m mypy --install-types --non-interactive ./ python -m mypy --install-types --non-interactive --exclude venv ./

@ -36,6 +36,7 @@ import AccessControl from '@/app/components/app/app-access-control'
import { AccessMode } from '@/models/access-control' import { AccessMode } from '@/models/access-control'
import { useGlobalPublicStore } from '@/context/global-public-context' import { useGlobalPublicStore } from '@/context/global-public-context'
import { formatTime } from '@/utils/time' import { formatTime } from '@/utils/time'
import { useGetUserCanAccessApp } from '@/service/access-control'
export type AppCardProps = { export type AppCardProps = {
app: App app: App
@ -190,6 +191,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
}, [onRefresh, mutateApps, setShowAccessControl]) }, [onRefresh, mutateApps, setShowAccessControl])
const Operations = (props: HtmlContentProps) => { const Operations = (props: HtmlContentProps) => {
const { data: userCanAccessApp, isLoading: isGettingUserCanAccessApp } = useGetUserCanAccessApp({ appId: app?.id, enabled: (!!props?.open && systemFeatures.webapp_auth.enabled) })
const onMouseLeave = async () => { const onMouseLeave = async () => {
props.onClose?.() props.onClose?.()
} }
@ -267,10 +269,14 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
</button> </button>
</> </>
)} )}
<Divider className="my-1" /> {
<button className='mx-1 flex h-8 cursor-pointer items-center gap-2 rounded-lg px-3 hover:bg-state-base-hover' onClick={onClickInstalledApp}> (isGettingUserCanAccessApp || !userCanAccessApp?.result) ? null : <>
<span className='system-sm-regular text-text-secondary'>{t('app.openInExplore')}</span> <Divider className="my-1" />
</button> <button className='mx-1 flex h-8 cursor-pointer items-center gap-2 rounded-lg px-3 hover:bg-state-base-hover' onClick={onClickInstalledApp}>
<span className='system-sm-regular text-text-secondary'>{t('app.openInExplore')}</span>
</button>
</>
}
<Divider className="my-1" /> <Divider className="my-1" />
{ {
systemFeatures.webapp_auth.enabled && isCurrentWorkspaceEditor && <> systemFeatures.webapp_auth.enabled && isCurrentWorkspaceEditor && <>

@ -80,6 +80,8 @@ import {
import PluginDependency from '@/app/components/workflow/plugin-dependency' import PluginDependency from '@/app/components/workflow/plugin-dependency'
import { supportFunctionCall } from '@/utils/tool-call' import { supportFunctionCall } from '@/utils/tool-call'
import { MittProvider } from '@/context/mitt-context' import { MittProvider } from '@/context/mitt-context'
import { fetchAndMergeValidCompletionParams } from '@/utils/completion-params'
import Toast from '@/app/components/base/toast'
type PublishConfig = { type PublishConfig = {
modelConfig: ModelConfig modelConfig: ModelConfig
@ -453,7 +455,21 @@ const Configuration: FC = () => {
...visionConfig, ...visionConfig,
enabled: supportVision, enabled: supportVision,
}, true) }, true)
setCompletionParams({})
try {
const { params: filtered, removedDetails } = await fetchAndMergeValidCompletionParams(
provider,
modelId,
completionParams,
)
if (Object.keys(removedDetails).length)
Toast.notify({ type: 'warning', message: `${t('common.modelProvider.parametersInvalidRemoved')}: ${Object.entries(removedDetails).map(([k, reason]) => `${k} (${reason})`).join(', ')}` })
setCompletionParams(filtered)
}
catch (e) {
Toast.notify({ type: 'error', message: t('common.error') })
setCompletionParams({})
}
} }
const isShowVisionConfig = !!currModel?.features?.includes(ModelFeatureEnum.vision) const isShowVisionConfig = !!currModel?.features?.includes(ModelFeatureEnum.vision)

@ -0,0 +1,27 @@
'use client'
import type { FC } from 'react'
import React from 'react'
import { RiRefreshLine } from '@remixicon/react'
import cn from '@/utils/classnames'
import TooltipPlus from '@/app/components/base/tooltip'
type Props = {
className?: string,
popupContent?: string,
onClick: () => void
}
const SyncButton: FC<Props> = ({
className,
popupContent = '',
onClick,
}) => {
return (
<TooltipPlus popupContent={popupContent}>
<div className={cn(className, 'cursor-pointer select-none rounded-md p-1 hover:bg-state-base-hover')} onClick={onClick}>
<RiRefreshLine className='h-4 w-4 text-text-tertiary' />
</div>
</TooltipPlus>
)
}
export default React.memo(SyncButton)

@ -3,6 +3,7 @@ import { Fragment, cloneElement, useRef } from 'react'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
export type HtmlContentProps = { export type HtmlContentProps = {
open?: boolean
onClose?: () => void onClose?: () => void
onClick?: () => void onClick?: () => void
} }
@ -100,7 +101,8 @@ export default function CustomPopover({
} }
> >
{cloneElement(htmlContent as React.ReactElement, { {cloneElement(htmlContent as React.ReactElement, {
onClose: () => onMouseLeave(open), open,
onClose: close,
...(manualClose ...(manualClose
? { ? {
onClick: close, onClick: close,

@ -30,6 +30,7 @@ import useEditDocumentMetadata from '../metadata/hooks/use-edit-dataset-metadata
import DatasetMetadataDrawer from '../metadata/metadata-dataset/dataset-metadata-drawer' import DatasetMetadataDrawer from '../metadata/metadata-dataset/dataset-metadata-drawer'
import StatusWithAction from '../common/document-status-with-action/status-with-action' import StatusWithAction from '../common/document-status-with-action/status-with-action'
import { useDocLink } from '@/context/i18n' import { useDocLink } from '@/context/i18n'
import { useFetchDefaultProcessRule } from '@/service/knowledge/use-create-dataset'
const FolderPlusIcon = ({ className }: React.SVGProps<SVGElement>) => { const FolderPlusIcon = ({ className }: React.SVGProps<SVGElement>) => {
return <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}> return <svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" className={className ?? ''}>
@ -178,6 +179,8 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
router.push(`/datasets/${datasetId}/documents/create`) router.push(`/datasets/${datasetId}/documents/create`)
} }
const fetchDefaultProcessRuleMutation = useFetchDefaultProcessRule()
const handleSaveNotionPageSelected = async (selectedPages: NotionPage[]) => { const handleSaveNotionPageSelected = async (selectedPages: NotionPage[]) => {
const workspacesMap = groupBy(selectedPages, 'workspace_id') const workspacesMap = groupBy(selectedPages, 'workspace_id')
const workspaces = Object.keys(workspacesMap).map((workspaceId) => { const workspaces = Object.keys(workspacesMap).map((workspaceId) => {
@ -186,6 +189,7 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
pages: workspacesMap[workspaceId], pages: workspacesMap[workspaceId],
} }
}) })
const { rules } = await fetchDefaultProcessRuleMutation.mutateAsync('/datasets/process-rule')
const params = { const params = {
data_source: { data_source: {
type: dataset?.data_source_type, type: dataset?.data_source_type,
@ -209,7 +213,7 @@ const Documents: FC<IDocumentsProps> = ({ datasetId }) => {
}, },
indexing_technique: dataset?.indexing_technique, indexing_technique: dataset?.indexing_technique,
process_rule: { process_rule: {
rules: {}, rules,
mode: ProcessMode.general, mode: ProcessMode.general,
}, },
} as CreateDocumentReq } as CreateDocumentReq

@ -9,6 +9,8 @@ import { useAppContext } from '@/context/app-context'
import { fetchNotionConnection } from '@/service/common' import { fetchNotionConnection } from '@/service/common'
import NotionIcon from '@/app/components/base/notion-icon' import NotionIcon from '@/app/components/base/notion-icon'
import { noop } from 'lodash-es' import { noop } from 'lodash-es'
import { useTranslation } from 'react-i18next'
import Toast from '@/app/components/base/toast'
const Icon: FC<{ const Icon: FC<{
src: string src: string
@ -33,6 +35,7 @@ const DataSourceNotion: FC<Props> = ({
const { isCurrentWorkspaceManager } = useAppContext() const { isCurrentWorkspaceManager } = useAppContext()
const [canConnectNotion, setCanConnectNotion] = useState(false) const [canConnectNotion, setCanConnectNotion] = useState(false)
const { data } = useSWR(canConnectNotion ? '/oauth/data-source/notion' : null, fetchNotionConnection) const { data } = useSWR(canConnectNotion ? '/oauth/data-source/notion' : null, fetchNotionConnection)
const { t } = useTranslation()
const connected = !!workspaces.length const connected = !!workspaces.length
@ -51,9 +54,19 @@ const DataSourceNotion: FC<Props> = ({
} }
useEffect(() => { useEffect(() => {
if (data?.data) if (data && 'data' in data) {
window.location.href = data.data if (data.data && typeof data.data === 'string' && data.data.startsWith('http')) {
}, [data]) window.location.href = data.data
}
else if (data.data === 'internal') {
Toast.notify({
type: 'info',
message: t('common.dataSource.notion.integratedAlert'),
})
}
}
}, [data, t])
return ( return (
<Panel <Panel
type={DataSourceType.notion} type={DataSourceType.notion}

@ -6,9 +6,9 @@ import Item from './item'
import type { Plugin } from '@/app/components/plugins/types.ts' import type { Plugin } from '@/app/components/plugins/types.ts'
import cn from '@/utils/classnames' import cn from '@/utils/classnames'
import Link from 'next/link' import Link from 'next/link'
import { MARKETPLACE_URL_PREFIX } from '@/config'
import { RiArrowRightUpLine, RiSearchLine } from '@remixicon/react' import { RiArrowRightUpLine, RiSearchLine } from '@remixicon/react'
import { noop } from 'lodash-es' import { noop } from 'lodash-es'
import { getMarketplaceUrl } from '@/utils/var'
export type ListProps = { export type ListProps = {
wrapElemRef: React.RefObject<HTMLElement> wrapElemRef: React.RefObject<HTMLElement>
@ -32,7 +32,7 @@ const List = forwardRef<ListRef, ListProps>(({
const { t } = useTranslation() const { t } = useTranslation()
const hasFilter = !searchText const hasFilter = !searchText
const hasRes = list.length > 0 const hasRes = list.length > 0
const urlWithSearchText = `${MARKETPLACE_URL_PREFIX}/?q=${searchText}&tags=${tags.join(',')}` const urlWithSearchText = getMarketplaceUrl('', { q: searchText, tags: tags.join(',') })
const nextToStickyELemRef = useRef<HTMLDivElement>(null) const nextToStickyELemRef = useRef<HTMLDivElement>(null)
const { handleScroll, scrollPosition } = useStickyScroll({ const { handleScroll, scrollPosition } = useStickyScroll({
@ -71,7 +71,7 @@ const List = forwardRef<ListRef, ListProps>(({
return ( return (
<Link <Link
className='system-sm-medium sticky bottom-0 z-10 flex h-8 cursor-pointer items-center rounded-b-lg border-[0.5px] border-t border-components-panel-border bg-components-panel-bg-blur px-4 py-1 text-text-accent-light-mode-only shadow-lg' className='system-sm-medium sticky bottom-0 z-10 flex h-8 cursor-pointer items-center rounded-b-lg border-[0.5px] border-t border-components-panel-border bg-components-panel-bg-blur px-4 py-1 text-text-accent-light-mode-only shadow-lg'
href={`${MARKETPLACE_URL_PREFIX}/`} href={getMarketplaceUrl('')}
target='_blank' target='_blank'
> >
<span>{t('plugin.findMoreInMarketplace')}</span> <span>{t('plugin.findMoreInMarketplace')}</span>

@ -11,12 +11,11 @@ import {
useEditInspectorVar, useEditInspectorVar,
useInvalidateConversationVarValues, useInvalidateConversationVarValues,
useInvalidateSysVarValues, useInvalidateSysVarValues,
useLastRun,
useResetConversationVar, useResetConversationVar,
useResetToLastRunValue, useResetToLastRunValue,
useSysVarValues, useSysVarValues,
} from '@/service/use-workflow' } from '@/service/use-workflow'
import { useCallback, useEffect, useState } from 'react' import { useCallback } from 'react'
import { isConversationVar, isENV, isSystemVar } from '../nodes/_base/components/variable/utils' import { isConversationVar, isENV, isSystemVar } from '../nodes/_base/components/variable/utils'
import produce from 'immer' import produce from 'immer'
import type { Node } from '@/app/components/workflow/types' import type { Node } from '@/app/components/workflow/types'
@ -123,6 +122,7 @@ const useInspectVarsCrud = () => {
nodeType: nodeInfo.data.type, nodeType: nodeInfo.data.type,
title: nodeInfo.data.title, title: nodeInfo.data.title,
vars: payload, vars: payload,
nodePayload: nodeInfo.data,
}) })
} }
else { else {
@ -180,16 +180,6 @@ const useInspectVarsCrud = () => {
invalidateSysVarValues() invalidateSysVarValues()
}, [doEditInspectorVar, invalidateConversationVarValues, invalidateSysVarValues, setInspectVarValue]) }, [doEditInspectorVar, invalidateConversationVarValues, invalidateSysVarValues, setInspectVarValue])
const [currNodeId, setCurrNodeId] = useState<string | null>(null)
const [currEditVarId, setCurrEditVarId] = useState<string | null>(null)
const { data } = useLastRun(appId, currNodeId || '', !!currNodeId)
useEffect(() => {
if (data && currNodeId && currEditVarId) {
const inspectVar = getNodeInspectVars(currNodeId)?.vars?.find(item => item.id === currEditVarId)
resetToLastRunVarInStore(currNodeId, currEditVarId, data.outputs?.[inspectVar?.selector?.[1] || ''])
}
}, [data, currNodeId, currEditVarId, getNodeInspectVars, editInspectVarValue, resetToLastRunVarInStore])
const renameInspectVarName = async (nodeId: string, oldName: string, newName: string) => { const renameInspectVarName = async (nodeId: string, oldName: string, newName: string) => {
const varId = getVarId(nodeId, oldName) const varId = getVarId(nodeId, oldName)
if (!varId) if (!varId)
@ -212,9 +202,13 @@ const useInspectVarsCrud = () => {
}, [getInspectVar]) }, [getInspectVar])
const resetToLastRunVar = async (nodeId: string, varId: string) => { const resetToLastRunVar = async (nodeId: string, varId: string) => {
await doResetToLastRunValue(varId) const isSysVar = nodeId === 'sys'
setCurrNodeId(nodeId) const data = await doResetToLastRunValue(varId)
setCurrEditVarId(varId)
if(isSysVar)
invalidateSysVarValues()
else
resetToLastRunVarInStore(nodeId, varId, data.value)
} }
return { return {

@ -15,7 +15,7 @@ import { pluginManifestToCardPluginProps } from '@/app/components/plugins/instal
import { Badge as Badge2, BadgeState } from '@/app/components/base/badge/index' import { Badge as Badge2, BadgeState } from '@/app/components/base/badge/index'
import Link from 'next/link' import Link from 'next/link'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { MARKETPLACE_URL_PREFIX } from '@/config' import { getMarketplaceUrl } from '@/utils/var'
export type SwitchPluginVersionProps = { export type SwitchPluginVersionProps = {
uniqueIdentifier: string uniqueIdentifier: string
@ -82,7 +82,7 @@ export const SwitchPluginVersion: FC<SwitchPluginVersionProps> = (props) => {
modalBottomLeft={ modalBottomLeft={
<Link <Link
className='flex items-center justify-center gap-1' className='flex items-center justify-center gap-1'
href={`${MARKETPLACE_URL_PREFIX}/plugins/${pluginDetail.declaration.author}/${pluginDetail.declaration.name}`} href={getMarketplaceUrl(`/plugins/${pluginDetail.declaration.author}/${pluginDetail.declaration.name}`)}
target='_blank' target='_blank'
> >
<span className='system-xs-regular text-xs text-text-accent'> <span className='system-xs-regular text-xs text-text-accent'>

@ -65,10 +65,11 @@ const VarList: FC<Props> = ({
}, [list, onVarNameChange, onChange]) }, [list, onVarNameChange, onChange])
const handleVarReferenceChange = useCallback((index: number) => { const handleVarReferenceChange = useCallback((index: number) => {
return (value: ValueSelector | string, varKindType: VarKindType) => { return (value: ValueSelector | string, varKindType: VarKindType, varInfo?: Var) => {
const newList = produce(list, (draft) => { const newList = produce(list, (draft) => {
if (!isSupportConstantValue || varKindType === VarKindType.variable) { if (!isSupportConstantValue || varKindType === VarKindType.variable) {
draft[index].value_selector = value as ValueSelector draft[index].value_selector = value as ValueSelector
draft[index].value_type = varInfo?.type
if (isSupportConstantValue) if (isSupportConstantValue)
draft[index].variable_type = VarKindType.variable draft[index].variable_type = VarKindType.variable

@ -14,6 +14,7 @@ import Split from '@/app/components/workflow/nodes/_base/components/split'
import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor' import CodeEditor from '@/app/components/workflow/nodes/_base/components/editor/code-editor'
import TypeSelector from '@/app/components/workflow/nodes/_base/components/selector' import TypeSelector from '@/app/components/workflow/nodes/_base/components/selector'
import type { NodePanelProps } from '@/app/components/workflow/types' import type { NodePanelProps } from '@/app/components/workflow/types'
import SyncButton from '@/app/components/base/button/sync-button'
const i18nPrefix = 'workflow.nodes.code' const i18nPrefix = 'workflow.nodes.code'
const codeLanguages = [ const codeLanguages = [
@ -40,6 +41,7 @@ const Panel: FC<NodePanelProps<CodeNodeType>> = ({
handleVarListChange, handleVarListChange,
handleAddVariable, handleAddVariable,
handleRemoveVariable, handleRemoveVariable,
handleSyncFunctionSignature,
handleCodeChange, handleCodeChange,
handleCodeLanguageChange, handleCodeLanguageChange,
handleVarsChange, handleVarsChange,
@ -68,7 +70,12 @@ const Panel: FC<NodePanelProps<CodeNodeType>> = ({
<Field <Field
title={t(`${i18nPrefix}.inputVars`)} title={t(`${i18nPrefix}.inputVars`)}
operations={ operations={
!readOnly ? <AddButton onClick={handleAddVariable} /> : undefined !readOnly ? (
<div className="flex gap-2">
<SyncButton popupContent={t(`${i18nPrefix}.syncFunctionSignature`)} onClick={handleSyncFunctionSignature} />
<AddButton onClick={handleAddVariable} />
</div>
) : undefined
} }
> >
<VarList <VarList

@ -84,6 +84,65 @@ const useConfig = (id: string, payload: CodeNodeType) => {
setInputs(newInputs) setInputs(newInputs)
}, [allLanguageDefault, inputs, setInputs]) }, [allLanguageDefault, inputs, setInputs])
const handleSyncFunctionSignature = useCallback(() => {
const generateSyncSignatureCode = (code: string) => {
let mainDefRe
let newMainDef
if (inputs.code_language === CodeLanguage.javascript) {
mainDefRe = /function\s+main\b\s*\([\s\S]*?\)/g
newMainDef = 'function main({{var_list}})'
let param_list = inputs.variables?.map(item => item.variable).join(', ') || ''
param_list = param_list ? `{${param_list}}` : ''
newMainDef = newMainDef.replace('{{var_list}}', param_list)
}
else if (inputs.code_language === CodeLanguage.python3) {
mainDefRe = /def\s+main\b\s*\([\s\S]*?\)/g
const param_list = []
for (const item of inputs.variables) {
let param = item.variable
let param_type = ''
switch (item.value_type) {
case VarType.string:
param_type = ': str'
break
case VarType.number:
param_type = ': float'
break
case VarType.object:
param_type = ': dict'
break
case VarType.array:
param_type = ': list'
break
case VarType.arrayNumber:
param_type = ': list[float]'
break
case VarType.arrayString:
param_type = ': list[str]'
break
case VarType.arrayObject:
param_type = ': list[dict]'
break
}
param += param_type
param_list.push(`${param}`)
}
newMainDef = `def main(${param_list.join(', ')})`
}
else { return code }
const newCode = code.replace(mainDefRe, newMainDef)
return newCode
}
const newInputs = produce(inputs, (draft) => {
draft.code = generateSyncSignatureCode(draft.code)
})
setInputs(newInputs)
}, [inputs, setInputs])
const { const {
handleVarsChange, handleVarsChange,
handleAddVariable: handleAddOutputVariable, handleAddVariable: handleAddOutputVariable,
@ -119,6 +178,7 @@ const useConfig = (id: string, payload: CodeNodeType) => {
handleVarListChange, handleVarListChange,
handleAddVariable, handleAddVariable,
handleRemoveVariable, handleRemoveVariable,
handleSyncFunctionSignature,
handleCodeChange, handleCodeChange,
handleCodeLanguageChange, handleCodeLanguageChange,
handleVarsChange, handleVarsChange,

@ -19,6 +19,8 @@ import Editor from '@/app/components/workflow/nodes/_base/components/prompt/edit
import StructureOutput from './components/structure-output' import StructureOutput from './components/structure-output'
import Switch from '@/app/components/base/switch' import Switch from '@/app/components/base/switch'
import { RiAlertFill, RiQuestionLine } from '@remixicon/react' import { RiAlertFill, RiQuestionLine } from '@remixicon/react'
import { fetchAndMergeValidCompletionParams } from '@/utils/completion-params'
import Toast from '@/app/components/base/toast'
const i18nPrefix = 'workflow.nodes.llm' const i18nPrefix = 'workflow.nodes.llm'
@ -68,10 +70,27 @@ const Panel: FC<NodePanelProps<LLMNodeType>> = ({
modelId: string modelId: string
mode?: string mode?: string
}) => { }) => {
handleCompletionParamsChange({}) (async () => {
handleModelChanged(model) try {
// eslint-disable-next-line react-hooks/exhaustive-deps const { params: filtered, removedDetails } = await fetchAndMergeValidCompletionParams(
}, []) model.provider,
model.modelId,
inputs.model.completion_params,
)
const keys = Object.keys(removedDetails)
if (keys.length)
Toast.notify({ type: 'warning', message: `${t('common.modelProvider.parametersInvalidRemoved')}: ${keys.map(k => `${k} (${removedDetails[k]})`).join(', ')}` })
handleCompletionParamsChange(filtered)
}
catch (e) {
Toast.notify({ type: 'error', message: t('common.error') })
handleCompletionParamsChange({})
}
finally {
handleModelChanged(model)
}
})()
}, [inputs.model.completion_params])
return ( return (
<div className='mt-2'> <div className='mt-2'>

@ -136,6 +136,7 @@ export type Variable = {
variable: string variable: string
} }
value_selector: ValueSelector value_selector: ValueSelector
value_type?: VarType
variable_type?: VarKindType variable_type?: VarKindType
value?: string value?: string
options?: string[] options?: string[]

@ -29,9 +29,10 @@ export const useTabSearchParams = ({
const router = useRouter() const router = useRouter()
const pathName = pathnameFromHook || window?.location?.pathname const pathName = pathnameFromHook || window?.location?.pathname
const searchParams = useSearchParams() const searchParams = useSearchParams()
const searchParamValue = searchParams.has(searchParamName) ? decodeURIComponent(searchParams.get(searchParamName)!) : defaultTab
const [activeTab, setTab] = useState<string>( const [activeTab, setTab] = useState<string>(
!disableSearchParams !disableSearchParams
? (searchParams.get(searchParamName) || defaultTab) ? searchParamValue
: defaultTab, : defaultTab,
) )
@ -39,7 +40,7 @@ export const useTabSearchParams = ({
setTab(newActiveTab) setTab(newActiveTab)
if (disableSearchParams) if (disableSearchParams)
return return
router[`${routingBehavior}`](`${pathName}?${searchParamName}=${newActiveTab}`) router[`${routingBehavior}`](`${pathName}?${searchParamName}=${encodeURIComponent(newActiveTab)}`)
} }
return [activeTab, setActiveTab] as const return [activeTab, setActiveTab] as const

@ -390,6 +390,8 @@ const translation = {
addChildChunk: 'Untergeordneten Block hinzufügen', addChildChunk: 'Untergeordneten Block hinzufügen',
regenerationConfirmTitle: 'Möchten Sie untergeordnete Chunks regenerieren?', regenerationConfirmTitle: 'Möchten Sie untergeordnete Chunks regenerieren?',
searchResults_one: 'ERGEBNIS', searchResults_one: 'ERGEBNIS',
keywordEmpty: 'Das Schlüsselwort darf nicht leer sein.',
keywordDuplicate: 'Das Schlüsselwort existiert bereits',
}, },
} }

@ -199,9 +199,9 @@ const translation = {
accessControl: 'Web App Access Control', accessControl: 'Web App Access Control',
accessItemsDescription: { accessItemsDescription: {
anyone: 'Anyone can access the web app (no login required)', anyone: 'Anyone can access the web app (no login required)',
specific: 'Only specific members within the platform can access the Web application', specific: 'Only specific members within the platform can access the web app',
organization: 'All members within the platform can access the Web application', organization: 'All members within the platform can access the web app',
external: 'Only authenticated external users can access the Web application', external: 'Only authenticated external users can access the web app',
}, },
accessControlDialog: { accessControlDialog: {
title: 'Web App Access Control', title: 'Web App Access Control',
@ -218,7 +218,7 @@ const translation = {
members_one: '{{count}} MEMBER', members_one: '{{count}} MEMBER',
members_other: '{{count}} MEMBERS', members_other: '{{count}} MEMBERS',
noGroupsOrMembers: 'No groups or members selected', noGroupsOrMembers: 'No groups or members selected',
webAppSSONotEnabledTip: 'Please contact your organization administrator to configure external authentication for the Web application.', webAppSSONotEnabledTip: 'Please contact your organization administrator to configure external authentication for the web app.',
operateGroupAndMember: { operateGroupAndMember: {
searchPlaceholder: 'Search groups and members', searchPlaceholder: 'Search groups and members',
allMembers: 'All members', allMembers: 'All members',

@ -456,6 +456,7 @@ const translation = {
connected: 'Connected', connected: 'Connected',
disconnected: 'Disconnected', disconnected: 'Disconnected',
changeAuthorizedPages: 'Change authorized pages', changeAuthorizedPages: 'Change authorized pages',
integratedAlert: 'Notion is integrated via internal credential, no need to re-authorize.',
pagesAuthorized: 'Pages authorized', pagesAuthorized: 'Pages authorized',
sync: 'Sync', sync: 'Sync',
remove: 'Remove', remove: 'Remove',

@ -549,6 +549,7 @@ const translation = {
advancedDependencies: 'Advanced Dependencies', advancedDependencies: 'Advanced Dependencies',
advancedDependenciesTip: 'Add some preloaded dependencies that take more time to consume or are not default built-in here', advancedDependenciesTip: 'Add some preloaded dependencies that take more time to consume or are not default built-in here',
searchDependencies: 'Search Dependencies', searchDependencies: 'Search Dependencies',
syncFunctionSignature: 'Sync function signature to code',
}, },
templateTransform: { templateTransform: {
inputVars: 'Input Variables', inputVars: 'Input Variables',

@ -389,6 +389,8 @@ const translation = {
characters_one: 'carácter', characters_one: 'carácter',
regenerationSuccessMessage: 'Puede cerrar esta ventana.', regenerationSuccessMessage: 'Puede cerrar esta ventana.',
regenerationConfirmTitle: '¿Desea regenerar fragmentos secundarios?', regenerationConfirmTitle: '¿Desea regenerar fragmentos secundarios?',
keywordEmpty: 'La palabra clave no puede estar vacía',
keywordDuplicate: 'La palabra clave ya existe',
}, },
} }

@ -388,6 +388,8 @@ const translation = {
regeneratingMessage: 'این ممکن است یک لحظه طول بکشد، لطفا صبر کنید...', regeneratingMessage: 'این ممکن است یک لحظه طول بکشد، لطفا صبر کنید...',
regenerationConfirmTitle: 'آیا می خواهید تکه های کودک را بازسازی کنید؟', regenerationConfirmTitle: 'آیا می خواهید تکه های کودک را بازسازی کنید؟',
regenerationSuccessMessage: 'می توانید این پنجره را ببندید.', regenerationSuccessMessage: 'می توانید این پنجره را ببندید.',
keywordEmpty: 'کلمه کلیدی نمی‌تواند خالی باشد',
keywordDuplicate: 'این کلیدواژه قبلاً وجود دارد',
}, },
} }

@ -389,6 +389,8 @@ const translation = {
searchResults_zero: 'RÉSULTAT', searchResults_zero: 'RÉSULTAT',
empty: 'Aucun Chunk trouvé', empty: 'Aucun Chunk trouvé',
editChildChunk: 'Modifier le morceau enfant', editChildChunk: 'Modifier le morceau enfant',
keywordDuplicate: 'Le mot-clé existe déjà',
keywordEmpty: 'Le mot-clé ne peut pas être vide.',
}, },
} }

@ -390,6 +390,8 @@ const translation = {
chunkAdded: '1 हिस्सा जोड़ा गया', chunkAdded: '1 हिस्सा जोड़ा गया',
chunkDetail: 'चंक विवरण', chunkDetail: 'चंक विवरण',
regenerationConfirmMessage: 'चाइल्ड चंक्स को रीजनरेट करने से वर्तमान चाइल्ड चंक्स ओवरराइट हो जाएंगे, जिसमें संपादित चंक्स और नए जोड़े गए चंक्स शामिल हैं। पुनरुत्थान को पूर्ववत नहीं किया जा सकता है।', regenerationConfirmMessage: 'चाइल्ड चंक्स को रीजनरेट करने से वर्तमान चाइल्ड चंक्स ओवरराइट हो जाएंगे, जिसमें संपादित चंक्स और नए जोड़े गए चंक्स शामिल हैं। पुनरुत्थान को पूर्ववत नहीं किया जा सकता है।',
keywordDuplicate: 'कीवर्ड पहले से मौजूद है',
keywordEmpty: 'कीवर्ड ख़ाली नहीं हो सकता',
}, },
} }

@ -391,6 +391,8 @@ const translation = {
regenerationSuccessMessage: 'È possibile chiudere questa finestra.', regenerationSuccessMessage: 'È possibile chiudere questa finestra.',
childChunkAdded: '1 blocco figlio aggiunto', childChunkAdded: '1 blocco figlio aggiunto',
childChunks_other: 'BLOCCHI FIGLIO', childChunks_other: 'BLOCCHI FIGLIO',
keywordEmpty: 'La parola chiave non può essere vuota',
keywordDuplicate: 'La parola chiave esiste già',
}, },
} }

@ -388,6 +388,8 @@ const translation = {
editedAt: '編集日時', editedAt: '編集日時',
expandChunks: 'チャンクを展開', expandChunks: 'チャンクを展開',
collapseChunks: 'チャンクを折りたたむ', collapseChunks: 'チャンクを折りたたむ',
keywordDuplicate: 'そのキーワードは既に存在しています',
keywordEmpty: 'キーワードは空であってはいけません',
}, },
} }

@ -550,6 +550,7 @@ const translation = {
advancedDependencies: '高度な依存関係', advancedDependencies: '高度な依存関係',
advancedDependenciesTip: '消費に時間がかかる、またはデフォルトで組み込まれていない事前ロードされた依存関係を追加します', advancedDependenciesTip: '消費に時間がかかる、またはデフォルトで組み込まれていない事前ロードされた依存関係を追加します',
searchDependencies: '依存関係を検索', searchDependencies: '依存関係を検索',
syncFunctionSignature: 'コードの関数署名を同期',
}, },
templateTransform: { templateTransform: {
inputVars: '入力変数', inputVars: '入力変数',

@ -388,6 +388,8 @@ const translation = {
addChunk: '청크 추가 (Add Chunk)', addChunk: '청크 추가 (Add Chunk)',
characters_other: '문자', characters_other: '문자',
regeneratingMessage: '시간이 걸릴 수 있으니 잠시만 기다려 주십시오...', regeneratingMessage: '시간이 걸릴 수 있으니 잠시만 기다려 주십시오...',
keywordDuplicate: '키워드가 이미 존재합니다.',
keywordEmpty: '키워드는 비워둘 수 없습니다.',
}, },
} }

@ -390,6 +390,8 @@ const translation = {
newChildChunk: 'Nowy fragment podrzędny', newChildChunk: 'Nowy fragment podrzędny',
clearFilter: 'Wyczyść filtr', clearFilter: 'Wyczyść filtr',
childChunks_one: 'FRAGMENT POTOMNY', childChunks_one: 'FRAGMENT POTOMNY',
keywordDuplicate: 'Słowo kluczowe już istnieje',
keywordEmpty: 'Słowo kluczowe nie może być puste',
}, },
} }

@ -389,6 +389,8 @@ const translation = {
newChildChunk: 'Novo pedaço filho', newChildChunk: 'Novo pedaço filho',
characters_one: 'personagem', characters_one: 'personagem',
parentChunk: 'Pedaço pai', parentChunk: 'Pedaço pai',
keywordEmpty: 'A palavra-chave não pode estar vazia',
keywordDuplicate: 'A palavra-chave já existe',
}, },
} }

@ -389,6 +389,8 @@ const translation = {
regeneratingTitle: 'Regenerarea bucăților secundare', regeneratingTitle: 'Regenerarea bucăților secundare',
addChildChunk: 'Adăugați o bucată copil', addChildChunk: 'Adăugați o bucată copil',
searchResults_other: 'REZULTATELE', searchResults_other: 'REZULTATELE',
keywordDuplicate: 'Cuvântul cheie există deja',
keywordEmpty: 'Cuvântul cheie nu poate fi gol',
}, },
} }

@ -389,6 +389,8 @@ const translation = {
characters_one: 'характер', characters_one: 'характер',
addChildChunk: 'Добавить дочерний чанк', addChildChunk: 'Добавить дочерний чанк',
newChildChunk: 'Новый дочерний чанк', newChildChunk: 'Новый дочерний чанк',
keywordEmpty: 'Ключевое слово не может быть пустым',
keywordDuplicate: 'Ключевое слово уже существует',
}, },
} }

@ -389,6 +389,8 @@ const translation = {
chunk: 'Kos', chunk: 'Kos',
addChunk: 'Dodajanje kosa', addChunk: 'Dodajanje kosa',
childChunkAdded: 'Dodan je 1 kos otroka', childChunkAdded: 'Dodan je 1 kos otroka',
keywordDuplicate: 'Ključna beseda že obstaja',
keywordEmpty: 'Ključna beseda ne more biti prazna',
}, },
} }

@ -388,6 +388,8 @@ const translation = {
searchResults_other: 'ผลลัพธ์', searchResults_other: 'ผลลัพธ์',
regenerationSuccessMessage: 'คุณสามารถปิดหน้าต่างนี้ได้', regenerationSuccessMessage: 'คุณสามารถปิดหน้าต่างนี้ได้',
childChunks_one: 'ก้อนเด็ก', childChunks_one: 'ก้อนเด็ก',
keywordDuplicate: 'คำสำคัญมีอยู่แล้ว',
keywordEmpty: 'คีย์เวิร์ดไม่สามารถว่างเปล่าได้',
}, },
} }

@ -388,6 +388,8 @@ const translation = {
chunks_other: 'Parçalar', chunks_other: 'Parçalar',
editedAt: 'Şurada düzenlendi:', editedAt: 'Şurada düzenlendi:',
addChildChunk: 'Alt Parça Ekle', addChildChunk: 'Alt Parça Ekle',
keywordDuplicate: 'Anahtar kelime zaten var',
keywordEmpty: 'Anahtar kelime boş olamaz',
}, },
} }

@ -389,6 +389,8 @@ const translation = {
regenerationSuccessMessage: 'Ви можете закрити це вікно.', regenerationSuccessMessage: 'Ви можете закрити це вікно.',
expandChunks: 'Розгортання фрагментів', expandChunks: 'Розгортання фрагментів',
regenerationConfirmTitle: 'Хочете регенерувати дитячі шматки?', regenerationConfirmTitle: 'Хочете регенерувати дитячі шматки?',
keywordEmpty: 'Ключове слово не може бути порожнім',
keywordDuplicate: 'Ключове слово вже існує',
}, },
} }

@ -388,6 +388,8 @@ const translation = {
clearFilter: 'Bộ lọc rõ ràng', clearFilter: 'Bộ lọc rõ ràng',
chunk: 'Khúc', chunk: 'Khúc',
edited: 'EDITED', edited: 'EDITED',
keywordDuplicate: 'Từ khóa đã tồn tại',
keywordEmpty: 'Từ khóa không được để trống',
}, },
} }

@ -387,6 +387,8 @@ const translation = {
editedAt: '编辑于', editedAt: '编辑于',
expandChunks: '展开分段', expandChunks: '展开分段',
collapseChunks: '折叠分段', collapseChunks: '折叠分段',
keywordEmpty: '关键词不能为空',
keywordDuplicate: '关键词已经存在',
}, },
} }

@ -550,6 +550,7 @@ const translation = {
advancedDependencies: '高级依赖', advancedDependencies: '高级依赖',
advancedDependenciesTip: '在这里添加一些预加载需要消耗较多时间或非默认内置的依赖包', advancedDependenciesTip: '在这里添加一些预加载需要消耗较多时间或非默认内置的依赖包',
searchDependencies: '搜索依赖', searchDependencies: '搜索依赖',
syncFunctionSignature: '同步函数签名至代码',
}, },
templateTransform: { templateTransform: {
inputVars: '输入变量', inputVars: '输入变量',

@ -388,6 +388,8 @@ const translation = {
searchResults_zero: '結果', searchResults_zero: '結果',
parentChunks_other: '父塊', parentChunks_other: '父塊',
newChildChunk: '新兒童塊', newChildChunk: '新兒童塊',
keywordEmpty: '關鍵字不能為空',
keywordDuplicate: '關鍵字已經存在',
}, },
} }

@ -544,6 +544,7 @@ const translation = {
advancedDependencies: '高級依賴', advancedDependencies: '高級依賴',
advancedDependenciesTip: '在這裡添加一些預加載需要消耗較多時間或非默認內置的依賴包', advancedDependenciesTip: '在這裡添加一些預加載需要消耗較多時間或非默認內置的依賴包',
searchDependencies: '搜索依賴', searchDependencies: '搜索依賴',
syncFunctionSignature: '同步函數簽名至代碼',
}, },
templateTransform: { templateTransform: {
inputVars: '輸入變量', inputVars: '輸入變量',

@ -103,7 +103,7 @@
"mime": "^4.0.4", "mime": "^4.0.4",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"negotiator": "^0.6.3", "negotiator": "^0.6.3",
"next": "15.2.3", "next": "15.2.4",
"next-themes": "^0.4.3", "next-themes": "^0.4.3",
"pinyin-pro": "^3.25.0", "pinyin-pro": "^3.25.0",
"qrcode.react": "^4.2.0", "qrcode.react": "^4.2.0",
@ -235,7 +235,11 @@
}, },
"pnpm": { "pnpm": {
"overrides": { "overrides": {
"esbuild@<0.25.0": "0.25.0" "esbuild@<0.25.0": "0.25.0",
"pbkdf2@<3.1.3": "3.1.3",
"vite@<6.2.7": "6.2.7",
"prismjs@<1.30.0": "1.30.0",
"brace-expansion@<2.0.2": "2.0.2"
} }
} }
} }

@ -9,6 +9,10 @@ overrides:
'@types/react-dom': ~18.2.0 '@types/react-dom': ~18.2.0
string-width: 4.2.3 string-width: 4.2.3
esbuild@<0.25.0: 0.25.0 esbuild@<0.25.0: 0.25.0
pbkdf2@<3.1.3: 3.1.3
vite@<6.2.7: 6.2.7
prismjs@<1.30.0: 1.30.0
brace-expansion@<2.0.2: 2.0.2
importers: importers:
@ -207,8 +211,8 @@ importers:
specifier: ^0.6.3 specifier: ^0.6.3
version: 0.6.4 version: 0.6.4
next: next:
specifier: 15.2.3 specifier: 15.2.4
version: 15.2.3(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.3) version: 15.2.4(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.3)
next-themes: next-themes:
specifier: ^0.4.3 specifier: ^0.4.3
version: 0.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0) version: 0.4.6(react-dom@19.0.0(react@19.0.0))(react@19.0.0)
@ -392,7 +396,7 @@ importers:
version: 8.5.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.0) version: 8.5.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.0)
'@storybook/nextjs': '@storybook/nextjs':
specifier: 8.5.0 specifier: 8.5.0
version: 8.5.0(esbuild@0.25.0)(next@15.2.3(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.3)(storybook@8.5.0)(type-fest@4.39.1)(typescript@4.9.5)(uglify-js@3.19.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.5(esbuild@0.25.0)(uglify-js@3.19.3)) version: 8.5.0(esbuild@0.25.0)(next@15.2.4(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.3)(storybook@8.5.0)(type-fest@4.39.1)(typescript@4.9.5)(uglify-js@3.19.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.5(esbuild@0.25.0)(uglify-js@3.19.3))
'@storybook/react': '@storybook/react':
specifier: 8.5.0 specifier: 8.5.0
version: 8.5.0(@storybook/test@8.5.0(storybook@8.5.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.0)(typescript@4.9.5) version: 8.5.0(@storybook/test@8.5.0(storybook@8.5.0))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(storybook@8.5.0)(typescript@4.9.5)
@ -2086,8 +2090,8 @@ packages:
'@napi-rs/wasm-runtime@0.2.8': '@napi-rs/wasm-runtime@0.2.8':
resolution: {integrity: sha512-OBlgKdX7gin7OIq4fadsjpg+cp2ZphvAIKucHsNfTdJiqdOmOEwQd/bHi0VwNrcw5xpBJyUw6cK/QilCqy1BSg==} resolution: {integrity: sha512-OBlgKdX7gin7OIq4fadsjpg+cp2ZphvAIKucHsNfTdJiqdOmOEwQd/bHi0VwNrcw5xpBJyUw6cK/QilCqy1BSg==}
'@next/env@15.2.3': '@next/env@15.2.4':
resolution: {integrity: sha512-a26KnbW9DFEUsSxAxKBORR/uD9THoYoKbkpFywMN/AFvboTt94b8+g/07T8J6ACsdLag8/PDU60ov4rPxRAixw==} resolution: {integrity: sha512-+SFtMgoiYP3WoSswuNmxJOCwi06TdWE733D+WPjpXIe4LXGULwEaofiiAy6kbS0+XjM5xF5n3lKuBwN2SnqD9g==}
'@next/eslint-plugin-next@15.3.0': '@next/eslint-plugin-next@15.3.0':
resolution: {integrity: sha512-511UUcpWw5GWTyKfzW58U2F/bYJyjLE9e3SlnGK/zSXq7RqLlqFO8B9bitJjumLpj317fycC96KZ2RZsjGNfBw==} resolution: {integrity: sha512-511UUcpWw5GWTyKfzW58U2F/bYJyjLE9e3SlnGK/zSXq7RqLlqFO8B9bitJjumLpj317fycC96KZ2RZsjGNfBw==}
@ -2103,50 +2107,50 @@ packages:
'@mdx-js/react': '@mdx-js/react':
optional: true optional: true
'@next/swc-darwin-arm64@15.2.3': '@next/swc-darwin-arm64@15.2.4':
resolution: {integrity: sha512-uaBhA8aLbXLqwjnsHSkxs353WrRgQgiFjduDpc7YXEU0B54IKx3vU+cxQlYwPCyC8uYEEX7THhtQQsfHnvv8dw==} resolution: {integrity: sha512-1AnMfs655ipJEDC/FHkSr0r3lXBgpqKo4K1kiwfUf3iE68rDFXZ1TtHdMvf7D0hMItgDZ7Vuq3JgNMbt/+3bYw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [darwin] os: [darwin]
'@next/swc-darwin-x64@15.2.3': '@next/swc-darwin-x64@15.2.4':
resolution: {integrity: sha512-pVwKvJ4Zk7h+4hwhqOUuMx7Ib02u3gDX3HXPKIShBi9JlYllI0nU6TWLbPT94dt7FSi6mSBhfc2JrHViwqbOdw==} resolution: {integrity: sha512-3qK2zb5EwCwxnO2HeO+TRqCubeI/NgCe+kL5dTJlPldV/uwCnUgC7VbEzgmxbfrkbjehL4H9BPztWOEtsoMwew==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [darwin] os: [darwin]
'@next/swc-linux-arm64-gnu@15.2.3': '@next/swc-linux-arm64-gnu@15.2.4':
resolution: {integrity: sha512-50ibWdn2RuFFkOEUmo9NCcQbbV9ViQOrUfG48zHBCONciHjaUKtHcYFiCwBVuzD08fzvzkWuuZkd4AqbvKO7UQ==} resolution: {integrity: sha512-HFN6GKUcrTWvem8AZN7tT95zPb0GUGv9v0d0iyuTb303vbXkkbHDp/DxufB04jNVD+IN9yHy7y/6Mqq0h0YVaQ==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@next/swc-linux-arm64-musl@15.2.3': '@next/swc-linux-arm64-musl@15.2.4':
resolution: {integrity: sha512-2gAPA7P652D3HzR4cLyAuVYwYqjG0mt/3pHSWTCyKZq/N/dJcUAEoNQMyUmwTZWCJRKofB+JPuDVP2aD8w2J6Q==} resolution: {integrity: sha512-Oioa0SORWLwi35/kVB8aCk5Uq+5/ZIumMK1kJV+jSdazFm2NzPDztsefzdmzzpx5oGCJ6FkUC7vkaUseNTStNA==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [linux] os: [linux]
'@next/swc-linux-x64-gnu@15.2.3': '@next/swc-linux-x64-gnu@15.2.4':
resolution: {integrity: sha512-ODSKvrdMgAJOVU4qElflYy1KSZRM3M45JVbeZu42TINCMG3anp7YCBn80RkISV6bhzKwcUqLBAmOiWkaGtBA9w==} resolution: {integrity: sha512-yb5WTRaHdkgOqFOZiu6rHV1fAEK0flVpaIN2HB6kxHVSy/dIajWbThS7qON3W9/SNOH2JWkVCyulgGYekMePuw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@next/swc-linux-x64-musl@15.2.3': '@next/swc-linux-x64-musl@15.2.4':
resolution: {integrity: sha512-ZR9kLwCWrlYxwEoytqPi1jhPd1TlsSJWAc+H/CJHmHkf2nD92MQpSRIURR1iNgA/kuFSdxB8xIPt4p/T78kwsg==} resolution: {integrity: sha512-Dcdv/ix6srhkM25fgXiyOieFUkz+fOYkHlydWCtB0xMST6X9XYI3yPDKBZt1xuhOytONsIFJFB08xXYsxUwJLw==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [linux] os: [linux]
'@next/swc-win32-arm64-msvc@15.2.3': '@next/swc-win32-arm64-msvc@15.2.4':
resolution: {integrity: sha512-+G2FrDcfm2YDbhDiObDU/qPriWeiz/9cRR0yMWJeTLGGX6/x8oryO3tt7HhodA1vZ8r2ddJPCjtLcpaVl7TE2Q==} resolution: {integrity: sha512-dW0i7eukvDxtIhCYkMrZNQfNicPDExt2jPb9AZPpL7cfyUo7QSNl1DjsHjmmKp6qNAqUESyT8YFl/Aw91cNJJg==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [arm64] cpu: [arm64]
os: [win32] os: [win32]
'@next/swc-win32-x64-msvc@15.2.3': '@next/swc-win32-x64-msvc@15.2.4':
resolution: {integrity: sha512-gHYS9tc+G2W0ZC8rBL+H6RdtXIyk40uLiaos0yj5US85FNhbFEndMA2nW3z47nzOWiSvXTZ5kBClc3rD0zJg0w==} resolution: {integrity: sha512-SbnWkJmkS7Xl3kre8SdMF6F/XDh1DTFEhp0jRTj/uB8iPKoU2bb2NDfcu+iifv1+mxQEd1g2vvSxcZbXSKyWiQ==}
engines: {node: '>= 10'} engines: {node: '>= 10'}
cpu: [x64] cpu: [x64]
os: [win32] os: [win32]
@ -3311,7 +3315,7 @@ packages:
resolution: {integrity: sha512-bmpJJm7Y7i9BBELlLuuM1J1Q6EQ6K5Ye4wcyOpOMXMcePYKSIYlpcrCm4l/O6ja4VJA5G2aMJiuZkZdnxlC3SA==} resolution: {integrity: sha512-bmpJJm7Y7i9BBELlLuuM1J1Q6EQ6K5Ye4wcyOpOMXMcePYKSIYlpcrCm4l/O6ja4VJA5G2aMJiuZkZdnxlC3SA==}
peerDependencies: peerDependencies:
msw: ^2.4.9 msw: ^2.4.9
vite: ^5.0.0 || ^6.0.0 vite: 6.2.7
peerDependenciesMeta: peerDependenciesMeta:
msw: msw:
optional: true optional: true
@ -3726,11 +3730,8 @@ packages:
boolbase@1.0.0: boolbase@1.0.0:
resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==}
brace-expansion@1.1.11: brace-expansion@2.0.2:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==}
brace-expansion@2.0.1:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
braces@3.0.3: braces@3.0.3:
resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==}
@ -4076,9 +4077,6 @@ packages:
compare-versions@6.1.1: compare-versions@6.1.1:
resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==}
concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
confbox@0.1.8: confbox@0.1.8:
resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
@ -4134,6 +4132,9 @@ packages:
create-ecdh@4.0.4: create-ecdh@4.0.4:
resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==} resolution: {integrity: sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==}
create-hash@1.1.3:
resolution: {integrity: sha512-snRpch/kwQhcdlnZKYanNF1m0RDlrCdSKQaH87w1FCFPVPNCQ/Il9QJKAX2jVBZddRdaHBMC+zXa9Gw9tmkNUA==}
create-hash@1.2.0: create-hash@1.2.0:
resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==}
@ -5383,6 +5384,9 @@ packages:
has-unicode@2.0.1: has-unicode@2.0.1:
resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==}
hash-base@2.0.2:
resolution: {integrity: sha512-0TROgQ1/SxE6KmxWSvXHvRj90/Xo1JvZShofnYF+f6ZsGtR4eES7WfrQzPalmyagfKZCXpVnitiRebZulWsbiw==}
hash-base@3.0.5: hash-base@3.0.5:
resolution: {integrity: sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==} resolution: {integrity: sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==}
engines: {node: '>= 0.10'} engines: {node: '>= 0.10'}
@ -6565,8 +6569,8 @@ packages:
react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
next@15.2.3: next@15.2.4:
resolution: {integrity: sha512-x6eDkZxk2rPpu46E1ZVUWIBhYCLszmUY6fvHBFcbzJ9dD+qRX6vcHusaqqDlnY+VngKzKbAiG2iRCkPbmi8f7w==} resolution: {integrity: sha512-VwL+LAaPSxEkd3lU2xWbgEOtrM8oedmyhBqaVNmgKB+GvZlCy9rgaEc+y2on0wv+l0oSFqLtYD6dcC1eAedUaQ==}
engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -6859,8 +6863,8 @@ packages:
resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==}
engines: {node: '>= 14.16'} engines: {node: '>= 14.16'}
pbkdf2@3.1.2: pbkdf2@3.1.3:
resolution: {integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==} resolution: {integrity: sha512-wfRLBZ0feWRhCIkoMB6ete7czJcnNnqRpcoWQBLqatqXXmelSRqfdDK4F3u9T2s2cXas/hQJcryI/4lAL+XTlA==}
engines: {node: '>=0.12'} engines: {node: '>=0.12'}
pdfjs-dist@4.4.168: pdfjs-dist@4.4.168:
@ -7042,10 +7046,6 @@ packages:
resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
prismjs@1.27.0:
resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==}
engines: {node: '>=6'}
prismjs@1.30.0: prismjs@1.30.0:
resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==}
engines: {node: '>=6'} engines: {node: '>=6'}
@ -7527,6 +7527,9 @@ packages:
deprecated: Rimraf versions prior to v4 are no longer supported deprecated: Rimraf versions prior to v4 are no longer supported
hasBin: true hasBin: true
ripemd160@2.0.1:
resolution: {integrity: sha512-J7f4wutN8mdbV08MJnXibYpCOPHR+yzy+iQ/AsjMv2j8cLavQ8VGagDFUwwTAdF8FmRKVeNpbTTEwNHCW1g94w==}
ripemd160@2.0.2: ripemd160@2.0.2:
resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==}
@ -8042,6 +8045,10 @@ packages:
tmpl@1.0.5: tmpl@1.0.5:
resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==}
to-buffer@1.2.1:
resolution: {integrity: sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==}
engines: {node: '>= 0.4'}
to-regex-range@5.0.1: to-regex-range@5.0.1:
resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
engines: {node: '>=8.0'} engines: {node: '>=8.0'}
@ -8367,8 +8374,8 @@ packages:
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true hasBin: true
vite@6.2.6: vite@6.2.7:
resolution: {integrity: sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==} resolution: {integrity: sha512-qg3LkeuinTrZoJHHF94coSaTfIPyBYoywp+ys4qu20oSJFbKMYoIJo0FWJT9q6Vp49l6z9IsJRbHdcGtiKbGoQ==}
engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0}
hasBin: true hasBin: true
peerDependencies: peerDependencies:
@ -10565,7 +10572,7 @@ snapshots:
'@tybys/wasm-util': 0.9.0 '@tybys/wasm-util': 0.9.0
optional: true optional: true
'@next/env@15.2.3': {} '@next/env@15.2.4': {}
'@next/eslint-plugin-next@15.3.0': '@next/eslint-plugin-next@15.3.0':
dependencies: dependencies:
@ -10578,28 +10585,28 @@ snapshots:
'@mdx-js/loader': 3.1.0(acorn@8.14.1)(webpack@5.99.5(esbuild@0.25.0)(uglify-js@3.19.3)) '@mdx-js/loader': 3.1.0(acorn@8.14.1)(webpack@5.99.5(esbuild@0.25.0)(uglify-js@3.19.3))
'@mdx-js/react': 3.1.0(@types/react@18.2.79)(react@19.0.0) '@mdx-js/react': 3.1.0(@types/react@18.2.79)(react@19.0.0)
'@next/swc-darwin-arm64@15.2.3': '@next/swc-darwin-arm64@15.2.4':
optional: true optional: true
'@next/swc-darwin-x64@15.2.3': '@next/swc-darwin-x64@15.2.4':
optional: true optional: true
'@next/swc-linux-arm64-gnu@15.2.3': '@next/swc-linux-arm64-gnu@15.2.4':
optional: true optional: true
'@next/swc-linux-arm64-musl@15.2.3': '@next/swc-linux-arm64-musl@15.2.4':
optional: true optional: true
'@next/swc-linux-x64-gnu@15.2.3': '@next/swc-linux-x64-gnu@15.2.4':
optional: true optional: true
'@next/swc-linux-x64-musl@15.2.3': '@next/swc-linux-x64-musl@15.2.4':
optional: true optional: true
'@next/swc-win32-arm64-msvc@15.2.3': '@next/swc-win32-arm64-msvc@15.2.4':
optional: true optional: true
'@next/swc-win32-x64-msvc@15.2.3': '@next/swc-win32-x64-msvc@15.2.4':
optional: true optional: true
'@nodelib/fs.scandir@2.1.5': '@nodelib/fs.scandir@2.1.5':
@ -11211,7 +11218,7 @@ snapshots:
dependencies: dependencies:
storybook: 8.5.0 storybook: 8.5.0
'@storybook/nextjs@8.5.0(esbuild@0.25.0)(next@15.2.3(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.3)(storybook@8.5.0)(type-fest@4.39.1)(typescript@4.9.5)(uglify-js@3.19.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.5(esbuild@0.25.0)(uglify-js@3.19.3))': '@storybook/nextjs@8.5.0(esbuild@0.25.0)(next@15.2.4(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.3)(storybook@8.5.0)(type-fest@4.39.1)(typescript@4.9.5)(uglify-js@3.19.3)(webpack-hot-middleware@2.26.1)(webpack@5.99.5(esbuild@0.25.0)(uglify-js@3.19.3))':
dependencies: dependencies:
'@babel/core': 7.26.10 '@babel/core': 7.26.10
'@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.10) '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.26.10)
@ -11237,7 +11244,7 @@ snapshots:
find-up: 5.0.0 find-up: 5.0.0
image-size: 1.2.1 image-size: 1.2.1
loader-utils: 3.3.1 loader-utils: 3.3.1
next: 15.2.3(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.3) next: 15.2.4(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.3)
node-polyfill-webpack-plugin: 2.0.1(webpack@5.99.5(esbuild@0.25.0)(uglify-js@3.19.3)) node-polyfill-webpack-plugin: 2.0.1(webpack@5.99.5(esbuild@0.25.0)(uglify-js@3.19.3))
pnp-webpack-plugin: 1.7.0(typescript@4.9.5) pnp-webpack-plugin: 1.7.0(typescript@4.9.5)
postcss: 8.5.3 postcss: 8.5.3
@ -11956,13 +11963,13 @@ snapshots:
chai: 5.2.0 chai: 5.2.0
tinyrainbow: 2.0.0 tinyrainbow: 2.0.0
'@vitest/mocker@3.1.1(vite@6.2.6(@types/node@18.15.0)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1))': '@vitest/mocker@3.1.1(vite@6.2.7(@types/node@18.15.0)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1))':
dependencies: dependencies:
'@vitest/spy': 3.1.1 '@vitest/spy': 3.1.1
estree-walker: 3.0.3 estree-walker: 3.0.3
magic-string: 0.30.17 magic-string: 0.30.17
optionalDependencies: optionalDependencies:
vite: 6.2.6(@types/node@18.15.0)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1) vite: 6.2.7(@types/node@18.15.0)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1)
'@vitest/pretty-format@2.0.5': '@vitest/pretty-format@2.0.5':
dependencies: dependencies:
@ -12488,12 +12495,7 @@ snapshots:
boolbase@1.0.0: {} boolbase@1.0.0: {}
brace-expansion@1.1.11: brace-expansion@2.0.2:
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
brace-expansion@2.0.1:
dependencies: dependencies:
balanced-match: 1.0.2 balanced-match: 1.0.2
@ -12846,8 +12848,6 @@ snapshots:
compare-versions@6.1.1: {} compare-versions@6.1.1: {}
concat-map@0.0.1: {}
confbox@0.1.8: {} confbox@0.1.8: {}
confbox@0.2.2: {} confbox@0.2.2: {}
@ -12905,6 +12905,13 @@ snapshots:
bn.js: 4.12.1 bn.js: 4.12.1
elliptic: 6.6.1 elliptic: 6.6.1
create-hash@1.1.3:
dependencies:
cipher-base: 1.0.6
inherits: 2.0.4
ripemd160: 2.0.2
sha.js: 2.4.11
create-hash@1.2.0: create-hash@1.2.0:
dependencies: dependencies:
cipher-base: 1.0.6 cipher-base: 1.0.6
@ -12959,7 +12966,7 @@ snapshots:
diffie-hellman: 5.0.3 diffie-hellman: 5.0.3
hash-base: 3.0.5 hash-base: 3.0.5
inherits: 2.0.4 inherits: 2.0.4
pbkdf2: 3.1.2 pbkdf2: 3.1.3
public-encrypt: 4.0.3 public-encrypt: 4.0.3
randombytes: 2.1.0 randombytes: 2.1.0
randomfill: 1.0.4 randomfill: 1.0.4
@ -14577,6 +14584,10 @@ snapshots:
has-unicode@2.0.1: has-unicode@2.0.1:
optional: true optional: true
hash-base@2.0.2:
dependencies:
inherits: 2.0.4
hash-base@3.0.5: hash-base@3.0.5:
dependencies: dependencies:
inherits: 2.0.4 inherits: 2.0.4
@ -16239,15 +16250,15 @@ snapshots:
minimatch@10.0.1: minimatch@10.0.1:
dependencies: dependencies:
brace-expansion: 2.0.1 brace-expansion: 2.0.2
minimatch@3.1.2: minimatch@3.1.2:
dependencies: dependencies:
brace-expansion: 1.1.11 brace-expansion: 2.0.2
minimatch@9.0.5: minimatch@9.0.5:
dependencies: dependencies:
brace-expansion: 2.0.1 brace-expansion: 2.0.2
minimist@1.2.8: {} minimist@1.2.8: {}
@ -16307,9 +16318,9 @@ snapshots:
react: 19.0.0 react: 19.0.0
react-dom: 19.0.0(react@19.0.0) react-dom: 19.0.0(react@19.0.0)
next@15.2.3(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.3): next@15.2.4(@babel/core@7.26.10)(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.86.3):
dependencies: dependencies:
'@next/env': 15.2.3 '@next/env': 15.2.4
'@swc/counter': 0.1.3 '@swc/counter': 0.1.3
'@swc/helpers': 0.5.15 '@swc/helpers': 0.5.15
busboy: 1.6.0 busboy: 1.6.0
@ -16319,14 +16330,14 @@ snapshots:
react-dom: 19.0.0(react@19.0.0) react-dom: 19.0.0(react@19.0.0)
styled-jsx: 5.1.6(@babel/core@7.26.10)(react@19.0.0) styled-jsx: 5.1.6(@babel/core@7.26.10)(react@19.0.0)
optionalDependencies: optionalDependencies:
'@next/swc-darwin-arm64': 15.2.3 '@next/swc-darwin-arm64': 15.2.4
'@next/swc-darwin-x64': 15.2.3 '@next/swc-darwin-x64': 15.2.4
'@next/swc-linux-arm64-gnu': 15.2.3 '@next/swc-linux-arm64-gnu': 15.2.4
'@next/swc-linux-arm64-musl': 15.2.3 '@next/swc-linux-arm64-musl': 15.2.4
'@next/swc-linux-x64-gnu': 15.2.3 '@next/swc-linux-x64-gnu': 15.2.4
'@next/swc-linux-x64-musl': 15.2.3 '@next/swc-linux-x64-musl': 15.2.4
'@next/swc-win32-arm64-msvc': 15.2.3 '@next/swc-win32-arm64-msvc': 15.2.4
'@next/swc-win32-x64-msvc': 15.2.3 '@next/swc-win32-x64-msvc': 15.2.4
sass: 1.86.3 sass: 1.86.3
sharp: 0.33.5 sharp: 0.33.5
transitivePeerDependencies: transitivePeerDependencies:
@ -16563,7 +16574,7 @@ snapshots:
browserify-aes: 1.2.0 browserify-aes: 1.2.0
evp_bytestokey: 1.0.3 evp_bytestokey: 1.0.3
hash-base: 3.0.5 hash-base: 3.0.5
pbkdf2: 3.1.2 pbkdf2: 3.1.3
safe-buffer: 5.2.1 safe-buffer: 5.2.1
parse-entities@2.0.0: parse-entities@2.0.0:
@ -16644,13 +16655,14 @@ snapshots:
pathval@2.0.0: {} pathval@2.0.0: {}
pbkdf2@3.1.2: pbkdf2@3.1.3:
dependencies: dependencies:
create-hash: 1.2.0 create-hash: 1.1.3
create-hmac: 1.1.7 create-hmac: 1.1.7
ripemd160: 2.0.2 ripemd160: 2.0.1
safe-buffer: 5.2.1 safe-buffer: 5.2.1
sha.js: 2.4.11 sha.js: 2.4.11
to-buffer: 1.2.1
pdfjs-dist@4.4.168: pdfjs-dist@4.4.168:
optionalDependencies: optionalDependencies:
@ -16831,8 +16843,6 @@ snapshots:
ansi-styles: 5.2.0 ansi-styles: 5.2.0
react-is: 18.3.1 react-is: 18.3.1
prismjs@1.27.0: {}
prismjs@1.30.0: {} prismjs@1.30.0: {}
process-nextick-args@2.0.1: {} process-nextick-args@2.0.1: {}
@ -17247,7 +17257,7 @@ snapshots:
dependencies: dependencies:
hastscript: 6.0.0 hastscript: 6.0.0
parse-entities: 2.0.0 parse-entities: 2.0.0
prismjs: 1.27.0 prismjs: 1.30.0
regenerate-unicode-properties@10.2.0: regenerate-unicode-properties@10.2.0:
dependencies: dependencies:
@ -17441,6 +17451,11 @@ snapshots:
dependencies: dependencies:
glob: 7.2.3 glob: 7.2.3
ripemd160@2.0.1:
dependencies:
hash-base: 2.0.2
inherits: 2.0.4
ripemd160@2.0.2: ripemd160@2.0.2:
dependencies: dependencies:
hash-base: 3.0.5 hash-base: 3.0.5
@ -18041,6 +18056,12 @@ snapshots:
tmpl@1.0.5: {} tmpl@1.0.5: {}
to-buffer@1.2.1:
dependencies:
isarray: 2.0.5
safe-buffer: 5.2.1
typed-array-buffer: 1.0.3
to-regex-range@5.0.1: to-regex-range@5.0.1:
dependencies: dependencies:
is-number: 7.0.0 is-number: 7.0.0
@ -18389,7 +18410,7 @@ snapshots:
debug: 4.4.0 debug: 4.4.0
es-module-lexer: 1.6.0 es-module-lexer: 1.6.0
pathe: 2.0.3 pathe: 2.0.3
vite: 6.2.6(@types/node@18.15.0)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1) vite: 6.2.7(@types/node@18.15.0)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1)
transitivePeerDependencies: transitivePeerDependencies:
- '@types/node' - '@types/node'
- jiti - jiti
@ -18404,7 +18425,7 @@ snapshots:
- tsx - tsx
- yaml - yaml
vite@6.2.6(@types/node@18.15.0)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1): vite@6.2.7(@types/node@18.15.0)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1):
dependencies: dependencies:
esbuild: 0.25.2 esbuild: 0.25.2
postcss: 8.5.3 postcss: 8.5.3
@ -18420,7 +18441,7 @@ snapshots:
vitest@3.1.1(@types/debug@4.1.12)(@types/node@18.15.0)(happy-dom@17.4.4)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1): vitest@3.1.1(@types/debug@4.1.12)(@types/node@18.15.0)(happy-dom@17.4.4)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1):
dependencies: dependencies:
'@vitest/expect': 3.1.1 '@vitest/expect': 3.1.1
'@vitest/mocker': 3.1.1(vite@6.2.6(@types/node@18.15.0)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1)) '@vitest/mocker': 3.1.1(vite@6.2.7(@types/node@18.15.0)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1))
'@vitest/pretty-format': 3.1.1 '@vitest/pretty-format': 3.1.1
'@vitest/runner': 3.1.1 '@vitest/runner': 3.1.1
'@vitest/snapshot': 3.1.1 '@vitest/snapshot': 3.1.1
@ -18436,7 +18457,7 @@ snapshots:
tinyexec: 0.3.2 tinyexec: 0.3.2
tinypool: 1.0.2 tinypool: 1.0.2
tinyrainbow: 2.0.0 tinyrainbow: 2.0.0
vite: 6.2.6(@types/node@18.15.0)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1) vite: 6.2.7(@types/node@18.15.0)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1)
vite-node: 3.1.1(@types/node@18.15.0)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1) vite-node: 3.1.1(@types/node@18.15.0)(jiti@1.21.7)(sass@1.86.3)(terser@5.39.0)(yaml@2.7.1)
why-is-node-running: 2.3.0 why-is-node-running: 2.3.0
optionalDependencies: optionalDependencies:

@ -86,5 +86,8 @@ export const useGetUserCanAccessApp = ({ appId, isInstalledApp = true, enabled }
enabled: !!appId && enabled, enabled: !!appId && enabled,
staleTime: 0, staleTime: 0,
gcTime: 0, gcTime: 0,
initialData: {
result: !enabled,
},
}) })
} }

@ -139,7 +139,7 @@ export const useResetConversationVar = (appId: string) => {
export const useResetToLastRunValue = (appId: string) => { export const useResetToLastRunValue = (appId: string) => {
return useMutation({ return useMutation({
mutationKey: [NAME_SPACE, 'reset to last run value', appId], mutationKey: [NAME_SPACE, 'reset to last run value', appId],
mutationFn: async (varId: string) => { mutationFn: async (varId: string): Promise<{ value: any }> => {
return put(`apps/${appId}/workflows/draft/variables/${varId}/reset`) return put(`apps/${appId}/workflows/draft/variables/${varId}/reset`)
}, },
}) })

@ -0,0 +1,88 @@
import type { FormValue, ModelParameterRule } from '@/app/components/header/account-setting/model-provider-page/declarations'
export const mergeValidCompletionParams = (
oldParams: FormValue | undefined,
rules: ModelParameterRule[],
): { params: FormValue; removedDetails: Record<string, string> } => {
if (!oldParams || Object.keys(oldParams).length === 0)
return { params: {}, removedDetails: {} }
const acceptedKeys = new Set(rules.map(r => r.name))
const ruleMap: Record<string, ModelParameterRule> = {}
rules.forEach((r) => {
ruleMap[r.name] = r
})
const nextParams: FormValue = {}
const removedDetails: Record<string, string> = {}
Object.entries(oldParams).forEach(([key, value]) => {
if (!acceptedKeys.has(key)) {
removedDetails[key] = 'unsupported'
return
}
const rule = ruleMap[key]
if (!rule) {
removedDetails[key] = 'unsupported'
return
}
switch (rule.type) {
case 'int':
case 'float': {
if (typeof value !== 'number') {
removedDetails[key] = 'invalid type'
return
}
const min = rule.min ?? Number.NEGATIVE_INFINITY
const max = rule.max ?? Number.POSITIVE_INFINITY
if (value < min || value > max) {
removedDetails[key] = `out of range (${min}-${max})`
return
}
nextParams[key] = value
return
}
case 'boolean': {
if (typeof value !== 'boolean') {
removedDetails[key] = 'invalid type'
return
}
nextParams[key] = value
return
}
case 'string':
case 'text': {
if (typeof value !== 'string') {
removedDetails[key] = 'invalid type'
return
}
if (Array.isArray(rule.options) && rule.options.length) {
if (!(rule.options as string[]).includes(value)) {
removedDetails[key] = 'unsupported option'
return
}
}
nextParams[key] = value
return
}
default: {
removedDetails[key] = `unsupported rule type: ${(rule as any)?.type ?? 'unknown'}`
}
}
})
return { params: nextParams, removedDetails }
}
export const fetchAndMergeValidCompletionParams = async (
provider: string,
modelId: string,
oldParams: FormValue | undefined,
): Promise<{ params: FormValue; removedDetails: Record<string, string> }> => {
const { fetchModelParameterRules } = await import('@/service/common')
const url = `/workspaces/current/model-providers/${provider}/models/parameter-rules?model=${modelId}`
const { data: parameterRules } = await fetchModelParameterRules(url)
return mergeValidCompletionParams(oldParams, parameterRules ?? [])
}
Loading…
Cancel
Save