Skip to content

Move pure utility functions out of UI components to reduce cross-feature coupling #1194

@MODSetter

Description

@MODSetter

Description

Several pure utility functions and constants are defined inside UI component files but imported by unrelated feature modules. This creates tight coupling between feature boundaries — refactoring one component file can break completely unrelated features.

Three confirmed instances:

1. convertRenderedToDisplay in comment-item.tsx

Defined at line 72 of surfsense_web/components/chat-comments/comment-item/comment-item.tsx:

export function convertRenderedToDisplay(contentRendered: string): string {
    return contentRendered.replace(/@\{([^}]+)\}/g, "@$1");
}

Imported by surfsense_web/components/layout/ui/sidebar/InboxSidebar.tsx (line 25) — layout feature depends on chat-comments internal.

2. getDocumentTypeLabel in DocumentTypeIcon.tsx

Defined at line 12 of surfsense_web/components/documents/DocumentTypeIcon.tsx.
Imported by InboxSidebar.tsx (line 26), DocumentsFilters.tsx (line 14), and active-connectors-tab.tsx (line 5) — three different features importing a pure function from a UI icon component.

3. SLIDEOUT_PANEL_OPENED_EVENT in SidebarSlideOutPanel.tsx

Defined at line 7 of surfsense_web/components/layout/ui/sidebar/SidebarSlideOutPanel.tsx:

export const SLIDEOUT_PANEL_OPENED_EVENT = "slideout-panel-opened";

Imported by surfsense_web/components/assistant-ui/thread.tsx (line 64) — chat thread depends on layout component internals.

What to do

  1. Move convertRenderedToDisplay to surfsense_web/lib/comments/utils.ts (or similar shared path)
  2. Move getDocumentTypeLabel to surfsense_web/lib/documents/document-type-labels.ts
  3. Move SLIDEOUT_PANEL_OPENED_EVENT to surfsense_web/lib/layout-events.ts (or contracts/events.ts)
  4. Update all imports in the original files and consumers
  5. Keep the original component files importing from the new shared location

Each move is a pure refactor — the functions/constants themselves do not change, only their file location.

Acceptance criteria

  • Each utility is defined in exactly one shared module, not inside a UI component
  • All existing imports are updated
  • next build succeeds
  • No runtime behavior changes

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions