Skip to content

feat: implement editable tags for knowledge base items#613

Closed
leex279 wants to merge 3 commits intomainfrom
feature/editable-tags-knowledge-base
Closed

feat: implement editable tags for knowledge base items#613
leex279 wants to merge 3 commits intomainfrom
feature/editable-tags-knowledge-base

Conversation

@leex279
Copy link
Copy Markdown
Collaborator

@leex279 leex279 commented Sep 7, 2025

Summary

Implements simple and focused editable tags functionality for knowledge base items, addressing the feature request in issue #538.

Features Implemented

  • Inline tag editing: Click any tag to edit it directly on knowledge cards
  • Add/remove tags: Easy tag management with "+" and "×" buttons
  • Modal tag editing: Full tag management within edit dialogs
  • Input validation: Prevents duplicates, empty tags, length limits (50 chars, 20 tags max)
  • Error handling: Toast notifications with detailed error messages
  • Keyboard support: Enter to save, Escape to cancel

Simplified Implementation

Based on user feedback, focused on essential functionality by removing:

  • ❌ Bulk tag editor (not needed)
  • ❌ Tag autocomplete suggestions (adds complexity)
  • ❌ Selection mode UI (unnecessary)

This keeps the implementation simple and focused on the core use case: editing tags on individual items.

Technical Implementation

  • EditableTags component: Core inline editing functionality
  • Enhanced EditKnowledgeItemModal: Added tag editing section
  • Updated KnowledgeItemCard: Integrated inline tag editing
  • Service enhancement: updateKnowledgeItemTags method
  • Comprehensive testing: Unit tests for core functionality

User Experience

  1. Individual Editing: Click any tag → edit inline → save with Enter or click outside
  2. Modal Editing: Click pencil icon → edit modal with tag editor section
  3. Validation: Real-time feedback for duplicates, length limits, empty tags
  4. Error Handling: Toast notifications for all operations
  5. Visual feedback: Loading states and success confirmations

Code Quality

Error Handling: Follows Archon Alpha "detailed errors" philosophy
Type Safety: Full TypeScript implementation
Performance: Efficient operations with race condition prevention
Accessibility: Keyboard navigation, focus management
Testing: Unit test coverage for core functionality
Code Review: All issues resolved

API Integration

  • Reuses existing PUT /api/knowledge-items/{source_id} endpoint
  • Tags stored in metadata.tags as JSON arrays (no backend changes needed)
  • Efficient validation and error handling
  • No additional API calls required

Test Plan

  • Individual tag editing (add/edit/remove)
  • Modal tag editing integration
  • API endpoint validation
  • Error handling scenarios
  • Input validation and user feedback
  • Keyboard shortcuts (Enter/Escape)

Database Impact

  • No schema changes required
  • Only updates existing metadata.tags field
  • Maintains backward compatibility

Fixes #538

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Inline tag editing everywhere (cards and edit modal) with validation, keyboard shortcuts, error toasts, and an optimized "tags-only" update path.
  • Refactor
    • Removed multi-item selection and selection toolbar; action controls are always visible and card interactions simplified.
  • Tests
    • Added comprehensive tests covering tag add/edit/remove, validation, and interaction states.

Resolves #538

## Summary
- Add inline tag editing functionality to knowledge base items
- Implement bulk tag editing for multiple items
- Add tag suggestions with autocomplete functionality
- Enhance edit modal with tag editing capabilities

## Features Added
- **EditableTags component**: Click-to-edit inline tag functionality
- **BulkTagEditor component**: Modal for editing tags on multiple items
- **TagSuggestions component**: Autocomplete using existing tags
- **Tag editing in edit modal**: Full tag management in item edit dialog
- **useTagSuggestions hook**: Cached tag suggestions with TanStack Query

## User Experience
- Click any tag to edit it inline
- Enter/Escape keyboard shortcuts for save/cancel
- "+" button to add new tags with autocomplete
- "×" button to remove tags
- Bulk selection and editing for multiple items
- Real-time validation with detailed error messages

## Technical Implementation
- Follows existing EditableTableCell pattern for consistency
- Integrates with existing knowledgeBaseService API
- Maintains Tron glassmorphism design system
- Includes comprehensive error handling and validation
- Race condition prevention for concurrent operations
- Full TypeScript support with proper types

## Quality Assurance
- ESLint compliant code
- Comprehensive unit test coverage
- API integration verified
- Error handling follows Archon Alpha philosophy
- Performance optimized with caching and batching

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Sep 7, 2025

Walkthrough

Adds an EditableTags component and integrates inline tag editing into KnowledgeItemCard and EditKnowledgeItemModal, introduces a tags-only update method in KnowledgeBaseService, adds unit tests for tag editing, and removes selection-mode logic across KnowledgeBasePage and KnowledgeItemCard.

Changes

Cohort / File(s) Summary
Editable Tags Component
archon-ui-main/src/components/knowledge-base/EditableTags.tsx
New reusable component for inline tag viewing/editing with validation, add/remove/rename, keyboard handling, overflow display, and error surfacing.
Modal Integration
archon-ui-main/src/components/knowledge-base/EditKnowledgeItemModal.tsx
Adds Tags UI block using EditableTags; manages local tag state, isUpdatingTags flag, change detection to include tags only when changed, and tag error toasts.
Item Card Integration & API Usage
archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx
Replaces previous tags display with EditableTags; implements async tag updates via service, toasts and error handling, adds isUpdatingTags state, and removes selection-mode props/UI from the component signature.
Service Support
archon-ui-main/src/services/knowledgeBaseService.ts
Adds updateKnowledgeItemTags(sourceId, tags) that delegates to existing update call with logging and error wrapping.
Tests
archon-ui-main/src/components/knowledge-base/tests/EditableTags.test.tsx
New unit tests covering rendering, edit lifecycle, add/remove, validation (length/duplicates/trim), overflow, and that onTagsUpdate receives expected arrays.
Page Removal of Selection Mode
archon-ui-main/src/pages/KnowledgeBasePage.tsx
Removes multi-selection state, handlers, toolbar/shortcuts, selection UI, and updates usage of KnowledgeItemCard to drop selection-related props; GroupCreationModal now receives an empty preselection.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor U as User
  participant KIC as KnowledgeItemCard
  participant ET as EditableTags
  participant S as KnowledgeBaseService
  participant API as Backend API

  U->>ET: Click tag / Add / Edit / Remove
  ET->>KIC: onTagsUpdate(updatedTags)
  KIC->>S: updateKnowledgeItemTags(sourceId, updatedTags)
  S->>API: PATCH /knowledge-items/{id} { tags }
  API-->>S: 200 OK
  S-->>KIC: Resolve
  KIC-->>ET: Success (refresh UI)
  KIC-->>U: Toast: Tags updated

  rect rgba(255,230,230,0.4)
    API-->>S: Error
    S-->>KIC: Reject(error)
    KIC-->>ET: onError(error)
    KIC-->>U: Toast: Update failed
  end
Loading
sequenceDiagram
  autonumber
  actor U as User
  participant EM as EditKnowledgeItemModal
  participant ET as EditableTags
  participant S as KnowledgeBaseService
  participant API as Backend API

  U->>ET: Edit tags in modal
  ET-->>EM: onTagsUpdate(updatedTags)
  EM->>S: updateKnowledgeItem(sourceId, { tags }) only if changed
  S->>API: PATCH { tags }
  API-->>S: 200 OK
  S-->>EM: Resolve
  EM-->>U: Toast / close modal
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Assessment against linked issues

