mirror of
https://github.com/langgenius/dify.git
synced 2026-02-14 15:25:34 +08:00
Compare commits
5 Commits
refactor/r
...
build/opti
| Author | SHA1 | Date | |
|---|---|---|---|
| 9f5078f271 | |||
| f6c07a53cb | |||
| 0118b45cff | |||
| 8fd3eeb760 | |||
| f233e2036f |
@ -719,6 +719,7 @@ SANDBOX_EXPIRED_RECORDS_CLEAN_GRACEFUL_PERIOD=21
|
||||
SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_SIZE=1000
|
||||
SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_MAX_INTERVAL=200
|
||||
SANDBOX_EXPIRED_RECORDS_RETENTION_DAYS=30
|
||||
SANDBOX_EXPIRED_RECORDS_CLEAN_SCAN_WINDOW_DAYS=0
|
||||
SANDBOX_EXPIRED_RECORDS_CLEAN_TASK_LOCK_TTL=90000
|
||||
|
||||
|
||||
|
||||
@ -1355,6 +1355,12 @@ class SandboxExpiredRecordsCleanConfig(BaseSettings):
|
||||
description="Retention days for sandbox expired workflow_run records and message records",
|
||||
default=30,
|
||||
)
|
||||
SANDBOX_EXPIRED_RECORDS_CLEAN_SCAN_WINDOW_DAYS: NonNegativeInt = Field(
|
||||
description="Scan window lower bound in days relative to cutoff for scheduled cleanup tasks. "
|
||||
"0 means disabled (scan all records before cutoff). "
|
||||
"When > 0, only records in [cutoff - window, cutoff) are scanned.",
|
||||
default=0,
|
||||
)
|
||||
SANDBOX_EXPIRED_RECORDS_CLEAN_TASK_LOCK_TTL: PositiveInt = Field(
|
||||
description="Lock TTL for sandbox expired records clean task in seconds",
|
||||
default=90000,
|
||||
|
||||
@ -29,7 +29,7 @@ from typing import Any, cast
|
||||
|
||||
import sqlalchemy as sa
|
||||
from pydantic import ValidationError
|
||||
from sqlalchemy import and_, delete, func, null, or_, select
|
||||
from sqlalchemy import and_, delete, func, null, or_, select, tuple_
|
||||
from sqlalchemy.engine import CursorResult
|
||||
from sqlalchemy.orm import Session, selectinload, sessionmaker
|
||||
|
||||
@ -423,9 +423,10 @@ class DifyAPISQLAlchemyWorkflowRunRepository(APIWorkflowRunRepository):
|
||||
|
||||
if last_seen:
|
||||
stmt = stmt.where(
|
||||
or_(
|
||||
WorkflowRun.created_at > last_seen[0],
|
||||
and_(WorkflowRun.created_at == last_seen[0], WorkflowRun.id > last_seen[1]),
|
||||
tuple_(WorkflowRun.created_at, WorkflowRun.id)
|
||||
> tuple_(
|
||||
sa.literal(last_seen[0], type_=sa.DateTime()),
|
||||
sa.literal(last_seen[1], type_=WorkflowRun.id.type),
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import logging
|
||||
import time
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
import click
|
||||
from redis.exceptions import LockError
|
||||
@ -32,16 +33,30 @@ def clean_messages():
|
||||
graceful_period_days=dify_config.SANDBOX_EXPIRED_RECORDS_CLEAN_GRACEFUL_PERIOD,
|
||||
)
|
||||
|
||||
retention_days = dify_config.SANDBOX_EXPIRED_RECORDS_RETENTION_DAYS
|
||||
scan_window_days = dify_config.SANDBOX_EXPIRED_RECORDS_CLEAN_SCAN_WINDOW_DAYS
|
||||
batch_size = dify_config.SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_SIZE
|
||||
|
||||
# Create and run the cleanup service
|
||||
# lock the task to avoid concurrent execution in case of the future data volume growth
|
||||
with redis_client.lock(
|
||||
"retention:clean_messages", timeout=dify_config.SANDBOX_EXPIRED_RECORDS_CLEAN_TASK_LOCK_TTL, blocking=False
|
||||
):
|
||||
service = MessagesCleanService.from_days(
|
||||
policy=policy,
|
||||
days=dify_config.SANDBOX_EXPIRED_RECORDS_RETENTION_DAYS,
|
||||
batch_size=dify_config.SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_SIZE,
|
||||
)
|
||||
if scan_window_days > 0:
|
||||
end_before = datetime.now() - timedelta(days=retention_days)
|
||||
start_from = end_before - timedelta(days=scan_window_days)
|
||||
service = MessagesCleanService.from_time_range(
|
||||
policy=policy,
|
||||
start_from=start_from,
|
||||
end_before=end_before,
|
||||
batch_size=batch_size,
|
||||
)
|
||||
else:
|
||||
service = MessagesCleanService.from_days(
|
||||
policy=policy,
|
||||
days=retention_days,
|
||||
batch_size=batch_size,
|
||||
)
|
||||
stats = service.run()
|
||||
|
||||
end_at = time.perf_counter()
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import logging
|
||||
from datetime import UTC, datetime
|
||||
from datetime import UTC, datetime, timedelta
|
||||
|
||||
import click
|
||||
from redis.exceptions import LockError
|
||||
@ -30,6 +30,16 @@ def clean_workflow_runs_task() -> None:
|
||||
|
||||
start_time = datetime.now(UTC)
|
||||
|
||||
retention_days = dify_config.SANDBOX_EXPIRED_RECORDS_RETENTION_DAYS
|
||||
scan_window_days = dify_config.SANDBOX_EXPIRED_RECORDS_CLEAN_SCAN_WINDOW_DAYS
|
||||
|
||||
if scan_window_days > 0:
|
||||
end_before = datetime.now() - timedelta(days=retention_days)
|
||||
start_from = end_before - timedelta(days=scan_window_days)
|
||||
else:
|
||||
start_from = None
|
||||
end_before = None
|
||||
|
||||
try:
|
||||
# lock the task to avoid concurrent execution in case of the future data volume growth
|
||||
with redis_client.lock(
|
||||
@ -38,10 +48,10 @@ def clean_workflow_runs_task() -> None:
|
||||
blocking=False,
|
||||
):
|
||||
WorkflowRunCleanup(
|
||||
days=dify_config.SANDBOX_EXPIRED_RECORDS_RETENTION_DAYS,
|
||||
days=retention_days,
|
||||
batch_size=dify_config.SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_SIZE,
|
||||
start_from=None,
|
||||
end_before=None,
|
||||
start_from=start_from,
|
||||
end_before=end_before,
|
||||
).run()
|
||||
|
||||
end_time = datetime.now(UTC)
|
||||
|
||||
@ -220,8 +220,8 @@ class MetadataService:
|
||||
doc_metadata[BuiltInField.source] = MetadataDataSource[document.data_source_type]
|
||||
document.doc_metadata = doc_metadata
|
||||
db.session.add(document)
|
||||
db.session.commit()
|
||||
# deal metadata binding
|
||||
|
||||
# deal metadata binding (in the same transaction as the doc_metadata update)
|
||||
if not operation.partial_update:
|
||||
db.session.query(DatasetMetadataBinding).filter_by(document_id=operation.document_id).delete()
|
||||
|
||||
@ -247,7 +247,9 @@ class MetadataService:
|
||||
db.session.add(dataset_metadata_binding)
|
||||
db.session.commit()
|
||||
except Exception:
|
||||
db.session.rollback()
|
||||
logger.exception("Update documents metadata failed")
|
||||
raise
|
||||
finally:
|
||||
redis_client.delete(lock_key)
|
||||
|
||||
|
||||
@ -914,9 +914,6 @@ class TestMetadataService:
|
||||
metadata_args = MetadataArgs(type="string", name="test_metadata")
|
||||
metadata = MetadataService.create_metadata(dataset.id, metadata_args)
|
||||
|
||||
# Mock DocumentService.get_document to return None (document not found)
|
||||
mock_external_service_dependencies["document_service"].get_document.return_value = None
|
||||
|
||||
# Create metadata operation data
|
||||
from services.entities.knowledge_entities.knowledge_entities import (
|
||||
DocumentMetadataOperation,
|
||||
@ -926,16 +923,17 @@ class TestMetadataService:
|
||||
|
||||
metadata_detail = MetadataDetail(id=metadata.id, name=metadata.name, value="test_value")
|
||||
|
||||
operation = DocumentMetadataOperation(document_id="non-existent-document-id", metadata_list=[metadata_detail])
|
||||
# Use a valid UUID format that does not exist in the database
|
||||
operation = DocumentMetadataOperation(
|
||||
document_id="00000000-0000-0000-0000-000000000000", metadata_list=[metadata_detail]
|
||||
)
|
||||
|
||||
operation_data = MetadataOperationData(operation_data=[operation])
|
||||
|
||||
# Act: Execute the method under test
|
||||
# The method should handle the error gracefully and continue
|
||||
MetadataService.update_documents_metadata(dataset, operation_data)
|
||||
|
||||
# Assert: Verify the method completes without raising exceptions
|
||||
# The main functionality (error handling) is verified
|
||||
# Act & Assert: The method should raise ValueError("Document not found.")
|
||||
# because the exception is now re-raised after rollback
|
||||
with pytest.raises(ValueError, match="Document not found"):
|
||||
MetadataService.update_documents_metadata(dataset, operation_data)
|
||||
|
||||
def test_knowledge_base_metadata_lock_check_dataset_id(
|
||||
self, db_session_with_containers, mock_external_service_dependencies
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import unittest
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from models.dataset import Dataset, Document
|
||||
from services.entities.knowledge_entities.knowledge_entities import (
|
||||
DocumentMetadataOperation,
|
||||
@ -148,6 +150,38 @@ class TestMetadataPartialUpdate(unittest.TestCase):
|
||||
# If it were added, there would be 2 calls. If skipped, 1 call.
|
||||
assert mock_db.session.add.call_count == 1
|
||||
|
||||
@patch("services.metadata_service.db")
|
||||
@patch("services.metadata_service.DocumentService")
|
||||
@patch("services.metadata_service.current_account_with_tenant")
|
||||
@patch("services.metadata_service.redis_client")
|
||||
def test_rollback_called_on_commit_failure(self, mock_redis, mock_current_account, mock_document_service, mock_db):
|
||||
"""When db.session.commit() raises, rollback must be called and the exception must propagate."""
|
||||
# Setup mocks
|
||||
mock_redis.get.return_value = None
|
||||
mock_document_service.get_document.return_value = self.document
|
||||
mock_current_account.return_value = (MagicMock(id="user_id"), "tenant_id")
|
||||
mock_db.session.query.return_value.filter_by.return_value.first.return_value = None
|
||||
|
||||
# Make commit raise an exception
|
||||
mock_db.session.commit.side_effect = RuntimeError("database connection lost")
|
||||
|
||||
operation = DocumentMetadataOperation(
|
||||
document_id="doc_id",
|
||||
metadata_list=[MetadataDetail(id="meta_id", name="key", value="value")],
|
||||
partial_update=True,
|
||||
)
|
||||
metadata_args = MetadataOperationData(operation_data=[operation])
|
||||
|
||||
# Act & Assert: the exception must propagate
|
||||
with pytest.raises(RuntimeError, match="database connection lost"):
|
||||
MetadataService.update_documents_metadata(self.dataset, metadata_args)
|
||||
|
||||
# Verify rollback was called
|
||||
mock_db.session.rollback.assert_called_once()
|
||||
|
||||
# Verify the lock key was cleaned up despite the failure
|
||||
mock_redis.delete.assert_called_with("document_metadata_lock_doc_id")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
62
api/uv.lock
generated
62
api/uv.lock
generated
@ -4473,39 +4473,39 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "pillow"
|
||||
version = "12.0.0"
|
||||
version = "12.1.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/cace85a1b0c9775a9f8f5d5423c8261c858760e2466c79b2dd184638b056/pillow-12.0.0.tar.gz", hash = "sha256:87d4f8125c9988bfbed67af47dd7a953e2fc7b0cc1e7800ec6d2080d490bb353", size = 47008828, upload-time = "2025-10-15T18:24:14.008Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1f/42/5c74462b4fd957fcd7b13b04fb3205ff8349236ea74c7c375766d6c82288/pillow-12.1.1.tar.gz", hash = "sha256:9ad8fa5937ab05218e2b6a4cff30295ad35afd2f83ac592e68c0d871bb0fdbc4", size = 46980264, upload-time = "2026-02-11T04:23:07.146Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0e/5a/a2f6773b64edb921a756eb0729068acad9fc5208a53f4a349396e9436721/pillow-12.0.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:0fd00cac9c03256c8b2ff58f162ebcd2587ad3e1f2e397eab718c47e24d231cc", size = 5289798, upload-time = "2025-10-15T18:21:47.763Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/05/069b1f8a2e4b5a37493da6c5868531c3f77b85e716ad7a590ef87d58730d/pillow-12.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3475b96f5908b3b16c47533daaa87380c491357d197564e0ba34ae75c0f3257", size = 4650589, upload-time = "2025-10-15T18:21:49.515Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/61/e3/2c820d6e9a36432503ead175ae294f96861b07600a7156154a086ba7111a/pillow-12.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:110486b79f2d112cf6add83b28b627e369219388f64ef2f960fef9ebaf54c642", size = 6230472, upload-time = "2025-10-15T18:21:51.052Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/89/63427f51c64209c5e23d4d52071c8d0f21024d3a8a487737caaf614a5795/pillow-12.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5269cc1caeedb67e6f7269a42014f381f45e2e7cd42d834ede3c703a1d915fe3", size = 8033887, upload-time = "2025-10-15T18:21:52.604Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f6/1b/c9711318d4901093c15840f268ad649459cd81984c9ec9887756cca049a5/pillow-12.0.0-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa5129de4e174daccbc59d0a3b6d20eaf24417d59851c07ebb37aeb02947987c", size = 6343964, upload-time = "2025-10-15T18:21:54.619Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/41/1e/db9470f2d030b4995083044cd8738cdd1bf773106819f6d8ba12597d5352/pillow-12.0.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bee2a6db3a7242ea309aa7ee8e2780726fed67ff4e5b40169f2c940e7eb09227", size = 7034756, upload-time = "2025-10-15T18:21:56.151Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/cc/b0/6177a8bdd5ee4ed87cba2de5a3cc1db55ffbbec6176784ce5bb75aa96798/pillow-12.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:90387104ee8400a7b4598253b4c406f8958f59fcf983a6cea2b50d59f7d63d0b", size = 6458075, upload-time = "2025-10-15T18:21:57.759Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/5e/61537aa6fa977922c6a03253a0e727e6e4a72381a80d63ad8eec350684f2/pillow-12.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bc91a56697869546d1b8f0a3ff35224557ae7f881050e99f615e0119bf934b4e", size = 7125955, upload-time = "2025-10-15T18:21:59.372Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/3d/d5033539344ee3cbd9a4d69e12e63ca3a44a739eb2d4c8da350a3d38edd7/pillow-12.0.0-cp311-cp311-win32.whl", hash = "sha256:27f95b12453d165099c84f8a8bfdfd46b9e4bda9e0e4b65f0635430027f55739", size = 6298440, upload-time = "2025-10-15T18:22:00.982Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/42/aaca386de5cc8bd8a0254516957c1f265e3521c91515b16e286c662854c4/pillow-12.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:b583dc9070312190192631373c6c8ed277254aa6e6084b74bdd0a6d3b221608e", size = 6999256, upload-time = "2025-10-15T18:22:02.617Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/f1/9197c9c2d5708b785f631a6dfbfa8eb3fb9672837cb92ae9af812c13b4ed/pillow-12.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:759de84a33be3b178a64c8ba28ad5c135900359e85fb662bc6e403ad4407791d", size = 2436025, upload-time = "2025-10-15T18:22:04.598Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/90/4fcce2c22caf044e660a198d740e7fbc14395619e3cb1abad12192c0826c/pillow-12.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:53561a4ddc36facb432fae7a9d8afbfaf94795414f5cdc5fc52f28c1dca90371", size = 5249377, upload-time = "2025-10-15T18:22:05.993Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/e0/ed960067543d080691d47d6938ebccbf3976a931c9567ab2fbfab983a5dd/pillow-12.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:71db6b4c1653045dacc1585c1b0d184004f0d7e694c7b34ac165ca70c0838082", size = 4650343, upload-time = "2025-10-15T18:22:07.718Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e7/a1/f81fdeddcb99c044bf7d6faa47e12850f13cee0849537a7d27eeab5534d4/pillow-12.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2fa5f0b6716fc88f11380b88b31fe591a06c6315e955c096c35715788b339e3f", size = 6232981, upload-time = "2025-10-15T18:22:09.287Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/88/e1/9098d3ce341a8750b55b0e00c03f1630d6178f38ac191c81c97a3b047b44/pillow-12.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:82240051c6ca513c616f7f9da06e871f61bfd7805f566275841af15015b8f98d", size = 8041399, upload-time = "2025-10-15T18:22:10.872Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/62/a22e8d3b602ae8cc01446d0c57a54e982737f44b6f2e1e019a925143771d/pillow-12.0.0-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:55f818bd74fe2f11d4d7cbc65880a843c4075e0ac7226bc1a23261dbea531953", size = 6347740, upload-time = "2025-10-15T18:22:12.769Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4f/87/424511bdcd02c8d7acf9f65caa09f291a519b16bd83c3fb3374b3d4ae951/pillow-12.0.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b87843e225e74576437fd5b6a4c2205d422754f84a06942cfaf1dc32243e45a8", size = 7040201, upload-time = "2025-10-15T18:22:14.813Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/dc/4d/435c8ac688c54d11755aedfdd9f29c9eeddf68d150fe42d1d3dbd2365149/pillow-12.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c607c90ba67533e1b2355b821fef6764d1dd2cbe26b8c1005ae84f7aea25ff79", size = 6462334, upload-time = "2025-10-15T18:22:16.375Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/f2/ad34167a8059a59b8ad10bc5c72d4d9b35acc6b7c0877af8ac885b5f2044/pillow-12.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:21f241bdd5080a15bc86d3466a9f6074a9c2c2b314100dd896ac81ee6db2f1ba", size = 7134162, upload-time = "2025-10-15T18:22:17.996Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0c/b1/a7391df6adacf0a5c2cf6ac1cf1fcc1369e7d439d28f637a847f8803beb3/pillow-12.0.0-cp312-cp312-win32.whl", hash = "sha256:dd333073e0cacdc3089525c7df7d39b211bcdf31fc2824e49d01c6b6187b07d0", size = 6298769, upload-time = "2025-10-15T18:22:19.923Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/0b/d87733741526541c909bbf159e338dcace4f982daac6e5a8d6be225ca32d/pillow-12.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:9fe611163f6303d1619bbcb653540a4d60f9e55e622d60a3108be0d5b441017a", size = 7001107, upload-time = "2025-10-15T18:22:21.644Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/96/aaa61ce33cc98421fb6088af2a03be4157b1e7e0e87087c888e2370a7f45/pillow-12.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:7dfb439562f234f7d57b1ac6bc8fe7f838a4bd49c79230e0f6a1da93e82f1fad", size = 2436012, upload-time = "2025-10-15T18:22:23.621Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1d/b3/582327e6c9f86d037b63beebe981425d6811104cb443e8193824ef1a2f27/pillow-12.0.0-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:b22bd8c974942477156be55a768f7aa37c46904c175be4e158b6a86e3a6b7ca8", size = 5215068, upload-time = "2025-10-15T18:23:59.594Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/fd/d6/67748211d119f3b6540baf90f92fae73ae51d5217b171b0e8b5f7e5d558f/pillow-12.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:805ebf596939e48dbb2e4922a1d3852cfc25c38160751ce02da93058b48d252a", size = 4614994, upload-time = "2025-10-15T18:24:01.669Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2d/e1/f8281e5d844c41872b273b9f2c34a4bf64ca08905668c8ae730eedc7c9fa/pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:cae81479f77420d217def5f54b5b9d279804d17e982e0f2fa19b1d1e14ab5197", size = 5246639, upload-time = "2025-10-15T18:24:03.403Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/94/5a/0d8ab8ffe8a102ff5df60d0de5af309015163bf710c7bb3e8311dd3b3ad0/pillow-12.0.0-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aeaefa96c768fc66818730b952a862235d68825c178f1b3ffd4efd7ad2edcb7c", size = 6986839, upload-time = "2025-10-15T18:24:05.344Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/2e/3434380e8110b76cd9eb00a363c484b050f949b4bbe84ba770bb8508a02c/pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:09f2d0abef9e4e2f349305a4f8cc784a8a6c2f58a8c4892eea13b10a943bd26e", size = 5313505, upload-time = "2025-10-15T18:24:07.137Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/57/ca/5a9d38900d9d74785141d6580950fe705de68af735ff6e727cb911b64740/pillow-12.0.0-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bdee52571a343d721fb2eb3b090a82d959ff37fc631e3f70422e0c2e029f3e76", size = 5963654, upload-time = "2025-10-15T18:24:09.579Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/7e/f896623c3c635a90537ac093c6a618ebe1a90d87206e42309cb5d98a1b9e/pillow-12.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:b290fd8aa38422444d4b50d579de197557f182ef1068b75f5aa8558638b8d0a5", size = 6997850, upload-time = "2025-10-15T18:24:11.495Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/46/5da1ec4a5171ee7bf1a0efa064aba70ba3d6e0788ce3f5acd1375d23c8c0/pillow-12.1.1-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:e879bb6cd5c73848ef3b2b48b8af9ff08c5b71ecda8048b7dd22d8a33f60be32", size = 5304084, upload-time = "2026-02-11T04:20:27.501Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/78/93/a29e9bc02d1cf557a834da780ceccd54e02421627200696fcf805ebdc3fb/pillow-12.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:365b10bb9417dd4498c0e3b128018c4a624dc11c7b97d8cc54effe3b096f4c38", size = 4657866, upload-time = "2026-02-11T04:20:29.827Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/13/84/583a4558d492a179d31e4aae32eadce94b9acf49c0337c4ce0b70e0a01f2/pillow-12.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d4ce8e329c93845720cd2014659ca67eac35f6433fd3050393d85f3ecef0dad5", size = 6232148, upload-time = "2026-02-11T04:20:31.329Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d5/e2/53c43334bbbb2d3b938978532fbda8e62bb6e0b23a26ce8592f36bcc4987/pillow-12.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc354a04072b765eccf2204f588a7a532c9511e8b9c7f900e1b64e3e33487090", size = 8038007, upload-time = "2026-02-11T04:20:34.225Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b8/a6/3d0e79c8a9d58150dd98e199d7c1c56861027f3829a3a60b3c2784190180/pillow-12.1.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e7976bf1910a8116b523b9f9f58bf410f3e8aa330cd9a2bb2953f9266ab49af", size = 6345418, upload-time = "2026-02-11T04:20:35.858Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a2/c8/46dfeac5825e600579157eea177be43e2f7ff4a99da9d0d0a49533509ac5/pillow-12.1.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:597bd9c8419bc7c6af5604e55847789b69123bbe25d65cc6ad3012b4f3c98d8b", size = 7034590, upload-time = "2026-02-11T04:20:37.91Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/af/bf/e6f65d3db8a8bbfeaf9e13cc0417813f6319863a73de934f14b2229ada18/pillow-12.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2c1fc0f2ca5f96a3c8407e41cca26a16e46b21060fe6d5b099d2cb01412222f5", size = 6458655, upload-time = "2026-02-11T04:20:39.496Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/c2/66091f3f34a25894ca129362e510b956ef26f8fb67a0e6417bc5744e56f1/pillow-12.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:578510d88c6229d735855e1f278aa305270438d36a05031dfaae5067cc8eb04d", size = 7159286, upload-time = "2026-02-11T04:20:41.139Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/5a/24bc8eb526a22f957d0cec6243146744966d40857e3d8deb68f7902ca6c1/pillow-12.1.1-cp311-cp311-win32.whl", hash = "sha256:7311c0a0dcadb89b36b7025dfd8326ecfa36964e29913074d47382706e516a7c", size = 6328663, upload-time = "2026-02-11T04:20:43.184Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/31/03/bef822e4f2d8f9d7448c133d0a18185d3cce3e70472774fffefe8b0ed562/pillow-12.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:fbfa2a7c10cc2623f412753cddf391c7f971c52ca40a3f65dc5039b2939e8563", size = 7031448, upload-time = "2026-02-11T04:20:44.696Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/49/70/f76296f53610bd17b2e7d31728b8b7825e3ac3b5b3688b51f52eab7c0818/pillow-12.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:b81b5e3511211631b3f672a595e3221252c90af017e399056d0faabb9538aa80", size = 2453651, upload-time = "2026-02-11T04:20:46.243Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/d3/8df65da0d4df36b094351dce696f2989bec731d4f10e743b1c5f4da4d3bf/pillow-12.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ab323b787d6e18b3d91a72fc99b1a2c28651e4358749842b8f8dfacd28ef2052", size = 5262803, upload-time = "2026-02-11T04:20:47.653Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/71/5026395b290ff404b836e636f51d7297e6c83beceaa87c592718747e670f/pillow-12.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:adebb5bee0f0af4909c30db0d890c773d1a92ffe83da908e2e9e720f8edf3984", size = 4657601, upload-time = "2026-02-11T04:20:49.328Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b1/2e/1001613d941c67442f745aff0f7cc66dd8df9a9c084eb497e6a543ee6f7e/pillow-12.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bb66b7cc26f50977108790e2456b7921e773f23db5630261102233eb355a3b79", size = 6234995, upload-time = "2026-02-11T04:20:51.032Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/07/26/246ab11455b2549b9233dbd44d358d033a2f780fa9007b61a913c5b2d24e/pillow-12.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aee2810642b2898bb187ced9b349e95d2a7272930796e022efaf12e99dccd293", size = 8045012, upload-time = "2026-02-11T04:20:52.882Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b2/8b/07587069c27be7535ac1fe33874e32de118fbd34e2a73b7f83436a88368c/pillow-12.1.1-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:a0b1cd6232e2b618adcc54d9882e4e662a089d5768cd188f7c245b4c8c44a397", size = 6349638, upload-time = "2026-02-11T04:20:54.444Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/79/6df7b2ee763d619cda2fb4fea498e5f79d984dae304d45a8999b80d6cf5c/pillow-12.1.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7aac39bcf8d4770d089588a2e1dd111cbaa42df5a94be3114222057d68336bd0", size = 7041540, upload-time = "2026-02-11T04:20:55.97Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2c/5e/2ba19e7e7236d7529f4d873bdaf317a318896bac289abebd4bb00ef247f0/pillow-12.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ab174cd7d29a62dd139c44bf74b698039328f45cb03b4596c43473a46656b2f3", size = 6462613, upload-time = "2026-02-11T04:20:57.542Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/03/03/31216ec124bb5c3dacd74ce8efff4cc7f52643653bad4825f8f08c697743/pillow-12.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:339ffdcb7cbeaa08221cd401d517d4b1fe7a9ed5d400e4a8039719238620ca35", size = 7166745, upload-time = "2026-02-11T04:20:59.196Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/e7/7c4552d80052337eb28653b617eafdef39adfb137c49dd7e831b8dc13bc5/pillow-12.1.1-cp312-cp312-win32.whl", hash = "sha256:5d1f9575a12bed9e9eedd9a4972834b08c97a352bd17955ccdebfeca5913fa0a", size = 6328823, upload-time = "2026-02-11T04:21:01.385Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3d/17/688626d192d7261bbbf98846fc98995726bddc2c945344b65bec3a29d731/pillow-12.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:21329ec8c96c6e979cd0dfd29406c40c1d52521a90544463057d2aaa937d66a6", size = 7033367, upload-time = "2026-02-11T04:21:03.536Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ed/fe/a0ef1f73f939b0eca03ee2c108d0043a87468664770612602c63266a43c4/pillow-12.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:af9a332e572978f0218686636610555ae3defd1633597be015ed50289a03c523", size = 2453811, upload-time = "2026-02-11T04:21:05.116Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/56/11/5d43209aa4cb58e0cc80127956ff1796a68b928e6324bbf06ef4db34367b/pillow-12.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:600fd103672b925fe62ed08e0d874ea34d692474df6f4bf7ebe148b30f89f39f", size = 5228606, upload-time = "2026-02-11T04:22:52.106Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/5f/d5/3b005b4e4fda6698b371fa6c21b097d4707585d7db99e98d9b0b87ac612a/pillow-12.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:665e1b916b043cef294bc54d47bf02d87e13f769bc4bc5fa225a24b3a6c5aca9", size = 4622321, upload-time = "2026-02-11T04:22:53.827Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/36/ed3ea2d594356fd8037e5a01f6156c74bc8d92dbb0fa60746cc96cabb6e8/pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:495c302af3aad1ca67420ddd5c7bd480c8867ad173528767d906428057a11f0e", size = 5247579, upload-time = "2026-02-11T04:22:56.094Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/54/9a/9cc3e029683cf6d20ae5085da0dafc63148e3252c2f13328e553aaa13cfb/pillow-12.1.1-pp311-pypy311_pp73-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8fd420ef0c52c88b5a035a0886f367748c72147b2b8f384c9d12656678dfdfa9", size = 6989094, upload-time = "2026-02-11T04:22:58.288Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/00/98/fc53ab36da80b88df0967896b6c4b4cd948a0dc5aa40a754266aa3ae48b3/pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f975aa7ef9684ce7e2c18a3aa8f8e2106ce1e46b94ab713d156b2898811651d3", size = 5313850, upload-time = "2026-02-11T04:23:00.554Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/30/02/00fa585abfd9fe9d73e5f6e554dc36cc2b842898cbfc46d70353dae227f8/pillow-12.1.1-pp311-pypy311_pp73-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8089c852a56c2966cf18835db62d9b34fef7ba74c726ad943928d494fa7f4735", size = 5963343, upload-time = "2026-02-11T04:23:02.934Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f2/26/c56ce33ca856e358d27fda9676c055395abddb82c35ac0f593877ed4562e/pillow-12.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:cb9bb857b2d057c6dfc72ac5f3b44836924ba15721882ef103cecb40d002d80e", size = 7029880, upload-time = "2026-02-11T04:23:04.783Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@ -1527,6 +1527,7 @@ SANDBOX_EXPIRED_RECORDS_CLEAN_GRACEFUL_PERIOD=21
|
||||
SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_SIZE=1000
|
||||
SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_MAX_INTERVAL=200
|
||||
SANDBOX_EXPIRED_RECORDS_RETENTION_DAYS=30
|
||||
SANDBOX_EXPIRED_RECORDS_CLEAN_SCAN_WINDOW_DAYS=0
|
||||
|
||||
|
||||
# Redis URL used for PubSub between API and
|
||||
|
||||
@ -687,6 +687,7 @@ x-shared-env: &shared-api-worker-env
|
||||
SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_SIZE: ${SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_SIZE:-1000}
|
||||
SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_MAX_INTERVAL: ${SANDBOX_EXPIRED_RECORDS_CLEAN_BATCH_MAX_INTERVAL:-200}
|
||||
SANDBOX_EXPIRED_RECORDS_RETENTION_DAYS: ${SANDBOX_EXPIRED_RECORDS_RETENTION_DAYS:-30}
|
||||
SANDBOX_EXPIRED_RECORDS_CLEAN_SCAN_WINDOW_DAYS: ${SANDBOX_EXPIRED_RECORDS_CLEAN_SCAN_WINDOW_DAYS:-0}
|
||||
PUBSUB_REDIS_URL: ${PUBSUB_REDIS_URL:-}
|
||||
PUBSUB_REDIS_CHANNEL_TYPE: ${PUBSUB_REDIS_CHANNEL_TYPE:-pubsub}
|
||||
PUBSUB_REDIS_USE_CLUSTERS: ${PUBSUB_REDIS_USE_CLUSTERS:-false}
|
||||
|
||||
@ -1,11 +1,9 @@
|
||||
import type {
|
||||
FileEntity,
|
||||
} from './types'
|
||||
import { isEqual } from 'es-toolkit/predicate'
|
||||
import {
|
||||
createContext,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
} from 'react'
|
||||
import {
|
||||
@ -57,20 +55,10 @@ export const FileContextProvider = ({
|
||||
onChange,
|
||||
}: FileProviderProps) => {
|
||||
const storeRef = useRef<FileStore | undefined>(undefined)
|
||||
|
||||
if (!storeRef.current)
|
||||
storeRef.current = createFileStore(value, onChange)
|
||||
|
||||
useEffect(() => {
|
||||
if (!storeRef.current)
|
||||
return
|
||||
if (isEqual(value, storeRef.current.getState().files))
|
||||
return
|
||||
|
||||
storeRef.current.setState({
|
||||
files: value ? [...value] : [],
|
||||
})
|
||||
}, [value])
|
||||
|
||||
return (
|
||||
<FileContext.Provider value={storeRef.current}>
|
||||
{children}
|
||||
|
||||
@ -22,6 +22,7 @@ type MetadataItemWithEdit = {
|
||||
type: DataType
|
||||
value: string | number | null
|
||||
isMultipleValue?: boolean
|
||||
isUpdated?: boolean
|
||||
updateType?: UpdateType
|
||||
}
|
||||
|
||||
@ -615,6 +616,91 @@ describe('useBatchEditDocumentMetadata', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('toCleanMetadataItem sanitization', () => {
|
||||
it('should strip extra fields (isMultipleValue, updateType, isUpdated) from metadata items sent to backend', async () => {
|
||||
const docListSingleDoc: DocListItem[] = [
|
||||
{
|
||||
id: 'doc-1',
|
||||
doc_metadata: [
|
||||
{ id: '1', name: 'field_one', type: DataType.string, value: 'Old Value' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useBatchEditDocumentMetadata({
|
||||
...defaultProps,
|
||||
docList: docListSingleDoc as Parameters<typeof useBatchEditDocumentMetadata>[0]['docList'],
|
||||
}),
|
||||
)
|
||||
|
||||
const editedList: MetadataItemWithEdit[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'field_one',
|
||||
type: DataType.string,
|
||||
value: 'New Value',
|
||||
isMultipleValue: true,
|
||||
isUpdated: true,
|
||||
updateType: UpdateType.changeValue,
|
||||
},
|
||||
]
|
||||
|
||||
await act(async () => {
|
||||
await result.current.handleSave(editedList, [], false)
|
||||
})
|
||||
|
||||
const callArgs = mockMutateAsync.mock.calls[0][0]
|
||||
const sentItem = callArgs.metadata_list[0].metadata_list[0]
|
||||
|
||||
// Only id, name, type, value should be present
|
||||
expect(Object.keys(sentItem).sort()).toEqual(['id', 'name', 'type', 'value'].sort())
|
||||
expect(sentItem).not.toHaveProperty('isMultipleValue')
|
||||
expect(sentItem).not.toHaveProperty('updateType')
|
||||
expect(sentItem).not.toHaveProperty('isUpdated')
|
||||
})
|
||||
|
||||
it('should coerce undefined value to null in metadata items sent to backend', async () => {
|
||||
const docListSingleDoc: DocListItem[] = [
|
||||
{
|
||||
id: 'doc-1',
|
||||
doc_metadata: [
|
||||
{ id: '1', name: 'field_one', type: DataType.string, value: 'Value' },
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
const { result } = renderHook(() =>
|
||||
useBatchEditDocumentMetadata({
|
||||
...defaultProps,
|
||||
docList: docListSingleDoc as Parameters<typeof useBatchEditDocumentMetadata>[0]['docList'],
|
||||
}),
|
||||
)
|
||||
|
||||
// Pass an item with value explicitly set to undefined (via cast)
|
||||
const editedList: MetadataItemWithEdit[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: 'field_one',
|
||||
type: DataType.string,
|
||||
value: undefined as unknown as null,
|
||||
updateType: UpdateType.changeValue,
|
||||
},
|
||||
]
|
||||
|
||||
await act(async () => {
|
||||
await result.current.handleSave(editedList, [], false)
|
||||
})
|
||||
|
||||
const callArgs = mockMutateAsync.mock.calls[0][0]
|
||||
const sentItem = callArgs.metadata_list[0].metadata_list[0]
|
||||
|
||||
// value should be null, not undefined
|
||||
expect(sentItem.value).toBeNull()
|
||||
expect(sentItem.value).not.toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
describe('Edge Cases', () => {
|
||||
it('should handle empty docList', () => {
|
||||
const { result } = renderHook(() =>
|
||||
|
||||
@ -71,6 +71,13 @@ const useBatchEditDocumentMetadata = ({
|
||||
return res
|
||||
}, [metaDataList])
|
||||
|
||||
const toCleanMetadataItem = (item: MetadataItemWithValue | MetadataItemWithEdit | MetadataItemInBatchEdit): MetadataItemWithValue => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
value: item.value ?? null,
|
||||
})
|
||||
|
||||
const formateToBackendList = (editedList: MetadataItemWithEdit[], addedList: MetadataItemInBatchEdit[], isApplyToAllSelectDocument: boolean) => {
|
||||
const updatedList = editedList.filter((editedItem) => {
|
||||
return editedItem.updateType === UpdateType.changeValue
|
||||
@ -92,24 +99,19 @@ const useBatchEditDocumentMetadata = ({
|
||||
.filter((item) => {
|
||||
return !removedList.find(removedItem => removedItem.id === item.id)
|
||||
})
|
||||
.map(item => ({
|
||||
id: item.id,
|
||||
name: item.name,
|
||||
type: item.type,
|
||||
value: item.value,
|
||||
}))
|
||||
.map(toCleanMetadataItem)
|
||||
if (isApplyToAllSelectDocument) {
|
||||
// add missing metadata item
|
||||
updatedList.forEach((editedItem) => {
|
||||
if (!newMetadataList.find(i => i.id === editedItem.id) && !editedItem.isMultipleValue)
|
||||
newMetadataList.push(editedItem)
|
||||
newMetadataList.push(toCleanMetadataItem(editedItem))
|
||||
})
|
||||
}
|
||||
|
||||
newMetadataList = newMetadataList.map((item) => {
|
||||
const editedItem = updatedList.find(i => i.id === item.id)
|
||||
if (editedItem)
|
||||
return editedItem
|
||||
return toCleanMetadataItem(editedItem)
|
||||
return item
|
||||
})
|
||||
|
||||
|
||||
@ -108,7 +108,7 @@ const FormItem: FC<Props> = ({
|
||||
const isIteratorItemFile = isIterator && payload.isFileItem
|
||||
const singleFileValue = useMemo(() => {
|
||||
if (payload.variable === '#files#')
|
||||
return value?.[0] || []
|
||||
return value || []
|
||||
|
||||
return value ? [value] : []
|
||||
}, [payload.variable, value])
|
||||
@ -124,19 +124,19 @@ const FormItem: FC<Props> = ({
|
||||
return (
|
||||
<div className={cn(className)}>
|
||||
{!isArrayLikeType && !isBooleanType && (
|
||||
<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">
|
||||
{typeof payload.label === 'object' ? nodeKey : payload.label}
|
||||
</div>
|
||||
{payload.hide === true
|
||||
? (
|
||||
<span className="system-xs-regular text-text-tertiary">
|
||||
<span className="text-text-tertiary system-xs-regular">
|
||||
{t('panel.optional_and_hidden', { ns: 'workflow' })}
|
||||
</span>
|
||||
)
|
||||
: (
|
||||
!payload.required && (
|
||||
<span className="system-xs-regular text-text-tertiary">
|
||||
<span className="text-text-tertiary system-xs-regular">
|
||||
{t('panel.optional', { ns: 'workflow' })}
|
||||
</span>
|
||||
)
|
||||
|
||||
@ -4102,11 +4102,6 @@
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"app/components/explore/app-card/index.spec.tsx": {
|
||||
"ts/no-explicit-any": {
|
||||
"count": 1
|
||||
}
|
||||
},
|
||||
"app/components/explore/app-card/index.tsx": {
|
||||
"tailwindcss/enforce-consistent-class-order": {
|
||||
"count": 1
|
||||
@ -6201,9 +6196,6 @@
|
||||
}
|
||||
},
|
||||
"app/components/workflow/nodes/_base/components/before-run-form/form-item.tsx": {
|
||||
"tailwindcss/enforce-consistent-class-order": {
|
||||
"count": 3
|
||||
},
|
||||
"ts/no-explicit-any": {
|
||||
"count": 11
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user