Merge remote-tracking branch 'origin/main' into feat/support-agent-sandbox

This commit is contained in:
yyh
2026-02-09 18:43:04 +08:00
920 changed files with 4057 additions and 3430 deletions

View File

@@ -34,6 +34,7 @@ from .dataset import (
metadata,
segment,
)
from .dataset.rag_pipeline import rag_pipeline_workflow
from .end_user import end_user
from .workspace import models
@@ -53,6 +54,7 @@ __all__ = [
"message",
"metadata",
"models",
"rag_pipeline_workflow",
"segment",
"site",
"workflow",

View File

@@ -1,5 +1,3 @@
import string
import uuid
from collections.abc import Generator
from typing import Any
@@ -12,6 +10,7 @@ from controllers.common.errors import FilenameNotExistsError, NoFileUploadedErro
from controllers.common.schema import register_schema_model
from controllers.service_api import service_api_ns
from controllers.service_api.dataset.error import PipelineRunError
from controllers.service_api.dataset.rag_pipeline.serializers import serialize_upload_file
from controllers.service_api.wraps import DatasetApiResource
from core.app.apps.pipeline.pipeline_generator import PipelineGenerator
from core.app.entities.app_invoke_entities import InvokeFrom
@@ -41,7 +40,7 @@ register_schema_model(service_api_ns, DatasourceNodeRunPayload)
register_schema_model(service_api_ns, PipelineRunApiEntity)
@service_api_ns.route(f"/datasets/{uuid:dataset_id}/pipeline/datasource-plugins")
@service_api_ns.route("/datasets/<uuid:dataset_id>/pipeline/datasource-plugins")
class DatasourcePluginsApi(DatasetApiResource):
"""Resource for datasource plugins."""
@@ -76,7 +75,7 @@ class DatasourcePluginsApi(DatasetApiResource):
return datasource_plugins, 200
@service_api_ns.route(f"/datasets/{uuid:dataset_id}/pipeline/datasource/nodes/{string:node_id}/run")
@service_api_ns.route("/datasets/<uuid:dataset_id>/pipeline/datasource/nodes/<string:node_id>/run")
class DatasourceNodeRunApi(DatasetApiResource):
"""Resource for datasource node run."""
@@ -131,7 +130,7 @@ class DatasourceNodeRunApi(DatasetApiResource):
)
@service_api_ns.route(f"/datasets/{uuid:dataset_id}/pipeline/run")
@service_api_ns.route("/datasets/<uuid:dataset_id>/pipeline/run")
class PipelineRunApi(DatasetApiResource):
"""Resource for datasource node run."""
@@ -232,12 +231,4 @@ class KnowledgebasePipelineFileUploadApi(DatasetApiResource):
except services.errors.file.UnsupportedFileTypeError:
raise UnsupportedFileTypeError()
return {
"id": upload_file.id,
"name": upload_file.name,
"size": upload_file.size,
"extension": upload_file.extension,
"mime_type": upload_file.mime_type,
"created_by": upload_file.created_by,
"created_at": upload_file.created_at,
}, 201
return serialize_upload_file(upload_file), 201

View File

@@ -0,0 +1,22 @@
"""
Serialization helpers for Service API knowledge pipeline endpoints.
"""
from __future__ import annotations
from typing import TYPE_CHECKING, Any
if TYPE_CHECKING:
from models.model import UploadFile
def serialize_upload_file(upload_file: UploadFile) -> dict[str, Any]:
return {
"id": upload_file.id,
"name": upload_file.name,
"size": upload_file.size,
"extension": upload_file.extension,
"mime_type": upload_file.mime_type,
"created_by": upload_file.created_by,
"created_at": upload_file.created_at.isoformat() if upload_file.created_at else None,
}

View File

