发布

  • [OPIK-3137][OPIK-3161] [BE][FE] Add bulk tag adding and removing operations (#5122)

    frostbyte_neo 发布于 2026-02-23 15:05:37 +00:00

    • [OPIK-3137][OPIK-3161] [BE][FE] Add bulk tag adding and removing operations

    Implement single-call batch operations for adding and removing tags across multiple entities:

    Backend:

    • Add tagsToAdd/tagsToRemove fields to API models (Experiments, Traces, Spans, Threads, Dataset Items)
    • Update ClickHouse DAOs with array operations (arrayConcat, arrayFilter, arrayDistinct)
    • Add backwards compatibility with existing tags/mergeTags parameters
    • Add validation (100 char max per tag, 50 max tags for experiments)
    • Add integration tests for batch tag operations

    Frontend:

    • Update mutation hooks to support tagsToAdd/tagsToRemove
    • Simplify AddTagDialog components to use single API call
    • Add shared ManageTagsDialog component with client-side validation
    • Add maxEntities limit (1000) with improved UX
    • Add comprehensive unit tests for ManageTagsDialog

    Implements OPIK-3137: Allow multiple tags to be added in bulk
    Implements OPIK-3161: Allow tag removal from multiple items at once

    • Revision 1: Address PR feedback - code quality improvements

    Backend:

    • Extract duplicated SQL tags logic into SqlFragments.tagUpdateFragment()
    • Refactor test naming from test* to batchUpdateWhen* for clarity
    • Parameterize duplicate validation tests using @MethodSource
    • Fix import order in TraceThreadDAO

    Frontend:

    • Optimize tag operations from O(n²) to O(n) using Set data structures
    • Fix React state update bug by moving setOpen to useEffect
    • Prevent adding tags that already exist on all selected entities
    • Add deduplication in draft mode tag additions
    • Fix import ordering violations
    • Revision 2: Cleanup tags/mergeTags approach and improve tag limits

    Backend:

    • Add comprehensive documentation explaining dual tag update strategy
      (NEW: tagsToAdd/tagsToRemove for frontend vs OLD: tags+mergeTags for SDK)
    • Clarify backwards compatibility requirements in all DAOs
    • Document mutual exclusivity and precedence rules

    Frontend:

    • Remove dead code: eliminate tags/mergeTags from mutation hooks
      (experiments, traces, spans, threads, dataset items)
    • Add comment to usePromptVersionsUpdateMutation explaining why it still
      uses the legacy approach (SQL complexity for bulk removals)
    • Convert maxTags, maxEntities, maxTagLength from props to constants
      (never overridden in production code)
    • Update tests to reflect validation on submit instead of on add
    • Revision 3: Add validation limits for tag fields in Update DTOs
    • Add @Valid and @Size annotations to tags, tagsToAdd, and tagsToRemove fields
    • Limit tags to max 50 per operation and 100 characters per tag
    • Applied to TraceUpdate, SpanUpdate, ExperimentUpdate, DatasetItemUpdate, TraceThreadUpdate
    • Provides per-operation validation at API boundary level
    • Revision 4: Enforce 50-tag limit via SQL throwIf and refactor tag operations
    • Rename SqlFragments to TagOperations; add TagUpdatable interface, shared
      configureTagTemplate/bindTagParams helpers, and mapTagLimitError for 422 mapping
    • Add ClickHouse throwIf validation in tagUpdateFragment with short_circuit_function_evaluation
    • Add @Valid @Size annotations on all Update DTOs (tags, tagsToAdd, tagsToRemove)
    • Add server-side tag limit check in DatasetItemService.applyDeltaChanges for versioned inserts
    • Wire mapTagLimitError into all service reactive chains (experiments, traces, spans, threads, dataset items)
    • Update 6 frontend mutation hooks to parse ErrorMessage.errors[0] with message fallback
    • Add integration test for sequential tag limit enforcement
    • Revision 5: Redesign ManageTagsDialog with simpler and only common tags UI
    • Rename to "Manage shared tags", show only tags common to all items
    • Replace accordion layout with flat inline tag list
    • Add inline "+ Add tag" editable tag (click to input, Enter to add)
    • Removed tags shown as strikethrough with faded original color
    • New tags distinguished with outline border
    • RemovableTag: overlay close icon with gradient mask blend
    • RemovableTag: tooltip on truncated tags, max-w-40 constraint
    • Scrollable tag area for many tags
    • Revision 6: Extract shared TagUpdateFields type and buildTagUpdatePayload helper

    • Revision 7: Improve ManageTagsDialog UX - inline save/discard, Enter shortcut, Escape handling

    • Revision 8: Improve error handling - join multi-error responses and extract to shared utility

    • Add extractErrorMessage utility to lib/tags.ts that handles multi-error responses
    • Join multiple backend errors with comma separator instead of only showing first error
    • Add fallback chain: errors array → message → error.message → generic message
    • Update 6 mutation hooks to use shared extractErrorMessage utility
    • Remove lodash/get imports where no longer needed
    • Improve toast message in ManageTagsDialog to show item count
    • Update tagUpdateFragment in TagOperations.java: avoid running throwIf when not needed
    • Revision 9: Fix operator precedence issue in tagUpdateFragment

    The .replace() method was binding to the last text block instead of the
    concatenated result due to operator precedence (. has higher precedence than +).

    Added parentheses to force concatenation before calling .replace(), ensuring
    TAGS_COL placeholder is properly replaced throughout the SQL fragment.

    Fixes: BatchTagOperationsTest

    • Revision 10: Add more batch tag tests, simplify RemovableTag tooltip, fix removed tag truncation

    [BE] Add 3 tests to BatchTagOperationsTest: tags with mergeTags=false, tagsToAdd
    with tags simultaneously, and no tag fields provided. Format SQL in all DAOs for
    consistent tagUpdateFragment concatenation.

    [FE] Simplify RemovableTag to always show tooltip instead of conditional truncation
    detection. Fix long tags not truncating when marked for removal in ManageTagsDialog.

    • Revision 11: Reuse TAG_LIMIT_ERROR constant in DatasetItemService
    下载附件