diff --git a/api/core/model_runtime/model_providers/tongyi/text_embedding/text-embedding-v3.yaml b/api/core/model_runtime/model_providers/tongyi/text_embedding/text-embedding-v3.yaml new file mode 100644 index 0000000000..171a379ee2 --- /dev/null +++ b/api/core/model_runtime/model_providers/tongyi/text_embedding/text-embedding-v3.yaml @@ -0,0 +1,9 @@ +model: text-embedding-v3 +model_type: text-embedding +model_properties: + context_size: 8192 + max_chunks: 25 +pricing: + input: "0.0007" + unit: "0.001" + currency: RMB diff --git a/api/core/ops/entities/config_entity.py b/api/core/ops/entities/config_entity.py index 221e6239ab..447f668e26 100644 --- a/api/core/ops/entities/config_entity.py +++ b/api/core/ops/entities/config_entity.py @@ -21,6 +21,7 @@ class LangfuseConfig(BaseTracingConfig): """ public_key: str secret_key: str + project_key: str host: str = 'https://api.langfuse.com' @field_validator("host") diff --git a/api/core/ops/langfuse_trace/langfuse_trace.py b/api/core/ops/langfuse_trace/langfuse_trace.py index 698398e0cb..a21c67ed50 100644 --- a/api/core/ops/langfuse_trace/langfuse_trace.py +++ b/api/core/ops/langfuse_trace/langfuse_trace.py @@ -419,3 +419,11 @@ class LangFuseDataTrace(BaseTraceInstance): except Exception as e: logger.debug(f"LangFuse API check failed: {str(e)}") raise ValueError(f"LangFuse API check failed: {str(e)}") + + def get_project_key(self): + try: + projects = self.langfuse_client.client.projects.get() + return projects.data[0].id + except Exception as e: + logger.debug(f"LangFuse get project key failed: {str(e)}") + raise ValueError(f"LangFuse get project key failed: {str(e)}") diff --git a/api/core/ops/ops_trace_manager.py b/api/core/ops/ops_trace_manager.py index 068b490ec8..1416d6bd2d 100644 --- a/api/core/ops/ops_trace_manager.py +++ b/api/core/ops/ops_trace_manager.py @@ -38,7 +38,7 @@ provider_config_map = { TracingProviderEnum.LANGFUSE.value: { 'config_class': LangfuseConfig, 'secret_keys': ['public_key', 'secret_key'], - 'other_keys': ['host'], + 'other_keys': ['host', 'project_key'], 'trace_instance': LangFuseDataTrace }, TracingProviderEnum.LANGSMITH.value: { @@ -123,7 +123,6 @@ class OpsTraceManager: for key in other_keys: new_config[key] = decrypt_tracing_config.get(key, "") - return config_class(**new_config).model_dump() @classmethod @@ -252,6 +251,19 @@ class OpsTraceManager: tracing_config = config_type(**tracing_config) return trace_instance(tracing_config).api_check() + @staticmethod + def get_trace_config_project_key(tracing_config: dict, tracing_provider: str): + """ + get trace config is project key + :param tracing_config: tracing config + :param tracing_provider: tracing provider + :return: + """ + config_type, trace_instance = provider_config_map[tracing_provider]['config_class'], \ + provider_config_map[tracing_provider]['trace_instance'] + tracing_config = config_type(**tracing_config) + return trace_instance(tracing_config).get_project_key() + class TraceTask: def __init__( diff --git a/api/services/ops_service.py b/api/services/ops_service.py index ffc12a9acd..7b2edcf7cb 100644 --- a/api/services/ops_service.py +++ b/api/services/ops_service.py @@ -22,6 +22,10 @@ class OpsService: # decrypt_token and obfuscated_token tenant_id = db.session.query(App).filter(App.id == app_id).first().tenant_id decrypt_tracing_config = OpsTraceManager.decrypt_tracing_config(tenant_id, tracing_provider, trace_config_data.tracing_config) + if tracing_provider == 'langfuse' and ('project_key' not in decrypt_tracing_config or not decrypt_tracing_config.get('project_key')): + project_key = OpsTraceManager.get_trace_config_project_key(decrypt_tracing_config, tracing_provider) + decrypt_tracing_config['project_key'] = project_key + decrypt_tracing_config = OpsTraceManager.obfuscated_decrypt_token(tracing_provider, decrypt_tracing_config) trace_config_data.tracing_config = decrypt_tracing_config @@ -37,7 +41,7 @@ class OpsService: :param tracing_config: tracing config :return: """ - if tracing_provider not in provider_config_map.keys() and tracing_provider != None: + if tracing_provider not in provider_config_map.keys() and tracing_provider: return {"error": f"Invalid tracing provider: {tracing_provider}"} config_class, other_keys = provider_config_map[tracing_provider]['config_class'], \ @@ -51,6 +55,9 @@ class OpsService: if not OpsTraceManager.check_trace_config_is_effective(tracing_config, tracing_provider): return {"error": "Invalid Credentials"} + # get project key + project_key = OpsTraceManager.get_trace_config_project_key(tracing_config, tracing_provider) + # check if trace config already exists trace_config_data: TraceAppConfig = db.session.query(TraceAppConfig).filter( TraceAppConfig.app_id == app_id, TraceAppConfig.tracing_provider == tracing_provider @@ -62,6 +69,8 @@ class OpsService: # get tenant id tenant_id = db.session.query(App).filter(App.id == app_id).first().tenant_id tracing_config = OpsTraceManager.encrypt_tracing_config(tenant_id, tracing_provider, tracing_config) + if tracing_provider == 'langfuse': + tracing_config['project_key'] = project_key trace_config_data = TraceAppConfig( app_id=app_id, tracing_provider=tracing_provider, diff --git a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-panel.tsx b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-panel.tsx index 120fe29dff..4a39586064 100644 --- a/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-panel.tsx +++ b/web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/tracing/provider-panel.tsx @@ -6,6 +6,7 @@ import { TracingProvider } from './type' import cn from '@/utils/classnames' import { LangfuseIconBig, LangsmithIconBig } from '@/app/components/base/icons/src/public/tracing' import { Settings04 } from '@/app/components/base/icons/src/vender/line/general' +import { Eye as View } from '@/app/components/base/icons/src/vender/solid/general' const I18N_PREFIX = 'app.tracing' @@ -13,6 +14,7 @@ type Props = { type: TracingProvider readOnly: boolean isChosen: boolean + Config: any onChoose: () => void hasConfigured: boolean onConfig: () => void @@ -29,6 +31,7 @@ const ProviderPanel: FC = ({ type, readOnly, isChosen, + Config, onChoose, hasConfigured, onConfig, @@ -41,6 +44,14 @@ const ProviderPanel: FC = ({ onConfig() }, [onConfig]) + const viewBtnClick = useCallback((e: React.MouseEvent) => { + e.preventDefault() + e.stopPropagation() + + const url = `${Config?.host}/project/${Config?.project_key}` + window.open(url, '_blank', 'noopener,noreferrer') + }, [Config?.host, Config?.project_key]) + const handleChosen = useCallback((e: React.MouseEvent) => { e.stopPropagation() if (isChosen || !hasConfigured || readOnly) @@ -58,12 +69,20 @@ const ProviderPanel: FC = ({ {isChosen &&
{t(`${I18N_PREFIX}.inUse`)}
} {!readOnly && ( -
- -
{t(`${I18N_PREFIX}.config`)}
+
+ {hasConfigured && ( +
+ +
{t(`${I18N_PREFIX}.view`)}
+
+ )} +
+ +
{t(`${I18N_PREFIX}.config`)}
+
)} 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 20fcf49de1..3296c77fb2 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 @@ -42,18 +42,19 @@ const ConfigModal: FC = ({ const { type, label, variable, options, max_length } = tempPayload const isStringInput = type === InputVarType.textInput || type === InputVarType.paragraph + const checkVariableName = useCallback((value: string) => { + const { isValid, errorMessageKey } = checkKeys([value], false) + if (!isValid) { + Toast.notify({ + type: 'error', + message: t(`appDebug.varKeyError.${errorMessageKey}`, { key: t('appDebug.variableConig.varName') }), + }) + return false + } + return true + }, [t]) const handlePayloadChange = useCallback((key: string) => { return (value: any) => { - if (key === 'variable') { - const { isValid, errorKey, errorMessageKey } = checkKeys([value], true) - if (!isValid) { - Toast.notify({ - type: 'error', - message: t(`appDebug.varKeyError.${errorMessageKey}`, { key: errorKey }), - }) - return - } - } setTempPayload((prev) => { const newPayload = { ...prev, @@ -63,19 +64,20 @@ const ConfigModal: FC = ({ return newPayload }) } - }, [t]) + }, []) const handleVarKeyBlur = useCallback((e: any) => { - if (tempPayload.label) + const varName = e.target.value + if (!checkVariableName(varName) || tempPayload.label) return setTempPayload((prev) => { return { ...prev, - label: e.target.value, + label: varName, } }) - }, [tempPayload]) + }, [checkVariableName, tempPayload.label]) const handleConfirm = () => { const moreInfo = tempPayload.variable === payload?.variable @@ -84,10 +86,11 @@ const ConfigModal: FC = ({ type: ChangeType.changeVarName, payload: { beforeKey: payload?.variable || '', afterKey: tempPayload.variable }, } - if (!tempPayload.variable) { - Toast.notify({ type: 'error', message: t('appDebug.variableConig.errorMsg.varNameRequired') }) + + const isVariableNameValid = checkVariableName(tempPayload.variable) + if (!isVariableNameValid) return - } + // TODO: check if key already exists. should the consider the edit case // if (varKeys.map(key => key?.trim()).includes(tempPayload.variable.trim())) { // Toast.notify({ diff --git a/web/app/components/workflow/panel/chat-variable-panel/components/variable-modal.tsx b/web/app/components/workflow/panel/chat-variable-panel/components/variable-modal.tsx index 289e29d592..e6c1ebb5cc 100644 --- a/web/app/components/workflow/panel/chat-variable-panel/components/variable-modal.tsx +++ b/web/app/components/workflow/panel/chat-variable-panel/components/variable-modal.tsx @@ -15,6 +15,7 @@ import type { ConversationVariable } from '@/app/components/workflow/types' import { CodeLanguage } from '@/app/components/workflow/nodes/code/types' import { ChatVarType } from '@/app/components/workflow/panel/chat-variable-panel/type' import cn from '@/utils/classnames' +import { checkKeys } from '@/utils/var' export type ModalPropsType = { chatVar?: ConversationVariable @@ -128,14 +129,16 @@ const ChatVariableModal = ({ } } - const handleNameChange = (v: string) => { - if (!v) - return setName('') - if (!/^[a-zA-Z0-9_]+$/.test(v)) - return notify({ type: 'error', message: 'name is can only contain letters, numbers and underscores' }) - if (/^[0-9]/.test(v)) - return notify({ type: 'error', message: 'name can not start with a number' }) - setName(v) + const checkVariableName = (value: string) => { + const { isValid, errorMessageKey } = checkKeys([value], false) + if (!isValid) { + notify({ + type: 'error', + message: t(`appDebug.varKeyError.${errorMessageKey}`, { key: t('workflow.env.modal.name') }), + }) + return false + } + return true } const handleTypeChange = (v: ChatVarType) => { @@ -211,8 +214,8 @@ const ChatVariableModal = ({ } const handleSave = () => { - if (!name) - return notify({ type: 'error', message: 'name can not be empty' }) + if (!checkVariableName(name)) + return if (!chatVar && varList.some(chatVar => chatVar.name === name)) return notify({ type: 'error', message: 'name is existed' }) // if (type !== ChatVarType.Object && !value) @@ -272,7 +275,8 @@ const ChatVariableModal = ({ className='block px-3 w-full h-8 bg-components-input-bg-normal system-sm-regular radius-md border border-transparent appearance-none outline-none caret-primary-600 hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:bg-components-input-bg-active focus:border-components-input-border-active focus:shadow-xs placeholder:system-sm-regular placeholder:text-components-input-text-placeholder' placeholder={t('workflow.chatVariable.modal.namePlaceholder') || ''} value={name} - onChange={e => handleNameChange(e.target.value)} + onChange={e => setName(e.target.value || '')} + onBlur={e => checkVariableName(e.target.value)} type='text' />
diff --git a/web/app/components/workflow/panel/env-panel/variable-modal.tsx b/web/app/components/workflow/panel/env-panel/variable-modal.tsx index 46f92bd8ed..c62a849f36 100644 --- a/web/app/components/workflow/panel/env-panel/variable-modal.tsx +++ b/web/app/components/workflow/panel/env-panel/variable-modal.tsx @@ -9,6 +9,7 @@ import { ToastContext } from '@/app/components/base/toast' import { useStore } from '@/app/components/workflow/store' import type { EnvironmentVariable } from '@/app/components/workflow/types' import cn from '@/utils/classnames' +import { checkKeys } from '@/utils/var' export type ModalPropsType = { env?: EnvironmentVariable @@ -28,19 +29,21 @@ const VariableModal = ({ const [name, setName] = React.useState('') const [value, setValue] = React.useState() - const handleNameChange = (v: string) => { - if (!v) - return setName('') - if (!/^[a-zA-Z0-9_]+$/.test(v)) - return notify({ type: 'error', message: 'name is can only contain letters, numbers and underscores' }) - if (/^[0-9]/.test(v)) - return notify({ type: 'error', message: 'name can not start with a number' }) - setName(v) + const checkVariableName = (value: string) => { + const { isValid, errorMessageKey } = checkKeys([value], false) + if (!isValid) { + notify({ + type: 'error', + message: t(`appDebug.varKeyError.${errorMessageKey}`, { key: t('workflow.env.modal.name') }), + }) + return false + } + return true } const handleSave = () => { - if (!name) - return notify({ type: 'error', message: 'name can not be empty' }) + if (!checkVariableName(name)) + return if (!value) return notify({ type: 'error', message: 'value can not be empty' }) if (!env && envList.some(env => env.name === name)) @@ -118,7 +121,8 @@ const VariableModal = ({ className='block px-3 w-full h-8 bg-components-input-bg-normal system-sm-regular radius-md border border-transparent appearance-none outline-none caret-primary-600 hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:bg-components-input-bg-active focus:border-components-input-border-active focus:shadow-xs placeholder:system-sm-regular placeholder:text-components-input-text-placeholder' placeholder={t('workflow.env.modal.namePlaceholder') || ''} value={name} - onChange={e => handleNameChange(e.target.value)} + onChange={e => setName(e.target.value || '')} + onBlur={e => checkVariableName(e.target.value)} type='text' /> diff --git a/web/i18n/de-DE/app-debug.ts b/web/i18n/de-DE/app-debug.ts index e78b6c0d7a..acb3f53904 100644 --- a/web/i18n/de-DE/app-debug.ts +++ b/web/i18n/de-DE/app-debug.ts @@ -237,11 +237,11 @@ const translation = { typeSelect: 'Auswählen', }, varKeyError: { - canNoBeEmpty: 'Variablenschlüssel darf nicht leer sein', - tooLong: 'Variablenschlüssel: {{key}} zu lang. Darf nicht länger als 30 Zeichen sein', - notValid: 'Variablenschlüssel: {{key}} ist ungültig. Darf nur Buchstaben, Zahlen und Unterstriche enthalten', - notStartWithNumber: 'Variablenschlüssel: {{key}} darf nicht mit einer Zahl beginnen', - keyAlreadyExists: 'Variablenschlüssel: :{{key}} existiert bereits', + canNoBeEmpty: '{{key}} ist erforderlich', + tooLong: '{{key}} zu lang. Darf nicht länger als 30 Zeichen sein', + notValid: '{{key}} ist ungültig. Darf nur Buchstaben, Zahlen und Unterstriche enthalten', + notStartWithNumber: '{{key}} darf nicht mit einer Zahl beginnen', + keyAlreadyExists: '{{key}} existiert bereits', }, otherError: { promptNoBeEmpty: 'Prompt darf nicht leer sein', diff --git a/web/i18n/de-DE/common.ts b/web/i18n/de-DE/common.ts index a7c7bb58fd..9a66d5b175 100644 --- a/web/i18n/de-DE/common.ts +++ b/web/i18n/de-DE/common.ts @@ -60,6 +60,10 @@ const translation = { ukUA: 'Ukrainisch', viVN: 'Vietnamesisch', plPL: 'Polnisch', + roRO: 'Rumänisch', + hiIN: 'Hindi', + trTR: 'Türkisch', + faIR: 'Persisch', }, }, unit: { diff --git a/web/i18n/en-US/app-debug.ts b/web/i18n/en-US/app-debug.ts index a4e8a4f7fa..86c5f720c3 100644 --- a/web/i18n/en-US/app-debug.ts +++ b/web/i18n/en-US/app-debug.ts @@ -290,11 +290,11 @@ const translation = { typeSelect: 'Select', }, varKeyError: { - canNoBeEmpty: 'Variable key can not be empty', - tooLong: 'Variable key: {{key}} too length. Can not be longer then 30 characters', - notValid: 'Variable key: {{key}} is invalid. Can only contain letters, numbers, and underscores', - notStartWithNumber: 'Variable key: {{key}} can not start with a number', - keyAlreadyExists: 'Variable key: :{{key}} already exists', + canNoBeEmpty: '{{key}} is required', + tooLong: '{{key}} is too length. Can not be longer then 30 characters', + notValid: '{{key}} is invalid. Can only contain letters, numbers, and underscores', + notStartWithNumber: '{{key}} can not start with a number', + keyAlreadyExists: '{{key}} already exists', }, otherError: { promptNoBeEmpty: 'Prompt can not be empty', @@ -323,7 +323,6 @@ const translation = { 'content': 'Content', 'required': 'Required', 'errorMsg': { - varNameRequired: 'Variable name is required', labelNameRequired: 'Label name is required', varNameCanBeRepeat: 'Variable name can not be repeated', atLeastOneOption: 'At least one option is required', diff --git a/web/i18n/en-US/app.ts b/web/i18n/en-US/app.ts index 39b47c8eb4..90724098de 100644 --- a/web/i18n/en-US/app.ts +++ b/web/i18n/en-US/app.ts @@ -95,6 +95,7 @@ const translation = { title: 'Tracing app performance', description: 'Configuring a Third-Party LLMOps provider and tracing app performance.', config: 'Config', + view: 'View', collapse: 'Collapse', expand: 'Expand', tracing: 'Tracing', diff --git a/web/i18n/en-US/common.ts b/web/i18n/en-US/common.ts index d48a9c233e..87dab5cb71 100644 --- a/web/i18n/en-US/common.ts +++ b/web/i18n/en-US/common.ts @@ -55,7 +55,7 @@ const translation = { frFR: 'French', esES: 'Spanish', itIT: 'Italian', - thTH: 'Thai.', + thTH: 'Thai', idID: 'Indonesian', jaJP: 'Japanese', koKR: 'Korean', @@ -64,6 +64,10 @@ const translation = { ukUA: 'Ukrainian', viVN: 'Vietnamese', plPL: 'Polish', + roRO: 'Romanian', + hiIN: 'Hindi', + trTR: 'Türkçe', + faIR: 'Farsi', }, }, unit: { diff --git a/web/i18n/es-ES/app-debug.ts b/web/i18n/es-ES/app-debug.ts index 9e309a7d62..68088c26a6 100644 --- a/web/i18n/es-ES/app-debug.ts +++ b/web/i18n/es-ES/app-debug.ts @@ -248,11 +248,11 @@ const translation = { typeSelect: 'Seleccionar', }, varKeyError: { - canNoBeEmpty: 'La clave de la variable no puede estar vacía', - tooLong: 'Clave de la variable: {{key}} demasiado larga. No puede tener más de 30 caracteres', - notValid: 'Clave de la variable: {{key}} no es válida. Solo puede contener letras, números y guiones bajos', - notStartWithNumber: 'Clave de la variable: {{key}} no puede comenzar con un número', - keyAlreadyExists: 'Clave de la variable: {{key}} ya existe', + canNoBeEmpty: 'Se requiere {{key}}', + tooLong: '{{key}} demasiado larga. No puede tener más de 30 caracteres', + notValid: '{{key}} no es válida. Solo puede contener letras, números y guiones bajos', + notStartWithNumber: '{{key}} no puede comenzar con un número', + keyAlreadyExists: '{{key}} ya existe', }, otherError: { promptNoBeEmpty: 'La indicación no puede estar vacía', diff --git a/web/i18n/es-ES/common.ts b/web/i18n/es-ES/common.ts index 4afc06b098..fc37775263 100644 --- a/web/i18n/es-ES/common.ts +++ b/web/i18n/es-ES/common.ts @@ -64,6 +64,10 @@ const translation = { ukUA: 'Ucraniano', viVN: 'Vietnamita', plPL: 'Polaco', + roRO: 'Rumano', + hiIN: 'Hindi', + trTR: 'Turco', + faIR: 'Persa', }, }, unit: { diff --git a/web/i18n/fa-IR/app-debug.ts b/web/i18n/fa-IR/app-debug.ts index 863f47bb18..1ce222581d 100644 --- a/web/i18n/fa-IR/app-debug.ts +++ b/web/i18n/fa-IR/app-debug.ts @@ -283,11 +283,11 @@ const translation = { typeSelect: 'انتخاب', }, varKeyError: { - canNoBeEmpty: 'کلید متغیر نمی‌تواند خالی باشد', - tooLong: 'کلید متغیر: {{key}} طولانی است. نمی‌تواند بیش از 30 کاراکتر باشد', - notValid: 'کلید متغیر: {{key}} نامعتبر است. فقط می‌تواند شامل حروف، اعداد و زیرخط باشد', - notStartWithNumber: 'کلید متغیر: {{key}} نمی‌تواند با عدد شروع شود', - keyAlreadyExists: 'کلید متغیر: :{{key}} از قبل وجود دارد', + canNoBeEmpty: '{{key}} مطلوب', + tooLong: '{{key}} طولانی است. نمی‌تواند بیش از 30 کاراکتر باشد', + notValid: '{{key}} نامعتبر است. فقط می‌تواند شامل حروف، اعداد و زیرخط باشد', + notStartWithNumber: '{{key}} نمی‌تواند با عدد شروع شود', + keyAlreadyExists: '{{key}} از قبل وجود دارد', }, otherError: { promptNoBeEmpty: 'پرس و جو نمی‌تواند خالی باشد', diff --git a/web/i18n/fa-IR/common.ts b/web/i18n/fa-IR/common.ts index 2b1c4647db..e4417bcbcc 100644 --- a/web/i18n/fa-IR/common.ts +++ b/web/i18n/fa-IR/common.ts @@ -64,6 +64,10 @@ const translation = { ukUA: 'اوکراینی', viVN: 'ویتنامی', plPL: 'لهستانی', + roRO: 'رومانیایی', + hiIN: 'هندی', + trTR: 'ترکی', + faIR: 'فارسی', }, }, unit: { diff --git a/web/i18n/fr-FR/app-debug.ts b/web/i18n/fr-FR/app-debug.ts index 91d2dcb142..b71d251956 100644 --- a/web/i18n/fr-FR/app-debug.ts +++ b/web/i18n/fr-FR/app-debug.ts @@ -237,11 +237,11 @@ const translation = { typeSelect: 'Sélectionner', }, varKeyError: { - canNoBeEmpty: 'La clé variable ne peut pas être vide', - tooLong: 'Variable key: {{key}} too length. Can not be longer then 30 characters', - notValid: 'Variable key: {{key}} is invalid. Can only contain letters, numbers, and underscores', - notStartWithNumber: 'Variable key: {{key}} can not start with a number', - keyAlreadyExists: 'Variable key: :{{key}} already exists', + canNoBeEmpty: '{{key}} est obligatoire', + tooLong: '{{key}} too length. Can not be longer then 30 characters', + notValid: '{{key}} is invalid. Can only contain letters, numbers, and underscores', + notStartWithNumber: '{{key}} can not start with a number', + keyAlreadyExists: '{{key}} already exists', }, otherError: { promptNoBeEmpty: 'Le prompt ne peut pas être vide', diff --git a/web/i18n/fr-FR/common.ts b/web/i18n/fr-FR/common.ts index 424d8e4a99..2ae0731006 100644 --- a/web/i18n/fr-FR/common.ts +++ b/web/i18n/fr-FR/common.ts @@ -51,7 +51,7 @@ const translation = { frFR: 'Français', esES: 'Espagnol', itIT: 'Italien', - thTH: 'Thaï.', + thTH: 'Thaï', idID: 'Indonésien', jaJP: 'Japonais', koKR: 'Coréen', @@ -60,6 +60,10 @@ const translation = { ukUA: 'Ukrainien', viVN: 'Vietnamien', plPL: 'Polonais', + roRO: 'Roumain', + hiIN: 'Hindi', + trTR: 'Turc', + faIR: 'Persan', }, }, unit: { diff --git a/web/i18n/hi-IN/app-debug.ts b/web/i18n/hi-IN/app-debug.ts index 872a1b9fe8..29944c8d84 100644 --- a/web/i18n/hi-IN/app-debug.ts +++ b/web/i18n/hi-IN/app-debug.ts @@ -276,14 +276,14 @@ const translation = { typeSelect: 'चुनें', }, varKeyError: { - canNoBeEmpty: 'वेरिएबल कुंजी खाली नहीं हो सकती', + canNoBeEmpty: '{{key}} आवश्यक है', tooLong: - 'वेरिएबल कुंजी: {{key}} बहुत लंबी है। 30 वर्णों से अधिक नहीं हो सकती', + '{{key}} बहुत लंबी है। 30 वर्णों से अधिक नहीं हो सकती', notValid: - 'वेरिएबल कुंजी: {{key}} अवैध है। केवल अक्षर, संख्याएं, और अंडरस्कोर शामिल हो सकते हैं', + '{{key}} अवैध है। केवल अक्षर, संख्याएं, और अंडरस्कोर शामिल हो सकते हैं', notStartWithNumber: - 'वेरिएबल कुंजी: {{key}} एक संख्या से प्रारंभ नहीं हो सकती', - keyAlreadyExists: 'वेरिएबल कुंजी: {{key}} पहले से मौजूद है', + '{{key}} एक संख्या से प्रारंभ नहीं हो सकती', + keyAlreadyExists: '{{key}} पहले से मौजूद है', }, otherError: { promptNoBeEmpty: 'प्रॉम्प्ट खाली नहीं हो सकता', diff --git a/web/i18n/hi-IN/common.ts b/web/i18n/hi-IN/common.ts index 2be7cddf8f..0a210072e1 100644 --- a/web/i18n/hi-IN/common.ts +++ b/web/i18n/hi-IN/common.ts @@ -64,6 +64,10 @@ const translation = { ukUA: 'यूक्रेनी', viVN: 'वियतनामी', plPL: 'पोलिश', + roRO: 'रोमानियाई', + hiIN: 'हिन्दी', + trTR: 'तुर्की', + faIR: 'फ़ारसी', }, }, unit: { diff --git a/web/i18n/it-IT/app-debug.ts b/web/i18n/it-IT/app-debug.ts index 8efe575945..a4cf7bba2d 100644 --- a/web/i18n/it-IT/app-debug.ts +++ b/web/i18n/it-IT/app-debug.ts @@ -278,14 +278,14 @@ const translation = { typeSelect: 'Seleziona', }, varKeyError: { - canNoBeEmpty: 'La chiave della variabile non può essere vuota', + canNoBeEmpty: '{{key}} è obbligatorio', tooLong: - 'La chiave della variabile: {{key}} è troppo lunga. Non può essere più lunga di 30 caratteri', + '{{key}} è troppo lunga. Non può essere più lunga di 30 caratteri', notValid: - 'La chiave della variabile: {{key}} non è valida. Può contenere solo lettere, numeri e underscore', + '{{key}} non è valida. Può contenere solo lettere, numeri e underscore', notStartWithNumber: - 'La chiave della variabile: {{key}} non può iniziare con un numero', - keyAlreadyExists: 'La chiave della variabile: {{key}} esiste già', + '{{key}} non può iniziare con un numero', + keyAlreadyExists: '{{key}} esiste già', }, otherError: { promptNoBeEmpty: 'Il prompt non può essere vuoto', diff --git a/web/i18n/it-IT/common.ts b/web/i18n/it-IT/common.ts index cc9c34e2dc..595a5075eb 100644 --- a/web/i18n/it-IT/common.ts +++ b/web/i18n/it-IT/common.ts @@ -64,6 +64,10 @@ const translation = { ukUA: 'Ucraino', viVN: 'Vietnamita', plPL: 'Polacco', + roRO: 'Rumeno', + hiIN: 'Hindi', + trTR: 'Turco', + faIR: 'Persiano', }, }, unit: { diff --git a/web/i18n/ja-JP/app-debug.ts b/web/i18n/ja-JP/app-debug.ts index 39ea3386ed..6049be2406 100644 --- a/web/i18n/ja-JP/app-debug.ts +++ b/web/i18n/ja-JP/app-debug.ts @@ -284,11 +284,11 @@ const translation = { typeSelect: '選択', }, varKeyError: { - canNoBeEmpty: '変数キーを空にすることはできません', - tooLong: '変数キー: {{key}} が長すぎます。30文字を超えることはできません', - notValid: '変数キー: {{key}} が無効です。文字、数字、アンダースコアのみを含めることができます', - notStartWithNumber: '変数キー: {{key}} は数字で始めることはできません', - keyAlreadyExists: '変数キー: {{key}} はすでに存在します', + canNoBeEmpty: '{{key}} は必須です', + tooLong: '{{key}} が長すぎます。30文字を超えることはできません', + notValid: '{{key}} が無効です。文字、数字、アンダースコアのみを含めることができます', + notStartWithNumber: '{{key}} は数字で始めることはできません', + keyAlreadyExists: '{{key}} はすでに存在します', }, otherError: { promptNoBeEmpty: 'プロンプトを空にすることはできません', diff --git a/web/i18n/ja-JP/common.ts b/web/i18n/ja-JP/common.ts index f3fb8466f1..fc61141bd3 100644 --- a/web/i18n/ja-JP/common.ts +++ b/web/i18n/ja-JP/common.ts @@ -64,6 +64,10 @@ const translation = { ukUA: 'ウクライナ語', viVN: 'ベトナム語', plPL: 'ポーランド語', + roRO: 'ルーマニア語', + hiIN: 'ヒンディー語', + trTR: 'トルコ語', + faIR: 'ペルシア語', }, }, unit: { diff --git a/web/i18n/ko-KR/app-debug.ts b/web/i18n/ko-KR/app-debug.ts index 77eac2503d..0a2488b64c 100644 --- a/web/i18n/ko-KR/app-debug.ts +++ b/web/i18n/ko-KR/app-debug.ts @@ -248,11 +248,11 @@ const translation = { typeSelect: '선택', }, varKeyError: { - canNoBeEmpty: '변수 키를 비울 수 없습니다', - tooLong: '변수 키: {{key}}가 너무 깁니다. 30자를 넘을 수 없습니다', - notValid: '변수 키: {{key}}가 유효하지 않습니다. 문자, 숫자, 밑줄만 포함할 수 있습니다', - notStartWithNumber: '변수 키: {{key}}는 숫자로 시작할 수 없습니다', - keyAlreadyExists: '변수 키: {{key}}는 이미 존재합니다', + canNoBeEmpty: '{{key}}가 필요합니다', + tooLong: '{{key}}가 너무 깁니다. 30자를 넘을 수 없습니다', + notValid: '{{key}}가 유효하지 않습니다. 문자, 숫자, 밑줄만 포함할 수 있습니다', + notStartWithNumber: '{{key}}는 숫자로 시작할 수 없습니다', + keyAlreadyExists: '{{key}}는 이미 존재합니다', }, otherError: { promptNoBeEmpty: '프롬프트를 비울 수 없습니다', diff --git a/web/i18n/ko-KR/common.ts b/web/i18n/ko-KR/common.ts index 9e78510078..edd0295b89 100644 --- a/web/i18n/ko-KR/common.ts +++ b/web/i18n/ko-KR/common.ts @@ -60,6 +60,10 @@ const translation = { ukUA: '우크라이나어', viVN: '베트남어', plPL: '폴란드어', + roRO: '루마니아어', + hiIN: '힌디어', + trTR: '터키어', + faIR: '페르시아어', }, }, unit: { diff --git a/web/i18n/pl-PL/app-debug.ts b/web/i18n/pl-PL/app-debug.ts index 960209c045..afb412f264 100644 --- a/web/i18n/pl-PL/app-debug.ts +++ b/web/i18n/pl-PL/app-debug.ts @@ -275,14 +275,14 @@ const translation = { typeSelect: 'Wybierz', }, varKeyError: { - canNoBeEmpty: 'Klucz zmiennej nie może być pusty', + canNoBeEmpty: '{{klucz}} jest wymagany', tooLong: - 'Klucz zmiennej: {{key}} za długi. Nie może być dłuższy niż 30 znaków', + '{{key}} za długi. Nie może być dłuższy niż 30 znaków', notValid: - 'Klucz zmiennej: {{key}} jest nieprawidłowy. Może zawierać tylko litery, cyfry i podkreślenia', + '{{key}} jest nieprawidłowy. Może zawierać tylko litery, cyfry i podkreślenia', notStartWithNumber: - 'Klucz zmiennej: {{key}} nie może zaczynać się od cyfry', - keyAlreadyExists: 'Klucz zmiennej: :{{key}} już istnieje', + '{{key}} nie może zaczynać się od cyfry', + keyAlreadyExists: '{{key}} już istnieje', }, otherError: { promptNoBeEmpty: 'Monit nie może być pusty', diff --git a/web/i18n/pl-PL/common.ts b/web/i18n/pl-PL/common.ts index 39572ce09b..1f41abe154 100644 --- a/web/i18n/pl-PL/common.ts +++ b/web/i18n/pl-PL/common.ts @@ -60,6 +60,10 @@ const translation = { ukUA: 'Ukraiński', viVN: 'Wietnamski', plPL: 'Polski', + roRO: 'Rumuński', + hiIN: 'Hindi', + trTR: 'Turecki', + faIR: 'Perski', }, }, unit: { diff --git a/web/i18n/pt-BR/app-debug.ts b/web/i18n/pt-BR/app-debug.ts index 91730d44b3..9605bd5d95 100644 --- a/web/i18n/pt-BR/app-debug.ts +++ b/web/i18n/pt-BR/app-debug.ts @@ -254,11 +254,11 @@ const translation = { typeSelect: 'Selecionar', }, varKeyError: { - canNoBeEmpty: 'A chave da variável não pode estar vazia', - tooLong: 'A chave da variável: {{key}} é muito longa. Não pode ter mais de 30 caracteres', - notValid: 'A chave da variável: {{key}} é inválida. Pode conter apenas letras, números e sublinhados', - notStartWithNumber: 'A chave da variável: {{key}} não pode começar com um número', - keyAlreadyExists: 'A chave da variável: :{{key}} já existe', + canNoBeEmpty: '{{key}} é obrigatório', + tooLong: '{{key}} é muito longa. Não pode ter mais de 30 caracteres', + notValid: '{{key}} é inválida. Pode conter apenas letras, números e sublinhados', + notStartWithNumber: '{{key}} não pode começar com um número', + keyAlreadyExists: '{{key}} já existe', }, otherError: { promptNoBeEmpty: 'A solicitação não pode estar vazia', diff --git a/web/i18n/pt-BR/common.ts b/web/i18n/pt-BR/common.ts index 1b29d06669..f93979404b 100644 --- a/web/i18n/pt-BR/common.ts +++ b/web/i18n/pt-BR/common.ts @@ -60,6 +60,10 @@ const translation = { ukUA: 'Ucraniano', viVN: 'Vietnamita', plPL: 'Polonês', + roRO: 'Romeno', + hiIN: 'Hindi', + trTR: 'Turco', + faIR: 'Persa', }, }, unit: { diff --git a/web/i18n/ro-RO/app-debug.ts b/web/i18n/ro-RO/app-debug.ts index b4e9442de8..7363f2954f 100644 --- a/web/i18n/ro-RO/app-debug.ts +++ b/web/i18n/ro-RO/app-debug.ts @@ -254,11 +254,11 @@ const translation = { typeSelect: 'Selectează', }, varKeyError: { - canNoBeEmpty: 'Cheia variabilei nu poate fi goală', - tooLong: 'Cheia variabilei: {{key}} este prea lungă. Nu poate fi mai lungă de 30 de caractere', - notValid: 'Cheia variabilei: {{key}} este nevalidă. Poate conține doar litere, cifre și sublinieri', - notStartWithNumber: 'Cheia variabilei: {{key}} nu poate începe cu un număr', - keyAlreadyExists: 'Cheia variabilei: :{{key}} deja există', + canNoBeEmpty: '{{key}} este necesară', + tooLong: '{{key}} este prea lungă. Nu poate fi mai lungă de 30 de caractere', + notValid: '{{key}} este nevalidă. Poate conține doar litere, cifre și sublinieri', + notStartWithNumber: '{{key}} nu poate începe cu un număr', + keyAlreadyExists: ':{{key}} deja există', }, otherError: { promptNoBeEmpty: 'Promptul nu poate fi gol', diff --git a/web/i18n/ro-RO/common.ts b/web/i18n/ro-RO/common.ts index e7037f65b8..34ca1c4671 100644 --- a/web/i18n/ro-RO/common.ts +++ b/web/i18n/ro-RO/common.ts @@ -59,6 +59,10 @@ const translation = { ruRU: 'Rusă', ukUA: 'Ucraineană', viVN: 'Vietnameză', + roRO: 'Română', + hiIN: 'Hindi', + trTR: 'Turcă', + faIR: 'Persană', }, }, unit: { diff --git a/web/i18n/tr-TR/app-debug.ts b/web/i18n/tr-TR/app-debug.ts index 889f48c78e..fbf51535fe 100644 --- a/web/i18n/tr-TR/app-debug.ts +++ b/web/i18n/tr-TR/app-debug.ts @@ -290,11 +290,11 @@ const translation = { typeSelect: 'Seçim', }, varKeyError: { - canNoBeEmpty: 'Değişken anahtarı boş olamaz', - tooLong: 'Değişken anahtarı: {{key}} çok uzun. 30 karakterden uzun olamaz', - notValid: 'Değişken anahtarı: {{key}} geçersizdir. Sadece harfler, rakamlar ve altçizgiler içerebilir', - notStartWithNumber: 'Değişken anahtarı: {{key}} bir rakamla başlamamalıdır', - keyAlreadyExists: 'Değişken anahtarı: {{key}} zaten mevcut', + canNoBeEmpty: '{{key}} gereklidir', + tooLong: '{{key}} çok uzun. 30 karakterden uzun olamaz', + notValid: '{{key}} geçersizdir. Sadece harfler, rakamlar ve altçizgiler içerebilir', + notStartWithNumber: '{{key}} bir rakamla başlamamalıdır', + keyAlreadyExists: '{{key}} zaten mevcut', }, otherError: { promptNoBeEmpty: 'Prompt boş olamaz', diff --git a/web/i18n/tr-TR/common.ts b/web/i18n/tr-TR/common.ts index f7981c3f48..a194ffd769 100644 --- a/web/i18n/tr-TR/common.ts +++ b/web/i18n/tr-TR/common.ts @@ -55,7 +55,7 @@ const translation = { frFR: 'French', esES: 'Spanish', itIT: 'Italian', - thTH: 'Thai.', + thTH: 'Thai', idID: 'Indonesian', jaJP: 'Japanese', koKR: 'Korean', @@ -64,6 +64,10 @@ const translation = { ukUA: 'Ukrainian', viVN: 'Vietnamese', plPL: 'Polish', + roRO: 'Romence', + hiIN: 'Hintçe', + trTR: 'Türkçe', + faIR: 'Farsça', }, }, unit: { diff --git a/web/i18n/uk-UA/app-debug.ts b/web/i18n/uk-UA/app-debug.ts index c64444c871..7c0ba45b3c 100644 --- a/web/i18n/uk-UA/app-debug.ts +++ b/web/i18n/uk-UA/app-debug.ts @@ -248,11 +248,11 @@ const translation = { typeSelect: 'Вибрати', // Select }, varKeyError: { - canNoBeEmpty: 'Ключ змінної не може бути порожнім', // Variable key can not be empty - tooLong: 'Ключ змінної: {{key}} занадто довгий. Не може бути більше 30 символів', // Variable key: {{key}} too length. Can not be longer then 30 characters - notValid: 'Ключ змінної: {{key}} недійсний. Може містити лише літери, цифри та підкреслення', // Variable key: {{key}} is invalid. Can only contain letters, numbers, and underscores - notStartWithNumber: 'Ключ змінної: {{key}} не може починатися з цифри', // Variable key: {{key}} can not start with a number - keyAlreadyExists: 'Ключ змінної: :{{key}} вже існує', // Variable key: :{{key}} already exists + canNoBeEmpty: 'Потрібен {{key}}', // Variable key can not be empty + tooLong: '{{key}} занадто довгий. Не може бути більше 30 символів', // Variable key: {{key}} too length. Can not be longer then 30 characters + notValid: '{{key}} недійсний. Може містити лише літери, цифри та підкреслення', // Variable key: {{key}} is invalid. Can only contain letters, numbers, and underscores + notStartWithNumber: '{{key}} не може починатися з цифри', // Variable key: {{key}} can not start with a number + keyAlreadyExists: ':{{key}} вже існує', // Variable key: :{{key}} already exists }, otherError: { promptNoBeEmpty: 'Команда не може бути порожньою', // Prompt can not be empty diff --git a/web/i18n/uk-UA/common.ts b/web/i18n/uk-UA/common.ts index fb0003d35f..33324ce0f2 100644 --- a/web/i18n/uk-UA/common.ts +++ b/web/i18n/uk-UA/common.ts @@ -60,6 +60,10 @@ const translation = { ukUA: 'Українська', viVN: 'В\'є тнамська', plPL: 'Польська', + roRO: 'Румунська', + hiIN: 'Хінді', + trTR: 'Турецька', + faIR: 'Перська', }, }, unit: { diff --git a/web/i18n/vi-VN/app-debug.ts b/web/i18n/vi-VN/app-debug.ts index 4797f768e3..906b39d10a 100644 --- a/web/i18n/vi-VN/app-debug.ts +++ b/web/i18n/vi-VN/app-debug.ts @@ -248,11 +248,11 @@ const translation = { typeSelect: 'Lựa chọn', }, varKeyError: { - canNoBeEmpty: 'Khóa biến không thể trống', - tooLong: 'Khóa biến: {{key}} quá dài. Không thể dài hơn 30 ký tự', - notValid: 'Khóa biến: {{key}} không hợp lệ. Chỉ có thể chứa chữ cái, số, và dấu gạch dưới', - notStartWithNumber: 'Khóa biến: {{key}} không thể bắt đầu bằng số', - keyAlreadyExists: 'Khóa biến: {{key}} đã tồn tại', + canNoBeEmpty: '{{key}} là bắt buộc', + tooLong: '{{key}} quá dài. Không thể dài hơn 30 ký tự', + notValid: '{{key}} không hợp lệ. Chỉ có thể chứa chữ cái, số, và dấu gạch dưới', + notStartWithNumber: '{{key}} không thể bắt đầu bằng số', + keyAlreadyExists: '{{key}} đã tồn tại', }, otherError: { promptNoBeEmpty: 'Lời nhắc không thể trống', diff --git a/web/i18n/vi-VN/common.ts b/web/i18n/vi-VN/common.ts index 232148ce74..19855d31f0 100644 --- a/web/i18n/vi-VN/common.ts +++ b/web/i18n/vi-VN/common.ts @@ -45,6 +45,7 @@ const translation = { voice: { language: { zhHans: 'Tiếng Trung', + zhHant: 'Tiếng Trung phồn thể', enUS: 'Tiếng Anh', deDE: 'Tiếng Đức', frFR: 'Tiếng Pháp', @@ -59,6 +60,10 @@ const translation = { ukUA: 'Tiếng Ukraina', viVN: 'Tiếng Việt', plPL: 'Tiếng Ba Lan', + roRO: 'Tiếng Rumani', + hiIN: 'Tiếng Hindi', + trTR: 'Tiếng Thổ Nhĩ Kỳ', + faIR: 'Tiếng Ba Tư', }, }, unit: { diff --git a/web/i18n/zh-Hans/app-debug.ts b/web/i18n/zh-Hans/app-debug.ts index b95bb8ce51..febf80d786 100644 --- a/web/i18n/zh-Hans/app-debug.ts +++ b/web/i18n/zh-Hans/app-debug.ts @@ -287,11 +287,11 @@ const translation = { typeSelect: '下拉选项', }, varKeyError: { - canNoBeEmpty: '变量不能为空', - tooLong: '变量: {{key}} 长度太长。不能超过 30 个字符', - notValid: '变量: {{key}} 非法。只能包含英文字符,数字和下划线', - notStartWithNumber: '变量: {{key}} 不能以数字开头', - keyAlreadyExists: '变量:{{key}} 已存在', + canNoBeEmpty: '{{key}}必填', + tooLong: '{{key}} 长度太长。不能超过 30 个字符', + notValid: '{{key}} 非法。只能包含英文字符,数字和下划线', + notStartWithNumber: '{{key}} 不能以数字开头', + keyAlreadyExists: '{{key}} 已存在', }, otherError: { promptNoBeEmpty: '提示词不能为空', @@ -320,7 +320,6 @@ const translation = { 'required': '必填', 'content': '内容', 'errorMsg': { - varNameRequired: '变量名称必填', labelNameRequired: '显示名称必填', varNameCanBeRepeat: '变量名称不能重复', atLeastOneOption: '至少需要一个选项', diff --git a/web/i18n/zh-Hans/app.ts b/web/i18n/zh-Hans/app.ts index 6703e1ca95..e12ed1b35d 100644 --- a/web/i18n/zh-Hans/app.ts +++ b/web/i18n/zh-Hans/app.ts @@ -94,6 +94,7 @@ const translation = { title: '追踪应用性能', description: '配置第三方 LLMOps 提供商并跟踪应用程序性能。', config: '配置', + view: '查看', collapse: '折叠', expand: '展开', tracing: '追踪', diff --git a/web/i18n/zh-Hans/common.ts b/web/i18n/zh-Hans/common.ts index e0072e2cba..73cf435a7c 100644 --- a/web/i18n/zh-Hans/common.ts +++ b/web/i18n/zh-Hans/common.ts @@ -64,6 +64,10 @@ const translation = { ukUA: '乌克兰语', viVN: '越南语', plPL: '波兰语', + roRO: '罗马尼亚语', + hiIN: '印地语', + trTR: '土耳其语', + faIR: '波斯语', }, }, unit: { diff --git a/web/i18n/zh-Hant/app-debug.ts b/web/i18n/zh-Hant/app-debug.ts index ec5d536bb9..ca4dfbb0cf 100644 --- a/web/i18n/zh-Hant/app-debug.ts +++ b/web/i18n/zh-Hant/app-debug.ts @@ -233,11 +233,11 @@ const translation = { typeSelect: '下拉選項', }, varKeyError: { - canNoBeEmpty: '變數不能為空', - tooLong: '變數: {{key}} 長度太長。不能超過 30 個字元', - notValid: '變數: {{key}} 非法。只能包含英文字元,數字和下劃線', - notStartWithNumber: '變數: {{key}} 不能以數字開頭', - keyAlreadyExists: '變數:{{key}} 已存在', + canNoBeEmpty: '{{key}} 是必要的', + tooLong: '{{key}} 長度太長。不能超過 30 個字元', + notValid: '{{key}} 非法。只能包含英文字元,數字和下劃線', + notStartWithNumber: '{{key}} 不能以數字開頭', + keyAlreadyExists: '{{key}} 已存在', }, otherError: { promptNoBeEmpty: '提示詞不能為空', diff --git a/web/i18n/zh-Hant/app.ts b/web/i18n/zh-Hant/app.ts index 4b915b7f2d..ff162c5b61 100644 --- a/web/i18n/zh-Hant/app.ts +++ b/web/i18n/zh-Hant/app.ts @@ -90,6 +90,7 @@ const translation = { title: '追蹤應用程式效能', description: '配置第三方LLMOps提供商並追蹤應用程式效能。', config: '配置', + view: '查看', collapse: '收起', expand: '展開', tracing: '追蹤', diff --git a/web/i18n/zh-Hant/common.ts b/web/i18n/zh-Hant/common.ts index f4d6952f76..e14c3c3196 100644 --- a/web/i18n/zh-Hant/common.ts +++ b/web/i18n/zh-Hant/common.ts @@ -60,6 +60,10 @@ const translation = { ukUA: '烏克蘭語', viVN: '越南語', plPL: '波蘭語', + roRO: '羅馬尼亞語', + hiIN: '印地語', + trTR: '土耳其語', + faIR: '波斯語', }, }, unit: { diff --git a/web/yarn.lock b/web/yarn.lock index f6a6694b51..d50aa33f3e 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -9373,4 +9373,4 @@ zustand@^4.4.1, zustand@^4.5.2: zwitch@^2.0.0: version "2.0.4" resolved "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz" - integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A== + integrity sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A== \ No newline at end of file