@@ -217,6 +217,8 @@ def validate_dataset_token(view: Callable[Concatenate[T, P], R] | None = None):
def decorator(view: Callable[Concatenate[T, P], R]):
@wraps(view)
def decorated(*args: P.args, **kwargs: P.kwargs):
api_token = validate_and_get_api_token("dataset")
# get url path dataset_id from positional args or kwargs
# Flask passes URL path parameters as positional arguments
dataset_id = None
@@ -253,12 +255,18 @@ def validate_dataset_token(view: Callable[Concatenate[T, P], R] | None = None):
# Validate dataset if dataset_id is provided
if dataset_id:
dataset_id = str(dataset_id)
dataset = db.session.query(Dataset).where(Dataset.id == dataset_id).first()
dataset = (
db.session.query(Dataset)
.where(
Dataset.id == dataset_id,
Dataset.tenant_id == api_token.tenant_id,
)
.first()
)
if not dataset:
raise NotFound("Dataset not found.")
if not dataset.enable_api:
raise Forbidden("Dataset api access is not enabled.")
api_token = validate_and_get_api_token("dataset")
tenant_account_join = (
db.session.query(Tenant, TenantAccountJoin)
.where(Tenant.id == api_token.tenant_id)

View File

@@ -1329,10 +1329,24 @@ class RagPipelineService:
"""
Get datasource plugins
"""
dataset: Dataset | None = db.session.query(Dataset).where(Dataset.id == dataset_id).first()
dataset: Dataset | None = (
db.session.query(Dataset)
.where(
Dataset.id == dataset_id,
Dataset.tenant_id == tenant_id,
)
.first()
)
if not dataset:
raise ValueError("Dataset not found")
pipeline: Pipeline | None = db.session.query(Pipeline).where(Pipeline.id == dataset.pipeline_id).first()
pipeline: Pipeline | None = (
db.session.query(Pipeline)
.where(
Pipeline.id == dataset.pipeline_id,
Pipeline.tenant_id == tenant_id,
)
.first()
)
if not pipeline:
raise ValueError("Pipeline not found")
@@ -1413,10 +1427,24 @@ class RagPipelineService:
"""
Get pipeline
"""
dataset: Dataset | None = db.session.query(Dataset).where(Dataset.id == dataset_id).first()
dataset: Dataset | None = (
db.session.query(Dataset)
.where(
Dataset.id == dataset_id,
Dataset.tenant_id == tenant_id,
)
.first()
)
if not dataset:
raise ValueError("Dataset not found")
pipeline: Pipeline | None = db.session.query(Pipeline).where(Pipeline.id == dataset.pipeline_id).first()
pipeline: Pipeline | None = (
db.session.query(Pipeline)
.where(
Pipeline.id == dataset.pipeline_id,
Pipeline.tenant_id == tenant_id,
)
.first()
)
if not pipeline:
raise ValueError("Pipeline not found")
return pipeline

View File

@@ -23,40 +23,40 @@ def clean_notion_document_task(document_ids: list[str], dataset_id: str):
"""
logger.info(click.style(f"Start clean document when import form notion document deleted: {dataset_id}", fg="green"))
start_at = time.perf_counter()
total_index_node_ids = []
with session_factory.create_session() as session:
try:
dataset = session.query(Dataset).where(Dataset.id == dataset_id).first()
dataset = session.query(Dataset).where(Dataset.id == dataset_id).first()
if not dataset:
raise Exception("Document has no dataset")
index_type = dataset.doc_form
index_processor = IndexProcessorFactory(index_type).init_index_processor()
if not dataset:
raise Exception("Document has no dataset")
index_type = dataset.doc_form
index_processor = IndexProcessorFactory(index_type).init_index_processor()
document_delete_stmt = delete(Document).where(Document.id.in_(document_ids))
session.execute(document_delete_stmt)
document_delete_stmt = delete(Document).where(Document.id.in_(document_ids))
session.execute(document_delete_stmt)
for document_id in document_ids:
segments = session.scalars(
select(DocumentSegment).where(DocumentSegment.document_id == document_id)
).all()
index_node_ids = [segment.index_node_id for segment in segments]
for document_id in document_ids:
segments = session.scalars(select(DocumentSegment).where(DocumentSegment.document_id == document_id)).all()
total_index_node_ids.extend([segment.index_node_id for segment in segments])
index_processor.clean(
dataset, index_node_ids, with_keywords=True, delete_child_chunks=True, delete_summaries=True
)
segment_ids = [segment.id for segment in segments]
segment_delete_stmt = delete(DocumentSegment).where(DocumentSegment.id.in_(segment_ids))
session.execute(segment_delete_stmt)
session.commit()
end_at = time.perf_counter()
logger.info(
click.style(
"Clean document when import form notion document deleted end :: {} latency: {}".format(
dataset_id, end_at - start_at
),
fg="green",
)
with session_factory.create_session() as session:
dataset = session.query(Dataset).where(Dataset.id == dataset_id).first()
if dataset:
index_processor.clean(
dataset, total_index_node_ids, with_keywords=True, delete_child_chunks=True, delete_summaries=True
)
except Exception:
logger.exception("Cleaned document when import form notion document deleted failed")
with session_factory.create_session() as session, session.begin():
segment_delete_stmt = delete(DocumentSegment).where(DocumentSegment.document_id.in_(document_ids))
session.execute(segment_delete_stmt)
end_at = time.perf_counter()
logger.info(
click.style(
"Clean document when import form notion document deleted end :: {} latency: {}".format(
dataset_id, end_at - start_at
),
fg="green",
)
)

View File

@@ -27,6 +27,7 @@ def document_indexing_sync_task(dataset_id: str, document_id: str):
"""
logger.info(click.style(f"Start sync document: {document_id}", fg="green"))
start_at = time.perf_counter()
tenant_id = None
with session_factory.create_session() as session, session.begin():
document = session.query(Document).where(Document.id == document_id, Document.dataset_id == dataset_id).first()
@@ -35,94 +36,120 @@ def document_indexing_sync_task(dataset_id: str, document_id: str):
logger.info(click.style(f"Document not found: {document_id}", fg="red"))
return
if document.indexing_status == "parsing":
logger.info(click.style(f"Document {document_id} is already being processed, skipping", fg="yellow"))
return
dataset = session.query(Dataset).where(Dataset.id == dataset_id).first()
if not dataset:
raise Exception("Dataset not found")
data_source_info = document.data_source_info_dict
if document.data_source_type == "notion_import":
if (
not data_source_info
or "notion_page_id" not in data_source_info
or "notion_workspace_id" not in data_source_info
):
raise ValueError("no notion page found")
workspace_id = data_source_info["notion_workspace_id"]
page_id = data_source_info["notion_page_id"]
page_type = data_source_info["type"]
page_edited_time = data_source_info["last_edited_time"]
credential_id = data_source_info.get("credential_id")
if document.data_source_type != "notion_import":
logger.info(click.style(f"Document {document_id} is not a notion_import, skipping", fg="yellow"))
return
# Get credentials from datasource provider
datasource_provider_service = DatasourceProviderService()
credential = datasource_provider_service.get_datasource_credentials(
tenant_id=document.tenant_id,
credential_id=credential_id,
provider="notion_datasource",
plugin_id="langgenius/notion_datasource",
)
if (
not data_source_info
or "notion_page_id" not in data_source_info
or "notion_workspace_id" not in data_source_info
):
raise ValueError("no notion page found")
if not credential:
logger.error(
"Datasource credential not found for document %s, tenant_id: %s, credential_id: %s",
document_id,
document.tenant_id,
credential_id,
)
workspace_id = data_source_info["notion_workspace_id"]
page_id = data_source_info["notion_page_id"]
page_type = data_source_info["type"]
page_edited_time = data_source_info["last_edited_time"]
credential_id = data_source_info.get("credential_id")
tenant_id = document.tenant_id
index_type = document.doc_form
segments = session.scalars(select(DocumentSegment).where(DocumentSegment.document_id == document_id)).all()
index_node_ids = [segment.index_node_id for segment in segments]
# Get credentials from datasource provider
datasource_provider_service = DatasourceProviderService()
credential = datasource_provider_service.get_datasource_credentials(
tenant_id=tenant_id,
credential_id=credential_id,
provider="notion_datasource",
plugin_id="langgenius/notion_datasource",
)
if not credential:
logger.error(
"Datasource credential not found for document %s, tenant_id: %s, credential_id: %s",
document_id,
tenant_id,
credential_id,
)
with session_factory.create_session() as session, session.begin():
document = session.query(Document).filter_by(id=document_id).first()
if document:
document.indexing_status = "error"
document.error = "Datasource credential not found. Please reconnect your Notion workspace."
document.stopped_at = naive_utc_now()
return
return
loader = NotionExtractor(
notion_workspace_id=workspace_id,
notion_obj_id=page_id,
notion_page_type=page_type,
notion_access_token=credential.get("integration_secret"),
tenant_id=document.tenant_id,
)
loader = NotionExtractor(
notion_workspace_id=workspace_id,
notion_obj_id=page_id,
notion_page_type=page_type,
notion_access_token=credential.get("integration_secret"),
tenant_id=tenant_id,
)
last_edited_time = loader.get_notion_last_edited_time()
last_edited_time = loader.get_notion_last_edited_time()
if last_edited_time == page_edited_time:
logger.info(click.style(f"Document {document_id} content unchanged, skipping sync", fg="yellow"))
return
# check the page is updated
if last_edited_time != page_edited_time:
document.indexing_status = "parsing"
document.processing_started_at = naive_utc_now()
logger.info(click.style(f"Document {document_id} content changed, starting sync", fg="green"))
# delete all document segment and index
try:
dataset = session.query(Dataset).where(Dataset.id == dataset_id).first()
if not dataset:
raise Exception("Dataset not found")
index_type = document.doc_form
index_processor = IndexProcessorFactory(index_type).init_index_processor()
try:
index_processor = IndexProcessorFactory(index_type).init_index_processor()
with session_factory.create_session() as session:
dataset = session.query(Dataset).where(Dataset.id == dataset_id).first()
if dataset:
index_processor.clean(dataset, index_node_ids, with_keywords=True, delete_child_chunks=True)
logger.info(click.style(f"Cleaned vector index for document {document_id}", fg="green"))
except Exception:
logger.exception("Failed to clean vector index for document %s", document_id)
segments = session.scalars(
select(DocumentSegment).where(DocumentSegment.document_id == document_id)
).all()
index_node_ids = [segment.index_node_id for segment in segments]
with session_factory.create_session() as session, session.begin():
document = session.query(Document).filter_by(id=document_id).first()
if not document:
logger.warning(click.style(f"Document {document_id} not found during sync", fg="yellow"))
return
# delete from vector index
index_processor.clean(dataset, index_node_ids, with_keywords=True, delete_child_chunks=True)
data_source_info = document.data_source_info_dict
data_source_info["last_edited_time"] = last_edited_time
document.data_source_info = data_source_info
segment_ids = [segment.id for segment in segments]
segment_delete_stmt = delete(DocumentSegment).where(DocumentSegment.id.in_(segment_ids))
session.execute(segment_delete_stmt)
document.indexing_status = "parsing"
document.processing_started_at = naive_utc_now()
end_at = time.perf_counter()
logger.info(
click.style(
"Cleaned document when document update data source or process rule: {} latency: {}".format(
document_id, end_at - start_at
),
fg="green",
)
)
except Exception:
logger.exception("Cleaned document when document update data source or process rule failed")
segment_delete_stmt = delete(DocumentSegment).where(DocumentSegment.document_id == document_id)
session.execute(segment_delete_stmt)
try:
indexing_runner = IndexingRunner()
indexing_runner.run([document])
end_at = time.perf_counter()
logger.info(click.style(f"update document: {document.id} latency: {end_at - start_at}", fg="green"))
except DocumentIsPausedError as ex:
logger.info(click.style(str(ex), fg="yellow"))
except Exception:
logger.exception("document_indexing_sync_task failed, document_id: %s", document_id)
logger.info(click.style(f"Deleted segments for document {document_id}", fg="green"))
try:
indexing_runner = IndexingRunner()
with session_factory.create_session() as session:
document = session.query(Document).filter_by(id=document_id).first()
if document:
indexing_runner.run([document])
end_at = time.perf_counter()
logger.info(click.style(f"Sync completed for document {document_id} latency: {end_at - start_at}", fg="green"))
except DocumentIsPausedError as ex:
logger.info(click.style(str(ex), fg="yellow"))
except Exception as e:
logger.exception("document_indexing_sync_task failed for document_id: %s", document_id)
with session_factory.create_session() as session, session.begin():
document = session.query(Document).filter_by(id=document_id).first()
if document:
document.indexing_status = "error"
document.error = str(e)
document.stopped_at = naive_utc_now()

View File

@@ -153,8 +153,7 @@ class TestCleanNotionDocumentTask:
# Execute cleanup task
clean_notion_document_task(document_ids, dataset.id)
# Verify documents and segments are deleted
assert db_session_with_containers.query(Document).filter(Document.id.in_(document_ids)).count() == 0
# Verify segments are deleted
assert (
db_session_with_containers.query(DocumentSegment)
.filter(DocumentSegment.document_id.in_(document_ids))
@@ -162,9 +161,9 @@ class TestCleanNotionDocumentTask:
== 0
)
# Verify index processor was called for each document
# Verify index processor was called
mock_processor = mock_index_processor_factory.return_value.init_index_processor.return_value
assert mock_processor.clean.call_count == len(document_ids)
mock_processor.clean.assert_called_once()
# This test successfully verifies:
# 1. Document records are properly deleted from the database
@@ -186,12 +185,12 @@ class TestCleanNotionDocumentTask:
non_existent_dataset_id = str(uuid.uuid4())
document_ids = [str(uuid.uuid4()), str(uuid.uuid4())]
# Execute cleanup task with non-existent dataset
clean_notion_document_task(document_ids, non_existent_dataset_id)
# Execute cleanup task with non-existent dataset - expect exception
with pytest.raises(Exception, match="Document has no dataset"):
clean_notion_document_task(document_ids, non_existent_dataset_id)
# Verify that the index processor was not called
mock_processor = mock_index_processor_factory.return_value.init_index_processor.return_value
mock_processor.clean.assert_not_called()
# Verify that the index processor factory was not used
mock_index_processor_factory.return_value.init_index_processor.assert_not_called()
def test_clean_notion_document_task_empty_document_list(
self, db_session_with_containers, mock_index_processor_factory, mock_external_service_dependencies
@@ -229,9 +228,13 @@ class TestCleanNotionDocumentTask:
# Execute cleanup task with empty document list
clean_notion_document_task([], dataset.id)
# Verify that the index processor was not called
# Verify that the index processor was called once with empty node list
mock_processor = mock_index_processor_factory.return_value.init_index_processor.return_value
mock_processor.clean.assert_not_called()
assert mock_processor.clean.call_count == 1
args, kwargs = mock_processor.clean.call_args
# args: (dataset, total_index_node_ids)
assert isinstance(args[0], Dataset)
assert args[1] == []
def test_clean_notion_document_task_with_different_index_types(
self, db_session_with_containers, mock_index_processor_factory, mock_external_service_dependencies
@@ -315,8 +318,7 @@ class TestCleanNotionDocumentTask:
# Note: This test successfully verifies cleanup with different document types.
# The task properly handles various index types and document configurations.
# Verify documents and segments are deleted
assert db_session_with_containers.query(Document).filter(Document.id == document.id).count() == 0
# Verify segments are deleted
assert (
db_session_with_containers.query(DocumentSegment)
.filter(DocumentSegment.document_id == document.id)
@@ -404,8 +406,7 @@ class TestCleanNotionDocumentTask:
# Execute cleanup task
clean_notion_document_task([document.id], dataset.id)
# Verify documents and segments are deleted
assert db_session_with_containers.query(Document).filter(Document.id == document.id).count() == 0
# Verify segments are deleted
assert (
db_session_with_containers.query(DocumentSegment).filter(DocumentSegment.document_id == document.id).count()
== 0
@@ -508,8 +509,7 @@ class TestCleanNotionDocumentTask:
clean_notion_document_task(documents_to_clean, dataset.id)
# Verify only specified documents and segments are deleted
assert db_session_with_containers.query(Document).filter(Document.id.in_(documents_to_clean)).count() == 0
# Verify only specified documents' segments are deleted
assert (
db_session_with_containers.query(DocumentSegment)
.filter(DocumentSegment.document_id.in_(documents_to_clean))
@@ -697,11 +697,12 @@ class TestCleanNotionDocumentTask:
db_session_with_containers.commit()
# Mock index processor to raise an exception
mock_index_processor = mock_index_processor_factory.init_index_processor.return_value
mock_index_processor = mock_index_processor_factory.return_value.init_index_processor.return_value
mock_index_processor.clean.side_effect = Exception("Index processor error")
# Execute cleanup task - it should handle the exception gracefully
clean_notion_document_task([document.id], dataset.id)
# Execute cleanup task - current implementation propagates the exception
with pytest.raises(Exception, match="Index processor error"):
clean_notion_document_task([document.id], dataset.id)
# Note: This test demonstrates the task's error handling capability.
# Even with external service errors, the database operations complete successfully.
@@ -803,8 +804,7 @@ class TestCleanNotionDocumentTask:
all_document_ids = [doc.id for doc in documents]
clean_notion_document_task(all_document_ids, dataset.id)
# Verify all documents and segments are deleted
assert db_session_with_containers.query(Document).filter(Document.dataset_id == dataset.id).count() == 0
# Verify all segments are deleted
assert (
db_session_with_containers.query(DocumentSegment).filter(DocumentSegment.dataset_id == dataset.id).count()
== 0
@@ -914,8 +914,7 @@ class TestCleanNotionDocumentTask:
clean_notion_document_task([target_document.id], target_dataset.id)
# Verify only documents from target dataset are deleted
assert db_session_with_containers.query(Document).filter(Document.id == target_document.id).count() == 0
# Verify only documents' segments from target dataset are deleted
assert (
db_session_with_containers.query(DocumentSegment)
.filter(DocumentSegment.document_id == target_document.id)
@@ -1030,8 +1029,7 @@ class TestCleanNotionDocumentTask:
all_document_ids = [doc.id for doc in documents]
clean_notion_document_task(all_document_ids, dataset.id)
# Verify all documents and segments are deleted regardless of status
assert db_session_with_containers.query(Document).filter(Document.dataset_id == dataset.id).count() == 0
# Verify all segments are deleted regardless of status
assert (
db_session_with_containers.query(DocumentSegment).filter(DocumentSegment.dataset_id == dataset.id).count()
== 0
@@ -1142,8 +1140,7 @@ class TestCleanNotionDocumentTask:
# Execute cleanup task
clean_notion_document_task([document.id], dataset.id)
# Verify documents and segments are deleted
assert db_session_with_containers.query(Document).filter(Document.id == document.id).count() == 0
# Verify segments are deleted
assert (
db_session_with_containers.query(DocumentSegment).filter(DocumentSegment.document_id == document.id).count()
== 0

View File

@@ -0,0 +1,62 @@
"""
Unit tests for Service API knowledge pipeline file-upload serialization.
"""
import importlib.util
from datetime import UTC, datetime
from pathlib import Path
class FakeUploadFile:
id: str
name: str
size: int
extension: str
mime_type: str
created_by: str
created_at: datetime | None
def _load_serialize_upload_file():
api_dir = Path(__file__).resolve().parents[5]
serializers_path = api_dir / "controllers" / "service_api" / "dataset" / "rag_pipeline" / "serializers.py"
spec = importlib.util.spec_from_file_location("rag_pipeline_serializers", serializers_path)
assert spec
assert spec.loader
module = importlib.util.module_from_spec(spec)
spec.loader.exec_module(module) # type: ignore[attr-defined]
return module.serialize_upload_file
def test_file_upload_created_at_is_isoformat_string():
serialize_upload_file = _load_serialize_upload_file()
created_at = datetime(2026, 2, 8, 12, 0, 0, tzinfo=UTC)
upload_file = FakeUploadFile()
upload_file.id = "file-1"
upload_file.name = "test.pdf"
upload_file.size = 123
upload_file.extension = "pdf"
upload_file.mime_type = "application/pdf"
upload_file.created_by = "account-1"
upload_file.created_at = created_at
result = serialize_upload_file(upload_file)
assert result["created_at"] == created_at.isoformat()
def test_file_upload_created_at_none_serializes_to_null():
serialize_upload_file = _load_serialize_upload_file()
upload_file = FakeUploadFile()
upload_file.id = "file-1"
upload_file.name = "test.pdf"
upload_file.size = 123
upload_file.extension = "pdf"
upload_file.mime_type = "application/pdf"
upload_file.created_by = "account-1"
upload_file.created_at = None
result = serialize_upload_file(upload_file)
assert result["created_at"] is None

View File

@@ -0,0 +1,54 @@
"""
Unit tests for Service API knowledge pipeline route registration.
"""
import ast
from pathlib import Path
def test_rag_pipeline_routes_registered():
api_dir = Path(__file__).resolve().parents[5]
service_api_init = api_dir / "controllers" / "service_api" / "__init__.py"
rag_pipeline_workflow = (
api_dir / "controllers" / "service_api" / "dataset" / "rag_pipeline" / "rag_pipeline_workflow.py"
)
assert service_api_init.exists()
assert rag_pipeline_workflow.exists()
init_tree = ast.parse(service_api_init.read_text(encoding="utf-8"))
import_found = False
for node in ast.walk(init_tree):
if not isinstance(node, ast.ImportFrom):
continue
if node.module != "dataset.rag_pipeline" or node.level != 1:
continue
if any(alias.name == "rag_pipeline_workflow" for alias in node.names):
import_found = True
break
assert import_found, "from .dataset.rag_pipeline import rag_pipeline_workflow not found in service_api/__init__.py"
workflow_tree = ast.parse(rag_pipeline_workflow.read_text(encoding="utf-8"))
route_paths: set[str] = set()
for node in ast.walk(workflow_tree):
if not isinstance(node, ast.ClassDef):
continue
for decorator in node.decorator_list:
if not isinstance(decorator, ast.Call):
continue
if not isinstance(decorator.func, ast.Attribute):
continue
if decorator.func.attr != "route":
continue
if not decorator.args:
continue
first_arg = decorator.args[0]
if isinstance(first_arg, ast.Constant) and isinstance(first_arg.value, str):
route_paths.add(first_arg.value)
assert "/datasets/<uuid:dataset_id>/pipeline/datasource-plugins" in route_paths
assert "/datasets/<uuid:dataset_id>/pipeline/datasource/nodes/<string:node_id>/run" in route_paths
assert "/datasets/<uuid:dataset_id>/pipeline/run" in route_paths
assert "/datasets/pipeline/file-upload" in route_paths

View File

@@ -4,7 +4,7 @@ from typing import Any
from uuid import uuid4
import pytest
from hypothesis import given, settings
from hypothesis import HealthCheck, given, settings
from hypothesis import strategies as st
from core.file import File, FileTransferMethod, FileType
@@ -493,7 +493,7 @@ def _scalar_value() -> st.SearchStrategy[int | float | str | File | None]:
)
@settings(max_examples=50)
@settings(max_examples=30, suppress_health_check=[HealthCheck.too_slow, HealthCheck.filter_too_much], deadline=None)
@given(_scalar_value())
def test_build_segment_and_extract_values_for_scalar_types(value):
seg = variable_factory.build_segment(value)
@@ -504,7 +504,7 @@ def test_build_segment_and_extract_values_for_scalar_types(value):
assert seg.value == value
@settings(max_examples=50)
@settings(max_examples=30, suppress_health_check=[HealthCheck.too_slow, HealthCheck.filter_too_much], deadline=None)
@given(values=st.lists(_scalar_value(), max_size=20))
def test_build_segment_and_extract_values_for_array_types(values):
seg = variable_factory.build_segment(values)

View File

@@ -109,40 +109,87 @@ def mock_document_segments(document_id):
@pytest.fixture
def mock_db_session():
"""Mock database session via session_factory.create_session()."""
"""Mock database session via session_factory.create_session().
After session split refactor, the code calls create_session() multiple times.
This fixture creates shared query mocks so all sessions use the same
query configuration, simulating database persistence across sessions.
The fixture automatically converts side_effect to cycle to prevent StopIteration.
Tests configure mocks the same way as before, but behind the scenes the values
are cycled infinitely for all sessions.
"""
from itertools import cycle
with patch("tasks.document_indexing_sync_task.session_factory") as mock_sf:
session = MagicMock()
# Ensure tests can observe session.close() via context manager teardown
session.close = MagicMock()
session.commit = MagicMock()
sessions = []
# Mock session.begin() context manager to auto-commit on exit
begin_cm = MagicMock()
begin_cm.__enter__.return_value = session
# Shared query mocks - all sessions use these
shared_query = MagicMock()
shared_filter_by = MagicMock()
shared_scalars_result = MagicMock()
def _begin_exit_side_effect(*args, **kwargs):
# session.begin().__exit__() should commit if no exception
if args[0] is None: # No exception
session.commit()
# Create custom first mock that auto-cycles side_effect
class CyclicMock(MagicMock):
def __setattr__(self, name, value):
if name == "side_effect" and value is not None:
# Convert list/tuple to infinite cycle
if isinstance(value, (list, tuple)):
value = cycle(value)
super().__setattr__(name, value)
begin_cm.__exit__.side_effect = _begin_exit_side_effect
session.begin.return_value = begin_cm
shared_query.where.return_value.first = CyclicMock()
shared_filter_by.first = CyclicMock()
# Mock create_session() context manager
cm = MagicMock()
cm.__enter__.return_value = session
def _create_session():
"""Create a new mock session for each create_session() call."""
session = MagicMock()
session.close = MagicMock()
session.commit = MagicMock()
def _exit_side_effect(*args, **kwargs):
session.close()
# Mock session.begin() context manager
begin_cm = MagicMock()
begin_cm.__enter__.return_value = session
cm.__exit__.side_effect = _exit_side_effect
mock_sf.create_session.return_value = cm
def _begin_exit_side_effect(exc_type, exc, tb):
# commit on success
if exc_type is None:
session.commit()
# return False to propagate exceptions
return False
query = MagicMock()
session.query.return_value = query
query.where.return_value = query
session.scalars.return_value = MagicMock()
yield session
begin_cm.__exit__.side_effect = _begin_exit_side_effect
session.begin.return_value = begin_cm
# Mock create_session() context manager
cm = MagicMock()
cm.__enter__.return_value = session
def _exit_side_effect(exc_type, exc, tb):
session.close()
return False
cm.__exit__.side_effect = _exit_side_effect
# All sessions use the same shared query mocks
session.query.return_value = shared_query
shared_query.where.return_value = shared_query
shared_query.filter_by.return_value = shared_filter_by
session.scalars.return_value = shared_scalars_result
sessions.append(session)
# Attach helpers on the first created session for assertions across all sessions
if len(sessions) == 1:
session.get_all_sessions = lambda: sessions
session.any_close_called = lambda: any(s.close.called for s in sessions)
session.any_commit_called = lambda: any(s.commit.called for s in sessions)
return cm
mock_sf.create_session.side_effect = _create_session
# Create first session and return it
_create_session()
yield sessions[0]
@pytest.fixture
@@ -201,8 +248,8 @@ class TestDocumentIndexingSyncTask:
# Act
document_indexing_sync_task(dataset_id, document_id)
# Assert
mock_db_session.close.assert_called_once()
# Assert - at least one session should have been closed
assert mock_db_session.any_close_called()
def test_missing_notion_workspace_id(self, mock_db_session, mock_document, dataset_id, document_id):
"""Test that task raises error when notion_workspace_id is missing."""
@@ -245,6 +292,7 @@ class TestDocumentIndexingSyncTask:
"""Test that task handles missing credentials by updating document status."""
# Arrange
mock_db_session.query.return_value.where.return_value.first.return_value = mock_document
mock_db_session.query.return_value.filter_by.return_value.first.return_value = mock_document
mock_datasource_provider_service.get_datasource_credentials.return_value = None
# Act
@@ -254,8 +302,8 @@ class TestDocumentIndexingSyncTask:
assert mock_document.indexing_status == "error"
assert "Datasource credential not found" in mock_document.error
assert mock_document.stopped_at is not None
mock_db_session.commit.assert_called()
mock_db_session.close.assert_called()
assert mock_db_session.any_commit_called()
assert mock_db_session.any_close_called()
def test_page_not_updated(
self,
@@ -269,6 +317,7 @@ class TestDocumentIndexingSyncTask:
"""Test that task does nothing when page has not been updated."""
# Arrange
mock_db_session.query.return_value.where.return_value.first.return_value = mock_document
mock_db_session.query.return_value.filter_by.return_value.first.return_value = mock_document
# Return same time as stored in document
mock_notion_extractor.get_notion_last_edited_time.return_value = "2024-01-01T00:00:00Z"
@@ -278,8 +327,8 @@ class TestDocumentIndexingSyncTask:
# Assert
# Document status should remain unchanged
assert mock_document.indexing_status == "completed"
# Session should still be closed via context manager teardown
assert mock_db_session.close.called
# At least one session should have been closed via context manager teardown
assert mock_db_session.any_close_called()
def test_successful_sync_when_page_updated(
self,
@@ -296,7 +345,20 @@ class TestDocumentIndexingSyncTask:
):
"""Test successful sync flow when Notion page has been updated."""
# Arrange
mock_db_session.query.return_value.where.return_value.first.side_effect = [mock_document, mock_dataset]
# Set exact sequence of returns across calls to `.first()`:
# 1) document (initial fetch)
# 2) dataset (pre-check)
# 3) dataset (cleaning phase)
# 4) document (pre-indexing update)
# 5) document (indexing runner fetch)
mock_db_session.query.return_value.where.return_value.first.side_effect = [
mock_document,
mock_dataset,
mock_dataset,
mock_document,
mock_document,
]
mock_db_session.query.return_value.filter_by.return_value.first.return_value = mock_document
mock_db_session.scalars.return_value.all.return_value = mock_document_segments
# NotionExtractor returns updated time
mock_notion_extractor.get_notion_last_edited_time.return_value = "2024-01-02T00:00:00Z"
@@ -314,28 +376,40 @@ class TestDocumentIndexingSyncTask:
mock_processor.clean.assert_called_once()
# Verify segments were deleted from database in batch (DELETE FROM document_segments)
execute_sqls = [" ".join(str(c[0][0]).split()) for c in mock_db_session.execute.call_args_list]
# Aggregate execute calls across all created sessions
execute_sqls = []
for s in mock_db_session.get_all_sessions():
execute_sqls.extend([" ".join(str(c[0][0]).split()) for c in s.execute.call_args_list])
assert any("DELETE FROM document_segments" in sql for sql in execute_sqls)
# Verify indexing runner was called
mock_indexing_runner.run.assert_called_once_with([mock_document])
# Verify session operations
assert mock_db_session.commit.called
mock_db_session.close.assert_called_once()
# Verify session operations (across any created session)
assert mock_db_session.any_commit_called()
assert mock_db_session.any_close_called()
def test_dataset_not_found_during_cleaning(
self,
mock_db_session,
mock_datasource_provider_service,
mock_notion_extractor,
mock_indexing_runner,
mock_document,
dataset_id,
document_id,
):
"""Test that task handles dataset not found during cleaning phase."""
# Arrange
mock_db_session.query.return_value.where.return_value.first.side_effect = [mock_document, None]
# Sequence: document (initial), dataset (pre-check), None (cleaning), document (update), document (indexing)
mock_db_session.query.return_value.where.return_value.first.side_effect = [
mock_document,
mock_dataset,
None,
mock_document,
mock_document,
]
mock_db_session.query.return_value.filter_by.return_value.first.return_value = mock_document
mock_notion_extractor.get_notion_last_edited_time.return_value = "2024-01-02T00:00:00Z"
# Act
@@ -344,8 +418,8 @@ class TestDocumentIndexingSyncTask:
# Assert
# Document should still be set to parsing
assert mock_document.indexing_status == "parsing"
# Session should be closed after error
mock_db_session.close.assert_called_once()
# At least one session should be closed after error
assert mock_db_session.any_close_called()
def test_cleaning_error_continues_to_indexing(
self,
@@ -361,8 +435,14 @@ class TestDocumentIndexingSyncTask:
):
"""Test that indexing continues even if cleaning fails."""
# Arrange
mock_db_session.query.return_value.where.return_value.first.side_effect = [mock_document, mock_dataset]
mock_db_session.scalars.return_value.all.side_effect = Exception("Cleaning error")
from itertools import cycle
mock_db_session.query.return_value.where.return_value.first.side_effect = cycle([mock_document, mock_dataset])
mock_db_session.query.return_value.filter_by.return_value.first.return_value = mock_document
# Make the cleaning step fail but not the segment fetch
processor = mock_index_processor_factory.return_value.init_index_processor.return_value
processor.clean.side_effect = Exception("Cleaning error")
mock_db_session.scalars.return_value.all.return_value = []
mock_notion_extractor.get_notion_last_edited_time.return_value = "2024-01-02T00:00:00Z"
# Act
@@ -371,7 +451,7 @@ class TestDocumentIndexingSyncTask:
# Assert
# Indexing should still be attempted despite cleaning error
mock_indexing_runner.run.assert_called_once_with([mock_document])
mock_db_session.close.assert_called_once()
assert mock_db_session.any_close_called()
def test_indexing_runner_document_paused_error(
self,
@@ -388,7 +468,10 @@ class TestDocumentIndexingSyncTask:
):
"""Test that DocumentIsPausedError is handled gracefully."""
# Arrange
mock_db_session.query.return_value.where.return_value.first.side_effect = [mock_document, mock_dataset]
from itertools import cycle
mock_db_session.query.return_value.where.return_value.first.side_effect = cycle([mock_document, mock_dataset])
mock_db_session.query.return_value.filter_by.return_value.first.return_value = mock_document
mock_db_session.scalars.return_value.all.return_value = mock_document_segments
mock_notion_extractor.get_notion_last_edited_time.return_value = "2024-01-02T00:00:00Z"
mock_indexing_runner.run.side_effect = DocumentIsPausedError("Document paused")
@@ -398,7 +481,7 @@ class TestDocumentIndexingSyncTask:
# Assert
# Session should be closed after handling error
mock_db_session.close.assert_called_once()
assert mock_db_session.any_close_called()
def test_indexing_runner_general_error(
self,
@@ -415,7 +498,10 @@ class TestDocumentIndexingSyncTask:
):
"""Test that general exceptions during indexing are handled."""
# Arrange
mock_db_session.query.return_value.where.return_value.first.side_effect = [mock_document, mock_dataset]
from itertools import cycle
mock_db_session.query.return_value.where.return_value.first.side_effect = cycle([mock_document, mock_dataset])
mock_db_session.query.return_value.filter_by.return_value.first.return_value = mock_document
mock_db_session.scalars.return_value.all.return_value = mock_document_segments
mock_notion_extractor.get_notion_last_edited_time.return_value = "2024-01-02T00:00:00Z"
mock_indexing_runner.run.side_effect = Exception("Indexing error")
@@ -425,7 +511,7 @@ class TestDocumentIndexingSyncTask:
# Assert
# Session should be closed after error
mock_db_session.close.assert_called_once()
assert mock_db_session.any_close_called()
def test_notion_extractor_initialized_with_correct_params(
self,
@@ -532,7 +618,14 @@ class TestDocumentIndexingSyncTask:
):
"""Test that index processor clean is called with correct parameters."""
# Arrange
mock_db_session.query.return_value.where.return_value.first.side_effect = [mock_document, mock_dataset]
# Sequence: document (initial), dataset (pre-check), dataset (cleaning), document (update), document (indexing)
mock_db_session.query.return_value.where.return_value.first.side_effect = [
mock_document,
mock_dataset,
mock_dataset,
mock_document,
mock_document,
]
mock_db_session.scalars.return_value.all.return_value = mock_document_segments
mock_notion_extractor.get_notion_last_edited_time.return_value = "2024-01-02T00:00:00Z"

View File

@@ -48,7 +48,7 @@ export default function ChartView({ appId, headerRight }: IChartViewProps) {
return (
<div>
<div className="mb-4">
<div className="system-xl-semibold mb-2 text-text-primary">{t('appMenus.overview', { ns: 'common' })}</div>
<div className="mb-2 text-text-primary system-xl-semibold">{t('appMenus.overview', { ns: 'common' })}</div>
<div className="flex items-center justify-between">
{IS_CLOUD_EDITION
? (

View File

@@ -30,7 +30,7 @@ const DatePicker: FC<Props> = ({
const renderDate = useCallback(({ value, handleClickTrigger, isOpen }: TriggerProps) => {
return (
<div className={cn('system-sm-regular flex h-7 cursor-pointer items-center rounded-lg px-1 text-components-input-text-filled hover:bg-state-base-hover', isOpen && 'bg-state-base-hover')} onClick={handleClickTrigger}>
<div className={cn('flex h-7 cursor-pointer items-center rounded-lg px-1 text-components-input-text-filled system-sm-regular hover:bg-state-base-hover', isOpen && 'bg-state-base-hover')} onClick={handleClickTrigger}>
{value ? formatToLocalTime(value, locale, 'MMM D') : ''}
</div>
)
@@ -64,7 +64,7 @@ const DatePicker: FC<Props> = ({
noConfirm
getIsDateDisabled={startDateDisabled}
/>
<span className="system-sm-regular text-text-tertiary">-</span>
<span className="text-text-tertiary system-sm-regular">-</span>
<Picker
value={end}
onChange={onEndChange}

View File

@@ -45,7 +45,7 @@ const RangeSelector: FC<Props> = ({
const renderTrigger = useCallback((item: Item | null, isOpen: boolean) => {
return (
<div className={cn('flex h-8 cursor-pointer items-center space-x-1.5 rounded-lg bg-components-input-bg-normal pl-3 pr-2', isOpen && 'bg-state-base-hover-alt')}>
<div className="system-sm-regular text-components-input-text-filled">{isCustomRange ? t('filter.period.custom', { ns: 'appLog' }) : item?.name}</div>
<div className="text-components-input-text-filled system-sm-regular">{isCustomRange ? t('filter.period.custom', { ns: 'appLog' }) : item?.name}</div>
<RiArrowDownSLine className={cn('size-4 text-text-quaternary', isOpen && 'text-text-secondary')} />
</div>
)
@@ -63,7 +63,7 @@ const RangeSelector: FC<Props> = ({
<RiCheckLine className="h-4 w-4" aria-hidden="true" />
</span>
)}
<span className={cn('system-md-regular block truncate')}>{item.name}</span>
<span className={cn('block truncate system-md-regular')}>{item.name}</span>
</>
)
}, [])

View File

@@ -327,11 +327,11 @@ const ConfigPopup: FC<PopupProps> = ({
<div className="flex items-center justify-between">
<div className="flex items-center">
<TracingIcon size="md" className="mr-2" />
<div className="title-2xl-semi-bold text-text-primary">{t(`${I18N_PREFIX}.tracing`, { ns: 'app' })}</div>
<div className="text-text-primary title-2xl-semi-bold">{t(`${I18N_PREFIX}.tracing`, { ns: 'app' })}</div>
</div>
<div className="flex items-center">
<Indicator color={enabled ? 'green' : 'gray'} />
<div className={cn('system-xs-semibold-uppercase ml-1 text-text-tertiary', enabled && 'text-util-colors-green-green-600')}>
<div className={cn('ml-1 text-text-tertiary system-xs-semibold-uppercase', enabled && 'text-util-colors-green-green-600')}>
{t(`${I18N_PREFIX}.${enabled ? 'enabled' : 'disabled'}`, { ns: 'app' })}
</div>
{!readOnly && (
@@ -350,7 +350,7 @@ const ConfigPopup: FC<PopupProps> = ({
</div>
</div>
<div className="system-xs-regular mt-2 text-text-tertiary">
<div className="mt-2 text-text-tertiary system-xs-regular">
{t(`${I18N_PREFIX}.tracingDescription`, { ns: 'app' })}
</div>
<Divider className="my-3" />
@@ -358,7 +358,7 @@ const ConfigPopup: FC<PopupProps> = ({
{(providerAllConfigured || providerAllNotConfigured)
? (
<>
<div className="system-xs-medium-uppercase text-text-tertiary">{t(`${I18N_PREFIX}.configProviderTitle.${providerAllConfigured ? 'configured' : 'notConfigured'}`, { ns: 'app' })}</div>
<div className="text-text-tertiary system-xs-medium-uppercase">{t(`${I18N_PREFIX}.configProviderTitle.${providerAllConfigured ? 'configured' : 'notConfigured'}`, { ns: 'app' })}</div>
<div className="mt-2 max-h-96 space-y-2 overflow-y-auto">
{langfusePanel}
{langSmithPanel}
@@ -375,11 +375,11 @@ const ConfigPopup: FC<PopupProps> = ({
)
: (
<>
<div className="system-xs-medium-uppercase text-text-tertiary">{t(`${I18N_PREFIX}.configProviderTitle.configured`, { ns: 'app' })}</div>
<div className="text-text-tertiary system-xs-medium-uppercase">{t(`${I18N_PREFIX}.configProviderTitle.configured`, { ns: 'app' })}</div>
<div className="mt-2 max-h-40 space-y-2 overflow-y-auto">
{configuredProviderPanel()}
</div>
<div className="system-xs-medium-uppercase mt-3 text-text-tertiary">{t(`${I18N_PREFIX}.configProviderTitle.moreProvider`, { ns: 'app' })}</div>
<div className="mt-3 text-text-tertiary system-xs-medium-uppercase">{t(`${I18N_PREFIX}.configProviderTitle.moreProvider`, { ns: 'app' })}</div>
<div className="mt-2 max-h-40 space-y-2 overflow-y-auto">
{moreProviderPanel()}
</div>

View File

@@ -254,7 +254,7 @@ const Panel: FC = () => {
)}
>
<TracingIcon size="md" />
<div className="system-sm-semibold mx-2 text-text-secondary">{t(`${I18N_PREFIX}.title`, { ns: 'app' })}</div>
<div className="mx-2 text-text-secondary system-sm-semibold">{t(`${I18N_PREFIX}.title`, { ns: 'app' })}</div>
<div className="rounded-md p-1">
<RiEqualizer2Line className="h-4 w-4 text-text-tertiary" />
</div>
@@ -294,7 +294,7 @@ const Panel: FC = () => {
>
<div className="ml-4 mr-1 flex items-center">
<Indicator color={enabled ? 'green' : 'gray'} />
<div className="system-xs-semibold-uppercase ml-1.5 text-text-tertiary">
<div className="ml-1.5 text-text-tertiary system-xs-semibold-uppercase">
{t(`${I18N_PREFIX}.${enabled ? 'enabled' : 'disabled'}`, { ns: 'app' })}
</div>
</div>

View File

@@ -302,7 +302,7 @@ const ProviderConfigModal: FC<Props> = ({
<div className="mx-2 max-h-[calc(100vh-120px)] w-[640px] overflow-y-auto rounded-2xl bg-components-panel-bg shadow-xl">
<div className="px-8 pt-8">
<div className="mb-4 flex items-center justify-between">
<div className="title-2xl-semi-bold text-text-primary">
<div className="text-text-primary title-2xl-semi-bold">
{t(`${I18N_PREFIX}.title`, { ns: 'app' })}
{t(`tracing.${type}.title`, { ns: 'app' })}
</div>

View File

@@ -82,7 +82,7 @@ const ProviderPanel: FC<Props> = ({
<div className="flex items-center justify-between space-x-1">
<div className="flex items-center">
<Icon className="h-6" />
{isChosen && <div className="system-2xs-medium-uppercase ml-1 flex h-4 items-center rounded-[4px] border border-text-accent-secondary px-1 text-text-accent-secondary">{t(`${I18N_PREFIX}.inUse`, { ns: 'app' })}</div>}
{isChosen && <div className="ml-1 flex h-4 items-center rounded-[4px] border border-text-accent-secondary px-1 text-text-accent-secondary system-2xs-medium-uppercase">{t(`${I18N_PREFIX}.inUse`, { ns: 'app' })}</div>}
</div>
{!readOnly && (
<div className="flex items-center justify-between space-x-1">
@@ -102,7 +102,7 @@ const ProviderPanel: FC<Props> = ({
</div>
)}
</div>
<div className="system-xs-regular mt-2 text-text-tertiary">
<div className="mt-2 text-text-tertiary system-xs-regular">
{t(`${I18N_PREFIX}.${type}.description`, { ns: 'app' })}
</div>
</div>

View File

@@ -7,8 +7,8 @@ const Settings = () => {
return (
<div className="h-full overflow-y-auto">
<div className="flex flex-col gap-y-0.5 px-6 pb-2 pt-3">
<div className="system-xl-semibold text-text-primary">{t('title')}</div>
<div className="system-sm-regular text-text-tertiary">{t('desc')}</div>
<div className="text-text-primary system-xl-semibold">{t('title')}</div>
<div className="text-text-tertiary system-sm-regular">{t('desc')}</div>
</div>
<Form />
</div>

View File

@@ -106,17 +106,17 @@ const FormContent = () => {
<RiCheckboxCircleFill className="h-8 w-8 text-text-success" />
</div>
<div className="grow">
<div className="title-4xl-semi-bold text-text-primary">{t('humanInput.thanks', { ns: 'share' })}</div>
<div className="title-4xl-semi-bold text-text-primary">{t('humanInput.recorded', { ns: 'share' })}</div>
<div className="text-text-primary title-4xl-semi-bold">{t('humanInput.thanks', { ns: 'share' })}</div>
<div className="text-text-primary title-4xl-semi-bold">{t('humanInput.recorded', { ns: 'share' })}</div>
</div>
<div className="system-2xs-regular-uppercase shrink-0 text-text-tertiary">{t('humanInput.submissionID', { id: token, ns: 'share' })}</div>
<div className="shrink-0 text-text-tertiary system-2xs-regular-uppercase">{t('humanInput.submissionID', { id: token, ns: 'share' })}</div>
</div>
<div className="flex flex-row-reverse px-2 py-3">
<div className={cn(
'flex shrink-0 items-center gap-1.5 px-1',
)}
>
<div className="system-2xs-medium-uppercase text-text-tertiary">{t('chat.poweredBy', { ns: 'share' })}</div>
<div className="text-text-tertiary system-2xs-medium-uppercase">{t('chat.poweredBy', { ns: 'share' })}</div>
<DifyLogo size="small" />
</div>
</div>
@@ -134,17 +134,17 @@ const FormContent = () => {
<RiInformation2Fill className="h-8 w-8 text-text-accent" />
</div>
<div className="grow">
<div className="title-4xl-semi-bold text-text-primary">{t('humanInput.sorry', { ns: 'share' })}</div>
<div className="title-4xl-semi-bold text-text-primary">{t('humanInput.expired', { ns: 'share' })}</div>
<div className="text-text-primary title-4xl-semi-bold">{t('humanInput.sorry', { ns: 'share' })}</div>
<div className="text-text-primary title-4xl-semi-bold">{t('humanInput.expired', { ns: 'share' })}</div>
</div>
<div className="system-2xs-regular-uppercase shrink-0 text-text-tertiary">{t('humanInput.submissionID', { id: token, ns: 'share' })}</div>
<div className="shrink-0 text-text-tertiary system-2xs-regular-uppercase">{t('humanInput.submissionID', { id: token, ns: 'share' })}</div>
</div>
<div className="flex flex-row-reverse px-2 py-3">
<div className={cn(
'flex shrink-0 items-center gap-1.5 px-1',
)}
>
<div className="system-2xs-medium-uppercase text-text-tertiary">{t('chat.poweredBy', { ns: 'share' })}</div>
<div className="text-text-tertiary system-2xs-medium-uppercase">{t('chat.poweredBy', { ns: 'share' })}</div>
<DifyLogo size="small" />
</div>
</div>
@@ -162,17 +162,17 @@ const FormContent = () => {
<RiInformation2Fill className="h-8 w-8 text-text-accent" />
</div>
<div className="grow">
<div className="title-4xl-semi-bold text-text-primary">{t('humanInput.sorry', { ns: 'share' })}</div>
<div className="title-4xl-semi-bold text-text-primary">{t('humanInput.completed', { ns: 'share' })}</div>
<div className="text-text-primary title-4xl-semi-bold">{t('humanInput.sorry', { ns: 'share' })}</div>
<div className="text-text-primary title-4xl-semi-bold">{t('humanInput.completed', { ns: 'share' })}</div>
</div>
<div className="system-2xs-regular-uppercase shrink-0 text-text-tertiary">{t('humanInput.submissionID', { id: token, ns: 'share' })}</div>
<div className="shrink-0 text-text-tertiary system-2xs-regular-uppercase">{t('humanInput.submissionID', { id: token, ns: 'share' })}</div>
</div>
<div className="flex flex-row-reverse px-2 py-3">
<div className={cn(
'flex shrink-0 items-center gap-1.5 px-1',
)}
>
<div className="system-2xs-medium-uppercase text-text-tertiary">{t('chat.poweredBy', { ns: 'share' })}</div>
<div className="text-text-tertiary system-2xs-medium-uppercase">{t('chat.poweredBy', { ns: 'share' })}</div>
<DifyLogo size="small" />
</div>
</div>
@@ -190,7 +190,7 @@ const FormContent = () => {
<RiErrorWarningFill className="h-8 w-8 text-text-destructive" />
</div>
<div className="grow">
<div className="title-4xl-semi-bold text-text-primary">{t('humanInput.rateLimitExceeded', { ns: 'share' })}</div>
<div className="text-text-primary title-4xl-semi-bold">{t('humanInput.rateLimitExceeded', { ns: 'share' })}</div>
</div>
</div>
<div className="flex flex-row-reverse px-2 py-3">
@@ -198,7 +198,7 @@ const FormContent = () => {
'flex shrink-0 items-center gap-1.5 px-1',
)}
>
<div className="system-2xs-medium-uppercase text-text-tertiary">{t('chat.poweredBy', { ns: 'share' })}</div>
<div className="text-text-tertiary system-2xs-medium-uppercase">{t('chat.poweredBy', { ns: 'share' })}</div>
<DifyLogo size="small" />
</div>
</div>
@@ -216,7 +216,7 @@ const FormContent = () => {
<RiErrorWarningFill className="h-8 w-8 text-text-destructive" />
</div>
<div className="grow">
<div className="title-4xl-semi-bold text-text-primary">{t('humanInput.formNotFound', { ns: 'share' })}</div>
<div className="text-text-primary title-4xl-semi-bold">{t('humanInput.formNotFound', { ns: 'share' })}</div>
</div>
</div>
<div className="flex flex-row-reverse px-2 py-3">
@@ -224,7 +224,7 @@ const FormContent = () => {
'flex shrink-0 items-center gap-1.5 px-1',
)}
>
<div className="system-2xs-medium-uppercase text-text-tertiary">{t('chat.poweredBy', { ns: 'share' })}</div>
<div className="text-text-tertiary system-2xs-medium-uppercase">{t('chat.poweredBy', { ns: 'share' })}</div>
<DifyLogo size="small" />
</div>
</div>
@@ -245,7 +245,7 @@ const FormContent = () => {
background={site.icon_background}
imageUrl={site.icon_url}
/>
<div className="system-xl-semibold grow text-text-primary">{site.title}</div>
<div className="grow text-text-primary system-xl-semibold">{site.title}</div>
</div>
<div className="h-0 w-full grow overflow-y-auto">
<div className="border-components-divider-subtle rounded-[20px] border bg-chat-bubble-bg p-4 shadow-lg backdrop-blur-sm">
@@ -277,7 +277,7 @@ const FormContent = () => {
'flex shrink-0 items-center gap-1.5 px-1',
)}
>
<div className="system-2xs-medium-uppercase text-text-tertiary">{t('chat.poweredBy', { ns: 'share' })}</div>
<div className="text-text-tertiary system-2xs-medium-uppercase">{t('chat.poweredBy', { ns: 'share' })}</div>
<DifyLogo size="small" />
</div>
</div>

View File

@@ -81,7 +81,7 @@ const AuthenticatedLayout = ({ children }: { children: React.ReactNode }) => {
return (
<div className="flex h-full flex-col items-center justify-center gap-y-2">
<AppUnavailable className="h-auto w-auto" code={403} unknownReason="no permission." />
<span className="system-sm-regular cursor-pointer text-text-tertiary" onClick={backToHome}>{t('userProfile.logout', { ns: 'common' })}</span>
<span className="cursor-pointer text-text-tertiary system-sm-regular" onClick={backToHome}>{t('userProfile.logout', { ns: 'common' })}</span>
</div>
)
}

View File

@@ -95,7 +95,7 @@ const Splash: FC<PropsWithChildren> = ({ children }) => {
return (
<div className="flex h-full flex-col items-center justify-center gap-y-4">
<AppUnavailable className="h-auto w-auto" code={code || t('common.appUnavailable', { ns: 'share' })} unknownReason={message} />
<span className="system-sm-regular cursor-pointer text-text-tertiary" onClick={backToHome}>{code === '403' ? t('userProfile.logout', { ns: 'common' }) : t('login.backToHome', { ns: 'share' })}</span>
<span className="cursor-pointer text-text-tertiary system-sm-regular" onClick={backToHome}>{code === '403' ? t('userProfile.logout', { ns: 'common' }) : t('login.backToHome', { ns: 'share' })}</span>
</div>
)
}

View File

@@ -69,8 +69,8 @@ export default function CheckCode() {
<RiMailSendFill className="h-6 w-6 text-2xl" />
</div>
<div className="pb-4 pt-2">
<h2 className="title-4xl-semi-bold text-text-primary">{t('checkCode.checkYourEmail', { ns: 'login' })}</h2>
<p className="body-md-regular mt-2 text-text-secondary">
<h2 className="text-text-primary title-4xl-semi-bold">{t('checkCode.checkYourEmail', { ns: 'login' })}</h2>
<p className="mt-2 text-text-secondary body-md-regular">
<span>
{t('checkCode.tipsPrefix', { ns: 'login' })}
<strong>{email}</strong>
@@ -82,7 +82,7 @@ export default function CheckCode() {
<form action="">
<input type="text" className="hidden" />
<label htmlFor="code" className="system-md-semibold mb-1 text-text-secondary">{t('checkCode.verificationCode', { ns: 'login' })}</label>
<label htmlFor="code" className="mb-1 text-text-secondary system-md-semibold">{t('checkCode.verificationCode', { ns: 'login' })}</label>
<Input value={code} onChange={e => setVerifyCode(e.target.value)} maxLength={6} className="mt-1" placeholder={t('checkCode.verificationCodePlaceholder', { ns: 'login' }) || ''} />
<Button loading={loading} disabled={loading} className="my-3 w-full" variant="primary" onClick={verify}>{t('checkCode.verify', { ns: 'login' })}</Button>
<Countdown onResend={resendCode} />
@@ -94,7 +94,7 @@ export default function CheckCode() {
<div className="bg-background-default-dimm inline-block rounded-full p-1">
<RiArrowLeftLine size={12} />
</div>
<span className="system-xs-regular ml-2">{t('back', { ns: 'login' })}</span>
<span className="ml-2 system-xs-regular">{t('back', { ns: 'login' })}</span>
</div>
</div>
)

View File

@@ -24,7 +24,7 @@ export default function SignInLayout({ children }: any) {
</div>
</div>
{!systemFeatures.branding.enabled && (
<div className="system-xs-regular px-8 py-6 text-text-tertiary">
<div className="px-8 py-6 text-text-tertiary system-xs-regular">
©
{' '}
{new Date().getFullYear()}

View File

@@ -74,8 +74,8 @@ export default function CheckCode() {
<RiLockPasswordLine className="h-6 w-6 text-2xl text-text-accent-light-mode-only" />
</div>
<div className="pb-4 pt-2">
<h2 className="title-4xl-semi-bold text-text-primary">{t('resetPassword', { ns: 'login' })}</h2>
<p className="body-md-regular mt-2 text-text-secondary">
<h2 className="text-text-primary title-4xl-semi-bold">{t('resetPassword', { ns: 'login' })}</h2>
<p className="mt-2 text-text-secondary body-md-regular">
{t('resetPasswordDesc', { ns: 'login' })}
</p>
</div>
@@ -83,7 +83,7 @@ export default function CheckCode() {
<form onSubmit={noop}>
<input type="text" className="hidden" />
<div className="mb-2">
<label htmlFor="email" className="system-md-semibold my-2 text-text-secondary">{t('email', { ns: 'login' })}</label>
<label htmlFor="email" className="my-2 text-text-secondary system-md-semibold">{t('email', { ns: 'login' })}</label>
<div className="mt-1">
<Input id="email" type="email" disabled={loading} value={email} placeholder={t('emailPlaceholder', { ns: 'login' }) as string} onChange={e => setEmail(e.target.value)} />
</div>
@@ -99,7 +99,7 @@ export default function CheckCode() {
<div className="inline-block rounded-full bg-background-default-dimmed p-1">
<RiArrowLeftLine size={12} />
</div>
<span className="system-xs-regular ml-2">{t('backToLogin', { ns: 'login' })}</span>
<span className="ml-2 system-xs-regular">{t('backToLogin', { ns: 'login' })}</span>
</Link>
</div>
)

View File

@@ -91,10 +91,10 @@ const ChangePasswordForm = () => {
{!showSuccess && (
<div className="flex flex-col md:w-[400px]">
<div className="mx-auto w-full">
<h2 className="title-4xl-semi-bold text-text-primary">
<h2 className="text-text-primary title-4xl-semi-bold">
{t('changePassword', { ns: 'login' })}
</h2>
<p className="body-md-regular mt-2 text-text-secondary">
<p className="mt-2 text-text-secondary body-md-regular">
{t('changePasswordTip', { ns: 'login' })}
</p>
</div>
@@ -103,7 +103,7 @@ const ChangePasswordForm = () => {
<div className="bg-white">
{/* Password */}
<div className="mb-5">
<label htmlFor="password" className="system-md-semibold my-2 text-text-secondary">
<label htmlFor="password" className="my-2 text-text-secondary system-md-semibold">
{t('account.newPassword', { ns: 'common' })}
</label>
<div className="relative mt-1">
@@ -125,11 +125,11 @@ const ChangePasswordForm = () => {
</Button>
</div>
</div>
<div className="body-xs-regular mt-1 text-text-secondary">{t('error.passwordInvalid', { ns: 'login' })}</div>
<div className="mt-1 text-text-secondary body-xs-regular">{t('error.passwordInvalid', { ns: 'login' })}</div>
</div>
{/* Confirm Password */}
<div className="mb-5">
<label htmlFor="confirmPassword" className="system-md-semibold my-2 text-text-secondary">
<label htmlFor="confirmPassword" className="my-2 text-text-secondary system-md-semibold">
{t('account.confirmPassword', { ns: 'common' })}
</label>
<div className="relative mt-1">
@@ -170,7 +170,7 @@ const ChangePasswordForm = () => {
<div className="mb-3 flex h-14 w-14 items-center justify-center rounded-2xl border border-components-panel-border-subtle font-bold shadow-lg">
<RiCheckboxCircleFill className="h-6 w-6 text-text-success" />
</div>
<h2 className="title-4xl-semi-bold text-text-primary">
<h2 className="text-text-primary title-4xl-semi-bold">
{t('passwordChangedTip', { ns: 'login' })}
</h2>
</div>

View File

@@ -110,8 +110,8 @@ export default function CheckCode() {
<RiMailSendFill className="h-6 w-6 text-2xl text-text-accent-light-mode-only" />
</div>
<div className="pb-4 pt-2">
<h2 className="title-4xl-semi-bold text-text-primary">{t('checkCode.checkYourEmail', { ns: 'login' })}</h2>
<p className="body-md-regular mt-2 text-text-secondary">
<h2 className="text-text-primary title-4xl-semi-bold">{t('checkCode.checkYourEmail', { ns: 'login' })}</h2>
<p className="mt-2 text-text-secondary body-md-regular">
<span>
{t('checkCode.tipsPrefix', { ns: 'login' })}
<strong>{email}</strong>
@@ -122,7 +122,7 @@ export default function CheckCode() {
</div>
<form onSubmit={handleSubmit}>
<label htmlFor="code" className="system-md-semibold mb-1 text-text-secondary">{t('checkCode.verificationCode', { ns: 'login' })}</label>
<label htmlFor="code" className="mb-1 text-text-secondary system-md-semibold">{t('checkCode.verificationCode', { ns: 'login' })}</label>
<Input
ref={codeInputRef}
id="code"
@@ -142,7 +142,7 @@ export default function CheckCode() {
<div className="bg-background-default-dimm inline-block rounded-full p-1">
<RiArrowLeftLine size={12} />
</div>
<span className="system-xs-regular ml-2">{t('back', { ns: 'login' })}</span>
<span className="ml-2 system-xs-regular">{t('back', { ns: 'login' })}</span>
</div>
</div>
)

View File

@@ -55,7 +55,7 @@ export default function MailAndCodeAuth() {
<form onSubmit={noop}>
<input type="text" className="hidden" />
<div className="mb-2">
<label htmlFor="email" className="system-md-semibold my-2 text-text-secondary">{t('email', { ns: 'login' })}</label>
<label htmlFor="email" className="my-2 text-text-secondary system-md-semibold">{t('email', { ns: 'login' })}</label>
<div className="mt-1">
<Input id="email" type="email" value={email} placeholder={t('emailPlaceholder', { ns: 'login' }) as string} onChange={e => setEmail(e.target.value)} />
</div>

View File

@@ -112,7 +112,7 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
return (
<form onSubmit={noop}>
<div className="mb-3">
<label htmlFor="email" className="system-md-semibold my-2 text-text-secondary">
<label htmlFor="email" className="my-2 text-text-secondary system-md-semibold">
{t('email', { ns: 'login' })}
</label>
<div className="mt-1">
@@ -130,7 +130,7 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
<div className="mb-3">
<label htmlFor="password" className="my-2 flex items-center justify-between">
<span className="system-md-semibold text-text-secondary">{t('password', { ns: 'login' })}</span>
<span className="text-text-secondary system-md-semibold">{t('password', { ns: 'login' })}</span>
<Link
href={`/webapp-reset-password?${searchParams.toString()}`}
className={`system-xs-regular ${isEmailSetup ? 'text-components-button-secondary-accent-text' : 'pointer-events-none text-components-button-secondary-accent-text-disabled'}`}

View File

@@ -21,7 +21,7 @@ export default function SignInLayout({ children }: PropsWithChildren) {
</div>
</div>
{systemFeatures.branding.enabled === false && (
<div className="system-xs-regular px-8 py-6 text-text-tertiary">
<div className="px-8 py-6 text-text-tertiary system-xs-regular">
©
{' '}
{new Date().getFullYear()}

View File

@@ -60,8 +60,8 @@ const NormalForm = () => {
<RiContractLine className="h-5 w-5" />
<RiErrorWarningFill className="absolute -right-1 -top-1 h-4 w-4 text-text-warning-secondary" />
</div>
<p className="system-sm-medium text-text-primary">{t('licenseLost', { ns: 'login' })}</p>
<p className="system-xs-regular mt-1 text-text-tertiary">{t('licenseLostTip', { ns: 'login' })}</p>
<p className="text-text-primary system-sm-medium">{t('licenseLost', { ns: 'login' })}</p>
<p className="mt-1 text-text-tertiary system-xs-regular">{t('licenseLostTip', { ns: 'login' })}</p>
</div>
</div>
</div>
@@ -76,8 +76,8 @@ const NormalForm = () => {
<RiContractLine className="h-5 w-5" />
<RiErrorWarningFill className="absolute -right-1 -top-1 h-4 w-4 text-text-warning-secondary" />
</div>
<p className="system-sm-medium text-text-primary">{t('licenseExpired', { ns: 'login' })}</p>
<p className="system-xs-regular mt-1 text-text-tertiary">{t('licenseExpiredTip', { ns: 'login' })}</p>
<p className="text-text-primary system-sm-medium">{t('licenseExpired', { ns: 'login' })}</p>
<p className="mt-1 text-text-tertiary system-xs-regular">{t('licenseExpiredTip', { ns: 'login' })}</p>
</div>
</div>
</div>
@@ -92,8 +92,8 @@ const NormalForm = () => {
<RiContractLine className="h-5 w-5" />
<RiErrorWarningFill className="absolute -right-1 -top-1 h-4 w-4 text-text-warning-secondary" />
</div>
<p className="system-sm-medium text-text-primary">{t('licenseInactive', { ns: 'login' })}</p>
<p className="system-xs-regular mt-1 text-text-tertiary">{t('licenseInactiveTip', { ns: 'login' })}</p>
<p className="text-text-primary system-sm-medium">{t('licenseInactive', { ns: 'login' })}</p>
<p className="mt-1 text-text-tertiary system-xs-regular">{t('licenseInactiveTip', { ns: 'login' })}</p>
</div>
</div>
</div>
@@ -104,8 +104,8 @@ const NormalForm = () => {
<>
<div className="mx-auto mt-8 w-full">
<div className="mx-auto w-full">
<h2 className="title-4xl-semi-bold text-text-primary">{systemFeatures.branding.enabled ? t('pageTitleForE', { ns: 'login' }) : t('pageTitle', { ns: 'login' })}</h2>
<p className="body-md-regular mt-2 text-text-tertiary">{t('welcome', { ns: 'login' })}</p>
<h2 className="text-text-primary title-4xl-semi-bold">{systemFeatures.branding.enabled ? t('pageTitleForE', { ns: 'login' }) : t('pageTitle', { ns: 'login' })}</h2>
<p className="mt-2 text-text-tertiary body-md-regular">{t('welcome', { ns: 'login' })}</p>
</div>
<div className="relative">
<div className="mt-6 flex flex-col gap-3">
@@ -122,7 +122,7 @@ const NormalForm = () => {
<div className="h-px w-full bg-gradient-to-r from-background-gradient-mask-transparent via-divider-regular to-background-gradient-mask-transparent"></div>
</div>
<div className="relative flex justify-center">
<span className="system-xs-medium-uppercase px-2 text-text-tertiary">{t('or', { ns: 'login' })}</span>
<span className="px-2 text-text-tertiary system-xs-medium-uppercase">{t('or', { ns: 'login' })}</span>
</div>
</div>
)}
@@ -134,7 +134,7 @@ const NormalForm = () => {
<MailAndCodeAuth />
{systemFeatures.enable_email_password_login && (
<div className="cursor-pointer py-1 text-center" onClick={() => { updateAuthType('password') }}>
<span className="system-xs-medium text-components-button-secondary-accent-text">{t('usePassword', { ns: 'login' })}</span>
<span className="text-components-button-secondary-accent-text system-xs-medium">{t('usePassword', { ns: 'login' })}</span>
</div>
)}
</>
@@ -144,7 +144,7 @@ const NormalForm = () => {
<MailAndPasswordAuth isEmailSetup={systemFeatures.is_email_setup} />
{systemFeatures.enable_email_code_login && (
<div className="cursor-pointer py-1 text-center" onClick={() => { updateAuthType('code') }}>
<span className="system-xs-medium text-components-button-secondary-accent-text">{t('useVerificationCode', { ns: 'login' })}</span>
<span className="text-components-button-secondary-accent-text system-xs-medium">{t('useVerificationCode', { ns: 'login' })}</span>
</div>
)}
</>
@@ -158,8 +158,8 @@ const NormalForm = () => {
<div className="shadows-shadow-lg mb-2 flex h-10 w-10 items-center justify-center rounded-xl bg-components-card-bg shadow">
<RiDoorLockLine className="h-5 w-5" />
</div>
<p className="system-sm-medium text-text-primary">{t('noLoginMethod', { ns: 'login' })}</p>
<p className="system-xs-regular mt-1 text-text-tertiary">{t('noLoginMethodTip', { ns: 'login' })}</p>
<p className="text-text-primary system-sm-medium">{t('noLoginMethod', { ns: 'login' })}</p>
<p className="mt-1 text-text-tertiary system-xs-regular">{t('noLoginMethodTip', { ns: 'login' })}</p>
</div>
<div className="relative my-2 py-2">
<div className="absolute inset-0 flex items-center" aria-hidden="true">
@@ -170,11 +170,11 @@ const NormalForm = () => {
)}
{!systemFeatures.branding.enabled && (
<>
<div className="system-xs-regular mt-2 block w-full text-text-tertiary">
<div className="mt-2 block w-full text-text-tertiary system-xs-regular">
{t('tosDesc', { ns: 'login' })}
&nbsp;
<Link
className="system-xs-medium text-text-secondary hover:underline"
className="text-text-secondary system-xs-medium hover:underline"
target="_blank"
rel="noopener noreferrer"
href="https://dify.ai/terms"
@@ -183,7 +183,7 @@ const NormalForm = () => {
</Link>
&nbsp;&&nbsp;
<Link
className="system-xs-medium text-text-secondary hover:underline"
className="text-text-secondary system-xs-medium hover:underline"
target="_blank"
rel="noopener noreferrer"
href="https://dify.ai/privacy"
@@ -192,11 +192,11 @@ const NormalForm = () => {
</Link>
</div>
{IS_CE_EDITION && (
<div className="w-hull system-xs-regular mt-2 block text-text-tertiary">
<div className="w-hull mt-2 block text-text-tertiary system-xs-regular">
{t('goToInit', { ns: 'login' })}
&nbsp;
<Link
className="system-xs-medium text-text-secondary hover:underline"
className="text-text-secondary system-xs-medium hover:underline"
href="/install"
>
{t('setAdminAccount', { ns: 'login' })}

View File

@@ -45,7 +45,7 @@ const WebSSOForm: FC = () => {
if (!systemFeatures.webapp_auth.enabled) {
return (
<div className="flex h-full items-center justify-center">
<p className="system-xs-regular text-text-tertiary">{t('webapp.disabled', { ns: 'login' })}</p>
<p className="text-text-tertiary system-xs-regular">{t('webapp.disabled', { ns: 'login' })}</p>
</div>
)
}
@@ -63,7 +63,7 @@ const WebSSOForm: FC = () => {
return (
<div className="flex h-full flex-col items-center justify-center gap-y-4">
<AppUnavailable className="h-auto w-auto" isUnknownReason={true} />
<span className="system-sm-regular cursor-pointer text-text-tertiary" onClick={backToHome}>{t('login.backToHome', { ns: 'share' })}</span>
<span className="cursor-pointer text-text-tertiary system-sm-regular" onClick={backToHome}>{t('login.backToHome', { ns: 'share' })}</span>
</div>
)
}

View File

@@ -160,7 +160,7 @@ const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => {
isShow={isShowDeleteConfirm}
onClose={() => setIsShowDeleteConfirm(false)}
>
<div className="title-2xl-semi-bold mb-3 text-text-primary">{t('avatar.deleteTitle', { ns: 'common' })}</div>
<div className="mb-3 text-text-primary title-2xl-semi-bold">{t('avatar.deleteTitle', { ns: 'common' })}</div>
<p className="mb-8 text-text-secondary">{t('avatar.deleteDescription', { ns: 'common' })}</p>
<div className="flex w-full items-center justify-center gap-2">

View File

@@ -209,14 +209,14 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
</div>
{step === STEP.start && (
<>
<div className="title-2xl-semi-bold pb-3 text-text-primary">{t('account.changeEmail.title', { ns: 'common' })}</div>
<div className="pb-3 text-text-primary title-2xl-semi-bold">{t('account.changeEmail.title', { ns: 'common' })}</div>
<div className="space-y-0.5 pb-2 pt-1">
<div className="body-md-medium text-text-warning">{t('account.changeEmail.authTip', { ns: 'common' })}</div>
<div className="body-md-regular text-text-secondary">
<div className="text-text-warning body-md-medium">{t('account.changeEmail.authTip', { ns: 'common' })}</div>
<div className="text-text-secondary body-md-regular">
<Trans
i18nKey="account.changeEmail.content1"
ns="common"
components={{ email: <span className="body-md-medium text-text-primary"></span> }}
components={{ email: <span className="text-text-primary body-md-medium"></span> }}
values={{ email }}
/>
</div>
@@ -241,19 +241,19 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
)}
{step === STEP.verifyOrigin && (
<>
<div className="title-2xl-semi-bold pb-3 text-text-primary">{t('account.changeEmail.verifyEmail', { ns: 'common' })}</div>
<div className="pb-3 text-text-primary title-2xl-semi-bold">{t('account.changeEmail.verifyEmail', { ns: 'common' })}</div>
<div className="space-y-0.5 pb-2 pt-1">
<div className="body-md-regular text-text-secondary">
<div className="text-text-secondary body-md-regular">
<Trans
i18nKey="account.changeEmail.content2"
ns="common"
components={{ email: <span className="body-md-medium text-text-primary"></span> }}
components={{ email: <span className="text-text-primary body-md-medium"></span> }}
values={{ email }}
/>
</div>
</div>
<div className="pt-3">
<div className="system-sm-medium mb-1 flex h-6 items-center text-text-secondary">{t('account.changeEmail.codeLabel', { ns: 'common' })}</div>
<div className="mb-1 flex h-6 items-center text-text-secondary system-sm-medium">{t('account.changeEmail.codeLabel', { ns: 'common' })}</div>
<Input
className="!w-full"
placeholder={t('account.changeEmail.codePlaceholder', { ns: 'common' })}
@@ -278,25 +278,25 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
{t('operation.cancel', { ns: 'common' })}
</Button>
</div>
<div className="system-xs-regular mt-3 flex items-center gap-1 text-text-tertiary">
<div className="mt-3 flex items-center gap-1 text-text-tertiary system-xs-regular">
<span>{t('account.changeEmail.resendTip', { ns: 'common' })}</span>
{time > 0 && (
<span>{t('account.changeEmail.resendCount', { ns: 'common', count: time })}</span>
)}
{!time && (
<span onClick={sendCodeToOriginEmail} className="system-xs-medium cursor-pointer text-text-accent-secondary">{t('account.changeEmail.resend', { ns: 'common' })}</span>
<span onClick={sendCodeToOriginEmail} className="cursor-pointer text-text-accent-secondary system-xs-medium">{t('account.changeEmail.resend', { ns: 'common' })}</span>
)}
</div>
</>
)}
{step === STEP.newEmail && (
<>
<div className="title-2xl-semi-bold pb-3 text-text-primary">{t('account.changeEmail.newEmail', { ns: 'common' })}</div>
<div className="pb-3 text-text-primary title-2xl-semi-bold">{t('account.changeEmail.newEmail', { ns: 'common' })}</div>
<div className="space-y-0.5 pb-2 pt-1">
<div className="body-md-regular text-text-secondary">{t('account.changeEmail.content3', { ns: 'common' })}</div>
<div className="text-text-secondary body-md-regular">{t('account.changeEmail.content3', { ns: 'common' })}</div>
</div>
<div className="pt-3">
<div className="system-sm-medium mb-1 flex h-6 items-center text-text-secondary">{t('account.changeEmail.emailLabel', { ns: 'common' })}</div>
<div className="mb-1 flex h-6 items-center text-text-secondary system-sm-medium">{t('account.changeEmail.emailLabel', { ns: 'common' })}</div>
<Input
className="!w-full"
placeholder={t('account.changeEmail.emailPlaceholder', { ns: 'common' })}
@@ -305,10 +305,10 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
destructive={newEmailExited || unAvailableEmail}
/>
{newEmailExited && (
<div className="body-xs-regular mt-1 py-0.5 text-text-destructive">{t('account.changeEmail.existingEmail', { ns: 'common' })}</div>
<div className="mt-1 py-0.5 text-text-destructive body-xs-regular">{t('account.changeEmail.existingEmail', { ns: 'common' })}</div>
)}
{unAvailableEmail && (
<div className="body-xs-regular mt-1 py-0.5 text-text-destructive">{t('account.changeEmail.unAvailableEmail', { ns: 'common' })}</div>
<div className="mt-1 py-0.5 text-text-destructive body-xs-regular">{t('account.changeEmail.unAvailableEmail', { ns: 'common' })}</div>
)}
</div>
<div className="mt-3 space-y-2">
@@ -331,19 +331,19 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
)}
{step === STEP.verifyNew && (
<>
<div className="title-2xl-semi-bold pb-3 text-text-primary">{t('account.changeEmail.verifyNew', { ns: 'common' })}</div>
<div className="pb-3 text-text-primary title-2xl-semi-bold">{t('account.changeEmail.verifyNew', { ns: 'common' })}</div>
<div className="space-y-0.5 pb-2 pt-1">
<div className="body-md-regular text-text-secondary">
<div className="text-text-secondary body-md-regular">
<Trans
i18nKey="account.changeEmail.content4"
ns="common"
components={{ email: <span className="body-md-medium text-text-primary"></span> }}
components={{ email: <span className="text-text-primary body-md-medium"></span> }}
values={{ email: mail }}
/>
</div>
</div>
<div className="pt-3">
<div className="system-sm-medium mb-1 flex h-6 items-center text-text-secondary">{t('account.changeEmail.codeLabel', { ns: 'common' })}</div>
<div className="mb-1 flex h-6 items-center text-text-secondary system-sm-medium">{t('account.changeEmail.codeLabel', { ns: 'common' })}</div>
<Input
className="!w-full"
placeholder={t('account.changeEmail.codePlaceholder', { ns: 'common' })}
@@ -368,13 +368,13 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
{t('operation.cancel', { ns: 'common' })}
</Button>
</div>
<div className="system-xs-regular mt-3 flex items-center gap-1 text-text-tertiary">
<div className="mt-3 flex items-center gap-1 text-text-tertiary system-xs-regular">
<span>{t('account.changeEmail.resendTip', { ns: 'common' })}</span>
{time > 0 && (
<span>{t('account.changeEmail.resendCount', { ns: 'common', count: time })}</span>
)}
{!time && (
<span onClick={sendCodeToNewEmail} className="system-xs-medium cursor-pointer text-text-accent-secondary">{t('account.changeEmail.resend', { ns: 'common' })}</span>
<span onClick={sendCodeToNewEmail} className="cursor-pointer text-text-accent-secondary system-xs-medium">{t('account.changeEmail.resend', { ns: 'common' })}</span>
)}
</div>
</>

View File

@@ -138,7 +138,7 @@ export default function AccountPage() {
imageUrl={icon_url}
/>
</div>
<div className="system-sm-medium mt-[3px] text-text-secondary">{item.name}</div>
<div className="mt-[3px] text-text-secondary system-sm-medium">{item.name}</div>
</div>
)
}
@@ -146,12 +146,12 @@ export default function AccountPage() {
return (
<>
<div className="pb-3 pt-2">
<h4 className="title-2xl-semi-bold text-text-primary">{t('account.myAccount', { ns: 'common' })}</h4>
<h4 className="text-text-primary title-2xl-semi-bold">{t('account.myAccount', { ns: 'common' })}</h4>
</div>
<div className="mb-8 flex items-center rounded-xl bg-gradient-to-r from-background-gradient-bg-fill-chat-bg-2 to-background-gradient-bg-fill-chat-bg-1 p-6">
<AvatarWithEdit avatar={userProfile.avatar_url} name={userProfile.name} onSave={mutateUserProfile} size={64} />
<div className="ml-4">
<p className="system-xl-semibold text-text-primary">
<p className="text-text-primary system-xl-semibold">
{userProfile.name}
{isEducationAccount && (
<PremiumBadge size="s" color="blue" className="ml-1 !px-2">
@@ -160,16 +160,16 @@ export default function AccountPage() {
</PremiumBadge>
)}
</p>
<p className="system-xs-regular text-text-tertiary">{userProfile.email}</p>
<p className="text-text-tertiary system-xs-regular">{userProfile.email}</p>
</div>
</div>
<div className="mb-8">
<div className={titleClassName}>{t('account.name', { ns: 'common' })}</div>
<div className="mt-2 flex w-full items-center justify-between gap-2">
<div className="system-sm-regular flex-1 rounded-lg bg-components-input-bg-normal p-2 text-components-input-text-filled">
<div className="flex-1 rounded-lg bg-components-input-bg-normal p-2 text-components-input-text-filled system-sm-regular">
<span className="pl-1">{userProfile.name}</span>
</div>
<div className="system-sm-medium cursor-pointer rounded-lg bg-components-button-tertiary-bg px-3 py-2 text-components-button-tertiary-text" onClick={handleEditName}>
<div className="cursor-pointer rounded-lg bg-components-button-tertiary-bg px-3 py-2 text-components-button-tertiary-text system-sm-medium" onClick={handleEditName}>
{t('operation.edit', { ns: 'common' })}
</div>
</div>
@@ -177,11 +177,11 @@ export default function AccountPage() {
<div className="mb-8">
<div className={titleClassName}>{t('account.email', { ns: 'common' })}</div>
<div className="mt-2 flex w-full items-center justify-between gap-2">
<div className="system-sm-regular flex-1 rounded-lg bg-components-input-bg-normal p-2 text-components-input-text-filled">
<div className="flex-1 rounded-lg bg-components-input-bg-normal p-2 text-components-input-text-filled system-sm-regular">
<span className="pl-1">{userProfile.email}</span>
</div>
{systemFeatures.enable_change_email && (
<div className="system-sm-medium cursor-pointer rounded-lg bg-components-button-tertiary-bg px-3 py-2 text-components-button-tertiary-text" onClick={() => setShowUpdateEmail(true)}>
<div className="cursor-pointer rounded-lg bg-components-button-tertiary-bg px-3 py-2 text-components-button-tertiary-text system-sm-medium" onClick={() => setShowUpdateEmail(true)}>
{t('operation.change', { ns: 'common' })}
</div>
)}
@@ -191,8 +191,8 @@ export default function AccountPage() {
systemFeatures.enable_email_password_login && (
<div className="mb-8 flex justify-between gap-2">
<div>
<div className="system-sm-semibold mb-1 text-text-secondary">{t('account.password', { ns: 'common' })}</div>
<div className="body-xs-regular mb-2 text-text-tertiary">{t('account.passwordTip', { ns: 'common' })}</div>
<div className="mb-1 text-text-secondary system-sm-semibold">{t('account.password', { ns: 'common' })}</div>
<div className="mb-2 text-text-tertiary body-xs-regular">{t('account.passwordTip', { ns: 'common' })}</div>
</div>
<Button onClick={() => setEditPasswordModalVisible(true)}>{userProfile.is_password_set ? t('account.resetPassword', { ns: 'common' }) : t('account.setPassword', { ns: 'common' })}</Button>
</div>
@@ -219,7 +219,7 @@ export default function AccountPage() {
onClose={() => setEditNameModalVisible(false)}
className="!w-[420px] !p-6"
>
<div className="title-2xl-semi-bold mb-6 text-text-primary">{t('account.editName', { ns: 'common' })}</div>
<div className="mb-6 text-text-primary title-2xl-semi-bold">{t('account.editName', { ns: 'common' })}</div>
<div className={titleClassName}>{t('account.name', { ns: 'common' })}</div>
<Input
className="mt-2"
@@ -249,7 +249,7 @@ export default function AccountPage() {
}}
className="!w-[420px] !p-6"
>
<div className="title-2xl-semi-bold mb-6 text-text-primary">{userProfile.is_password_set ? t('account.resetPassword', { ns: 'common' }) : t('account.setPassword', { ns: 'common' })}</div>
<div className="mb-6 text-text-primary title-2xl-semi-bold">{userProfile.is_password_set ? t('account.resetPassword', { ns: 'common' }) : t('account.setPassword', { ns: 'common' })}</div>
{userProfile.is_password_set && (
<>
<div className={titleClassName}>{t('account.currentPassword', { ns: 'common' })}</div>
@@ -272,7 +272,7 @@ export default function AccountPage() {
</div>
</>
)}
<div className="system-sm-semibold mt-8 text-text-secondary">
<div className="mt-8 text-text-secondary system-sm-semibold">
{userProfile.is_password_set ? t('account.newPassword', { ns: 'common' }) : t('account.password', { ns: 'common' })}
</div>
<div className="relative mt-2">
@@ -291,7 +291,7 @@ export default function AccountPage() {
</Button>
</div>
</div>
<div className="system-sm-semibold mt-8 text-text-secondary">{t('account.confirmPassword', { ns: 'common' })}</div>
<div className="mt-8 text-text-secondary system-sm-semibold">{t('account.confirmPassword', { ns: 'common' })}</div>
<div className="relative mt-2">
<Input
type={showConfirmPassword ? 'text' : 'password'}

View File

@@ -73,7 +73,7 @@ export default function AppSelector() {
<div className="p-1">
<div className="flex flex-nowrap items-center px-3 py-2">
<div className="grow">
<div className="system-md-medium break-all text-text-primary">
<div className="break-all text-text-primary system-md-medium">
{userProfile.name}
{isEducationAccount && (
<PremiumBadge size="s" color="blue" className="ml-1 !px-2">
@@ -82,7 +82,7 @@ export default function AppSelector() {
</PremiumBadge>
)}
</div>
<div className="system-xs-regular break-all text-text-tertiary">{userProfile.email}</div>
<div className="break-all text-text-tertiary system-xs-regular">{userProfile.email}</div>
</div>
<Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={32} />
</div>

View File

@@ -30,14 +30,14 @@ export default function CheckEmail(props: DeleteAccountProps) {
return (
<>
<div className="body-md-medium py-1 text-text-destructive">
<div className="py-1 text-text-destructive body-md-medium">
{t('account.deleteTip', { ns: 'common' })}
</div>
<div className="body-md-regular pb-2 pt-1 text-text-secondary">
<div className="pb-2 pt-1 text-text-secondary body-md-regular">
{t('account.deletePrivacyLinkTip', { ns: 'common' })}
<Link href="https://dify.ai/privacy" className="text-text-accent">{t('account.deletePrivacyLink', { ns: 'common' })}</Link>
</div>
<label className="system-sm-semibold mb-1 mt-3 flex h-6 items-center text-text-secondary">{t('account.deleteLabel', { ns: 'common' })}</label>
<label className="mb-1 mt-3 flex h-6 items-center text-text-secondary system-sm-semibold">{t('account.deleteLabel', { ns: 'common' })}</label>
<Input
placeholder={t('account.deletePlaceholder', { ns: 'common' }) as string}
onChange={(e) => {

View File

@@ -54,7 +54,7 @@ export default function FeedBack(props: DeleteAccountProps) {
className="max-w-[480px]"
footer={false}
>
<label className="system-sm-semibold mb-1 mt-3 flex items-center text-text-secondary">{t('account.feedbackLabel', { ns: 'common' })}</label>
<label className="mb-1 mt-3 flex items-center text-text-secondary system-sm-semibold">{t('account.feedbackLabel', { ns: 'common' })}</label>
<Textarea
rows={6}
value={userFeedback}

View File

@@ -36,14 +36,14 @@ export default function VerifyEmail(props: DeleteAccountProps) {
}, [emailToken, verificationCode, confirmDeleteAccount, props])
return (
<>
<div className="body-md-medium pt-1 text-text-destructive">
<div className="pt-1 text-text-destructive body-md-medium">
{t('account.deleteTip', { ns: 'common' })}
</div>
<div className="body-md-regular pb-2 pt-1 text-text-secondary">
<div className="pb-2 pt-1 text-text-secondary body-md-regular">
{t('account.deletePrivacyLinkTip', { ns: 'common' })}
<Link href="https://dify.ai/privacy" className="text-text-accent">{t('account.deletePrivacyLink', { ns: 'common' })}</Link>
</div>
<label className="system-sm-semibold mb-1 mt-3 flex h-6 items-center text-text-secondary">{t('account.verificationLabel', { ns: 'common' })}</label>
<label className="mb-1 mt-3 flex h-6 items-center text-text-secondary system-sm-semibold">{t('account.verificationLabel', { ns: 'common' })}</label>
<Input
minLength={6}
maxLength={6}

View File

@@ -32,10 +32,10 @@ const Header = () => {
: <DifyLogo />}
</div>
<div className="h-4 w-[1px] origin-center rotate-[11.31deg] bg-divider-regular" />
<p className="title-3xl-semi-bold relative mt-[-2px] text-text-primary">{t('account.account', { ns: 'common' })}</p>
<p className="relative mt-[-2px] text-text-primary title-3xl-semi-bold">{t('account.account', { ns: 'common' })}</p>
</div>
<div className="flex shrink-0 items-center gap-3">
<Button className="system-sm-medium gap-2 px-3 py-2" onClick={goToStudio}>
<Button className="gap-2 px-3 py-2 system-sm-medium" onClick={goToStudio}>
<RiRobot2Line className="h-4 w-4" />
<p>{t('account.studio', { ns: 'common' })}</p>
<RiArrowRightUpLine className="h-4 w-4" />

View File

@@ -38,7 +38,7 @@ export default function SignInLayout({ children }: any) {
</div>
</div>
{systemFeatures.branding.enabled === false && (
<div className="system-xs-regular px-8 py-6 text-text-tertiary">
<div className="px-8 py-6 text-text-tertiary system-xs-regular">
©
{' '}
{new Date().getFullYear()}

View File

@@ -145,7 +145,7 @@ export default function OAuthAuthorize() {
<div className="text-[var(--color-saas-dify-blue-inverted)]">{authAppInfo?.app_label[language] || authAppInfo?.app_label?.en_US || t('unknownApp', { ns: 'oauth' })}</div>
{!isLoggedIn && <div className="text-text-primary">{t('tips.notLoggedIn', { ns: 'oauth' })}</div>}
</div>
<div className="body-md-regular text-text-secondary">{isLoggedIn ? `${authAppInfo?.app_label[language] || authAppInfo?.app_label?.en_US || t('unknownApp', { ns: 'oauth' })} ${t('tips.loggedIn', { ns: 'oauth' })}` : t('tips.needLogin', { ns: 'oauth' })}</div>
<div className="text-text-secondary body-md-regular">{isLoggedIn ? `${authAppInfo?.app_label[language] || authAppInfo?.app_label?.en_US || t('unknownApp', { ns: 'oauth' })} ${t('tips.loggedIn', { ns: 'oauth' })}` : t('tips.needLogin', { ns: 'oauth' })}</div>
</div>
{isLoggedIn && userProfile && (
@@ -154,7 +154,7 @@ export default function OAuthAuthorize() {
<Avatar avatar={userProfile.avatar_url} name={userProfile.name} size={36} />
<div>
<div className="system-md-semi-bold text-text-secondary">{userProfile.name}</div>
<div className="system-xs-regular text-text-tertiary">{userProfile.email}</div>
<div className="text-text-tertiary system-xs-regular">{userProfile.email}</div>
</div>
</div>
<Button variant="tertiary" size="small" onClick={onLoginSwitchClick}>{t('switchAccount', { ns: 'oauth' })}</Button>
@@ -166,7 +166,7 @@ export default function OAuthAuthorize() {
{authAppInfo!.scope.split(/\s+/).filter(Boolean).map((scope: string) => {
const Icon = SCOPE_INFO_MAP[scope]
return (
<div key={scope} className="body-sm-medium flex items-center gap-2 text-text-secondary">
<div key={scope} className="flex items-center gap-2 text-text-secondary body-sm-medium">
{Icon ? <Icon.icon className="h-4 w-4" /> : <RiAccountCircleLine className="h-4 w-4" />}
{Icon.label}
</div>
@@ -199,7 +199,7 @@ export default function OAuthAuthorize() {
</defs>
</svg>
</div>
<div className="system-xs-regular mt-3 text-text-tertiary">{t('tips.common', { ns: 'oauth' })}</div>
<div className="mt-3 text-text-tertiary system-xs-regular">{t('tips.common', { ns: 'oauth' })}</div>
</div>
)
}

View File

@@ -369,9 +369,9 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
{expand && (
<div className="flex flex-col items-start gap-1">
<div className="flex w-full">
<div className="system-md-semibold truncate whitespace-nowrap text-text-secondary">{appDetail.name}</div>
<div className="truncate whitespace-nowrap text-text-secondary system-md-semibold">{appDetail.name}</div>
</div>
<div className="system-2xs-medium-uppercase whitespace-nowrap text-text-tertiary">
<div className="whitespace-nowrap text-text-tertiary system-2xs-medium-uppercase">
{appDetail.mode === AppModeEnum.ADVANCED_CHAT
? t('types.advanced', { ns: 'app' })
: appDetail.mode === AppModeEnum.AGENT_CHAT
@@ -405,13 +405,13 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
imageUrl={appDetail.icon_url}
/>
<div className="flex flex-1 flex-col items-start justify-center overflow-hidden">
<div className="system-md-semibold w-full truncate text-text-secondary">{appDetail.name}</div>
<div className="system-2xs-medium-uppercase text-text-tertiary">{appDetail.mode === AppModeEnum.ADVANCED_CHAT ? t('types.advanced', { ns: 'app' }) : appDetail.mode === AppModeEnum.AGENT_CHAT ? t('types.agent', { ns: 'app' }) : appDetail.mode === AppModeEnum.CHAT ? t('types.chatbot', { ns: 'app' }) : appDetail.mode === AppModeEnum.COMPLETION ? t('types.completion', { ns: 'app' }) : t('types.workflow', { ns: 'app' })}</div>
<div className="w-full truncate text-text-secondary system-md-semibold">{appDetail.name}</div>
<div className="text-text-tertiary system-2xs-medium-uppercase">{appDetail.mode === AppModeEnum.ADVANCED_CHAT ? t('types.advanced', { ns: 'app' }) : appDetail.mode === AppModeEnum.AGENT_CHAT ? t('types.agent', { ns: 'app' }) : appDetail.mode === AppModeEnum.CHAT ? t('types.chatbot', { ns: 'app' }) : appDetail.mode === AppModeEnum.COMPLETION ? t('types.completion', { ns: 'app' }) : t('types.workflow', { ns: 'app' })}</div>
</div>
</div>
{/* description */}
{appDetail.description && (
<div className="system-xs-regular overflow-wrap-anywhere max-h-[105px] w-full max-w-full overflow-y-auto whitespace-normal break-words text-text-tertiary">{appDetail.description}</div>
<div className="overflow-wrap-anywhere max-h-[105px] w-full max-w-full overflow-y-auto whitespace-normal break-words text-text-tertiary system-xs-regular">{appDetail.description}</div>
)}
{/* operations */}
<AppOperations
@@ -435,7 +435,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
onClick={switchOperation.onClick}
>
{switchOperation.icon}
<span className="system-sm-medium text-text-tertiary">{switchOperation.title}</span>
<span className="text-text-tertiary system-sm-medium">{switchOperation.title}</span>
</Button>
</div>
)}

View File

@@ -134,7 +134,7 @@ const AppOperations = ({
tabIndex={-1}
>
{cloneElement(operation.icon, { className: 'h-3.5 w-3.5 text-components-button-secondary-text' })}
<span className="system-xs-medium text-components-button-secondary-text">
<span className="text-components-button-secondary-text system-xs-medium">
{operation.title}
</span>
</Button>
@@ -147,7 +147,7 @@ const AppOperations = ({
tabIndex={-1}
>
<RiMoreLine className="h-3.5 w-3.5 text-components-button-secondary-text" />
<span className="system-xs-medium text-components-button-secondary-text">
<span className="text-components-button-secondary-text system-xs-medium">
{t('operation.more', { ns: 'common' })}
</span>
</Button>
@@ -163,7 +163,7 @@ const AppOperations = ({
onClick={operation.onClick}
>
{cloneElement(operation.icon, { className: 'h-3.5 w-3.5 text-components-button-secondary-text' })}
<span className="system-xs-medium text-components-button-secondary-text">
<span className="text-components-button-secondary-text system-xs-medium">
{operation.title}
</span>
</Button>
@@ -182,7 +182,7 @@ const AppOperations = ({
className="gap-[1px]"
>
<RiMoreLine className="h-3.5 w-3.5 text-components-button-secondary-text" />
<span className="system-xs-medium text-components-button-secondary-text">
<span className="text-components-button-secondary-text system-xs-medium">
{t('operation.more', { ns: 'common' })}
</span>
</Button>
@@ -200,7 +200,7 @@ const AppOperations = ({
onClick={item.onClick}
>
{cloneElement(item.icon, { className: 'h-4 w-4 text-text-tertiary' })}
<span className="system-md-regular text-text-secondary">{item.title}</span>
<span className="text-text-secondary system-md-regular">{item.title}</span>
</div>
))}
</div>

View File

@@ -97,9 +97,9 @@ const AppSidebarDropdown = ({ navigation }: Props) => {
</div>
<div className="flex flex-col items-start gap-1">
<div className="flex w-full">
<div className="system-md-semibold truncate text-text-secondary">{appDetail.name}</div>
<div className="truncate text-text-secondary system-md-semibold">{appDetail.name}</div>
</div>
<div className="system-2xs-medium-uppercase text-text-tertiary">{appDetail.mode === AppModeEnum.ADVANCED_CHAT ? t('types.advanced', { ns: 'app' }) : appDetail.mode === AppModeEnum.AGENT_CHAT ? t('types.agent', { ns: 'app' }) : appDetail.mode === AppModeEnum.CHAT ? t('types.chatbot', { ns: 'app' }) : appDetail.mode === AppModeEnum.COMPLETION ? t('types.completion', { ns: 'app' }) : t('types.workflow', { ns: 'app' })}</div>
<div className="text-text-tertiary system-2xs-medium-uppercase">{appDetail.mode === AppModeEnum.ADVANCED_CHAT ? t('types.advanced', { ns: 'app' }) : appDetail.mode === AppModeEnum.AGENT_CHAT ? t('types.agent', { ns: 'app' }) : appDetail.mode === AppModeEnum.CHAT ? t('types.chatbot', { ns: 'app' }) : appDetail.mode === AppModeEnum.COMPLETION ? t('types.completion', { ns: 'app' }) : t('types.workflow', { ns: 'app' })}</div>
</div>
</div>
</div>

View File

@@ -76,7 +76,7 @@ export default function AppBasic({ icon, icon_background, name, isExternal, type
)}
{mode === 'expand' && (
<div className="group w-full">
<div className={`system-md-semibold flex flex-row items-center text-text-secondary group-hover:text-text-primary ${textStyle?.main ?? ''}`}>
<div className={`flex flex-row items-center text-text-secondary system-md-semibold group-hover:text-text-primary ${textStyle?.main ?? ''}`}>
<div className="min-w-0 overflow-hidden text-ellipsis break-normal">
{name}
</div>
@@ -95,10 +95,10 @@ export default function AppBasic({ icon, icon_background, name, isExternal, type
)}
</div>
{!hideType && isExtraInLine && (
<div className="system-2xs-medium-uppercase flex text-text-tertiary">{type}</div>
<div className="flex text-text-tertiary system-2xs-medium-uppercase">{type}</div>
)}
{!hideType && !isExtraInLine && (
<div className="system-2xs-medium-uppercase text-text-tertiary">{isExternal ? t('externalTag', { ns: 'dataset' }) : type}</div>
<div className="text-text-tertiary system-2xs-medium-uppercase">{isExternal ? t('externalTag', { ns: 'dataset' }) : type}</div>
)}
</div>
)}

View File

@@ -64,12 +64,12 @@ const DatasetInfo: FC<DatasetInfoProps> = ({
{expand && (
<div className="flex flex-col gap-y-1 pb-0.5">
<div
className="system-md-semibold truncate text-text-secondary"
className="truncate text-text-secondary system-md-semibold"
title={dataset.name}
>
{dataset.name}
</div>
<div className="system-2xs-medium-uppercase text-text-tertiary">
<div className="text-text-tertiary system-2xs-medium-uppercase">
{isExternalProvider && t('externalTag', { ns: 'dataset' })}
{!!(!isExternalProvider && isPipelinePublished && dataset.doc_form && dataset.indexing_technique) && (
<div className="flex items-center gap-x-2">
@@ -79,7 +79,7 @@ const DatasetInfo: FC<DatasetInfoProps> = ({
)}
</div>
{!!dataset.description && (
<p className="system-xs-regular line-clamp-3 text-text-tertiary first-letter:capitalize">
<p className="line-clamp-3 text-text-tertiary system-xs-regular first-letter:capitalize">
{dataset.description}
</p>
)}

View File

@@ -22,7 +22,7 @@ const MenuItem = ({
}}
>
<Icon className="size-4 text-text-tertiary" />
<span className="system-md-regular px-1 text-text-secondary">{name}</span>
<span className="px-1 text-text-secondary system-md-regular">{name}</span>
</div>
)
}

View File

@@ -107,12 +107,12 @@ const DatasetSidebarDropdown = ({
</div>
<div className="flex flex-col gap-y-1 pb-0.5">
<div
className="system-md-semibold truncate text-text-secondary"
className="truncate text-text-secondary system-md-semibold"
title={dataset.name}
>
{dataset.name}
</div>
<div className="system-2xs-medium-uppercase text-text-tertiary">
<div className="text-text-tertiary system-2xs-medium-uppercase">
{isExternalProvider && t('externalTag', { ns: 'dataset' })}
{!!(!isExternalProvider && dataset.doc_form && dataset.indexing_technique) && (
<div className="flex items-center gap-x-2">
@@ -123,7 +123,7 @@ const DatasetSidebarDropdown = ({
</div>
</div>
{!!dataset.description && (
<p className="system-xs-regular line-clamp-3 text-text-tertiary first-letter:capitalize">
<p className="line-clamp-3 text-text-tertiary system-xs-regular first-letter:capitalize">
{dataset.description}
</p>
)}

View File

@@ -54,7 +54,7 @@ const NavLink = ({
key={name}
type="button"
disabled
className={cn('system-sm-medium flex h-8 cursor-not-allowed items-center rounded-lg text-components-menu-item-text opacity-30 hover:bg-components-menu-item-bg-hover', 'pl-3 pr-1')}
className={cn('flex h-8 cursor-not-allowed items-center rounded-lg text-components-menu-item-text opacity-30 system-sm-medium hover:bg-components-menu-item-bg-hover', 'pl-3 pr-1')}
title={mode === 'collapse' ? name : ''}
aria-disabled
>
@@ -75,8 +75,8 @@ const NavLink = ({
key={name}
href={href}
className={cn(isActive
? 'system-sm-semibold border-b-[0.25px] border-l-[0.75px] border-r-[0.25px] border-t-[0.75px] border-effects-highlight-lightmode-off bg-components-menu-item-bg-active text-text-accent-light-mode-only'
: 'system-sm-medium text-components-menu-item-text hover:bg-components-menu-item-bg-hover hover:text-components-menu-item-text-hover', 'flex h-8 items-center rounded-lg pl-3 pr-1')}
? 'border-b-[0.25px] border-l-[0.75px] border-r-[0.25px] border-t-[0.75px] border-effects-highlight-lightmode-off bg-components-menu-item-bg-active text-text-accent-light-mode-only system-sm-semibold'
: 'text-components-menu-item-text system-sm-medium hover:bg-components-menu-item-bg-hover hover:text-components-menu-item-text-hover', 'flex h-8 items-center rounded-lg pl-3 pr-1')}
title={mode === 'collapse' ? name : ''}
>
{renderIcon()}

View File

@@ -19,7 +19,7 @@ const TooltipContent = ({
return (
<div className="flex items-center gap-x-1">
<span className="system-xs-medium px-0.5 text-text-secondary">{expand ? t('sidebar.collapseSidebar', { ns: 'layout' }) : t('sidebar.expandSidebar', { ns: 'layout' })}</span>
<span className="px-0.5 text-text-secondary system-xs-medium">{expand ? t('sidebar.collapseSidebar', { ns: 'layout' }) : t('sidebar.expandSidebar', { ns: 'layout' })}</span>
<ShortcutsName keys={TOGGLE_SHORTCUT} textColor="secondary" />
</div>
)

View File

@@ -31,7 +31,7 @@ const EditItem: FC<Props> = ({
{avatar}
</div>
<div className="grow">
<div className="system-xs-semibold mb-1 text-text-primary">{name}</div>
<div className="mb-1 text-text-primary system-xs-semibold">{name}</div>
<Textarea
value={content}
onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => onChange(e.target.value)}

View File

@@ -99,7 +99,7 @@ const AddAnnotationModal: FC<Props> = ({
<AnnotationFull />
</div>
)}
<div className="system-sm-medium flex h-16 items-center justify-between rounded-bl-xl rounded-br-xl border-t border-divider-subtle bg-background-section-burn px-4 text-text-tertiary">
<div className="flex h-16 items-center justify-between rounded-bl-xl rounded-br-xl border-t border-divider-subtle bg-background-section-burn px-4 text-text-tertiary system-sm-medium">
<div
className="flex items-center space-x-2"
>

View File

@@ -33,7 +33,7 @@ const CSVDownload: FC = () => {
return (
<div className="mt-6">
<div className="system-sm-medium text-text-primary">{t('generation.csvStructureTitle', { ns: 'share' })}</div>
<div className="text-text-primary system-sm-medium">{t('generation.csvStructureTitle', { ns: 'share' })}</div>
<div className="mt-2 max-h-[500px] overflow-auto">
<table className="w-full table-fixed border-separate border-spacing-0 rounded-lg border border-divider-regular text-xs">
<thead className="text-text-tertiary">
@@ -77,7 +77,7 @@ const CSVDownload: FC = () => {
bom={true}
data={getTemplate()}
>
<div className="system-xs-medium flex h-[18px] items-center space-x-1 text-text-accent">
<div className="flex h-[18px] items-center space-x-1 text-text-accent system-xs-medium">
<DownloadIcon className="mr-1 h-3 w-3" />
{t('batchModal.template', { ns: 'appAnnotation' })}
</div>

View File

@@ -94,7 +94,7 @@ const CSVUploader: FC<Props> = ({
/>
<div ref={dropRef}>
{!file && (
<div className={cn('system-sm-regular flex h-20 items-center rounded-xl border border-dashed border-components-dropzone-border bg-components-dropzone-bg', dragging && 'border border-components-dropzone-border-accent bg-components-dropzone-bg-accent')}>
<div className={cn('flex h-20 items-center rounded-xl border border-dashed border-components-dropzone-border bg-components-dropzone-bg system-sm-regular', dragging && 'border border-components-dropzone-border-accent bg-components-dropzone-bg-accent')}>
<div className="flex w-full items-center justify-center space-x-2">
<CSVIcon className="shrink-0" />
<div className="text-text-tertiary">

View File

@@ -90,7 +90,7 @@ const BatchModal: FC<IBatchModalProps> = ({
return (
<Modal isShow={isShow} onClose={noop} className="!max-w-[520px] !rounded-xl px-8 py-6">
<div className="system-xl-medium relative pb-1 text-text-primary">{t('batchModal.title', { ns: 'appAnnotation' })}</div>
<div className="relative pb-1 text-text-primary system-xl-medium">{t('batchModal.title', { ns: 'appAnnotation' })}</div>
<div className="absolute right-4 top-4 cursor-pointer p-2" onClick={onCancel}>
<RiCloseLine className="h-4 w-4 text-text-tertiary" />
</div>
@@ -107,7 +107,7 @@ const BatchModal: FC<IBatchModalProps> = ({
)}
<div className="mt-[28px] flex justify-end pt-6">
<Button className="system-sm-medium mr-2 text-text-tertiary" onClick={onCancel}>
<Button className="mr-2 text-text-tertiary system-sm-medium" onClick={onCancel}>
{t('batchModal.cancel', { ns: 'appAnnotation' })}
</Button>
<Button

View File

@@ -21,7 +21,7 @@ type Props = {
}
export const EditTitle: FC<{ className?: string, title: string }> = ({ className, title }) => (
<div className={cn(className, 'system-xs-medium flex h-[18px] items-center text-text-tertiary')}>
<div className={cn(className, 'flex h-[18px] items-center text-text-tertiary system-xs-medium')}>
<RiEditFill className="mr-1 h-3.5 w-3.5" />
<div>{title}</div>
<div
@@ -75,21 +75,21 @@ const EditItem: FC<Props> = ({
{avatar}
</div>
<div className="grow">
<div className="system-xs-semibold mb-1 text-text-primary">{name}</div>
<div className="system-sm-regular text-text-primary">{content}</div>
<div className="mb-1 text-text-primary system-xs-semibold">{name}</div>
<div className="text-text-primary system-sm-regular">{content}</div>
{!isEdit
? (
<div>
{showNewContent && (
<div className="mt-3">
<EditTitle title={editTitle} />
<div className="system-sm-regular mt-1 text-text-primary">{newContent}</div>
<div className="mt-1 text-text-primary system-sm-regular">{newContent}</div>
</div>
)}
<div className="mt-2 flex items-center">
{!readonly && (
<div
className="system-xs-medium flex cursor-pointer items-center space-x-1 text-text-accent"
className="flex cursor-pointer items-center space-x-1 text-text-accent system-xs-medium"
onClick={() => {
setIsEdit(true)
}}
@@ -100,7 +100,7 @@ const EditItem: FC<Props> = ({
)}
{showNewContent && (
<div className="system-xs-medium ml-2 flex items-center text-text-tertiary">
<div className="ml-2 flex items-center text-text-tertiary system-xs-medium">
<div className="mr-2">·</div>
<div
className="flex cursor-pointer items-center space-x-1"

View File

@@ -136,7 +136,7 @@ const EditAnnotationModal: FC<Props> = ({
{
annotationId
? (
<div className="system-sm-medium flex h-16 items-center justify-between rounded-bl-xl rounded-br-xl border-t border-divider-subtle bg-background-section-burn px-4 text-text-tertiary">
<div className="flex h-16 items-center justify-between rounded-bl-xl rounded-br-xl border-t border-divider-subtle bg-background-section-burn px-4 text-text-tertiary system-sm-medium">
<div
className="flex cursor-pointer items-center space-x-2 pl-3"
onClick={() => setShowModal(true)}

View File

@@ -17,11 +17,11 @@ const EmptyElement: FC = () => {
return (
<div className="flex h-full items-center justify-center">
<div className="box-border h-fit w-[560px] rounded-2xl bg-background-section-burn px-5 py-4">
<span className="system-md-semibold text-text-secondary">
<span className="text-text-secondary system-md-semibold">
{t('noData.title', { ns: 'appAnnotation' })}
<ThreeDotsIcon className="relative -left-1.5 -top-3 inline" />
</span>
<div className="system-sm-regular mt-2 text-text-tertiary">
<div className="mt-2 text-text-tertiary system-sm-regular">
{t('noData.description', { ns: 'appAnnotation' })}
</div>
</div>

View File

@@ -103,12 +103,12 @@ const HeaderOptions: FC<Props> = ({
}}
>
<FilePlus02 className="h-4 w-4 text-text-tertiary" />
<span className="system-sm-regular grow text-left text-text-secondary">{t('table.header.bulkImport', { ns: 'appAnnotation' })}</span>
<span className="grow text-left text-text-secondary system-sm-regular">{t('table.header.bulkImport', { ns: 'appAnnotation' })}</span>
</button>
<Menu as="div" className="relative h-full w-full">
<MenuButton className="mx-1 flex h-9 w-[calc(100%_-_8px)] cursor-pointer items-center space-x-2 rounded-lg px-3 py-2 hover:bg-components-panel-on-panel-item-bg-hover disabled:opacity-50">
<FileDownload02 className="h-4 w-4 text-text-tertiary" />
<span className="system-sm-regular grow text-left text-text-secondary">{t('table.header.bulkExport', { ns: 'appAnnotation' })}</span>
<span className="grow text-left text-text-secondary system-sm-regular">{t('table.header.bulkExport', { ns: 'appAnnotation' })}</span>
<ChevronRight className="h-[14px] w-[14px] shrink-0 text-text-tertiary" />
</MenuButton>
<Transition
@@ -135,11 +135,11 @@ const HeaderOptions: FC<Props> = ({
]}
>
<button type="button" disabled={annotationUnavailable} className="mx-1 flex h-9 w-[calc(100%_-_8px)] cursor-pointer items-center space-x-2 rounded-lg px-3 py-2 hover:bg-components-panel-on-panel-item-bg-hover disabled:opacity-50">
<span className="system-sm-regular grow text-left text-text-secondary">CSV</span>
<span className="grow text-left text-text-secondary system-sm-regular">CSV</span>
</button>
</CSVDownloader>
<button type="button" disabled={annotationUnavailable} className={cn('mx-1 flex h-9 w-[calc(100%_-_8px)] cursor-pointer items-center space-x-2 rounded-lg px-3 py-2 hover:bg-components-panel-on-panel-item-bg-hover disabled:opacity-50', '!border-0')} onClick={JSONLOutput}>
<span className="system-sm-regular grow text-left text-text-secondary">JSONL</span>
<span className="grow text-left text-text-secondary system-sm-regular">JSONL</span>
</button>
</MenuItems>
</Transition>
@@ -150,7 +150,7 @@ const HeaderOptions: FC<Props> = ({
className="mx-1 flex h-9 w-[calc(100%_-_8px)] cursor-pointer items-center space-x-2 rounded-lg px-3 py-2 text-red-600 hover:bg-red-50 disabled:opacity-50"
>
<RiDeleteBinLine className="h-4 w-4" />
<span className="system-sm-regular grow text-left">
<span className="grow text-left system-sm-regular">
{t('table.header.clearAll', { ns: 'appAnnotation' })}
</span>
</button>

View File

@@ -144,7 +144,7 @@ const Annotation: FC<Props> = (props) => {
return (
<div className="flex h-full flex-col">
<p className="system-sm-regular text-text-tertiary">{t('description', { ns: 'appLog' })}</p>
<p className="text-text-tertiary system-sm-regular">{t('description', { ns: 'appLog' })}</p>
<div className="relative flex h-full flex-1 flex-col py-4">
<Filter appId={appDetail.id} queryParams={queryParams} setQueryParams={setQueryParams}>
<div className="flex items-center space-x-2">
@@ -152,7 +152,7 @@ const Annotation: FC<Props> = (props) => {
<>
<div className={cn(!annotationConfig?.enabled && 'pr-2', 'flex h-7 items-center space-x-1 rounded-lg border border-components-panel-border bg-components-panel-bg-blur pl-2')}>
<MessageFast className="h-4 w-4 text-util-colors-indigo-indigo-600" />
<div className="system-sm-medium text-text-primary">{t('name', { ns: 'appAnnotation' })}</div>
<div className="text-text-primary system-sm-medium">{t('name', { ns: 'appAnnotation' })}</div>
<Switch
key={controlRefreshSwitch}
defaultValue={annotationConfig?.enabled}

View File

@@ -58,7 +58,7 @@ const List: FC<Props> = ({
<>
<div className="relative mt-2 grow overflow-x-auto">
<table className={cn('w-full min-w-[440px] border-collapse border-0')}>
<thead className="system-xs-medium-uppercase text-text-tertiary">
<thead className="text-text-tertiary system-xs-medium-uppercase">
<tr>
<td className="w-12 whitespace-nowrap rounded-l-lg bg-background-section-burn px-2">
<Checkbox
@@ -75,7 +75,7 @@ const List: FC<Props> = ({
<td className="w-[96px] whitespace-nowrap rounded-r-lg bg-background-section-burn py-1.5 pl-3">{t('table.header.actions', { ns: 'appAnnotation' })}</td>
</tr>
</thead>
<tbody className="system-sm-regular text-text-secondary">
<tbody className="text-text-secondary system-sm-regular">
{list.map(item => (
<tr
key={item.id}

View File

@@ -11,7 +11,7 @@ const HitHistoryNoData: FC = () => {
<div className="inline-block rounded-lg border border-divider-subtle p-3">
<ClockFastForward className="h-5 w-5 text-text-tertiary" />
</div>
<div className="system-sm-regular text-text-tertiary">{t('viewModal.noHitHistory', { ns: 'appAnnotation' })}</div>
<div className="text-text-tertiary system-sm-regular">{t('viewModal.noHitHistory', { ns: 'appAnnotation' })}</div>
</div>
)
}

View File

@@ -137,7 +137,7 @@ const ViewAnnotationModal: FC<Props> = ({
: (
<div>
<table className={cn('w-full min-w-[440px] border-collapse border-0')}>
<thead className="system-xs-medium-uppercase text-text-tertiary">
<thead className="text-text-tertiary system-xs-medium-uppercase">
<tr>
<td className="w-5 whitespace-nowrap rounded-l-lg bg-background-section-burn pl-2 pr-1">{t('hitHistoryTable.query', { ns: 'appAnnotation' })}</td>
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('hitHistoryTable.match', { ns: 'appAnnotation' })}</td>
@@ -147,7 +147,7 @@ const ViewAnnotationModal: FC<Props> = ({
<td className="w-[160px] whitespace-nowrap rounded-r-lg bg-background-section-burn py-1.5 pl-3">{t('hitHistoryTable.time', { ns: 'appAnnotation' })}</td>
</tr>
</thead>
<tbody className="system-sm-regular text-text-secondary">
<tbody className="text-text-secondary system-sm-regular">
{hitHistoryList.map(item => (
<tr
key={item.id}
@@ -226,7 +226,7 @@ const ViewAnnotationModal: FC<Props> = ({
)}
foot={id
? (
<div className="system-sm-medium flex h-16 items-center justify-between rounded-bl-xl rounded-br-xl border-t border-divider-subtle bg-background-section-burn px-4 text-text-tertiary">
<div className="flex h-16 items-center justify-between rounded-bl-xl rounded-br-xl border-t border-divider-subtle bg-background-section-burn px-4 text-text-tertiary system-sm-medium">
<div
className="flex cursor-pointer items-center space-x-2 pl-3"
onClick={() => setShowModal(true)}

View File

@@ -76,7 +76,7 @@ export default function AddMemberOrGroupDialog() {
)
: (
<div className="flex h-7 items-center justify-center px-2 py-0.5">
<span className="system-xs-regular text-text-tertiary">{t('accessControlDialog.operateGroupAndMember.noResult', { ns: 'app' })}</span>
<span className="text-text-tertiary system-xs-regular">{t('accessControlDialog.operateGroupAndMember.noResult', { ns: 'app' })}</span>
</div>
)
}
@@ -115,10 +115,10 @@ function SelectedGroupsBreadCrumb() {
}, [setSelectedGroupsForBreadcrumb])
return (
<div className="flex h-7 items-center gap-x-0.5 px-2 py-0.5">
<span className={cn('system-xs-regular text-text-tertiary', selectedGroupsForBreadcrumb.length > 0 && 'cursor-pointer text-text-accent')} onClick={handleReset}>{t('accessControlDialog.operateGroupAndMember.allMembers', { ns: 'app' })}</span>
<span className={cn('text-text-tertiary system-xs-regular', selectedGroupsForBreadcrumb.length > 0 && 'cursor-pointer text-text-accent')} onClick={handleReset}>{t('accessControlDialog.operateGroupAndMember.allMembers', { ns: 'app' })}</span>
{selectedGroupsForBreadcrumb.map((group, index) => {
return (
<div key={index} className="system-xs-regular flex items-center gap-x-0.5 text-text-tertiary">
<div key={index} className="flex items-center gap-x-0.5 text-text-tertiary system-xs-regular">
<span>/</span>
<span className={index === selectedGroupsForBreadcrumb.length - 1 ? '' : 'cursor-pointer text-text-accent'} onClick={() => handleBreadCrumbClick(index)}>{group.name}</span>
</div>
@@ -161,8 +161,8 @@ function GroupItem({ group }: GroupItemProps) {
<RiOrganizationChart className="h-[14px] w-[14px] text-components-avatar-shape-fill-stop-0" />
</div>
</div>
<p className="system-sm-medium mr-1 text-text-secondary">{group.name}</p>
<p className="system-xs-regular text-text-tertiary">{group.groupSize}</p>
<p className="mr-1 text-text-secondary system-sm-medium">{group.name}</p>
<p className="text-text-tertiary system-xs-regular">{group.groupSize}</p>
</div>
<Button
size="small"
@@ -206,16 +206,16 @@ function MemberItem({ member }: MemberItemProps) {
<Avatar className="h-[14px] w-[14px]" textClassName="text-[12px]" avatar={null} name={member.name} />
</div>
</div>
<p className="system-sm-medium mr-1 text-text-secondary">{member.name}</p>
<p className="mr-1 text-text-secondary system-sm-medium">{member.name}</p>
{currentUser.email === member.email && (
<p className="system-xs-regular text-text-tertiary">
<p className="text-text-tertiary system-xs-regular">
(
{t('you', { ns: 'common' })}
)
</p>
)}
</div>
<p className="system-xs-regular text-text-quaternary">{member.email}</p>
<p className="text-text-quaternary system-xs-regular">{member.email}</p>
</BaseItem>
)
}

View File

@@ -68,18 +68,18 @@ export default function AccessControl(props: AccessControlProps) {
<AccessControlDialog show onClose={onClose}>
<div className="flex flex-col gap-y-3">
<div className="pb-3 pl-6 pr-14 pt-6">
<DialogTitle className="title-2xl-semi-bold text-text-primary">{t('accessControlDialog.title', { ns: 'app' })}</DialogTitle>
<DialogDescription className="system-xs-regular mt-1 text-text-tertiary">{t('accessControlDialog.description', { ns: 'app' })}</DialogDescription>
<DialogTitle className="text-text-primary title-2xl-semi-bold">{t('accessControlDialog.title', { ns: 'app' })}</DialogTitle>
<DialogDescription className="mt-1 text-text-tertiary system-xs-regular">{t('accessControlDialog.description', { ns: 'app' })}</DialogDescription>
</div>
<div className="flex flex-col gap-y-1 px-6 pb-3">
<div className="leading-6">
<p className="system-sm-medium text-text-tertiary">{t('accessControlDialog.accessLabel', { ns: 'app' })}</p>
<p className="text-text-tertiary system-sm-medium">{t('accessControlDialog.accessLabel', { ns: 'app' })}</p>
</div>
<AccessControlItem type={AccessMode.ORGANIZATION}>
<div className="flex items-center p-3">
<div className="flex grow items-center gap-x-2">
<RiBuildingLine className="h-4 w-4 text-text-primary" />
<p className="system-sm-medium text-text-primary">{t('accessControlDialog.accessItems.organization', { ns: 'app' })}</p>
<p className="text-text-primary system-sm-medium">{t('accessControlDialog.accessItems.organization', { ns: 'app' })}</p>
</div>
</div>
</AccessControlItem>
@@ -90,7 +90,7 @@ export default function AccessControl(props: AccessControlProps) {
<div className="flex items-center p-3">
<div className="flex grow items-center gap-x-2">
<RiVerifiedBadgeLine className="h-4 w-4 text-text-primary" />
<p className="system-sm-medium text-text-primary">{t('accessControlDialog.accessItems.external', { ns: 'app' })}</p>
<p className="text-text-primary system-sm-medium">{t('accessControlDialog.accessItems.external', { ns: 'app' })}</p>
</div>
{!hideTip && <WebAppSSONotEnabledTip />}
</div>
@@ -98,7 +98,7 @@ export default function AccessControl(props: AccessControlProps) {
<AccessControlItem type={AccessMode.PUBLIC}>
<div className="flex items-center gap-x-2 p-3">
<RiGlobalLine className="h-4 w-4 text-text-primary" />
<p className="system-sm-medium text-text-primary">{t('accessControlDialog.accessItems.anyone', { ns: 'app' })}</p>
<p className="text-text-primary system-sm-medium">{t('accessControlDialog.accessItems.anyone', { ns: 'app' })}</p>
</div>
</AccessControlItem>
</div>

View File

@@ -29,7 +29,7 @@ export default function SpecificGroupsOrMembers() {
<div className="flex items-center p-3">
<div className="flex grow items-center gap-x-2">
<RiLockLine className="h-4 w-4 text-text-primary" />
<p className="system-sm-medium text-text-primary">{t('accessControlDialog.accessItems.specific', { ns: 'app' })}</p>
<p className="text-text-primary system-sm-medium">{t('accessControlDialog.accessItems.specific', { ns: 'app' })}</p>
</div>
</div>
)
@@ -40,7 +40,7 @@ export default function SpecificGroupsOrMembers() {
<div className="flex items-center gap-x-1 p-3">
<div className="flex grow items-center gap-x-1">
<RiLockLine className="h-4 w-4 text-text-primary" />
<p className="system-sm-medium text-text-primary">{t('accessControlDialog.accessItems.specific', { ns: 'app' })}</p>
<p className="text-text-primary system-sm-medium">{t('accessControlDialog.accessItems.specific', { ns: 'app' })}</p>
</div>
<div className="flex items-center gap-x-1">
<AddMemberOrGroupDialog />
@@ -60,14 +60,14 @@ function RenderGroupsAndMembers() {
const specificGroups = useAccessControlStore(s => s.specificGroups)
const specificMembers = useAccessControlStore(s => s.specificMembers)
if (specificGroups.length <= 0 && specificMembers.length <= 0)
return <div className="px-2 pb-1.5 pt-5"><p className="system-xs-regular text-center text-text-tertiary">{t('accessControlDialog.noGroupsOrMembers', { ns: 'app' })}</p></div>
return <div className="px-2 pb-1.5 pt-5"><p className="text-center text-text-tertiary system-xs-regular">{t('accessControlDialog.noGroupsOrMembers', { ns: 'app' })}</p></div>
return (
<>
<p className="system-2xs-medium-uppercase sticky top-0 text-text-tertiary">{t('accessControlDialog.groups', { ns: 'app', count: specificGroups.length ?? 0 })}</p>
<p className="sticky top-0 text-text-tertiary system-2xs-medium-uppercase">{t('accessControlDialog.groups', { ns: 'app', count: specificGroups.length ?? 0 })}</p>
<div className="flex flex-row flex-wrap gap-1">
{specificGroups.map((group, index) => <GroupItem key={index} group={group} />)}
</div>
<p className="system-2xs-medium-uppercase sticky top-0 text-text-tertiary">{t('accessControlDialog.members', { ns: 'app', count: specificMembers.length ?? 0 })}</p>
<p className="sticky top-0 text-text-tertiary system-2xs-medium-uppercase">{t('accessControlDialog.members', { ns: 'app', count: specificMembers.length ?? 0 })}</p>
<div className="flex flex-row flex-wrap gap-1">
{specificMembers.map((member, index) => <MemberItem key={index} member={member} />)}
</div>
@@ -89,8 +89,8 @@ function GroupItem({ group }: GroupItemProps) {
icon={<RiOrganizationChart className="h-[14px] w-[14px] text-components-avatar-shape-fill-stop-0" />}
onRemove={handleRemoveGroup}
>
<p className="system-xs-regular text-text-primary">{group.name}</p>
<p className="system-xs-regular text-text-tertiary">{group.groupSize}</p>
<p className="text-text-primary system-xs-regular">{group.name}</p>
<p className="text-text-tertiary system-xs-regular">{group.groupSize}</p>
</BaseItem>
)
}
@@ -109,7 +109,7 @@ function MemberItem({ member }: MemberItemProps) {
icon={<Avatar className="h-[14px] w-[14px]" textClassName="text-[12px]" avatar={null} name={member.name} />}
onRemove={handleRemoveMember}
>
<p className="system-xs-regular text-text-primary">{member.name}</p>
<p className="text-text-primary system-xs-regular">{member.name}</p>
</BaseItem>
)
}

View File

@@ -100,7 +100,7 @@ const AccessModeDisplay: React.FC<{ mode?: AccessMode }> = ({ mode }) => {
<>
<Icon className="h-4 w-4 shrink-0 text-text-secondary" />
<div className="grow truncate">
<span className="system-sm-medium text-text-secondary">{t(`accessControlDialog.accessItems.${label}`, { ns: 'app' })}</span>
<span className="text-text-secondary system-sm-medium">{t(`accessControlDialog.accessItems.${label}`, { ns: 'app' })}</span>
</div>
</>
)
@@ -354,13 +354,13 @@ const AppPublisher = ({
<PortalToFollowElemContent className="z-[11]">
<div className="w-[320px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl shadow-shadow-shadow-5">
<div className="p-4 pt-3">
<div className="system-xs-medium-uppercase flex h-6 items-center text-text-tertiary">
<div className="flex h-6 items-center text-text-tertiary system-xs-medium-uppercase">
{publishedAt ? t('common.latestPublished', { ns: 'workflow' }) : t('common.currentDraftUnpublished', { ns: 'workflow' })}
</div>
{publishedAt
? (
<div className="flex items-center justify-between">
<div className="system-sm-medium flex items-center text-text-secondary">
<div className="flex items-center text-text-secondary system-sm-medium">
{t('common.publishedAt', { ns: 'workflow' })}
{' '}
{formatTimeFromNow(publishedAt)}
@@ -378,7 +378,7 @@ const AppPublisher = ({
</div>
)
: (
<div className="system-sm-medium flex items-center text-text-secondary">
<div className="flex items-center text-text-secondary system-sm-medium">
{t('common.autoSaved', { ns: 'workflow' })}
{' '}
·
@@ -444,7 +444,7 @@ const AppPublisher = ({
{systemFeatures.webapp_auth.enabled && (
<div className="p-4 pt-3">
<div className="flex h-6 items-center">
<p className="system-xs-medium text-text-tertiary">{t('publishApp.title', { ns: 'app' })}</p>
<p className="text-text-tertiary system-xs-medium">{t('publishApp.title', { ns: 'app' })}</p>
</div>
<div
className="flex h-8 cursor-pointer items-center gap-x-0.5 rounded-lg bg-components-input-bg-normal py-1 pl-2.5 pr-2 hover:bg-primary-50 hover:text-text-accent"
@@ -455,12 +455,12 @@ const AppPublisher = ({
<div className="flex grow items-center gap-x-1.5 overflow-hidden pr-1">
<AccessModeDisplay mode={appDetail?.access_mode} />
</div>
{!isAppAccessSet && <p className="system-xs-regular shrink-0 text-text-tertiary">{t('publishApp.notSet', { ns: 'app' })}</p>}
{!isAppAccessSet && <p className="shrink-0 text-text-tertiary system-xs-regular">{t('publishApp.notSet', { ns: 'app' })}</p>}
<div className="flex h-4 w-4 shrink-0 items-center justify-center">
<RiArrowRightSLine className="h-4 w-4 text-text-quaternary" />
</div>
</div>
{!isAppAccessSet && <p className="system-xs-regular mt-1 text-text-warning">{t('publishApp.notSetDesc', { ns: 'app' })}</p>}
{!isAppAccessSet && <p className="mt-1 text-text-warning system-xs-regular">{t('publishApp.notSetDesc', { ns: 'app' })}</p>}
</div>
)}
{

View File

@@ -24,7 +24,7 @@ const SuggestedAction = ({ icon, link, disabled, children, className, onClick, .
{...props}
>
<div className="relative h-4 w-4">{icon}</div>
<div className="system-sm-medium shrink grow basis-0">{children}</div>
<div className="shrink grow basis-0 system-sm-medium">{children}</div>
<RiArrowRightUpLine className="h-3.5 w-3.5" />
</a>
)

View File

@@ -74,7 +74,7 @@ const VersionInfoModal: FC<VersionInfoModalProps> = ({
return (
<Modal className="p-0" isShow={isOpen} onClose={onClose}>
<div className="relative w-full p-6 pb-4 pr-14">
<div className="title-2xl-semi-bold text-text-primary first-letter:capitalize">
<div className="text-text-primary title-2xl-semi-bold first-letter:capitalize">
{versionInfo?.marked_name ? t('versionHistory.editVersionInfo', { ns: 'workflow' }) : t('versionHistory.nameThisVersion', { ns: 'workflow' })}
</div>
<div className="absolute right-5 top-5 flex h-8 w-8 cursor-pointer items-center justify-center p-1.5" onClick={onClose}>
@@ -83,7 +83,7 @@ const VersionInfoModal: FC<VersionInfoModalProps> = ({
</div>
<div className="flex flex-col gap-y-4 px-6 py-3">
<div className="flex flex-col gap-y-1">
<div className="system-sm-semibold flex h-6 items-center text-text-secondary">
<div className="flex h-6 items-center text-text-secondary system-sm-semibold">
{t('versionHistory.editField.title', { ns: 'workflow' })}
</div>
<Input
@@ -94,7 +94,7 @@ const VersionInfoModal: FC<VersionInfoModalProps> = ({
/>
</div>
<div className="flex flex-col gap-y-1">
<div className="system-sm-semibold flex h-6 items-center text-text-secondary">
<div className="flex h-6 items-center text-text-secondary system-sm-semibold">
{t('versionHistory.editField.releaseNotes', { ns: 'workflow' })}
</div>
<Textarea

View File

@@ -29,7 +29,7 @@ const FeaturePanel: FC<IFeaturePanelProps> = ({
<div className="flex h-8 items-center justify-between">
<div className="flex shrink-0 items-center space-x-1">
{!!headerIcon && <div className="flex h-6 w-6 items-center justify-center">{headerIcon}</div>}
<div className="system-sm-semibold text-text-secondary">{title}</div>
<div className="text-text-secondary system-sm-semibold">{title}</div>
</div>
<div className="flex items-center gap-2">
{!!headerRight && <div>{headerRight}</div>}

View File

@@ -178,7 +178,7 @@ const Prompt: FC<ISimplePromptInput> = ({
{!noTitle && (
<div className="flex h-11 items-center justify-between pl-3 pr-2.5">
<div className="flex items-center space-x-1">
<div className="h2 system-sm-semibold-uppercase text-text-secondary">{mode !== AppModeEnum.COMPLETION ? t('chatSubTitle', { ns: 'appDebug' }) : t('completionSubTitle', { ns: 'appDebug' })}</div>
<div className="h2 text-text-secondary system-sm-semibold-uppercase">{mode !== AppModeEnum.COMPLETION ? t('chatSubTitle', { ns: 'appDebug' }) : t('completionSubTitle', { ns: 'appDebug' })}</div>
{!readonly && (
<Tooltip
popupContent={(

View File

@@ -20,10 +20,10 @@ const Field: FC<Props> = ({
const { t } = useTranslation()
return (
<div className={cn(className)}>
<div className="system-sm-semibold leading-8 text-text-secondary">
<div className="leading-8 text-text-secondary system-sm-semibold">
{title}
{isOptional && (
<span className="system-xs-regular ml-1 text-text-tertiary">
<span className="ml-1 text-text-tertiary system-xs-regular">
(
{t('variableConfig.optional', { ns: 'appDebug' })}
)

View File

@@ -482,12 +482,12 @@ const ConfigModal: FC<IConfigModalProps> = ({
<div className="!mt-5 flex h-6 items-center space-x-2">
<Checkbox checked={tempPayload.required} disabled={tempPayload.hide} onCheck={() => handlePayloadChange('required')(!tempPayload.required)} />
<span className="system-sm-semibold text-text-secondary">{t('variableConfig.required', { ns: 'appDebug' })}</span>
<span className="text-text-secondary system-sm-semibold">{t('variableConfig.required', { ns: 'appDebug' })}</span>
</div>
<div className="!mt-5 flex h-6 items-center space-x-2">
<Checkbox checked={tempPayload.hide} disabled={tempPayload.required} onCheck={() => handlePayloadChange('hide')(!tempPayload.hide)} />
<span className="system-sm-semibold text-text-secondary">{t('variableConfig.hide', { ns: 'appDebug' })}</span>
<span className="text-text-secondary system-sm-semibold">{t('variableConfig.hide', { ns: 'appDebug' })}</span>
</div>
</div>
</div>

View File

@@ -90,7 +90,7 @@ const ConfigSelect: FC<IConfigSelectProps> = ({
className="mt-1 flex h-9 cursor-pointer items-center gap-2 rounded-lg bg-components-button-tertiary-bg px-3 text-components-button-tertiary-text hover:bg-components-button-tertiary-bg-hover"
>
<RiAddLine className="h-4 w-4" />
<div className="system-sm-medium text-[13px]">{t('variableConfig.addOption', { ns: 'appDebug' })}</div>
<div className="text-[13px] system-sm-medium">{t('variableConfig.addOption', { ns: 'appDebug' })}</div>
</div>
</div>
)

View File

@@ -33,7 +33,7 @@ const SelectTypeItem: FC<ISelectTypeItemProps> = ({
<div
className={cn(
'flex h-[58px] flex-col items-center justify-center space-y-1 rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg text-text-secondary',
selected ? 'system-xs-medium border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg shadow-xs' : 'system-xs-regular cursor-pointer hover:border-components-option-card-option-border-hover hover:bg-components-option-card-option-bg-hover hover:shadow-xs',
selected ? 'border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg shadow-xs system-xs-medium' : 'cursor-pointer system-xs-regular hover:border-components-option-card-option-border-hover hover:bg-components-option-card-option-bg-hover hover:shadow-xs',
)}
onClick={onClick}
>

View File

@@ -46,15 +46,15 @@ const VarItem: FC<ItemProps> = ({
)}
<div className="flex w-0 grow items-center">
<div className="truncate" title={`${name} · ${label}`}>
<span className="system-sm-medium text-text-secondary">{name}</span>
<span className="system-xs-regular px-1 text-text-quaternary">·</span>
<span className="system-xs-medium text-text-tertiary">{label}</span>
<span className="text-text-secondary system-sm-medium">{name}</span>
<span className="px-1 text-text-quaternary system-xs-regular">·</span>
<span className="text-text-tertiary system-xs-medium">{label}</span>
</div>
</div>
<div className="shrink-0">
<div className={cn('flex items-center', !readonly && 'group-hover:hidden')}>
{required && <Badge text="required" />}
<span className="system-xs-regular pl-2 pr-1 text-text-tertiary">{type}</span>
<span className="pl-2 pr-1 text-text-tertiary system-xs-regular">{type}</span>
<IconTypeIcon type={type as IInputTypeIconProps['type']} className="text-text-tertiary" />
</div>
<div className={cn('hidden items-center justify-end rounded-lg', !readonly && 'group-hover:flex')}>

View File

@@ -69,7 +69,7 @@ const ConfigVision: FC = () => {
</div>
</div>
<div className="flex grow items-center">
<div className="system-sm-semibold mr-1 text-text-secondary">{t('vision.name', { ns: 'appDebug' })}</div>
<div className="mr-1 text-text-secondary system-sm-semibold">{t('vision.name', { ns: 'appDebug' })}</div>
<Tooltip
popupContent={(
<div className="w-[180px]">
@@ -83,7 +83,7 @@ const ConfigVision: FC = () => {
? (
<>
<div className="mr-2 flex items-center gap-0.5">
<div className="system-xs-medium-uppercase text-text-tertiary">{t('vision.visionSettings.resolution', { ns: 'appDebug' })}</div>
<div className="text-text-tertiary system-xs-medium-uppercase">{t('vision.visionSettings.resolution', { ns: 'appDebug' })}</div>
<Tooltip
popupContent={(
<div className="w-[180px]">

View File

@@ -209,11 +209,11 @@ const AgentTools: FC = () => {
)}
<div
className={cn(
'system-xs-regular ml-1.5 flex w-0 grow items-center truncate',
'ml-1.5 flex w-0 grow items-center truncate system-xs-regular',
(item.isDeleted || item.notAuthor || !item.enabled) ? 'opacity-50' : '',
)}
>
<span className="system-xs-medium pr-1.5 text-text-secondary">{getProviderShowName(item)}</span>
<span className="pr-1.5 text-text-secondary system-xs-medium">{getProviderShowName(item)}</span>
<span className="text-text-tertiary">{item.tool_label}</span>
{!item.isDeleted && !readonly && (
<Tooltip

View File

@@ -131,16 +131,16 @@ const SettingBuiltInTool: FC<Props> = ({
{infoSchemas.map((item, index) => (
<div key={index} className="py-1">
<div className="flex items-center gap-2">
<div className="code-sm-semibold text-text-secondary">{item.label[language]}</div>
<div className="system-xs-regular text-text-tertiary">
<div className="text-text-secondary code-sm-semibold">{item.label[language]}</div>
<div className="text-text-tertiary system-xs-regular">
{getType(item.type)}
</div>
{item.required && (
<div className="system-xs-medium text-text-warning-secondary">{t('setBuiltInTools.required', { ns: 'tools' })}</div>
<div className="text-text-warning-secondary system-xs-medium">{t('setBuiltInTools.required', { ns: 'tools' })}</div>
)}
</div>
{item.human_description && (
<div className="system-xs-regular mt-0.5 text-text-tertiary">
<div className="mt-0.5 text-text-tertiary system-xs-regular">
{item.human_description?.[language]}
</div>
)}
@@ -186,7 +186,7 @@ const SettingBuiltInTool: FC<Props> = ({
</div>
{showBackButton && (
<div
className="system-xs-semibold-uppercase mb-2 flex cursor-pointer items-center gap-1 text-text-accent-secondary"
className="mb-2 flex cursor-pointer items-center gap-1 text-text-accent-secondary system-xs-semibold-uppercase"
onClick={onHide}
>
<RiArrowLeftLine className="h-4 w-4" />
@@ -201,7 +201,7 @@ const SettingBuiltInTool: FC<Props> = ({
packageName={collection.name.split('/').pop() || ''}
/>
</div>
<div className="system-md-semibold mt-1 text-text-primary">{currTool?.label[language]}</div>
<div className="mt-1 text-text-primary system-md-semibold">{currTool?.label[language]}</div>
{!!currTool?.description[language] && (
<Description className="mb-2 mt-3 h-auto" text={currTool.description[language]} descriptionLineRows={2}></Description>
)}
@@ -240,7 +240,7 @@ const SettingBuiltInTool: FC<Props> = ({
/>
)
: (
<div className="system-sm-semibold-uppercase p-4 pb-1 text-text-primary">{t('setBuiltInTools.parameters', { ns: 'tools' })}</div>
<div className="p-4 pb-1 text-text-primary system-sm-semibold-uppercase">{t('setBuiltInTools.parameters', { ns: 'tools' })}</div>
)}
<div className="h-0 grow overflow-y-auto px-4">
{isInfoActive ? infoUI : settingUI}

View File

@@ -336,7 +336,7 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
{/* inputs */}
<div className="mt-4">
<div>
<div className="system-sm-semibold-uppercase mb-1.5 text-text-secondary">{t('generate.instruction', { ns: 'appDebug' })}</div>
<div className="mb-1.5 text-text-secondary system-sm-semibold-uppercase">{t('generate.instruction', { ns: 'appDebug' })}</div>
{isBasicMode
? (
<InstructionEditorInBasic

View File

@@ -30,8 +30,8 @@ const IdeaOutput: FC<Props> = ({
className="mb-1.5 flex cursor-pointer items-center text-sm font-medium leading-5 text-text-primary"
onClick={toggleFoldIdeaOutput}
>
<div className="system-sm-semibold-uppercase mr-1 text-text-secondary">{t(`${i18nPrefix}.idealOutput`, { ns: 'appDebug' })}</div>
<div className="system-xs-regular text-text-tertiary">
<div className="mr-1 text-text-secondary system-sm-semibold-uppercase">{t(`${i18nPrefix}.idealOutput`, { ns: 'appDebug' })}</div>
<div className="text-text-tertiary system-xs-regular">
(
{t(`${i18nPrefix}.optional`, { ns: 'appDebug' })}
)

View File

@@ -45,12 +45,12 @@ const InstructionEditor: FC<Props> = ({
const isCode = generatorType === 'code'
const placeholder = isCode
? (
<div className="system-sm-regular whitespace-break-spaces !leading-6 text-text-placeholder">
<div className="whitespace-break-spaces !leading-6 text-text-placeholder system-sm-regular">
{t(`${i18nPrefix}.codeGenInstructionPlaceHolderLine`, { ns: 'appDebug' })}
</div>
)
: (
<div className="system-sm-regular text-text-placeholder">
<div className="text-text-placeholder system-sm-regular">
<div className="leading-6">{t(`${i18nPrefix}.instructionPlaceHolderTitle`, { ns: 'appDebug' })}</div>
<div className="mt-2">
<div>{t(`${i18nPrefix}.instructionPlaceHolderLine1`, { ns: 'appDebug' })}</div>
@@ -109,9 +109,9 @@ const InstructionEditor: FC<Props> = ({
editable
isSupportFileVar={false}
/>
<div className="system-xs-regular absolute bottom-0 left-4 flex h-8 items-center space-x-0.5 text-components-input-text-placeholder">
<div className="absolute bottom-0 left-4 flex h-8 items-center space-x-0.5 text-components-input-text-placeholder system-xs-regular">
<span>{t('generate.press', { ns: 'appDebug' })}</span>
<span className="system-kbd flex h-4 w-3.5 items-center justify-center rounded-[4px] bg-components-kbd-bg-gray text-text-placeholder">/</span>
<span className="flex h-4 w-3.5 items-center justify-center rounded-[4px] bg-components-kbd-bg-gray text-text-placeholder system-kbd">/</span>
<span>{t('generate.to', { ns: 'appDebug' })}</span>
<span onClick={handleInsertVariable} className="!ml-1 cursor-pointer hover:border-b hover:border-dotted hover:border-text-tertiary hover:text-text-tertiary">{t('generate.insertContext', { ns: 'appDebug' })}</span>
</div>

View File

@@ -52,7 +52,7 @@ const VersionSelector: React.FC<VersionSelectorProps> = ({ versionLen, value, on
asChild
>
<div className={cn(
'system-xs-medium flex items-center text-text-tertiary',
'flex items-center text-text-tertiary system-xs-medium',
isOpen && 'text-text-secondary',
moreThanOneVersion && 'cursor-pointer',
)}
@@ -75,7 +75,7 @@ const VersionSelector: React.FC<VersionSelectorProps> = ({ versionLen, value, on
'w-[208px] rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg',
)}
>
<div className={cn('system-xs-medium-uppercase flex h-[22px] items-center px-3 pl-3 text-text-tertiary')}>
<div className={cn('flex h-[22px] items-center px-3 pl-3 text-text-tertiary system-xs-medium-uppercase')}>
{t('generate.versions', { ns: 'appDebug' })}
</div>
{
@@ -83,7 +83,7 @@ const VersionSelector: React.FC<VersionSelectorProps> = ({ versionLen, value, on
<div
key={option.value}
className={cn(
'system-sm-medium flex h-7 cursor-pointer items-center rounded-lg px-2 text-text-secondary hover:bg-state-base-hover',
'flex h-7 cursor-pointer items-center rounded-lg px-2 text-text-secondary system-sm-medium hover:bg-state-base-hover',
)}
title={option.label}
onClick={() => {

View File

@@ -219,7 +219,7 @@ export const GetCodeGeneratorResModal: FC<IGetCodeGeneratorResProps> = (
</div>
<div>
<div className="text-[0px]">
<div className="system-sm-semibold-uppercase mb-1.5 text-text-secondary">{t('codegen.instruction', { ns: 'appDebug' })}</div>
<div className="mb-1.5 text-text-secondary system-sm-semibold-uppercase">{t('codegen.instruction', { ns: 'appDebug' })}</div>
<InstructionEditor
editorKey={editorKey}
value={instruction}

View File

@@ -56,7 +56,7 @@ const ConfigAudio: FC = () => {
</div>
</div>
<div className="flex grow items-center">
<div className="system-sm-semibold mr-1 text-text-secondary">{t('feature.audioUpload.title', { ns: 'appDebug' })}</div>
<div className="mr-1 text-text-secondary system-sm-semibold">{t('feature.audioUpload.title', { ns: 'appDebug' })}</div>
<Tooltip
popupContent={(
<div className="w-[180px]">

View File

@@ -56,7 +56,7 @@ const ConfigDocument: FC = () => {
</div>
</div>
<div className="flex grow items-center">
<div className="system-sm-semibold mr-1 text-text-secondary">{t('feature.documentUpload.title', { ns: 'appDebug' })}</div>
<div className="mr-1 text-text-secondary system-sm-semibold">{t('feature.documentUpload.title', { ns: 'appDebug' })}</div>
<Tooltip
popupContent={(
<div className="w-[180px]">

View File

@@ -68,7 +68,7 @@ const Item: FC<ItemProps> = ({
background={iconInfo.icon_type === 'image' ? undefined : iconInfo.icon_background}
imageUrl={iconInfo.icon_type === 'image' ? iconInfo.icon_url : undefined}
/>
<div className="system-sm-medium w-0 grow truncate text-text-secondary" title={config.name}>{config.name}</div>
<div className="w-0 grow truncate text-text-secondary system-sm-medium" title={config.name}>{config.name}</div>
</div>
<div className="ml-2 hidden shrink-0 items-center space-x-1 group-hover:flex">
{

View File

@@ -188,14 +188,14 @@ const ConfigContent: FC<Props> = ({
return (
<div>
<div className="system-xl-semibold text-text-primary">{t('retrievalSettings', { ns: 'dataset' })}</div>
<div className="system-xs-regular text-text-tertiary">
<div className="text-text-primary system-xl-semibold">{t('retrievalSettings', { ns: 'dataset' })}</div>
<div className="text-text-tertiary system-xs-regular">
{t('defaultRetrievalTip', { ns: 'dataset' })}
</div>
{type === RETRIEVE_TYPE.multiWay && (
<>
<div className="my-2 flex flex-col items-center py-1">
<div className="system-xs-semibold-uppercase mb-2 mr-2 shrink-0 text-text-secondary">
<div className="mb-2 mr-2 shrink-0 text-text-secondary system-xs-semibold-uppercase">
{t('rerankSettings', { ns: 'dataset' })}
</div>
<Divider bgStyle="gradient" className="m-0 !h-px" />
@@ -203,21 +203,21 @@ const ConfigContent: FC<Props> = ({
{
selectedDatasetsMode.inconsistentEmbeddingModel
&& (
<div className="system-xs-medium mt-4 text-text-warning">
<div className="mt-4 text-text-warning system-xs-medium">
{t('inconsistentEmbeddingModelTip', { ns: 'dataset' })}
</div>
)
}
{
selectedDatasetsMode.mixtureInternalAndExternal && (
<div className="system-xs-medium mt-4 text-text-warning">
<div className="mt-4 text-text-warning system-xs-medium">
{t('mixtureInternalAndExternalTip', { ns: 'dataset' })}
</div>
)
}
{
selectedDatasetsMode.allExternal && (
<div className="system-xs-medium mt-4 text-text-warning">
<div className="mt-4 text-text-warning system-xs-medium">
{t('allExternalTip', { ns: 'dataset' })}
</div>
)
@@ -225,7 +225,7 @@ const ConfigContent: FC<Props> = ({
{
selectedDatasetsMode.mixtureHighQualityAndEconomic
&& (
<div className="system-xs-medium mt-4 text-text-warning">
<div className="mt-4 text-text-warning system-xs-medium">
{t('mixtureHighQualityAndEconomicTip', { ns: 'dataset' })}
</div>
)
@@ -238,7 +238,7 @@ const ConfigContent: FC<Props> = ({
<div
key={option.value}
className={cn(
'system-sm-medium flex h-8 w-[calc((100%-8px)/2)] cursor-pointer items-center justify-center rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg text-text-secondary',
'flex h-8 w-[calc((100%-8px)/2)] cursor-pointer items-center justify-center rounded-lg border border-components-option-card-option-border bg-components-option-card-option-bg text-text-secondary system-sm-medium',
selectedRerankMode === option.value && 'border-[1.5px] border-components-option-card-option-selected-border bg-components-option-card-option-selected-bg text-text-primary',
)}
onClick={() => handleRerankModeChange(option.value)}
@@ -272,7 +272,7 @@ const ConfigContent: FC<Props> = ({
/>
)
}
<div className="system-sm-semibold ml-1 leading-[32px] text-text-secondary">{t('modelProvider.rerankModel.key', { ns: 'common' })}</div>
<div className="ml-1 leading-[32px] text-text-secondary system-sm-semibold">{t('modelProvider.rerankModel.key', { ns: 'common' })}</div>
<Tooltip
popupContent={(
<div className="w-[200px]">

View File

@@ -44,13 +44,13 @@ const WeightedScore = ({
disabled={readonly}
/>
<div className="mt-3 flex justify-between">
<div className="system-xs-semibold-uppercase flex w-[90px] shrink-0 items-center text-util-colors-blue-light-blue-light-500">
<div className="flex w-[90px] shrink-0 items-center text-util-colors-blue-light-blue-light-500 system-xs-semibold-uppercase">
<div className="mr-1 truncate uppercase" title={t('weightedScore.semantic', { ns: 'dataset' }) || ''}>
{t('weightedScore.semantic', { ns: 'dataset' })}
</div>
{formatNumber(value.value[0])}
</div>
<div className="system-xs-semibold-uppercase flex w-[90px] shrink-0 items-center justify-end text-util-colors-teal-teal-500">
<div className="flex w-[90px] shrink-0 items-center justify-end text-util-colors-teal-teal-500 system-xs-semibold-uppercase">
{formatNumber(value.value[1])}
<div className="ml-1 truncate uppercase" title={t('weightedScore.keyword', { ns: 'dataset' }) || ''}>
{t('weightedScore.keyword', { ns: 'dataset' })}

View File

@@ -210,7 +210,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
<div className="overflow-y-auto border-b border-divider-regular p-6 pb-[68px] pt-5">
<div className={cn(rowClass, 'items-center')}>
<div className={labelClass}>
<div className="system-sm-semibold text-text-secondary">{t('form.name', { ns: 'datasetSettings' })}</div>
<div className="text-text-secondary system-sm-semibold">{t('form.name', { ns: 'datasetSettings' })}</div>
</div>
<Input
value={localeCurrentDataset.name}
@@ -221,7 +221,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
</div>
<div className={cn(rowClass)}>
<div className={labelClass}>
<div className="system-sm-semibold text-text-secondary">{t('form.desc', { ns: 'datasetSettings' })}</div>
<div className="text-text-secondary system-sm-semibold">{t('form.desc', { ns: 'datasetSettings' })}</div>
</div>
<div className="w-full">
<Textarea
@@ -234,7 +234,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
</div>
<div className={rowClass}>
<div className={labelClass}>
<div className="system-sm-semibold text-text-secondary">{t('form.permissions', { ns: 'datasetSettings' })}</div>
<div className="text-text-secondary system-sm-semibold">{t('form.permissions', { ns: 'datasetSettings' })}</div>
</div>
<div className="w-full">
<PermissionSelector
@@ -250,7 +250,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
{!!(currentDataset && currentDataset.indexing_technique) && (
<div className={cn(rowClass)}>
<div className={labelClass}>
<div className="system-sm-semibold text-text-secondary">{t('form.indexMethod', { ns: 'datasetSettings' })}</div>
<div className="text-text-secondary system-sm-semibold">{t('form.indexMethod', { ns: 'datasetSettings' })}</div>
</div>
<div className="grow">
<IndexMethod
@@ -267,7 +267,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
{indexMethod === IndexingType.QUALIFIED && (
<div className={cn(rowClass)}>
<div className={labelClass}>
<div className="system-sm-semibold text-text-secondary">{t('form.embeddingModel', { ns: 'datasetSettings' })}</div>
<div className="text-text-secondary system-sm-semibold">{t('form.embeddingModel', { ns: 'datasetSettings' })}</div>
</div>
<div className="w-full">
<div className="h-8 w-full rounded-lg bg-components-input-bg-normal opacity-60">

View File

@@ -40,7 +40,7 @@ const ExternalRetrievalSection: FC<ExternalRetrievalSectionProps> = ({
<div className={rowClass}><Divider /></div>
<div className={rowClass}>
<div className={labelClass}>
<div className="system-sm-semibold text-text-secondary">{t('form.retrievalSetting.title', { ns: 'datasetSettings' })}</div>
<div className="text-text-secondary system-sm-semibold">{t('form.retrievalSetting.title', { ns: 'datasetSettings' })}</div>
</div>
<RetrievalSettings
topK={topK}
@@ -53,26 +53,26 @@ const ExternalRetrievalSection: FC<ExternalRetrievalSectionProps> = ({
<div className={rowClass}><Divider /></div>
<div className={rowClass}>
<div className={labelClass}>
<div className="system-sm-semibold text-text-secondary">{t('form.externalKnowledgeAPI', { ns: 'datasetSettings' })}</div>
<div className="text-text-secondary system-sm-semibold">{t('form.externalKnowledgeAPI', { ns: 'datasetSettings' })}</div>
</div>
<div className="w-full max-w-[480px]">
<div className="flex h-full items-center gap-1 rounded-lg bg-components-input-bg-normal px-3 py-2">
<ApiConnectionMod className="h-4 w-4 text-text-secondary" />
<div className="system-sm-medium overflow-hidden text-ellipsis text-text-secondary">
<div className="overflow-hidden text-ellipsis text-text-secondary system-sm-medium">
{currentDataset?.external_knowledge_info.external_knowledge_api_name}
</div>
<div className="system-xs-regular text-text-tertiary">·</div>
<div className="system-xs-regular text-text-tertiary">{currentDataset?.external_knowledge_info.external_knowledge_api_endpoint}</div>
<div className="text-text-tertiary system-xs-regular">·</div>
<div className="text-text-tertiary system-xs-regular">{currentDataset?.external_knowledge_info.external_knowledge_api_endpoint}</div>
</div>
</div>
</div>
<div className={rowClass}>
<div className={labelClass}>
<div className="system-sm-semibold text-text-secondary">{t('form.externalKnowledgeID', { ns: 'datasetSettings' })}</div>
<div className="text-text-secondary system-sm-semibold">{t('form.externalKnowledgeID', { ns: 'datasetSettings' })}</div>
</div>
<div className="w-full max-w-[480px]">
<div className="flex h-full items-center gap-1 rounded-lg bg-components-input-bg-normal px-3 py-2">
<div className="system-xs-regular text-text-tertiary">{currentDataset?.external_knowledge_info.external_knowledge_id}</div>
<div className="text-text-tertiary system-xs-regular">{currentDataset?.external_knowledge_info.external_knowledge_id}</div>
</div>
</div>
</div>
@@ -101,7 +101,7 @@ const InternalRetrievalSection: FC<InternalRetrievalSectionProps> = ({
<div className={rowClass}>
<div className={cn(labelClass, 'w-auto min-w-[168px]')}>
<div>
<div className="system-sm-semibold text-text-secondary">{t('form.retrievalSetting.title', { ns: 'datasetSettings' })}</div>
<div className="text-text-secondary system-sm-semibold">{t('form.retrievalSetting.title', { ns: 'datasetSettings' })}</div>
<div className="text-xs font-normal leading-[18px] text-text-tertiary">
<a target="_blank" rel="noopener noreferrer" href={docLink('/use-dify/knowledge/create-knowledge/setting-indexing-methods')} className="text-text-accent">{t('form.retrievalSetting.learnMore', { ns: 'datasetSettings' })}</a>
{t('form.retrievalSetting.description', { ns: 'datasetSettings' })}

View File

@@ -75,9 +75,9 @@ const ChatUserInput = ({
>
<div>
{type !== 'checkbox' && (
<div className="system-sm-semibold mb-1 flex h-6 items-center gap-1 text-text-secondary">
<div className="mb-1 flex h-6 items-center gap-1 text-text-secondary system-sm-semibold">
<div className="truncate">{name || key}</div>
{!required && <span className="system-xs-regular text-text-tertiary">{t('panel.optional', { ns: 'workflow' })}</span>}
{!required && <span className="text-text-tertiary system-xs-regular">{t('panel.optional', { ns: 'workflow' })}</span>}
</div>
)}
<div className="grow">

View File

@@ -394,7 +394,7 @@ const Debug: FC<IDebug> = ({
<>
<div className="shrink-0">
<div className="flex items-center justify-between px-4 pb-2 pt-3">
<div className="system-xl-semibold text-text-primary">{t('inputs.title', { ns: 'appDebug' })}</div>
<div className="text-text-primary system-xl-semibold">{t('inputs.title', { ns: 'appDebug' })}</div>
<div className="flex items-center">
{
debugWithMultipleModel
@@ -539,7 +539,7 @@ const Debug: FC<IDebug> = ({
{!completionRes && !isResponding && (
<div className="flex grow flex-col items-center justify-center gap-2">
<RiSparklingFill className="h-12 w-12 text-text-empty-state-icon" />
<div className="system-sm-regular text-text-quaternary">{t('noResult', { ns: 'appDebug' })}</div>
<div className="text-text-quaternary system-sm-regular">{t('noResult', { ns: 'appDebug' })}</div>
</div>
)}
</>

View File

@@ -967,10 +967,10 @@ const Configuration: FC = () => {
<div className="bg-default-subtle absolute left-0 top-0 h-14 w-full">
<div className="flex h-14 items-center justify-between px-6">
<div className="flex items-center">
<div className="system-xl-semibold text-text-primary">{t('orchestrate', { ns: 'appDebug' })}</div>
<div className="text-text-primary system-xl-semibold">{t('orchestrate', { ns: 'appDebug' })}</div>
<div className="flex h-[14px] items-center space-x-1 text-xs">
{isAdvancedMode && (
<div className="system-xs-medium-uppercase ml-1 flex h-5 items-center rounded-md border border-components-button-secondary-border px-1.5 uppercase text-text-tertiary">{t('promptMode.advanced', { ns: 'appDebug' })}</div>
<div className="ml-1 flex h-5 items-center rounded-md border border-components-button-secondary-border px-1.5 uppercase text-text-tertiary system-xs-medium-uppercase">{t('promptMode.advanced', { ns: 'appDebug' })}</div>
)}
</div>
</div>

View File

@@ -112,12 +112,12 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
<div className="relative z-[1] mx-3 rounded-xl border-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg shadow-md">
<div className={cn('px-4 pt-3', userInputFieldCollapse ? 'pb-3' : 'pb-1')}>
<div className="flex cursor-pointer items-center gap-0.5 py-0.5" onClick={() => setUserInputFieldCollapse(!userInputFieldCollapse)}>
<div className="system-md-semibold-uppercase text-text-secondary">{t('inputs.userInputField', { ns: 'appDebug' })}</div>
<div className="text-text-secondary system-md-semibold-uppercase">{t('inputs.userInputField', { ns: 'appDebug' })}</div>
{userInputFieldCollapse && <RiArrowRightSLine className="h-4 w-4 text-text-secondary" />}
{!userInputFieldCollapse && <RiArrowDownSLine className="h-4 w-4 text-text-secondary" />}
</div>
{!userInputFieldCollapse && (
<div className="system-xs-regular mt-1 text-text-tertiary">{t('inputs.completionVarTip', { ns: 'appDebug' })}</div>
<div className="mt-1 text-text-tertiary system-xs-regular">{t('inputs.completionVarTip', { ns: 'appDebug' })}</div>
)}
</div>
{!userInputFieldCollapse && promptVariables.length > 0 && (
@@ -129,9 +129,9 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
>
<div>
{type !== 'checkbox' && (
<div className="system-sm-semibold mb-1 flex h-6 items-center gap-1 text-text-secondary">
<div className="mb-1 flex h-6 items-center gap-1 text-text-secondary system-sm-semibold">
<div className="truncate">{name || key}</div>
{!required && <span className="system-xs-regular text-text-tertiary">{t('panel.optional', { ns: 'workflow' })}</span>}
{!required && <span className="text-text-tertiary system-xs-regular">{t('panel.optional', { ns: 'workflow' })}</span>}
</div>
)}
<div className="grow">

View File

@@ -52,12 +52,12 @@ const AppCard = ({
</div>
<div className="flex grow flex-col gap-1">
<div className="line-clamp-1">
<span className="system-md-semibold text-text-secondary" title={appBasicInfo.name}>{appBasicInfo.name}</span>
<span className="text-text-secondary system-md-semibold" title={appBasicInfo.name}>{appBasicInfo.name}</span>
</div>
<AppTypeLabel className="system-2xs-medium-uppercase text-text-tertiary" type={app.app.mode} />
<AppTypeLabel className="text-text-tertiary system-2xs-medium-uppercase" type={app.app.mode} />
</div>
</div>
<div className="system-xs-regular py-1 text-text-tertiary">
<div className="py-1 text-text-tertiary system-xs-regular">
<div className="line-clamp-3">
{app.description}
</div>

View File

@@ -165,7 +165,7 @@ const Apps = ({
<div className="flex h-full flex-col">
<div className="flex items-center justify-between border-b border-divider-burn py-3">
<div className="min-w-[180px] pl-5">
<span className="title-xl-semi-bold text-text-primary">{t('newApp.startFromTemplate', { ns: 'app' })}</span>
<span className="text-text-primary title-xl-semi-bold">{t('newApp.startFromTemplate', { ns: 'app' })}</span>
</div>
<div className="flex max-w-[548px] flex-1 items-center rounded-xl border border-components-panel-border bg-components-panel-bg-blur p-1.5 shadow-md">
<AppTypeSelector value={currentType} onChange={setCurrentType} />
@@ -195,10 +195,10 @@ const Apps = ({
<>
<div className="pb-1 pt-4">
{searchKeywords
? <p className="title-md-semi-bold text-text-tertiary">{searchFilteredList.length > 1 ? t('newApp.foundResults', { ns: 'app', count: searchFilteredList.length }) : t('newApp.foundResult', { ns: 'app', count: searchFilteredList.length })}</p>
? <p className="text-text-tertiary title-md-semi-bold">{searchFilteredList.length > 1 ? t('newApp.foundResults', { ns: 'app', count: searchFilteredList.length }) : t('newApp.foundResult', { ns: 'app', count: searchFilteredList.length })}</p>
: (
<div className="flex h-[22px] items-center">
<AppCategoryLabel category={currCategory as AppCategories} className="title-md-semi-bold text-text-primary" />
<AppCategoryLabel category={currCategory as AppCategories} className="text-text-primary title-md-semi-bold" />
</div>
)}
</div>
@@ -250,8 +250,8 @@ function NoTemplateFound() {
<div className="mb-2 inline-flex h-8 w-8 items-center justify-center rounded-lg bg-components-card-bg shadow-lg">
<RiRobot2Line className="h-5 w-5 text-text-tertiary" />
</div>
<p className="title-md-semi-bold text-text-primary">{t('newApp.noTemplateFound', { ns: 'app' })}</p>
<p className="system-sm-regular text-text-tertiary">{t('newApp.noTemplateFoundTip', { ns: 'app' })}</p>
<p className="text-text-primary title-md-semi-bold">{t('newApp.noTemplateFound', { ns: 'app' })}</p>
<p className="text-text-tertiary system-sm-regular">{t('newApp.noTemplateFoundTip', { ns: 'app' })}</p>
</div>
)
}

View File

@@ -22,7 +22,7 @@ export default function Sidebar({ current, categories, onClick, onCreateFromBlan
<ul className="pt-0.5">
<CategoryItem category={AppCategories.RECOMMENDED} active={current === AppCategories.RECOMMENDED} onClick={onClick} />
</ul>
<div className="system-xs-medium-uppercase mb-0.5 mt-3 px-3 pb-1 pt-2 text-text-tertiary">{t('newAppFromTemplate.byCategories', { ns: 'app' })}</div>
<div className="mb-0.5 mt-3 px-3 pb-1 pt-2 text-text-tertiary system-xs-medium-uppercase">{t('newAppFromTemplate.byCategories', { ns: 'app' })}</div>
<ul className="flex grow flex-col gap-0.5">
{categories.map(category => (<CategoryItem key={category} category={category} active={current === category} onClick={onClick} />))}
</ul>
@@ -53,7 +53,7 @@ function CategoryItem({ category, active, onClick }: CategoryItemProps) {
)}
<AppCategoryLabel
category={category}
className={cn('system-sm-medium text-components-menu-item-text group-hover:text-components-menu-item-text-hover group-[.active]:text-components-menu-item-text-active', active && 'system-sm-semibold')}
className={cn('text-components-menu-item-text system-sm-medium group-hover:text-components-menu-item-text-hover group-[.active]:text-components-menu-item-text-active', active && 'system-sm-semibold')}
/>
</li>
)

Some files were not shown because too many files have changed in this diff Show More