Objective Addressed Explanation
In-line tag editing in list/grid view [#538]
Edit modal supports modifying tags [#538]
Bulk tag editing across multiple items [#538] Bulk selection and multi-item edit flows were removed; no bulk-edit implementation present.
Tag suggestions/autocomplete from existing tags [#538] No autocomplete/suggestion mechanism or existing-tags lookup added.
Validation/normalization (duplicates, trimming, length); backend supports PATCH [#538]

Assessment against linked issues: Out-of-scope changes

Code Change Explanation
Removal of selection-mode props and UI in KnowledgeItemCard (archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx) Selection-mode removal is unrelated to the #538 objectives (tag editing) and removes multi-select APIs/UX.
Removal of selection-state/toolbar/shortcuts in KnowledgeBasePage (archon-ui-main/src/pages/KnowledgeBasePage.tsx) Eliminates multi-selection flows and UI that would be required for bulk tag editing requested in #538.

"I nibble keys and trim each tag,
A purple badge, a gentle drag.
Add, rename, remove — I hop with glee,
My knowledge burrow grows tidy and free.
Tiny paws, big changes — tags for me! 🐇"


📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 95c13ca and c39eac8.

📒 Files selected for processing (1)
  • archon-ui-main/src/components/knowledge-base/EditableTags.tsx (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • archon-ui-main/src/components/knowledge-base/EditableTags.tsx
✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feature/editable-tags-knowledge-base

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@leex279 leex279 marked this pull request as ready for review September 7, 2025 15:47
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (19)
archon-ui-main/src/components/knowledge-base/EditKnowledgeItemModal.tsx (1)

91-106: Confirm UX: onTagsUpdate only updates local state (no API call).

This makes EditableTags show a “saved” state while actual persistence happens on form submit. If intended, fine; otherwise consider calling the service here or toggling a local “dirty” indicator instead of “updating.”

archon-ui-main/src/components/knowledge-base/TagSuggestions.tsx (1)

21-30: Trim/ignore empty custom values and memoize options.

Prevents creating whitespace-only tags and avoids rebuilding options on every render.

-  // Convert string suggestions to ComboBox options
-  const options: ComboBoxOption[] = suggestions.map((tag) => ({
-    value: tag,
-    label: tag,
-    description: undefined,
-  }));
+  // Convert string suggestions to ComboBox options (memoized)
+  const options: ComboBoxOption[] = React.useMemo(
+    () =>
+      (suggestions || [])
+        .filter(Boolean)
+        .map((tag) => ({ value: tag, label: tag })),
+    [suggestions]
+  );
 
-  const handleValueChange = (value: string) => {
-    onSelect(value);
-  };
+  const handleValueChange = (value: string) => {
+    const v = value.trim();
+    if (!v) return;
+    onSelect(v);
+  };
archon-ui-main/src/pages/KnowledgeBasePage.tsx (2)

704-706: Prevent duplicate opens; minor a11y polish.

Disable the button while the modal is open and add an aria-label for screen readers.

-                  <Button onClick={() => setIsBulkEditModalOpen(true)} variant="secondary" size="sm" accentColor="purple">
+                  <Button
+                    onClick={() => setIsBulkEditModalOpen(true)}
+                    variant="secondary"
+                    size="sm"
+                    accentColor="purple"
+                    disabled={isBulkEditModalOpen}
+                    aria-label="Edit tags for selected items"
+                  >
                     Edit Tags
                   </Button>

821-833: Invalidate tag-suggestion cache after bulk updates.

Bulk edits change the global tag corpus; invalidate the tag suggestions query so subsequent suggestions reflect the new state immediately (staleTime is 5 min).

@@
-      {isBulkEditModalOpen && (
+      {isBulkEditModalOpen && (
         <BulkTagEditor
           selectedItems={knowledgeItems.filter(item => selectedItems.has(item.id))}
           onClose={() => setIsBulkEditModalOpen(false)}
           onUpdate={() => {
             setIsBulkEditModalOpen(false);
             setSelectedItems(new Set());
             setIsSelectionMode(false);
             loadKnowledgeItems();
+            // Also refresh tag suggestions (useTagSuggestions)
+            queryClient.invalidateQueries({ queryKey: ["knowledge-base", "tags", "suggestions"] });
           }}
         />
       )}

Add the query client once near the top:

+import { useQueryClient } from '@tanstack/react-query';
@@
 export const KnowledgeBasePage = () => {
+  const queryClient = useQueryClient();
archon-ui-main/src/hooks/useTagSuggestions.ts (5)

21-21: Beware partial coverage at per_page=1000.

If the KB can exceed 1000 items, suggestions will miss tags from later pages. Consider simple pagination (loop until empty) or a backend aggregate/tags endpoint. If pagination exists, I can wire it here.


27-37: Normalize tags case-insensitively to avoid duplicates (e.g., "React" vs "react").

Current logic treats casing as distinct, which conflicts with typical tag normalization expectations.

-        const allTags: string[] = [];
-        const tagFrequency: Record<string, number> = {};
+        const allTags: string[] = [];
+        const tagFrequency: Record<string, number> = {};
@@
-            item.metadata.tags.forEach(tag => {
-              if (typeof tag === 'string' && tag.trim()) {
-                const cleanTag = tag.trim();
-                allTags.push(cleanTag);
-                tagFrequency[cleanTag] = (tagFrequency[cleanTag] || 0) + 1;
-              }
-            });
+            item.metadata.tags.forEach(tag => {
+              if (typeof tag === 'string' && tag.trim()) {
+                const cleanTag = tag.trim().toLowerCase();
+                allTags.push(cleanTag);
+                tagFrequency[cleanTag] = (tagFrequency[cleanTag] || 0) + 1;
+              }
+            });
@@
-        const uniqueTags = Array.from(new Set(allTags));
+        const uniqueTags = Array.from(new Set(allTags));

Also applies to: 40-50


52-56: Silence debug logs in production builds.

Wrap logs with a DEV guard to avoid console noise in prod.

-        console.log(`📋 [TagSuggestions] Found ${sortedTags.length} unique tags from ${response.items.length} items`);
-        console.log(`📋 [TagSuggestions] Top tags:`, sortedTags.slice(0, 10));
+        if (import.meta.env?.DEV) {
+          console.log(`📋 [TagSuggestions] Found ${sortedTags.length} unique tags from ${response.items.length} items`);
+          console.log(`📋 [TagSuggestions] Top tags:`, sortedTags.slice(0, 10));
+        }

69-71: Use exponential backoff for retries.

Matches the project’s guidance on external-call robustness.

-    retry: 2, // Retry failed requests twice
-    retryDelay: 1000, // Wait 1 second between retries
+    retry: 3,
+    retryDelay: (attempt) => Math.min(500 * 2 ** attempt, 10_000),

16-18: Optional: adopt a query-key factory.

For consistency with the repo’s pattern, consider exporting keys like knowledgeBaseKeys.tags.suggestions to avoid stringly-typed keys across the app. I can add a small keys module if you want.

archon-ui-main/src/components/knowledge-base/tests/EditableTags.test.tsx (1)

1-13: Test location convention.

Per project guidance, tests for components under src/components should live under archon-ui-main/test. Consider relocating to keep structure consistent.

archon-ui-main/src/components/knowledge-base/EditableTags.tsx (3)

225-236: Minor: set type on the “Add tags...” button.

Consistent with the other buttons and safe in forms.

-        <button
+        <button
           onClick={() => {
             setIsEditing(true);
             setEditingIndex(null);
           }}
           disabled={isUpdating || isSaving}
+          type="button"
           className="flex items-center gap-1 px-2 py-1 text-xs text-gray-500 dark:text-gray-400 hover:text-purple-600 dark:hover:text-purple-400 transition-colors"
         >

72-78: Treat duplicates case-insensitively.

Prevents “React” and “react” from co-existing. Mirrors the normalization suggested for suggestions.

-    if (localTags.includes(trimmedTag)) {
+    if (localTags.some(t => t.toLowerCase() === trimmedTag.toLowerCase())) {
       return { isValid: false, error: 'Tag already exists' };
     }
-    if (otherTags.includes(trimmedValue)) {
+    if (otherTags.some(t => t.toLowerCase() === trimmedValue.toLowerCase())) {
       setValidationError('Tag already exists');
       return;
     }

Also applies to: 144-146


360-364: Announce validation errors to assistive tech.

Use role="alert" for immediate announcement.

-      {validationError && (
-        <div className="mt-2 text-xs text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded px-2 py-1">
+      {validationError && (
+        <div role="alert" className="mt-2 text-xs text-red-600 dark:text-red-400 bg-red-50 dark:bg-red-900/20 border border-red-200 dark:border-red-800 rounded px-2 py-1">
           {validationError}
         </div>
       )}
archon-ui-main/src/components/knowledge-base/BulkTagEditor.tsx (6)

66-88: No-op short-circuit: skip API call when tags are unchanged.

Avoids unnecessary network calls and speeds up bulk ops with large selections.

Apply this diff:

           switch (operation) {
             case 'add':
               // Add tags that don't already exist
               newTags = [...new Set([...currentTags, ...tagsToProcess])];
               break;
             case 'remove':
               // Remove specified tags
               newTags = currentTags.filter(tag => !tagsToProcess.includes(tag));
               break;
             case 'replace':
               // Replace all tags with new ones
               newTags = [...tagsToProcess];
               break;
           }
 
-          await knowledgeBaseService.updateKnowledgeItemTags(item.source_id, newTags);
+          // No-op: if no change, skip the update
+          if (
+            newTags.length === currentTags.length &&
+            newTags.every((t) => currentTags.includes(t))
+          ) {
+            return {
+              sourceId: item.source_id,
+              title: item.title,
+              success: true,
+            };
+          }
+
+          await knowledgeBaseService.updateKnowledgeItemTags(item.source_id, newTags);

36-37: Surface tag-suggestion load errors to users.

You already capture suggestionsError but don’t display it. Show a small inline error near the input.

Apply this diff:

                       <TagSuggestions
                         suggestions={tagSuggestions || []}
                         onSelect={setSelectedTag}
                         placeholder="Select or type a tag..."
                         isLoading={isLoadingSuggestions}
                         allowCustomValue={true}
                       />
+                      {suggestionsError && (
+                        <div className="mt-1 text-xs text-red-600 dark:text-red-400" role="status" aria-live="polite">
+                          {suggestionsError instanceof Error
+                            ? suggestionsError.message
+                            : 'Failed to load tag suggestions'}
+                        </div>
+                      )}

Also applies to: 187-213


146-152: Add dialog a11y attributes (role/aria) and label.

Improves screen-reader support per WAI-ARIA practices.

Apply this diff:

-      <motion.div
+      <motion.div
         initial={{ scale: 0.9, opacity: 0 }}
         animate={{ scale: 1, opacity: 1 }}
         exit={{ scale: 0.9, opacity: 0 }}
-        className="relative w-full max-w-2xl max-h-[90vh] overflow-hidden"
+        className="relative w-full max-w-2xl max-h-[90vh] overflow-hidden"
+        role="dialog"
+        aria-modal="true"
+        aria-labelledby="bulk-tag-editor-title"
+        aria-busy={isProcessing}
         onClick={(e) => e.stopPropagation()}
       >
@@
-                <h2 className="text-xl font-semibold text-gray-800 dark:text-white">
+                <h2 id="bulk-tag-editor-title" className="text-xl font-semibold text-gray-800 dark:text-white">
                   Bulk Tag Editor
                 </h2>

Also applies to: 161-166


270-273: Stabilize list keys in results.

If sourceId appears more than once (edge cases), keys may collide.

Apply this diff:

-                    {results.map((result) => (
+                    {results.map((result, idx) => (
                       <div
-                        key={result.sourceId}
+                        key={`${result.sourceId}-${idx}`}

236-244: Optional: confirm destructive “Replace All Tags.”

A quick confirm prevents accidental bulk overwrites.

Example:

-                <Button
-                  onClick={handleReplaceTags}
+                <Button
+                  onClick={() => {
+                    if (replaceTags.length === 0 || window.confirm('Replace all tags for selected items?')) {
+                      handleReplaceTags();
+                    }
+                  }}
                   disabled={isProcessing}

88-88: Add retry around knowledgeBaseService.updateKnowledgeItemTags

updateKnowledgeItemTags (via updateKnowledgeItem) applies a 10 s AbortController timeout but has no retry/backoff. Wrap the call in BulkTagEditor (around line 88) using the existing retry helper in src/services/api.ts, or incorporate retries with exponential backoff directly in updateKnowledgeItemTags to improve resilience.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 012d2c5 and a925efd.

📒 Files selected for processing (9)
  • archon-ui-main/src/components/knowledge-base/BulkTagEditor.tsx (1 hunks)
  • archon-ui-main/src/components/knowledge-base/EditKnowledgeItemModal.tsx (5 hunks)
  • archon-ui-main/src/components/knowledge-base/EditableTags.tsx (1 hunks)
  • archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx (4 hunks)
  • archon-ui-main/src/components/knowledge-base/TagSuggestions.tsx (1 hunks)
  • archon-ui-main/src/components/knowledge-base/tests/EditableTags.test.tsx (1 hunks)
  • archon-ui-main/src/hooks/useTagSuggestions.ts (1 hunks)
  • archon-ui-main/src/pages/KnowledgeBasePage.tsx (4 hunks)
  • archon-ui-main/src/services/knowledgeBaseService.ts (1 hunks)
🧰 Additional context used
📓 Path-based instructions (6)
archon-ui-main/src/components/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use ESLint (standard React rules) for legacy UI code in /src/components

Files:

  • archon-ui-main/src/components/knowledge-base/tests/EditableTags.test.tsx
  • archon-ui-main/src/components/knowledge-base/BulkTagEditor.tsx
  • archon-ui-main/src/components/knowledge-base/EditableTags.tsx
  • archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx
  • archon-ui-main/src/components/knowledge-base/EditKnowledgeItemModal.tsx
  • archon-ui-main/src/components/knowledge-base/TagSuggestions.tsx
archon-ui-main/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use state naming conventions: is[Action]ing for loading, [resource]Error for errors, selected[Resource] for selections

archon-ui-main/src/**/*.{ts,tsx}: WebSocket event failures should be logged and not crash serving other clients
External API calls should retry with exponential backoff and ultimately fail with a clear, specific message
Include actionable context in frontend error logs/messages (what was attempted, relevant IDs/URLs)
Never return null to signal failure in async/data flows; throw errors with details
Use polling (HTTP) with provided hooks (usePolling, useDatabaseMutation, useProjectMutation); Socket.IO is removed
State naming: is[Action]ing for loading, [resource]Error for errors, selected[Resource] for selections
Persist theme choice in localStorage and respect Tailwind dark mode classes across components

Files:

  • archon-ui-main/src/components/knowledge-base/tests/EditableTags.test.tsx
  • archon-ui-main/src/hooks/useTagSuggestions.ts
  • archon-ui-main/src/services/knowledgeBaseService.ts
  • archon-ui-main/src/components/knowledge-base/BulkTagEditor.tsx
  • archon-ui-main/src/components/knowledge-base/EditableTags.tsx
  • archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx
  • archon-ui-main/src/pages/KnowledgeBasePage.tsx
  • archon-ui-main/src/components/knowledge-base/EditKnowledgeItemModal.tsx
  • archon-ui-main/src/components/knowledge-base/TagSuggestions.tsx
archon-ui-main/src/**/*.test.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Frontend tests should use Vitest with React Testing Library

Files:

  • archon-ui-main/src/components/knowledge-base/tests/EditableTags.test.tsx
archon-ui-main/src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Legacy components live under src/components and may be used by pages; add related tests under archon-ui-main/test

Files:

  • archon-ui-main/src/components/knowledge-base/tests/EditableTags.test.tsx
  • archon-ui-main/src/components/knowledge-base/BulkTagEditor.tsx
  • archon-ui-main/src/components/knowledge-base/EditableTags.tsx
  • archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx
  • archon-ui-main/src/components/knowledge-base/EditKnowledgeItemModal.tsx
  • archon-ui-main/src/components/knowledge-base/TagSuggestions.tsx
archon-ui-main/src/**/*.{ts,tsx,py}

📄 CodeRabbit inference engine (AGENTS.md)

Avoid comment keywords like LEGACY, CHANGED, REMOVED; write comments that document current functionality only

Files:

  • archon-ui-main/src/components/knowledge-base/tests/EditableTags.test.tsx
  • archon-ui-main/src/hooks/useTagSuggestions.ts
  • archon-ui-main/src/services/knowledgeBaseService.ts
  • archon-ui-main/src/components/knowledge-base/BulkTagEditor.tsx
  • archon-ui-main/src/components/knowledge-base/EditableTags.tsx
  • archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx
  • archon-ui-main/src/pages/KnowledgeBasePage.tsx
  • archon-ui-main/src/components/knowledge-base/EditKnowledgeItemModal.tsx
  • archon-ui-main/src/components/knowledge-base/TagSuggestions.tsx
archon-ui-main/src/services/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

archon-ui-main/src/services/**/*.ts: Frontend service method naming: get[Resource]sByProject(projectId), getResource, create/update/delete[Resource]
Use GET /api/projects/{id}/tasks (not getTasks) for project tasks

Files:

  • archon-ui-main/src/services/knowledgeBaseService.ts
🧠 Learnings (4)
📚 Learning: 2025-09-06T20:05:27.061Z
Learnt from: CR
PR: coleam00/Archon#0
File: AGENTS.md:0-0
Timestamp: 2025-09-06T20:05:27.061Z
Learning: Applies to archon-ui-main/src/components/**/*.{ts,tsx} : Legacy components live under src/components and may be used by pages; add related tests under archon-ui-main/test

Applied to files:

  • archon-ui-main/src/components/knowledge-base/tests/EditableTags.test.tsx
📚 Learning: 2025-09-06T20:04:08.111Z
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T20:04:08.111Z
Learning: Applies to archon-ui-main/src/**/*.test.{ts,tsx} : Frontend tests should use Vitest with React Testing Library

Applied to files:

  • archon-ui-main/src/components/knowledge-base/tests/EditableTags.test.tsx
📚 Learning: 2025-09-06T20:04:08.111Z
Learnt from: CR
PR: coleam00/Archon#0
File: CLAUDE.md:0-0
Timestamp: 2025-09-06T20:04:08.111Z
Learning: Applies to archon-ui-main/src/features/**/{hooks,services}/**/*.{ts,tsx} : Use TanStack Query for all data fetching (no prop drilling), with query key factory pattern and smart polling via useSmartPolling

Applied to files:

  • archon-ui-main/src/hooks/useTagSuggestions.ts
📚 Learning: 2025-09-06T20:05:27.061Z
Learnt from: CR
PR: coleam00/Archon#0
File: AGENTS.md:0-0
Timestamp: 2025-09-06T20:05:27.061Z
Learning: Applies to archon-ui-main/src/features/**/*.{ts,tsx} : Use TanStack Query for all data fetching in /features (no manual fetch chains in components)

Applied to files:

  • archon-ui-main/src/hooks/useTagSuggestions.ts
🧬 Code graph analysis (8)
archon-ui-main/src/components/knowledge-base/tests/EditableTags.test.tsx (1)
archon-ui-main/src/components/knowledge-base/EditableTags.tsx (1)
  • EditableTags (20-367)
archon-ui-main/src/hooks/useTagSuggestions.ts (1)
archon-ui-main/src/services/knowledgeBaseService.ts (1)
  • knowledgeBaseService (353-353)
archon-ui-main/src/components/knowledge-base/BulkTagEditor.tsx (4)
archon-ui-main/src/services/knowledgeBaseService.ts (2)
  • KnowledgeItem (24-33)
  • knowledgeBaseService (353-353)
archon-ui-main/src/hooks/useTagSuggestions.ts (1)
  • useTagSuggestions (15-79)
archon-ui-main/src/components/knowledge-base/TagSuggestions.tsx (1)
  • TagSuggestions (13-44)
archon-ui-main/src/components/knowledge-base/EditableTags.tsx (1)
  • EditableTags (20-367)
archon-ui-main/src/components/knowledge-base/EditableTags.tsx (2)
archon-ui-main/src/features/ui/primitives/styles.ts (1)
  • cn (139-141)
archon-ui-main/src/features/ui/primitives/input.tsx (1)
  • Input (8-29)
archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx (2)
archon-ui-main/src/services/knowledgeBaseService.ts (1)
  • knowledgeBaseService (353-353)
archon-ui-main/src/components/knowledge-base/EditableTags.tsx (1)
  • EditableTags (20-367)
archon-ui-main/src/pages/KnowledgeBasePage.tsx (2)
archon-ui-main/src/features/ui/primitives/button.tsx (1)
  • Button (11-115)
archon-ui-main/src/components/knowledge-base/BulkTagEditor.tsx (1)
  • BulkTagEditor (25-336)
archon-ui-main/src/components/knowledge-base/EditKnowledgeItemModal.tsx (1)
archon-ui-main/src/components/knowledge-base/EditableTags.tsx (1)
  • EditableTags (20-367)
archon-ui-main/src/components/knowledge-base/TagSuggestions.tsx (1)
archon-ui-main/src/features/ui/primitives/combobox.tsx (2)
  • ComboBoxOption (14-18)
  • ComboBox (32-226)
🔇 Additional comments (8)
archon-ui-main/src/components/knowledge-base/EditKnowledgeItemModal.tsx (3)

11-11: Import looks good.


30-33: State naming and init LGTM.

tags default and isUpdatingTags follow the project’s state naming convention.


223-237: Tags UI integration looks correct.

Props wiring matches EditableTags expectations; maxVisibleTags={10} is a sensible modal default.

archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx (3)

10-12: New imports are appropriate.


100-103: State naming follows conventions.


342-348: EditableTags integration LGTM.

Disabling via isUpdatingTags prevents concurrent edits.

archon-ui-main/src/pages/KnowledgeBasePage.tsx (1)

20-20: Bulk editor integration is clean and scoped.

Import and modal-open state look good and follow the existing naming patterns.

Also applies to: 37-37

archon-ui-main/src/components/knowledge-base/BulkTagEditor.tsx (1)

4-4: No action needed: Replace icon is supported
The project uses lucide-react ^0.441.0, and the Replace icon was introduced in v0.135.0—so the existing import and usage are safe.

Comment on lines +47 to +55
const performBulkOperation = async (
operation: 'add' | 'remove' | 'replace',
tagsToProcess: string[]
) => {
if (tagsToProcess.length === 0) return;

setIsProcessing(true);
setResults([]);
setShowResults(true);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix: allow clearing all tags in “replace” mode (blocked by empty-tags guard).

Empty replace should clear tags for all selected items, but the early return prevents it.

Apply this diff:

   const performBulkOperation = async (
     operation: 'add' | 'remove' | 'replace',
     tagsToProcess: string[]
   ) => {
-    if (tagsToProcess.length === 0) return;
+    // Allow empty list for "replace" to clear all tags
+    if (operation !== 'replace' && tagsToProcess.length === 0) return;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const performBulkOperation = async (
operation: 'add' | 'remove' | 'replace',
tagsToProcess: string[]
) => {
if (tagsToProcess.length === 0) return;
setIsProcessing(true);
setResults([]);
setShowResults(true);
const performBulkOperation = async (
operation: 'add' | 'remove' | 'replace',
tagsToProcess: string[]
) => {
// Allow empty list for "replace" to clear all tags
if (operation !== 'replace' && tagsToProcess.length === 0) return;
setIsProcessing(true);
setResults([]);
setShowResults(true);
// …rest of implementation…
🤖 Prompt for AI Agents
In archon-ui-main/src/components/knowledge-base/BulkTagEditor.tsx around lines
47 to 55, the early return when tagsToProcess.length === 0 blocks "replace"
operations that should clear all tags; change the guard so it only returns for
add/remove (e.g. if tagsToProcess.length === 0 && operation !== 'replace'
return;), leaving replace to continue and execute setIsProcessing, setResults,
setShowResults and the rest of the replace logic so an empty replace clears
tags.

Comment on lines +279 to +291
<button
onClick={(e) => {
e.stopPropagation();
if (!isUpdating && !isSaving) {
handleTagRemove(index);
}
}}
disabled={isUpdating || isSaving}
className="absolute right-1 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity"
>
<X className="w-3 h-3 text-gray-400 hover:text-red-500" />
</button>
</Badge>
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add a11y labels and prevent unintended form submits.

Give the remove button an accessible name and set type="button" to avoid accidental form submit behavior.

-                <button
+                <button
                   onClick={(e) => {
                     e.stopPropagation();
                     if (!isUpdating && !isSaving) {
                       handleTagRemove(index);
                     }
                   }}
                   disabled={isUpdating || isSaving}
-                  className="absolute right-1 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity"
+                  type="button"
+                  aria-label={`Remove tag`}
+                  title="Remove tag"
+                  className="absolute right-1 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity"
                 >
                   <X className="w-3 h-3 text-gray-400 hover:text-red-500" />
                 </button>
🤖 Prompt for AI Agents
In archon-ui-main/src/components/knowledge-base/EditableTags.tsx around lines
279 to 291, the tag remove button is missing an accessible name and no type is
specified which can cause accidental form submissions; update the button to
include type="button" and an accessible label (e.g., aria-label or
aria-labelledby, such as aria-label={`Remove tag ${tag}`} or a generic "Remove
tag") so screen readers can announce its purpose, while keeping the existing
onClick, stopPropagation, disabled prop and className intact.

Comment on lines +316 to +326
<button
onClick={() => {
setIsEditing(true);
setEditingIndex(null);
}}
disabled={isUpdating || isSaving}
className="flex items-center justify-center w-6 h-6 rounded border border-dashed border-purple-300 dark:border-purple-500/30 text-purple-600 dark:text-purple-500 hover:bg-purple-50/50 dark:hover:bg-purple-900/20 transition-colors"
>
<Plus className="w-3 h-3" />
</button>
)}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Add a11y label and button type to the “+” add button.

Improves screen-reader usability and avoids default submit behavior.

-          <button
+          <button
             onClick={() => {
               setIsEditing(true);
               setEditingIndex(null);
             }}
             disabled={isUpdating || isSaving}
+            type="button"
+            aria-label="Add tag"
             className="flex items-center justify-center w-6 h-6 rounded border border-dashed border-purple-300 dark:border-purple-500/30 text-purple-600 dark:text-purple-500 hover:bg-purple-50/50 dark:hover:bg-purple-900/20 transition-colors"
           >
             <Plus className="w-3 h-3" />
           </button>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<button
onClick={() => {
setIsEditing(true);
setEditingIndex(null);
}}
disabled={isUpdating || isSaving}
className="flex items-center justify-center w-6 h-6 rounded border border-dashed border-purple-300 dark:border-purple-500/30 text-purple-600 dark:text-purple-500 hover:bg-purple-50/50 dark:hover:bg-purple-900/20 transition-colors"
>
<Plus className="w-3 h-3" />
</button>
)}
<button
onClick={() => {
setIsEditing(true);
setEditingIndex(null);
}}
disabled={isUpdating || isSaving}
type="button"
aria-label="Add tag"
className="flex items-center justify-center w-6 h-6 rounded border border-dashed border-purple-300 dark:border-purple-500/30 text-purple-600 dark:text-purple-500 hover:bg-purple-50/50 dark:hover:bg-purple-900/20 transition-colors"
>
<Plus className="w-3 h-3" />
</button>
🤖 Prompt for AI Agents
In archon-ui-main/src/components/knowledge-base/EditableTags.tsx around lines
316 to 326, the "+" add button is missing an accessible label and an explicit
button type; update the button element to include an appropriate aria-label
(e.g., aria-label="Add tag") to improve screen-reader usability and add
type="button" to prevent default form-submit behavior while keeping the existing
disabled and className props intact.

Comment on lines +69 to 77
// Only include tags if they have changed (using immutable comparison)
const originalTags = item.metadata?.tags || [];
const sortedFormTags = [...formData.tags].sort();
const sortedOriginalTags = [...originalTags].sort();
const tagsChanged = JSON.stringify(sortedFormTags) !== JSON.stringify(sortedOriginalTags);
if (tagsChanged) {
updates.tags = formData.tags;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Compare and persist normalized tags (trim + case-insensitive) to avoid dupes like "React" vs "react".

Aligns with the PR objective on tag normalization. Also persist normalized tags via updates.tags.

-      // Only include tags if they have changed (using immutable comparison)
-      const originalTags = item.metadata?.tags || [];
-      const sortedFormTags = [...formData.tags].sort();
-      const sortedOriginalTags = [...originalTags].sort();
-      const tagsChanged = JSON.stringify(sortedFormTags) !== JSON.stringify(sortedOriginalTags);
-      if (tagsChanged) {
-        updates.tags = formData.tags;
-      }
+      // Only include tags if they have changed (normalized, order-insensitive)
+      const normalizeTags = (ts: string[]) =>
+        Array.from(new Set(ts.map(t => t.trim()).filter(Boolean).map(t => t.toLowerCase())));
+      const originalTags = item.metadata?.tags || [];
+      const normForm = normalizeTags(formData.tags).sort();
+      const normOriginal = normalizeTags(originalTags).sort();
+      const tagsChanged = JSON.stringify(normForm) !== JSON.stringify(normOriginal);
+      if (tagsChanged) {
+        updates.tags = normForm;
+      }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Only include tags if they have changed (using immutable comparison)
const originalTags = item.metadata?.tags || [];
const sortedFormTags = [...formData.tags].sort();
const sortedOriginalTags = [...originalTags].sort();
const tagsChanged = JSON.stringify(sortedFormTags) !== JSON.stringify(sortedOriginalTags);
if (tagsChanged) {
updates.tags = formData.tags;
}
// Only include tags if they have changed (normalized, order-insensitive)
const normalizeTags = (ts: string[]) =>
Array.from(
new Set(
ts
.map(t => t.trim())
.filter(Boolean)
.map(t => t.toLowerCase())
)
);
const originalTags = item.metadata?.tags || [];
const normForm = normalizeTags(formData.tags).sort();
const normOriginal = normalizeTags(originalTags).sort();
const tagsChanged = JSON.stringify(normForm) !== JSON.stringify(normOriginal);
if (tagsChanged) {
updates.tags = normForm;
}
🤖 Prompt for AI Agents
In archon-ui-main/src/components/knowledge-base/EditKnowledgeItemModal.tsx
around lines 69 to 77, the current tag-change check compares raw tags and may
miss duplicates with casing/whitespace differences; normalize both formData.tags
and item.metadata.tags by trimming each tag and converting to lowercase, sort
the normalized arrays and compare their JSON strings, and when tagsChanged is
true set updates.tags to the normalized form (not the raw formData.tags) so
persisted tags are deduplicated and stored normalized.

Comment on lines +173 to +192
const handleTagsUpdate = async (tags: string[]) => {
setIsUpdatingTags(true);
try {
await knowledgeBaseService.updateKnowledgeItem(item.source_id, { tags });
if (onUpdate) {
onUpdate();
}
showToast('Tags updated successfully', 'success');
} catch (error) {
const errorMessage = error instanceof Error
? `Failed to update tags: ${error.message}`
: 'Failed to update tags: Unknown error occurred';

console.error('Tag update error for card:', error);
showToast(errorMessage, 'error');
throw error; // Re-throw to let EditableTags handle the error display
} finally {
setIsUpdatingTags(false);
}
};
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Use the dedicated service method and normalize tags before updating.

Centralizes behavior (logging, error shaping) and avoids case/whitespace dupes.

-  const handleTagsUpdate = async (tags: string[]) => {
+  const handleTagsUpdate = async (tags: string[]) => {
     setIsUpdatingTags(true);
     try {
-      await knowledgeBaseService.updateKnowledgeItem(item.source_id, { tags });
+      const normalized = Array.from(
+        new Set(tags.map(t => t.trim()).filter(Boolean).map(t => t.toLowerCase()))
+      );
+      await knowledgeBaseService.updateKnowledgeItemTags(item.source_id, normalized);
       if (onUpdate) {
         onUpdate();
       }
       showToast('Tags updated successfully', 'success');
     } catch (error) {
       const errorMessage = error instanceof Error 
-        ? `Failed to update tags: ${error.message}` 
-        : 'Failed to update tags: Unknown error occurred';
+        ? `Failed to update tags for ${item.source_id}: ${error.message}` 
+        : `Failed to update tags for ${item.source_id}: Unknown error occurred`;
       
       console.error('Tag update error for card:', error);
       showToast(errorMessage, 'error');
       throw error; // Re-throw to let EditableTags handle the error display
     } finally {
       setIsUpdatingTags(false);
     }
   };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const handleTagsUpdate = async (tags: string[]) => {
setIsUpdatingTags(true);
try {
await knowledgeBaseService.updateKnowledgeItem(item.source_id, { tags });
if (onUpdate) {
onUpdate();
}
showToast('Tags updated successfully', 'success');
} catch (error) {
const errorMessage = error instanceof Error
? `Failed to update tags: ${error.message}`
: 'Failed to update tags: Unknown error occurred';
console.error('Tag update error for card:', error);
showToast(errorMessage, 'error');
throw error; // Re-throw to let EditableTags handle the error display
} finally {
setIsUpdatingTags(false);
}
};
const handleTagsUpdate = async (tags: string[]) => {
setIsUpdatingTags(true);
try {
// Normalize tags: trim, remove empties, dedupe (case-insensitive), lowercase
const normalized = Array.from(
new Set(
tags
.map(t => t.trim())
.filter(Boolean)
.map(t => t.toLowerCase())
)
);
// Use the dedicated tags-only update method
await knowledgeBaseService.updateKnowledgeItemTags(item.source_id, normalized);
if (onUpdate) {
onUpdate();
}
showToast('Tags updated successfully', 'success');
} catch (error) {
const errorMessage = error instanceof Error
? `Failed to update tags for ${item.source_id}: ${error.message}`
: `Failed to update tags for ${item.source_id}: Unknown error occurred`;
console.error('Tag update error for card:', error);
showToast(errorMessage, 'error');
throw error; // Re-throw so EditableTags can display its own error state
} finally {
setIsUpdatingTags(false);
}
};
🤖 Prompt for AI Agents
In archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx around
lines 173 to 192, replace the current inline update logic with the dedicated
service method for updating tags (e.g.,
knowledgeBaseService.updateKnowledgeItemTags or the repo's equivalent) and
normalize the tags array before sending: trim whitespace, lower-case (or
canonicalize case per project convention), remove duplicates, and filter out
empty strings; call the dedicated service method with item.source_id and the
normalized tags, let the service handle central logging/error shaping, and keep
the UI callbacks (onUpdate, showToast) and local state toggles
(setIsUpdatingTags) but do not re-throw raw errors from here—surface user-facing
errors via showToast and allow the service to manage structured errors/logging.

Comment on lines +36 to +38
const addButton = screen.getByRole('button');
expect(addButton).toBeInTheDocument();
});
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Stabilize queries with accessible names (pairs with component a11y fix).

The remove/add buttons currently lack accessible names in the component, so these selectors are brittle. After adding aria-labels, target by role+name for reliability.

-    const addButton = screen.getByRole('button');
+    const addButton = screen.getByRole('button', { name: /add tag/i });
@@
-      const removeButton = screen.getByRole('button', { name: /remove/i });
+      const removeButton = screen.getByRole('button', { name: /remove tag/i });
@@
-    const addButton = screen.getByRole('button');
+    const addButton = screen.getByRole('button', { name: /add tag/i });
@@
-    const addButton = screen.getByRole('button');
+    const addButton = screen.getByRole('button', { name: /add tag/i });

Optionally scope the "remove tag" lookup to the tag’s badge to avoid collisions:

+import { within } from '../../../features/testing/test-utils';
@@
-    const reactTag = screen.getByText('react');
-    fireEvent.mouseEnter(reactTag.closest('.group')!);
-    await waitFor(() => {
-      const removeButton = screen.getByRole('button', { name: /remove tag/i });
-      fireEvent.click(removeButton);
-    });
+    const reactTag = screen.getByText('react');
+    const badge = reactTag.closest('.group') as HTMLElement;
+    fireEvent.mouseEnter(badge);
+    const removeButton = within(badge).getByRole('button', { name: /remove tag/i });
+    fireEvent.click(removeButton);

Also applies to: 124-138, 143-154, 224-239

🤖 Prompt for AI Agents
In archon-ui-main/src/components/knowledge-base/tests/EditableTags.test.tsx
around lines 36-38 (and also update the checks at 124-138, 143-154, 224-239),
the tests use role-only button queries which are brittle; after adding
aria-labels to the component, change the queries to role+accessible name (e.g.,
getByRole('button', { name: /add tag/i }) for the add button) and for remove
buttons scope the lookup to the specific tag badge using
within(badge).getByRole('button', { name: /remove tag/i }) to avoid collisions
and stabilize the tests.

Comment on lines +197 to +217
/**
* Update tags for a knowledge item (optimized method for tag updates)
*/
async updateKnowledgeItemTags(sourceId: string, tags: string[]): Promise<void> {
try {
console.log(`🏷️ [KnowledgeBase] Updating tags for ${sourceId}:`, tags);

await this.updateKnowledgeItem(sourceId, { tags });

console.log(`✅ [KnowledgeBase] Tags updated successfully for ${sourceId}`);
} catch (error) {
console.error(`❌ [KnowledgeBase] Failed to update tags for ${sourceId}:`, error);

// Provide more descriptive error message
const errorMessage = error instanceof Error
? `Failed to update tags: ${error.message}`
: 'Failed to update tags due to an unknown error';

throw new Error(errorMessage);
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Normalize/dedupe tags before sending; include context in thrown errors.

Prevent case/whitespace dupes and surface actionable error details (guideline: include IDs/URLs). Also preserve the original error via cause.

   async updateKnowledgeItemTags(sourceId: string, tags: string[]): Promise<void> {
     try {
-      console.log(`🏷️ [KnowledgeBase] Updating tags for ${sourceId}:`, tags);
-      
-      await this.updateKnowledgeItem(sourceId, { tags });
+      // Normalize and dedupe (case-insensitive)
+      const normalized = Array.from(
+        new Set(tags.map(t => t.trim()).filter(Boolean).map(t => t.toLowerCase()))
+      );
+      console.log(`🏷️ [KnowledgeBase] Updating tags for ${sourceId}:`, normalized);
+
+      await this.updateKnowledgeItem(sourceId, { tags: normalized });
       
       console.log(`✅ [KnowledgeBase] Tags updated successfully for ${sourceId}`);
     } catch (error) {
       console.error(`❌ [KnowledgeBase] Failed to update tags for ${sourceId}:`, error);
       
       // Provide more descriptive error message
-      const errorMessage = error instanceof Error 
-        ? `Failed to update tags: ${error.message}`
-        : 'Failed to update tags due to an unknown error';
-      
-      throw new Error(errorMessage);
+      const errorMessage = error instanceof Error 
+        ? `Failed to update tags for ${sourceId}: ${error.message}`
+        : `Failed to update tags for ${sourceId}: Unknown error`;
+      const e = new Error(errorMessage) as any;
+      (e as any).cause = error;
+      throw e;
     }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Update tags for a knowledge item (optimized method for tag updates)
*/
async updateKnowledgeItemTags(sourceId: string, tags: string[]): Promise<void> {
try {
console.log(`🏷️ [KnowledgeBase] Updating tags for ${sourceId}:`, tags);
await this.updateKnowledgeItem(sourceId, { tags });
console.log(`✅ [KnowledgeBase] Tags updated successfully for ${sourceId}`);
} catch (error) {
console.error(`❌ [KnowledgeBase] Failed to update tags for ${sourceId}:`, error);
// Provide more descriptive error message
const errorMessage = error instanceof Error
? `Failed to update tags: ${error.message}`
: 'Failed to update tags due to an unknown error';
throw new Error(errorMessage);
}
}
/**
* Update tags for a knowledge item (optimized method for tag updates)
*/
async updateKnowledgeItemTags(sourceId: string, tags: string[]): Promise<void> {
try {
// Normalize and dedupe (case-insensitive)
const normalized = Array.from(
new Set(
tags
.map(t => t.trim())
.filter(Boolean)
.map(t => t.toLowerCase())
)
);
console.log(`🏷️ [KnowledgeBase] Updating tags for ${sourceId}:`, normalized);
await this.updateKnowledgeItem(sourceId, { tags: normalized });
console.log(`✅ [KnowledgeBase] Tags updated successfully for ${sourceId}`);
} catch (error) {
console.error(`❌ [KnowledgeBase] Failed to update tags for ${sourceId}:`, error);
// Provide more descriptive error message and preserve original cause
const errorMessage = error instanceof Error
? `Failed to update tags for ${sourceId}: ${error.message}`
: `Failed to update tags for ${sourceId}: Unknown error`;
const e = new Error(errorMessage) as any;
e.cause = error;
throw e;
}
}
🤖 Prompt for AI Agents
In archon-ui-main/src/services/knowledgeBaseService.ts around lines 197 to 217,
normalize and deduplicate the tags before calling updateKnowledgeItem (e.g.,
trim whitespace and convert to lower-case, then remove duplicates) and pass the
cleaned array to updateKnowledgeItem; in the catch block, include context (at
minimum the sourceId and, if available, the knowledge item URL or path) in the
thrown error message and preserve the original error by using the Error cause
option (throw new Error(<message>, { cause: error })) so callers can inspect the
underlying failure.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx (1)

134-135: Replace BoxIcon with Box (lucide-react).

lucide-react exports Box, not BoxIcon.

-  const TypeIcon = item.metadata.knowledge_type === 'technical' ? BoxIcon : Brain;
+  const TypeIcon = item.metadata.knowledge_type === 'technical' ? Box : Brain;

Also update the import accordingly at the top of the file:

-import { Link as LinkIcon, Upload, Trash2, RefreshCw, Code, FileText, Brain, BoxIcon, Pencil } from 'lucide-react';
+import { Link as LinkIcon, Upload, Trash2, RefreshCw, Code, FileText, Brain, Box, Pencil } from 'lucide-react';
♻️ Duplicate comments (1)
archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx (1)

166-185: Use dedicated service method and normalize tags before update.

Centralizes behavior and prevents case/whitespace dupes; include source_id in errors.

   const handleTagsUpdate = async (tags: string[]) => {
     setIsUpdatingTags(true);
     try {
-      await knowledgeBaseService.updateKnowledgeItem(item.source_id, { tags });
+      const normalized = Array.from(
+        new Set(tags.map(t => t.trim()).filter(Boolean).map(t => t.toLowerCase()))
+      );
+      await knowledgeBaseService.updateKnowledgeItemTags(item.source_id, normalized);
       if (onUpdate) {
         onUpdate();
       }
       showToast('Tags updated successfully', 'success');
     } catch (error) {
-      const errorMessage = error instanceof Error 
-        ? `Failed to update tags: ${error.message}` 
-        : 'Failed to update tags: Unknown error occurred';
+      const errorMessage = error instanceof Error 
+        ? `Failed to update tags for ${item.source_id}: ${error.message}` 
+        : `Failed to update tags for ${item.source_id}: Unknown error occurred`;
       
       console.error('Tag update error for card:', error);
       showToast(errorMessage, 'error');
       throw error; // Re-throw to let EditableTags handle the error display
     } finally {
       setIsUpdatingTags(false);
     }
   };
🧹 Nitpick comments (5)
PRPs/story_editable_tags_knowledge_base.md (3)

10-38: Add language identifiers to fenced code blocks (markdownlint MD040).

Mark the story block as markdown.

-```
+```md
 Feature Request: Edit tags after adding items to knowledge base
 ...
-```
+```

71-71: Remove trailing colons from headings (markdownlint MD026).

-### CREATE archon-ui-main/src/components/knowledge-base/EditableTags.tsx:
+### CREATE archon-ui-main/src/components/knowledge-base/EditableTags.tsx
-### CREATE archon-ui-main/src/components/knowledge-base/TagSuggestions.tsx:
+### CREATE archon-ui-main/src/components/knowledge-base/TagSuggestions.tsx
-### UPDATE archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx:
+### UPDATE archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx
-### UPDATE archon-ui-main/src/services/knowledgeBaseService.ts:
+### UPDATE archon-ui-main/src/services/knowledgeBaseService.ts
-### CREATE archon-ui-main/src/hooks/useTagSuggestions.ts:
+### CREATE archon-ui-main/src/hooks/useTagSuggestions.ts
-### ADD archon-ui-main/src/components/knowledge-base/BulkTagEditor.tsx:
+### ADD archon-ui-main/src/components/knowledge-base/BulkTagEditor.tsx
-### UPDATE archon-ui-main/src/components/knowledge-base/KnowledgeBasePage.tsx:
+### UPDATE archon-ui-main/src/components/knowledge-base/KnowledgeBasePage.tsx
-### ADD tests/components/EditableTags.test.tsx:
+### ADD tests/components/EditableTags.test.tsx

Also applies to: 83-83, 93-93, 104-104, 113-113, 124-124, 135-135, 145-145


212-216: Confirm request payload shape for PUT /api/knowledge-items/{source_id}.

Doc states tags live in metadata.tags. The example posts a top-level "tags". Align the sample with the API, or clarify the service maps it.

Proposed safer example:

-curl -X PUT http://localhost:8181/api/knowledge-items/{test_source_id} \
-  -H "Content-Type: application/json" \
-  -d '{"tags": ["test", "api", "update"]}' \
+curl -X PUT http://localhost:8181/api/knowledge-items/{test_source_id} \
+  -H "Content-Type: application/json" \
+  -d '{"metadata": {"tags": ["test", "api", "update"]}}' \
   | jq .

If the backend does accept top-level tags, add a note explicitly stating the accepted shapes.

code-review2.md (1)

92-95: Add Content-Type header to cURL example.

Without it, servers may not parse JSON.

-curl -X PUT http://localhost:8181/api/knowledge-items/d2291c3e9d498292 \
-  -d '{"tags": ["fixed","error-handling","validation","complete"]}'
+curl -X PUT http://localhost:8181/api/knowledge-items/d2291c3e9d498292 \
+  -H "Content-Type: application/json" \
+  -d '{"tags": ["fixed","error-handling","validation","complete"]}'
archon-ui-main/src/pages/KnowledgeBasePage.tsx (1)

650-656: GroupCreationModal receives an empty selection; confirm intended UX.

Passing selectedItems={[]} disables preselection. If bulk flows were intentionally removed, drop the prop. If not, reintroduce selection state.

Example (remove prop if optional):

-        <GroupCreationModal
-          selectedItems={[]}
+        <GroupCreationModal
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a925efd and e9fda77.

📒 Files selected for processing (5)
  • PRPs/story_editable_tags_knowledge_base.md (1 hunks)
  • archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx (7 hunks)
  • archon-ui-main/src/pages/KnowledgeBasePage.tsx (4 hunks)
  • code-review1.md (1 hunks)
  • code-review2.md (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • code-review1.md
🧰 Additional context used
📓 Path-based instructions (4)
archon-ui-main/src/components/**/*.{ts,tsx,js,jsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use ESLint (standard React rules) for legacy UI code in /src/components

Files:

  • archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx
archon-ui-main/src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (CLAUDE.md)

Use state naming conventions: is[Action]ing for loading, [resource]Error for errors, selected[Resource] for selections

archon-ui-main/src/**/*.{ts,tsx}: WebSocket event failures should be logged and not crash serving other clients
External API calls should retry with exponential backoff and ultimately fail with a clear, specific message
Include actionable context in frontend error logs/messages (what was attempted, relevant IDs/URLs)
Never return null to signal failure in async/data flows; throw errors with details
Use polling (HTTP) with provided hooks (usePolling, useDatabaseMutation, useProjectMutation); Socket.IO is removed
State naming: is[Action]ing for loading, [resource]Error for errors, selected[Resource] for selections
Persist theme choice in localStorage and respect Tailwind dark mode classes across components

Files:

  • archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx
  • archon-ui-main/src/pages/KnowledgeBasePage.tsx
archon-ui-main/src/components/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Legacy components live under src/components and may be used by pages; add related tests under archon-ui-main/test

Files:

  • archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx
archon-ui-main/src/**/*.{ts,tsx,py}

📄 CodeRabbit inference engine (AGENTS.md)

Avoid comment keywords like LEGACY, CHANGED, REMOVED; write comments that document current functionality only

Files:

  • archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx
  • archon-ui-main/src/pages/KnowledgeBasePage.tsx
🧬 Code graph analysis (1)
archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx (1)
archon-ui-main/src/components/knowledge-base/EditableTags.tsx (1)
  • EditableTags (20-367)
🪛 markdownlint-cli2 (0.17.2)
PRPs/story_editable_tags_knowledge_base.md

10-10: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


71-71: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


83-83: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


93-93: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


104-104: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


113-113: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


124-124: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


135-135: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)


145-145: Trailing punctuation in heading
Punctuation: ':'

(MD026, no-trailing-punctuation)

🔇 Additional comments (5)
code-review2.md (1)

15-17: Inconsistent with actual diff: KnowledgeBasePage does not add bulk tag editing.

Current PR page removes selection and does not integrate BulkTagEditor. Update this section or implement the feature before claiming it’s added.

archon-ui-main/src/pages/KnowledgeBasePage.tsx (1)

613-623: LGTM on ungrouped items render change.

Index param removed; keys now rely on item.id. Looks fine.

archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx (3)

9-11: Good integration: EditableTags + toasts.

Imports and context wiring look correct.


139-143: Tilt config change acknowledged.

Reasonable defaults; no concerns.


315-321: LGTM on EditableTags usage.

Props match the component contract; error propagation via onError is wired.

Comment on lines +1 to +2
import { useEffect, useState, useMemo } from 'react';
import { Search, Grid, Plus, Filter, BoxIcon, List, BookOpen, Brain } from 'lucide-react';
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Fix lucide icon import: BoxIcon is not exported; use Box.

This will otherwise cause a compile-time error.

-import { Search, Grid, Plus, Filter, BoxIcon, List, BookOpen, Brain } from 'lucide-react';
+import { Search, Grid, Plus, Filter, Box, List, BookOpen, Brain } from 'lucide-react';

And update usage:

-  <BoxIcon className="w-4 h-4" />
+  <Box className="w-4 h-4" />
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
import { useEffect, useState, useMemo } from 'react';
import { Search, Grid, Plus, Filter, BoxIcon, List, BookOpen, Brain } from 'lucide-react';
// archon-ui-main/src/pages/KnowledgeBasePage.tsx
import { useEffect, useState, useMemo } from 'react';
import { Search, Grid, Plus, Filter, Box, List, BookOpen, Brain } from 'lucide-react';
// …later in your JSX…
<Box className="w-4 h-4" />
🤖 Prompt for AI Agents
In archon-ui-main/src/pages/KnowledgeBasePage.tsx around lines 1-2, the import
uses BoxIcon from lucide-react which isn't exported; replace BoxIcon with Box in
the import statement and update all usages of <BoxIcon ...> to <Box ...>
(preserve props and attributes) so the correct lucide icon is imported and
referenced.

Comment on lines +52 to +58
- `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsx` - Inline editing pattern to mirror for tag editing functionality
- `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx` - Current TagsDisplay component to enhance with editing capabilities
- `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/features/ui/primitives/combobox.tsx` - Autocomplete component for tag suggestions
- `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/components/knowledge-base/AddKnowledgeModal.tsx` - Existing tag input pattern to reuse
- `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/python/src/server/api_routes/knowledge_api.py` - Existing PUT endpoint that already supports tag updates
- `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/services/knowledgeBaseService.ts` - API service layer with updateKnowledgeItem method

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Replace absolute local file paths with repo-relative paths (avoid PII, improve portability).

The Windows user paths leak local environment info and will break for other devs/CI. Use repo-relative paths.

Apply:

- - `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsx` - Inline editing pattern to mirror for tag editing functionality
- - `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx` - Current TagsDisplay component to enhance with editing capabilities
- - `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/features/ui/primitives/combobox.tsx` - Autocomplete component for tag suggestions
- - `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/components/knowledge-base/AddKnowledgeModal.tsx` - Existing tag input pattern to reuse
- - `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/python/src/server/api_routes/knowledge_api.py` - Existing PUT endpoint that already supports tag updates
- - `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/services/knowledgeBaseService.ts` - API service layer with updateKnowledgeItem method
+ - `archon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsx` - Inline editing pattern to mirror
+ - `archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx` - Enhance with editing capabilities
+ - `archon-ui-main/src/features/ui/primitives/combobox.tsx` - Autocomplete component
+ - `archon-ui-main/src/components/knowledge-base/AddKnowledgeModal.tsx` - Existing tag input pattern
+ - `python/src/server/api_routes/knowledge_api.py` - Existing PUT endpoint supports tag updates
+ - `archon-ui-main/src/services/knowledgeBaseService.ts` - API service layer with updateKnowledgeItem method
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsx` - Inline editing pattern to mirror for tag editing functionality
- `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx` - Current TagsDisplay component to enhance with editing capabilities
- `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/features/ui/primitives/combobox.tsx` - Autocomplete component for tag suggestions
- `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/components/knowledge-base/AddKnowledgeModal.tsx` - Existing tag input pattern to reuse
- `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/python/src/server/api_routes/knowledge_api.py` - Existing PUT endpoint that already supports tag updates
- `/mnt/c/Users/Leex279/Documents/GitHub/YouTube/tmp/Archon/archon-ui-main/src/services/knowledgeBaseService.ts` - API service layer with updateKnowledgeItem method
- `archon-ui-main/src/features/projects/tasks/components/EditableTableCell.tsx` Inline editing pattern to mirror
- `archon-ui-main/src/components/knowledge-base/KnowledgeItemCard.tsx` – Enhance with editing capabilities
- `archon-ui-main/src/features/ui/primitives/combobox.tsx` – Autocomplete component
- `archon-ui-main/src/components/knowledge-base/AddKnowledgeModal.tsx` Existing tag input pattern
- `python/src/server/api_routes/knowledge_api.py` Existing PUT endpoint supports tag updates
- `archon-ui-main/src/services/knowledgeBaseService.ts` API service layer with updateKnowledgeItem method
🤖 Prompt for AI Agents
In PRPs/story_editable_tags_knowledge_base.md around lines 52 to 58, the diff
lists absolute Windows-local paths exposing a user’s filesystem and breaking
portability; update each listed path to repo-relative paths (remove the leading
/mnt/c/Users/<username>/Documents/GitHub/YouTube/tmp/Archon/ and any
machine-specific prefixes) so they start from the repository root (e.g.,
src/features/projects/tasks/components/EditableTableCell.tsx,
src/components/knowledge-base/KnowledgeItemCard.tsx,
src/features/ui/primitives/combobox.tsx,
src/components/knowledge-base/AddKnowledgeModal.tsx,
python/src/server/api_routes/knowledge_api.py,
src/services/knowledgeBaseService.ts), and ensure no usernames or absolute
prefixes remain.

Based on user feedback, simplified the implementation to focus on core
inline tag editing functionality by removing:

- BulkTagEditor component and bulk selection UI
- TagSuggestions component and autocomplete functionality
- useTagSuggestions hook and related caching
- Selection mode and bulk operations
- PRP files from repository (development artifacts)

Fixed tooltip z-index issue where "+N more..." tooltip appeared behind
other UI elements like the Recrawl button.

Kept essential features:
- ✅ Inline tag editing (click to edit, Enter/Escape shortcuts)
- ✅ Add/remove tags with "+" and "×" buttons
- ✅ Tag editing in EditKnowledgeItemModal
- ✅ Input validation and error handling
- ✅ Toast notifications for success/error states
- ✅ Proper tooltip layering (z-index: 100)

This maintains the core user experience while significantly reducing
complexity and removing features that weren't needed.

Resolves #538

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@leex279 leex279 force-pushed the feature/editable-tags-knowledge-base branch from e9fda77 to 95c13ca Compare September 7, 2025 17:36
Fixed the '+N more...' tooltip appearing behind other UI elements
by using React Portal to render the tooltip at document.body level.

- Uses createPortal to render tooltip outside stacking context
- Calculates absolute position based on badge location
- Uses z-index 10001 to ensure it's above all other elements
- Maintains purple border styling for consistency

The tooltip now properly appears above all UI elements including
buttons, cards, and other components.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
@leex279 leex279 self-assigned this Sep 7, 2025
@Wirasm
Copy link
Copy Markdown
Collaborator

Wirasm commented Sep 12, 2025

@leex279 Should we close this or do you want to reimplement this with the new components?

@leex279
Copy link
Copy Markdown
Collaborator Author

leex279 commented Sep 12, 2025

@Wirasm i will update it. I would also like the "tags" back instead of putting in comma seperated lists.

@leex279 leex279 closed this Sep 14, 2025
@Wirasm Wirasm deleted the feature/editable-tags-knowledge-base branch April 6, 2026 07:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Feature Request: Edit tags after adding items to knowledge base

2 participants