← back to centy-io__centy-app

Function bodies 471 total

All specs Real LLM only Function bodies
useIssueDetailPage function · typescript · L14-L87 (74 LOC)
components/issues/IssueDetail/hooks/useIssueDetailPage.ts
export function useIssueDetailPage(issueNumber: string) {
  const { projectPath, isLoading: pathLoading } = usePathContext()
  useDaemonStatus()
  const { copyToClipboard } = useCopyToClipboard()
  const stateManager = useStateManager()
  const stateOptions = stateManager.getStateOptions()

  const detail = useIssueDetail(projectPath, issueNumber)
  const editState = useEditState(detail.issue)
  const nav = useIssueNavigation(projectPath)
  const actions = useIssueActions({
    projectPath,
    issueNumber,
    issuesListUrl: nav.issuesListUrl,
    setIssue: detail.setIssue,
    setError: detail.setError,
  })

  const [showMoveModal, setShowMoveModal] = useState(false)
  const [showDuplicateModal, setShowDuplicateModal] = useState(false)
  const [showStatusConfigDialog, setShowStatusConfigDialog] = useState(false)

  const editor = useEditorActions(
    projectPath,
    detail.issue,
    detail.setError,
    setShowStatusConfigDialog
  )
  const statusChange = useStatusChange(
    pro
useIssueDetail function · typescript · L13-L86 (74 LOC)
components/issues/IssueDetail/hooks/useIssueDetail.ts
export function useIssueDetail(projectPath: string, issueNumber: string) {
  const { recordLastSeen } = useLastSeenIssues()
  const [issue, setIssue] = useState<Issue | null>(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState<string | null>(null)
  const [assets, setAssets] = useState<Asset[]>([])

  const fetchIssue = useCallback(async () => {
    if (!projectPath || !issueNumber) {
      setError('Missing project path or issue number')
      setLoading(false)
      return
    }
    setLoading(true)
    setError(null)

    try {
      const request = create(GetItemRequestSchema, {
        projectPath,
        itemType: 'issues',
        itemId: issueNumber,
      })
      const response = await centyClient.getItem(request)
      if (response.item) {
        setIssue(genericItemToIssue(response.item))
      } else {
        setError(response.error || 'Issue not found')
      }
    } catch (err) {
      setError(
        err instanceof Error ? err.
useIssueNavigation function · typescript · L6-L60 (55 LOC)
components/issues/IssueDetail/hooks/useIssueNavigation.ts
export function useIssueNavigation(projectPath: string) {
  const router = useRouter()
  const resolvePathToUrl = useProjectPathToUrl()
  const { createLink, createProjectLink } = useAppLink()
  const issuesListUrl = createLink('/issues')

  const handleMoved = useCallback(
    async (targetProjectPath: string) => {
      const result = await resolvePathToUrl(targetProjectPath)
      if (result) {
        router.push(
          createProjectLink(result.orgSlug, result.projectName, 'issues')
        )
      } else {
        router.push(issuesListUrl)
      }
    },
    [resolvePathToUrl, createProjectLink, router, issuesListUrl]
  )

  const handleDuplicated = useCallback(
    async (newIssueId: string, targetProjectPath: string) => {
      if (targetProjectPath === projectPath) {
        router.push(createLink(`/issues/${newIssueId}`))
      } else {
        const result = await resolvePathToUrl(targetProjectPath)
        if (result) {
          router.push(
            createProjectLi
useStatusChange function · typescript · L8-L85 (78 LOC)
components/issues/IssueDetail/hooks/useStatusChange.ts
export function useStatusChange(
  projectPath: string,
  issueNumber: string,
  issue: Issue | null,
  setIssue: (issue: Issue) => void,
  setError: (error: string | null) => void,
  setEditStatus: (status: string) => void
) {
  const [showStatusDropdown, setShowStatusDropdown] = useState(false)
  const [updatingStatus, setUpdatingStatus] = useState(false)
  const statusDropdownRef = useRef<HTMLDivElement>(null)

  useEffect(() => {
    const handleClickOutside = (event: MouseEvent) => {
      if (
        statusDropdownRef.current &&
        !(
          event.target instanceof Node &&
          statusDropdownRef.current.contains(event.target)
        )
      ) {
        setShowStatusDropdown(false)
      }
    }

    if (showStatusDropdown) {
      document.addEventListener('mousedown', handleClickOutside)
    }
    return () => {
      document.removeEventListener('mousedown', handleClickOutside)
    }
  }, [showStatusDropdown])

  const handleStatusChange = useCallback(
    async 
IssueDetailBody function · typescript · L10-L83 (74 LOC)
components/issues/IssueDetail/IssueDetailBody.tsx
export function IssueDetailBody({
  issue,
  projectPath,
  issueNumber,
  editState,
  stateManager,
  stateOptions,
  statusChange,
  assets,
  setAssets,
  copyToClipboard,
}: IssueDetailBodyProps): ReactElement {
  return (
    <div className="issue-content">
      <button
        type="button"
        className="issue-number-badge"
        onClick={() =>
          copyToClipboard(issueNumber, `issue #${issue.displayNumber}`)
        }
        title="Click to copy UUID"
      >
        #{issue.displayNumber}
      </button>

      {editState.isEditing ? (
        <EditForm
          projectPath={projectPath}
          issueNumber={issueNumber}
          editTitle={editState.editTitle}
          setEditTitle={editState.setEditTitle}
          editDescription={editState.editDescription}
          setEditDescription={editState.setEditDescription}
          editStatus={editState.editStatus}
          setEditStatus={editState.setEditStatus}
          editPriority={editState.editPriority
IssueDetailContent function · typescript · L57-L99 (43 LOC)
components/issues/IssueDetail/IssueDetailContent.tsx
export function IssueDetailContent(
  props: IssueDetailContentProps
): ReactElement {
  const { editState, error, showDeleteConfirm } = props
  return (
    <div className="issue-detail">
      <Header
        issuesListUrl={props.issuesListUrl}
        isEditing={editState.isEditing}
        saving={props.saving}
        openingInVscode={props.openingInVscode}
        onEdit={() => editState.setIsEditing(true)}
        onCancelEdit={editState.handleCancelEdit}
        onSave={props.onSave}
        onMove={props.onMove}
        onDuplicate={props.onDuplicate}
        onDelete={() => props.onShowDeleteConfirm(true)}
        onOpenInVscode={props.onOpenInVscode}
        onOpenInTerminal={props.onOpenInTerminal}
      />
      {error && <DaemonErrorMessage error={error} />}
      {showDeleteConfirm && (
        <DeleteConfirmation
          deleting={props.deleting}
          onCancel={() => props.onShowDeleteConfirm(false)}
          onConfirm={props.onDelete}
        />
      )}
      
renderLoadingState function · typescript · L22-L65 (44 LOC)
components/issues/IssueDetail/IssueDetailLoading.tsx
export function renderLoadingState({
  projectPath,
  pathLoading,
  loading,
  error,
  issue,
  issuesListUrl,
}: LoadingCheckProps): ReactElement | null {
  if (!projectPath) {
    return (
      <div className="issue-detail">
        <DaemonErrorMessage error="No project path specified. Please go to the issues list and select a project." />
      </div>
    )
  }
  if (pathLoading || loading) {
    return (
      <div className="issue-detail">
        <div className="loading">Loading issue...</div>
      </div>
    )
  }
  if (error && !issue) {
    return (
      <div className="issue-detail">
        <DaemonErrorMessage error={error} />
        <Link href={issuesListUrl} className="back-link">
          Back to Issues
        </Link>
      </div>
    )
  }
  if (!issue) {
    return (
      <div className="issue-detail">
        <div className="error-message">Issue not found</div>
        <Link href={issuesListUrl} className="back-link">
          Back to Issues
        </Link>
 
Source: Repobility analyzer · https://repobility.com
IssueDetail function · typescript · L10-L68 (59 LOC)
components/issues/IssueDetail/IssueDetail.tsx
export function IssueDetail({ issueNumber }: IssueDetailProps): ReactElement {
  const state = useIssueDetailPage(issueNumber)

  const loadingView = renderLoadingState({
    projectPath: state.projectPath,
    pathLoading: state.pathLoading,
    loading: state.detail.loading,
    error: state.detail.error,
    issue: state.detail.issue,
    issuesListUrl: state.nav.issuesListUrl,
  })

  if (loadingView) return loadingView
  // After this point, issue is guaranteed to be non-null
  const issue = state.detail.issue!

  return (
    <>
      <IssueDetailContent
        issue={issue}
        projectPath={state.projectPath}
        issueNumber={issueNumber}
        error={state.detail.error}
        issuesListUrl={state.nav.issuesListUrl}
        editState={state.editState}
        saving={state.actions.saving}
        deleting={state.actions.deleting}
        showDeleteConfirm={state.actions.showDeleteConfirm}
        openingInVscode={state.editor.openingInVscode}
        stateManager={s
Metadata function · typescript · L24-L79 (56 LOC)
components/issues/IssueDetail/Metadata.tsx
export function Metadata({
  issue,
  projectPath,
  issueNumber,
  stateManager,
  stateOptions,
  showStatusDropdown,
  updatingStatus,
  statusDropdownRef,
  assignees,
  setAssignees,
  onToggleDropdown,
  onStatusChange,
}: MetadataProps): ReactElement {
  const priorityLabel = (issue.metadata && issue.metadata.priorityLabel) || ''
  return (
    <>
      <div className="issue-metadata">
        <StatusDropdown
          issue={issue}
          stateManager={stateManager}
          stateOptions={stateOptions}
          showStatusDropdown={showStatusDropdown}
          updatingStatus={updatingStatus}
          statusDropdownRef={statusDropdownRef}
          onToggleDropdown={onToggleDropdown}
          onStatusChange={onStatusChange}
        />
        <span className={`priority-badge ${getPriorityClass(priorityLabel)}`}>
          {priorityLabel || 'unknown'}
        </span>
        <span className="issue-date">
          Created:{' '}
          {issue.metadata && issue.metadata.c
Modals function · typescript · L23-L69 (47 LOC)
components/issues/IssueDetail/Modals.tsx
export function Modals({
  projectPath,
  issue,
  showMoveModal,
  showDuplicateModal,
  showStatusConfigDialog,
  onCloseMoveModal,
  onCloseDuplicateModal,
  onCloseStatusConfigDialog,
  onMoved,
  onDuplicated,
  onStatusConfigured,
}: ModalsProps): ReactElement {
  return (
    <>
      {showMoveModal && issue && (
        <MoveModal
          entityType="issue"
          entityId={issue.id}
          entityTitle={issue.title}
          currentProjectPath={projectPath}
          onClose={onCloseMoveModal}
          onMoved={onMoved}
        />
      )}

      {showDuplicateModal && issue && (
        <DuplicateModal
          entityType="issue"
          entityId={issue.id}
          entityTitle={issue.title}
          currentProjectPath={projectPath}
          onClose={onCloseDuplicateModal}
          onDuplicated={onDuplicated}
        />
      )}

      {showStatusConfigDialog && projectPath && (
        <StatusConfigDialog
          projectPath={projectPath}
          onClose=
StatusDropdown function · typescript · L24-L71 (48 LOC)
components/issues/IssueDetail/StatusDropdown.tsx
export function StatusDropdown({
  issue,
  stateManager,
  stateOptions,
  showStatusDropdown,
  updatingStatus,
  statusDropdownRef,
  onToggleDropdown,
  onStatusChange,
}: StatusDropdownProps): ReactElement {
  const currentStatus = (issue.metadata && issue.metadata.status) || ''
  return (
    <div className="status-selector" ref={statusDropdownRef}>
      <button
        className={`status-badge status-badge-clickable ${stateManager.getStateClass(currentStatus)} ${updatingStatus ? 'updating' : ''}`}
        onClick={onToggleDropdown}
        disabled={updatingStatus}
        aria-label="Change status"
        aria-expanded={showStatusDropdown}
        aria-haspopup="listbox"
      >
        {updatingStatus ? 'Updating...' : currentStatus || 'unknown'}
        <span className="status-dropdown-arrow" aria-hidden="true">
          &#9660;
        </span>
      </button>
      {showStatusDropdown && (
        <ul
          className="status-dropdown"
          role="listbox"
        
ViewContent function · typescript · L17-L53 (37 LOC)
components/issues/IssueDetail/ViewContent.tsx
export function ViewContent({
  issue,
  projectPath,
  issueNumber,
  assets,
  setAssets,
}: ViewContentProps): ReactElement {
  return (
    <>
      <div className="issue-description">
        <h3 className="section-title">Description</h3>
        {issue.description ? (
          <TextEditor value={issue.description} format="md" mode="display" />
        ) : (
          <p className="no-description">No description provided</p>
        )}
      </div>

      <div className="issue-assets">
        <h3 className="section-title">Attachments</h3>
        {assets.length > 0 ? (
          <AssetUploader
            projectPath={projectPath}
            issueId={issueNumber}
            mode="edit"
            initialAssets={assets}
            onAssetsChange={setAssets}
          />
        ) : (
          <p className="no-assets">No attachments</p>
        )}
      </div>

      <LinkSection entityId={issue.id} entityType="issue" editable={true} />
    </>
  )
}
createCreatedAtColumn function · typescript · L6-L31 (26 LOC)
components/issues/IssuesList/dateColumns.tsx
export function createCreatedAtColumn() {
  return columnHelper.accessor(
    row => (row.metadata && row.metadata.createdAt) || '',
    {
      id: 'createdAt',
      header: 'Created',
      cell: info => {
        const date = info.getValue()
        return (
          <span className="issue-date-text">
            {date ? new Date(date).toLocaleDateString() : '-'}
          </span>
        )
      },
      enableColumnFilter: false,
      sortingFn: (rowA, rowB) => {
        const a = String(rowA.getValue('createdAt'))
        const b = String(rowB.getValue('createdAt'))
        if (!a && !b) return 0
        if (!a) return 1
        if (!b) return -1
        return new Date(a).getTime() - new Date(b).getTime()
      },
    }
  )
}
createLastSeenColumn function · typescript · L33-L58 (26 LOC)
components/issues/IssuesList/dateColumns.tsx
export function createLastSeenColumn(lastSeenMap: Record<string, number>) {
  return columnHelper.accessor(row => lastSeenMap[row.id] || 0, {
    id: 'lastSeen',
    header: 'Last Seen',
    cell: info => {
      const timestamp = info.getValue()
      if (!timestamp) {
        return <span className="issue-not-seen">Never</span>
      }
      return (
        <span className="issue-date-text">
          {new Date(timestamp).toLocaleDateString()}
        </span>
      )
    },
    enableColumnFilter: false,
    sortingFn: (rowA, rowB) => {
      const a = Number(rowA.getValue('lastSeen'))
      const b = Number(rowB.getValue('lastSeen'))
      if (a === 0 && b === 0) return 0
      if (a === 0) return 1
      if (b === 0) return -1
      return a - b
    },
  })
}
buildContextMenuItems function · typescript · L20-L58 (39 LOC)
components/issues/IssuesList/hooks/buildContextMenuItems.ts
export function buildContextMenuItems({
  issue,
  pinActions,
  onView,
  onMove,
  onDuplicate,
  onClose,
}: BuildMenuParams): ContextMenuItem[] {
  return [
    {
      label: pinActions.isPinned(issue.issueNumber) ? 'Unpin' : 'Pin',
      onClick: () => {
        if (pinActions.isPinned(issue.issueNumber)) {
          pinActions.unpinItem(issue.issueNumber)
        } else {
          pinActions.pinItem({
            id: issue.issueNumber,
            type: 'issue',
            title: issue.title,
            displayNumber: issue.displayNumber,
          })
        }
        onClose()
      },
    },
    {
      label: 'View',
      onClick: onView,
    },
    {
      label: 'Move',
      onClick: onMove,
    },
    {
      label: 'Duplicate',
      onClick: onDuplicate,
    },
  ]
}
Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
useIssueContextMenu function · typescript · L9-L84 (76 LOC)
components/issues/IssuesList/hooks/useIssueContextMenu.ts
export function useIssueContextMenu(
  projectPath: string,
  fetchIssues: () => void
) {
  const router = useRouter()
  const { pinItem, unpinItem, isPinned } = usePinnedItems()
  const { createLink, handleMoved, handleDuplicated } = useIssueMoveActions(
    projectPath,
    fetchIssues
  )

  const [contextMenu, setContextMenu] = useState<{
    x: number
    y: number
    issue: Issue
  } | null>(null)
  const [showMoveModal, setShowMoveModal] = useState(false)
  const [showDuplicateModal, setShowDuplicateModal] = useState(false)
  const [showStandaloneModal, setShowStandaloneModal] = useState(false)
  const [selectedIssue, setSelectedIssue] = useState<Issue | null>(null)

  const handleContextMenu = useCallback((e: React.MouseEvent, issue: Issue) => {
    e.preventDefault()
    setContextMenu({ x: e.clientX, y: e.clientY, issue })
  }, [])

  const onDuplicated = useCallback(
    async (newIssueId: string, targetProjectPath: string) => {
      await handleDuplicated(newIssueId, targ
useIssueMoveActions function · typescript · L7-L69 (63 LOC)
components/issues/IssuesList/hooks/useIssueMoveActions.ts
export function useIssueMoveActions(
  projectPath: string,
  fetchIssues: () => void
) {
  const router = useRouter()
  const resolvePathToUrl = useProjectPathToUrl()
  const { createLink, createProjectLink } = useAppLink()

  const handleMoved = useCallback(
    async (targetProjectPath: string) => {
      const result = await resolvePathToUrl(targetProjectPath)
      if (result) {
        router.push(
          createProjectLink(result.orgSlug, result.projectName, 'issues')
        )
      } else {
        router.push(route({ pathname: '/' }))
      }
    },
    [resolvePathToUrl, createProjectLink, router]
  )

  const handleDuplicated = useCallback(
    async (
      newIssueId: string,
      targetProjectPath: string,
      onComplete: () => void
    ) => {
      if (targetProjectPath === projectPath) {
        fetchIssues()
        router.push(createLink(`/issues/${newIssueId}`))
      } else {
        const result = await resolvePathToUrl(targetProjectPath)
        if (result) 
useIssuesData function · typescript · L8-L51 (44 LOC)
components/issues/IssuesList/hooks/useIssuesData.ts
export function useIssuesData() {
  const { projectPath, isInitialized } = usePathContext()
  const [issues, setIssues] = useState<Issue[]>([])
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState<string | null>(null)

  const fetchIssues = useCallback(async () => {
    if (!projectPath.trim() || isInitialized !== true) return

    setLoading(true)
    setError(null)

    try {
      const request = create(ListItemsRequestSchema, {
        projectPath: projectPath.trim(),
        itemType: 'issues',
      })
      const response = await centyClient.listItems(request)
      setIssues(response.items.map(genericItemToIssue))
    } catch (err) {
      setError(
        err instanceof Error ? err.message : 'Failed to connect to daemon'
      )
    } finally {
      setLoading(false)
    }
  }, [projectPath, isInitialized])

  useEffect(() => {
    if (isInitialized === true) {
      fetchIssues()
    }
    // eslint-disable-next-line react-hooks/exhaustive-de
useIssuesTable function · typescript · L19-L60 (42 LOC)
components/issues/IssuesList/hooks/useIssuesTable.ts
export function useIssuesTable(
  issues: Issue[],
  createLink: (path: string) => RouteLiteral
) {
  const stateManager = useStateManager()
  const { copyToClipboard } = useCopyToClipboard()
  const { lastSeenMap } = useLastSeenIssues()
  const { sorting, setSorting, columnFilters, setColumnFilters } =
    useIssueTableSettings()

  const statusOptions: MultiSelectOption[] = useMemo(
    () =>
      stateManager.getStateOptions().map(opt => ({
        value: opt.value,
        label: opt.label,
      })),
    [stateManager]
  )

  const columns = useMemo(
    () => [
      ...createBaseColumns(copyToClipboard, createLink, stateManager),
      createPriorityColumn(),
      createCreatedAtColumn(),
      createLastSeenColumn(lastSeenMap),
    ],
    [lastSeenMap, stateManager, copyToClipboard, createLink]
  )

  const table = useReactTable({
    data: issues,
    columns,
    state: { sorting, columnFilters },
    onSortingChange: setSorting,
    onColumnFiltersChange: setColumnFilters,
IssuesContent function · typescript · L24-L80 (57 LOC)
components/issues/IssuesList/IssuesContent.tsx
export function IssuesContent({
  projectPath,
  isInitialized,
  loading,
  error,
  issues,
  table,
  statusOptions,
  createLink,
  onContextMenu,
}: IssuesContentProps): ReactElement {
  if (!projectPath) {
    return (
      <div className="no-project-message">
        <p className="no-project-text">
          Select a project from the header to view issues
        </p>
      </div>
    )
  }

  if (isInitialized === false) {
    return (
      <div className="not-initialized-message">
        <p className="not-initialized-text">
          Centy is not initialized in this directory
        </p>
        <Link href={createLink('/')}>Initialize Project</Link>
      </div>
    )
  }

  if (!(projectPath && isInitialized === true)) {
    return <></>
  }

  return (
    <>
      {error && <DaemonErrorMessage error={error} />}

      {loading && issues.length === 0 ? (
        <div className="loading">Loading issues...</div>
      ) : issues.length === 0 ? (
        <div className="emp
IssuesHeader function · typescript · L16-L50 (35 LOC)
components/issues/IssuesList/IssuesHeader.tsx
export function IssuesHeader({
  projectPath,
  isInitialized,
  loading,
  fetchIssues,
  onShowStandaloneModal,
  createLink,
}: IssuesHeaderProps): ReactElement {
  return (
    <div className="issues-header">
      <h2 className="issues-title">Issues</h2>
      <div className="header-actions">
        {projectPath && isInitialized === true && (
          <button
            onClick={fetchIssues}
            disabled={loading}
            className="refresh-btn"
          >
            {loading ? 'Loading...' : 'Refresh'}
          </button>
        )}
        <button
          onClick={onShowStandaloneModal}
          className="workspace-btn"
          title="Create a standalone workspace without an issue"
        >
          + New Workspace
        </button>
        <Link href={createLink('/issues/new')} className="create-btn">
          + New Issue
        </Link>
      </div>
    </div>
  )
}
IssuesList function · typescript · L10-L61 (52 LOC)
components/issues/IssuesList/IssuesList.tsx
export function IssuesList() {
  const { projectPath, isInitialized, issues, loading, error, fetchIssues } =
    useIssuesData()

  const ctx = useIssueContextMenu(projectPath, fetchIssues)
  const { table, statusOptions } = useIssuesTable(issues, ctx.createLink)

  return (
    <div className="issues-list">
      <IssuesHeader
        projectPath={projectPath}
        isInitialized={isInitialized}
        loading={loading}
        fetchIssues={fetchIssues}
        onShowStandaloneModal={() => ctx.setShowStandaloneModal(true)}
        createLink={ctx.createLink}
      />
      <IssuesContent
        projectPath={projectPath}
        isInitialized={isInitialized}
        loading={loading}
        error={error}
        issues={issues}
        table={table}
        statusOptions={statusOptions}
        createLink={ctx.createLink}
        onContextMenu={ctx.handleContextMenu}
      />
      <IssuesModals
        projectPath={projectPath}
        contextMenu={ctx.contextMenu}
        contex
IssuesModals function · typescript · L29-L85 (57 LOC)
components/issues/IssuesList/IssuesModals.tsx
export function IssuesModals({
  projectPath,
  contextMenu,
  contextMenuItems,
  onCloseContextMenu,
  showMoveModal,
  showDuplicateModal,
  showStandaloneModal,
  selectedIssue,
  onCloseMoveModal,
  onCloseDuplicateModal,
  onCloseStandaloneModal,
  onMoved,
  onDuplicated,
}: IssuesModalsProps): ReactElement {
  return (
    <>
      {contextMenu && (
        <ContextMenu
          items={contextMenuItems}
          x={contextMenu.x}
          y={contextMenu.y}
          onClose={onCloseContextMenu}
        />
      )}

      {showMoveModal && selectedIssue && (
        <MoveModal
          entityType="issue"
          entityId={selectedIssue.id}
          entityTitle={selectedIssue.title}
          currentProjectPath={projectPath}
          onClose={onCloseMoveModal}
          onMoved={onMoved}
        />
      )}

      {showDuplicateModal && selectedIssue && (
        <DuplicateModal
          entityType="issue"
          entityId={selectedIssue.id}
          entityTitle={sele
Repobility · code-quality intelligence platform · https://repobility.com
getFilterValue function · typescript · L18-L23 (6 LOC)
components/issues/IssuesList/IssuesTableHeader.tsx
function getFilterValue(column: { getFilterValue: () => unknown }) {
  const filterVal = column.getFilterValue()
  return Array.isArray(filterVal)
    ? filterVal.filter((v): v is string => typeof v === 'string')
    : []
}
IssuesTableHeader function · typescript · L26-L103 (78 LOC)
components/issues/IssuesList/IssuesTableHeader.tsx
export function IssuesTableHeader({
  headerGroups,
  statusOptions,
}: IssuesTableHeaderProps): ReactElement {
  return (
    <thead className="issues-thead">
      {headerGroups.map(headerGroup => (
        <tr className="header-row" key={headerGroup.id}>
          {headerGroup.headers.map(header => (
            <th className="header-cell" key={header.id}>
              <div className="th-content">
                <button
                  type="button"
                  className={`sort-btn ${header.column.getIsSorted() ? 'sorted' : ''}`}
                  onClick={header.column.getToggleSortingHandler()}
                >
                  {flexRender(
                    header.column.columnDef.header,
                    header.getContext()
                  )}
                  <span className="sort-indicator">
                    {(() => {
                      const sorted = header.column.getIsSorted()
                      return sorted === 'asc'
                        ? ' 
getCellClassName function · typescript · L16-L21 (6 LOC)
components/issues/IssuesList/IssuesTable.tsx
function getCellClassName(columnId: string): string {
  if (columnId === 'displayNumber') return 'issue-number'
  if (columnId === 'title') return 'issue-title'
  if (columnId === 'createdAt') return 'issue-date'
  return ''
}
IssuesTable function · typescript · L23-L53 (31 LOC)
components/issues/IssuesList/IssuesTable.tsx
export function IssuesTable({
  table,
  statusOptions,
  onContextMenu,
}: IssuesTableProps): ReactElement {
  return (
    <div className="issues-table">
      <table className="issues-data-table">
        <IssuesTableHeader
          headerGroups={table.getHeaderGroups()}
          statusOptions={statusOptions}
        />
        <tbody className="issues-tbody">
          {table.getRowModel().rows.map(row => (
            <tr
              key={row.original.issueNumber}
              onContextMenu={e => onContextMenu(e, row.original)}
              className="context-menu-row"
            >
              {row.getVisibleCells().map(cell => (
                <td key={cell.id} className={getCellClassName(cell.column.id)}>
                  {flexRender(cell.column.columnDef.cell, cell.getContext())}
                </td>
              ))}
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  )
}
createPriorityColumn function · typescript · L19-L47 (29 LOC)
components/issues/IssuesList/priorityColumn.tsx
export function createPriorityColumn() {
  return columnHelper.accessor(
    row => (row.metadata && row.metadata.priorityLabel) || 'unknown',
    {
      id: 'priority',
      header: 'Priority',
      cell: info => {
        const priority = info.getValue()
        return (
          <span className={`priority-badge ${getPriorityClass(priority)}`}>
            {priority}
          </span>
        )
      },
      enableColumnFilter: true,
      filterFn: (row, columnId, filterValue) => {
        const priority = String(row.getValue(columnId)).toLowerCase()
        const selectedValues = Array.isArray(filterValue) ? filterValue : []
        if (selectedValues.length === 0) return true
        return selectedValues.includes(priority)
      },
      sortingFn: (rowA, rowB) => {
        const a = String(rowA.getValue('priority')).toLowerCase()
        const b = String(rowB.getValue('priority')).toLowerCase()
        return (PRIORITY_ORDER.get(a) || 4) - (PRIORITY_ORDER.get(b) || 4)
     
ClientRouteHandler function · typescript · L13-L36 (24 LOC)
components/layout/ClientRouteHandler.tsx
export function ClientRouteHandler({ children }: ClientRouteHandlerProps) {
  const pathname = usePathname()
  useKeyboardNavigation()

  const routeContent = useMemo(() => {
    const pathParts = pathname.split('/').filter(Boolean)

    // Handle /issues/[issueNumber] routes
    if (pathParts[0] === 'issues' && pathParts[1] && pathParts[1] !== 'new') {
      return <IssueDetail issueNumber={pathParts[1]} />
    }

    // Handle /docs/[slug] routes
    if (pathParts[0] === 'docs' && pathParts[1] && pathParts[1] !== 'new') {
      return <DocDetail slug={pathParts[1]} />
    }

    // For all other routes, use the default children
    return null
  }, [pathname])

  // If we have a specific route to handle, render it; otherwise render children
  return <>{routeContent || children}</>
}
DisconnectedIcon function · typescript · L10-L35 (26 LOC)
components/layout/DaemonDisconnectedOverlay.tsx
function DisconnectedIcon() {
  return (
    <div className="daemon-disconnected-icon">
      <svg
        className="daemon-disconnected-svg"
        viewBox="0 0 24 24"
        fill="none"
        stroke="currentColor"
        strokeWidth="2"
        strokeLinecap="round"
        strokeLinejoin="round"
      >
        <line className="svg-line" x1="1" y1="1" x2="23" y2="23" />
        <path
          className="svg-path"
          d="M16.72 11.06A10.94 10.94 0 0 1 19 12.55"
        />
        <path className="svg-path" d="M5 12.55a10.94 10.94 0 0 1 5.17-2.39" />
        <path className="svg-path" d="M10.71 5.05A16 16 0 0 1 22.58 9" />
        <path className="svg-path" d="M1.42 9a15.91 15.91 0 0 1 4.7-2.88" />
        <path className="svg-path" d="M8.53 16.11a6 6 0 0 1 6.95 0" />
        <line className="svg-line" x1="12" y1="20" x2="12.01" y2="20" />
      </svg>
    </div>
  )
}
CopyButton function · typescript · L37-L89 (53 LOC)
components/layout/DaemonDisconnectedOverlay.tsx
function CopyButton({
  copied,
  onCopy,
}: {
  copied: boolean
  onCopy: () => void
}) {
  return (
    <button
      className="daemon-copy-button"
      onClick={onCopy}
      title="Copy to clipboard"
    >
      {copied ? (
        <svg
          className="copy-icon-svg"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          strokeWidth="2"
          strokeLinecap="round"
          strokeLinejoin="round"
        >
          <polyline className="svg-polyline" points="20 6 9 17 4 12" />
        </svg>
      ) : (
        <svg
          className="copy-icon-svg"
          viewBox="0 0 24 24"
          fill="none"
          stroke="currentColor"
          strokeWidth="2"
          strokeLinecap="round"
          strokeLinejoin="round"
        >
          <rect
            className="svg-rect"
            x="9"
            y="9"
            width="13"
            height="13"
            rx="2"
            ry="2"
          />
          <path
    
Citation: Repobility (2026). State of AI-Generated Code. https://repobility.com/research/
DaemonDisconnectedOverlay function · typescript · L91-L138 (48 LOC)
components/layout/DaemonDisconnectedOverlay.tsx
export function DaemonDisconnectedOverlay() {
  const { status, checkNow, enterDemoMode } = useDaemonStatus()
  const [copied, setCopied] = useState(false)

  if (status !== 'disconnected') {
    return null
  }

  const handleCopy = async () => {
    await navigator.clipboard.writeText(INSTALL_COMMAND)
    setCopied(true)
    setTimeout(() => setCopied(false), 2000)
  }

  return (
    <div className="daemon-disconnected-overlay">
      <div className="daemon-disconnected-content">
        <DisconnectedIcon />
        <h2 className="daemon-disconnected-title">Daemon Not Connected</h2>
        <p className="daemon-disconnected-description">
          The Centy daemon is not running or cannot be reached.
          <br className="daemon-line-break" />
          Please start the daemon to use the application.
        </p>
        <div className="daemon-disconnected-instructions">
          <p className="daemon-instruction-text">
            If you haven&apos;t installed the daemon yet, ru
DemoModeIndicator function · typescript · L5-L26 (22 LOC)
components/layout/DemoModeIndicator.tsx
export function DemoModeIndicator() {
  const { status, exitDemoMode } = useDaemonStatus()

  // Only show when in demo mode
  if (status !== 'demo') {
    return null
  }

  return (
    <div className="demo-mode-indicator">
      <div className="demo-mode-indicator-content">
        <span className="demo-mode-indicator-badge">Demo Mode</span>
        <span className="demo-mode-indicator-text">
          You&apos;re exploring with sample data. Changes won&apos;t be saved.
        </span>
        <button className="demo-mode-exit-button" onClick={exitDemoMode}>
          Exit Demo
        </button>
      </div>
    </div>
  )
}
ContextLink function · typescript · L12-L30 (19 LOC)
components/layout/Header/ContextLink.tsx
export function ContextLink({
  effectiveOrg,
  effectiveProject,
}: ContextLinkProps) {
  const href =
    effectiveOrg === UNGROUPED_ORG_MARKER
      ? route({ pathname: '/organizations' })
      : route({
          pathname: '/organizations/[orgSlug]',
          query: { orgSlug: effectiveOrg },
        })

  return (
    <Link href={href} className="header-context-link">
      {effectiveOrg === UNGROUPED_ORG_MARKER ? '' : `${effectiveOrg} / `}
      {effectiveProject}
    </Link>
  )
}
DesktopNav function · typescript · L15-L81 (67 LOC)
components/layout/Header/DesktopNav.tsx
export function DesktopNav({
  navLinks,
  pathname,
  isActive,
  itemTypes,
}: DesktopNavProps) {
  return (
    <nav className="app-nav">
      {navLinks && (
        <>
          <div className="nav-group nav-group-project">
            {itemTypes.map(t => (
              <Link
                key={t.plural}
                href={t.href}
                className={isActive(t.href) ? 'active' : ''}
              >
                {t.name}
              </Link>
            ))}
            <Link
              href={navLinks.assets}
              className={isActive(navLinks.assets, false) ? 'active' : ''}
            >
              Assets
            </Link>
            <Link
              href={navLinks.users}
              className={isActive(navLinks.users) ? 'active' : ''}
            >
              Users
            </Link>
            <Link
              href={navLinks.config}
              className={isActive(navLinks.config, false) ? 'active' : ''}
            >
            
Header function · typescript · L17-L81 (65 LOC)
components/layout/Header/Header.tsx
export function Header() {
  const { selectedOrgSlug } = useOrganization()
  const {
    pathname,
    hasProjectContext,
    effectiveOrg,
    effectiveProject,
    itemTypes,
    navLinks,
    isActive,
  } = useHeaderNav()
  const { mobileMenuOpen, setMobileMenuOpen, toggleMobileMenu } =
    useMobileMenu(pathname)

  return (
    <header className="app-header">
      <div className="header-top">
        <h1 className="header-title">
          <Link href={route({ pathname: '/' })} className="header-logo-link">
            <img
              src="/logo.svg"
              alt=""
              className="header-logo-icon"
              width={28}
              height={28}
              aria-hidden="true"
            />
            <span className="header-app-name">Centy</span>
          </Link>
          {hasProjectContext && effectiveOrg && effectiveProject && (
            <ContextLink
              effectiveOrg={effectiveOrg}
              effectiveProject={effectiveProject}
       
MobileMenuToggle function · typescript · L8-L21 (14 LOC)
components/layout/Header/MobileMenuToggle.tsx
export function MobileMenuToggle({ isOpen, onToggle }: MobileMenuToggleProps) {
  return (
    <button
      className={`mobile-menu-toggle ${isOpen ? 'open' : ''}`}
      onClick={onToggle}
      aria-label={isOpen ? 'Close menu' : 'Open menu'}
      aria-expanded={isOpen}
    >
      <span className="hamburger-line" />
      <span className="hamburger-line" />
      <span className="hamburger-line" />
    </button>
  )
}
MobileMenu function · typescript · L20-L54 (35 LOC)
components/layout/Header/MobileMenu.tsx
export function MobileMenu({
  mobileMenuOpen,
  setMobileMenuOpen,
  selectedOrgSlug,
  navLinks,
  pathname,
  isActive,
  itemTypes,
}: MobileMenuProps) {
  return (
    <>
      <div
        className={`mobile-menu-overlay ${mobileMenuOpen ? 'open' : ''}`}
        onClick={() => setMobileMenuOpen(false)}
        aria-hidden="true"
      />
      <div className={`mobile-menu ${mobileMenuOpen ? 'open' : ''}`}>
        <div className="mobile-menu-controls">
          <ThemeToggle />
          <DaemonStatusIndicator />
        </div>
        <div className="mobile-menu-selectors">
          <OrgSwitcher />
          {selectedOrgSlug !== undefined && <ProjectSelector />}
        </div>
        <MobileNavLinks
          navLinks={navLinks}
          pathname={pathname}
          isActive={isActive}
          itemTypes={itemTypes}
        />
      </div>
    </>
  )
}
MobileNavLinks function · typescript · L15-L81 (67 LOC)
components/layout/Header/MobileNavLinks.tsx
export function MobileNavLinks({
  navLinks,
  pathname,
  isActive,
  itemTypes,
}: MobileNavLinksProps) {
  return (
    <nav className="mobile-menu-nav">
      {navLinks && (
        <>
          <div className="mobile-nav-group">
            {itemTypes.map(t => (
              <Link
                key={t.plural}
                href={t.href}
                className={isActive(t.href) ? 'active' : ''}
              >
                {t.name}
              </Link>
            ))}
            <Link
              href={navLinks.assets}
              className={isActive(navLinks.assets, false) ? 'active' : ''}
            >
              Assets
            </Link>
            <Link
              href={navLinks.users}
              className={isActive(navLinks.users) ? 'active' : ''}
            >
              Users
            </Link>
            <Link
              href={navLinks.config}
              className={isActive(navLinks.config, false) ? 'active' : ''}
            >
       
Source: Repobility analyzer · https://repobility.com
useIsActive function · typescript · L8-L24 (17 LOC)
components/layout/Header/useHeaderNav.ts
function useIsActive(
  pathname: string,
  hasProjectContext: boolean
): (href: string, checkPrefix?: boolean) => boolean {
  return (href: string, checkPrefix?: boolean) => {
    const resolvedCheckPrefix = checkPrefix !== undefined ? checkPrefix : true
    if (resolvedCheckPrefix) {
      if (hasProjectContext) {
        const page = href.split('/').slice(3).join('/')
        const currentPage = pathname.split('/').slice(3).join('/')
        return currentPage.startsWith(page.split('/')[0])
      }
      return pathname.startsWith(href)
    }
    return pathname === href
  }
}
useHeaderNav function · typescript · L26-L34 (9 LOC)
components/layout/Header/useHeaderNav.ts
export function useHeaderNav(): {
  pathname: string
  hasProjectContext: boolean
  effectiveOrg: string | undefined
  effectiveProject: string | undefined
  navLinks: NavLinks | null
  isActive: (href: string, checkPrefix?: boolean) => boolean
  itemTypes: NavItemType[]
} {
useMobileMenu function · typescript · L5-L44 (40 LOC)
components/layout/Header/useMobileMenu.ts
export function useMobileMenu(pathname: string) {
  const [mobileMenuOpen, setMobileMenuOpen] = useState(false)

  // Close mobile menu on route change
  useEffect(() => {
    const timeoutId = setTimeout(() => {
      setMobileMenuOpen(false)
    }, 0)
    return () => clearTimeout(timeoutId)
  }, [pathname])

  // Close mobile menu on escape key
  useEffect(() => {
    const handleEscape = (e: KeyboardEvent) => {
      if (e.key === 'Escape') {
        setMobileMenuOpen(false)
      }
    }
    document.addEventListener('keydown', handleEscape)
    return () => document.removeEventListener('keydown', handleEscape)
  }, [])

  // Prevent body scroll when mobile menu is open
  useEffect(() => {
    if (mobileMenuOpen) {
      document.body.style.overflow = 'hidden'
    } else {
      document.body.style.overflow = ''
    }
    return () => {
      document.body.style.overflow = ''
    }
  }, [mobileMenuOpen])

  return {
    mobileMenuOpen,
    setMobileMenuOpen,
    toggleMobileMenu: 
buildItemHref function · typescript · L11-L19 (9 LOC)
components/layout/Header/useNavItemTypes.ts
function buildItemHref(
  org: string,
  project: string,
  plural: string
): RouteLiteral {
  return Object.assign(`/${org}/${project}/${plural}`, {
    __brand: 'RouteLiteral' as const,
  })
}
useNavItemTypes function · typescript · L21-L67 (47 LOC)
components/layout/Header/useNavItemTypes.ts
export function useNavItemTypes(
  hasProjectContext: boolean,
  effectiveOrg: string | undefined,
  effectiveProject: string | undefined
): NavItemType[] {
  const [itemTypes, setItemTypes] = useState<NavItemType[]>([])

  useEffect(() => {
    if (!hasProjectContext || !effectiveOrg || !effectiveProject) {
      setItemTypes([])
      return
    }
    let cancelled = false
    async function fetchItemTypes() {
      try {
        const resolution = await resolveProject(
          effectiveOrg!,
          effectiveProject!
        )
        if (cancelled || !resolution) return
        const req = create(ListItemTypesRequestSchema, {
          projectPath: resolution.projectPath,
        })
        const res = await centyClient.listItemTypes(req)
        if (cancelled) return
        setItemTypes(
          res.itemTypes
            .map(t => ({
              name: t.name,
              plural: t.plural,
              itemCount: t.itemCount,
              href: buildItemHref(effectiveO
fetchItemTypes function · typescript · L34-L59 (26 LOC)
components/layout/Header/useNavItemTypes.ts
    async function fetchItemTypes() {
      try {
        const resolution = await resolveProject(
          effectiveOrg!,
          effectiveProject!
        )
        if (cancelled || !resolution) return
        const req = create(ListItemTypesRequestSchema, {
          projectPath: resolution.projectPath,
        })
        const res = await centyClient.listItemTypes(req)
        if (cancelled) return
        setItemTypes(
          res.itemTypes
            .map(t => ({
              name: t.name,
              plural: t.plural,
              itemCount: t.itemCount,
              href: buildItemHref(effectiveOrg!, effectiveProject!, t.plural),
            }))
            .sort((a, b) => b.itemCount - a.itemCount)
        )
      } catch {
        // silently fall back to empty
      }
    }
useNavLinks function · typescript · L7-L31 (25 LOC)
components/layout/Header/useNavLinks.ts
export function useNavLinks(
  hasProjectContext: boolean,
  effectiveOrg: string | undefined,
  effectiveProject: string | undefined
): NavLinks | null {
  return useMemo(() => {
    if (!hasProjectContext || !effectiveOrg || !effectiveProject) {
      return null
    }
    return {
      assets: route({
        pathname: '/[organization]/[project]/assets',
        query: { organization: effectiveOrg, project: effectiveProject },
      }),
      users: route({
        pathname: '/[organization]/[project]/users',
        query: { organization: effectiveOrg, project: effectiveProject },
      }),
      config: route({
        pathname: '/[organization]/[project]/config',
        query: { organization: effectiveOrg, project: effectiveProject },
      }),
    }
  }, [hasProjectContext, effectiveOrg, effectiveProject])
}
useProjectContext function · typescript · L7-L35 (29 LOC)
components/layout/Header/useProjectContext.ts
export function useProjectContext() {
  const pathname = usePathname()
  const params = useParams()

  const orgParam = params ? params.organization : undefined
  const org: string | undefined =
    typeof orgParam === 'string' ? orgParam : undefined
  const projectParam = params ? params.project : undefined
  const project: string | undefined =
    typeof projectParam === 'string' ? projectParam : undefined

  const pathSegments = useMemo(() => {
    return pathname.split('/').filter(Boolean)
  }, [pathname])

  const hasProjectContext = useMemo(() => {
    if (org && project) return true
    if (pathSegments.length >= 2 && !ROOT_ROUTES.has(pathSegments[0])) {
      return true
    }
    return false
  }, [org, project, pathSegments])

  const effectiveOrg = org || (hasProjectContext ? pathSegments[0] : undefined)
  const effectiveProject =
    project || (hasProjectContext ? pathSegments[1] : undefined)

  return { pathname, hasProjectContext, effectiveOrg, effectiveProject }
}
Generated by Repobility's multi-pass static-analysis pipeline (https://repobility.com)
LegacyUrlRedirect function · typescript · L17-L87 (71 LOC)
components/layout/LegacyUrlRedirect.tsx
export function LegacyUrlRedirect() {
  const searchParams = useSearchParams()
  const pathname = usePathname()
  const router = useRouter()
  const [isRedirecting, setIsRedirecting] = useState(false)

  useEffect(() => {
    const projectPath = searchParams.get('project')

    if (!projectPath) {
      return
    }

    // Don't redirect if we're already on a path-based route
    const pathSegments = pathname.split('/').filter(Boolean)
    if (pathSegments.length >= 2) {
      // Looks like we're already on a path-based route
      // Check if this is a root-level route (doesn't require project context)
      // Note: 'issues', 'docs', 'users' are NOT in this list
      // because they require project context and are handled by project-scoped routes
      const rootLevelRoutes = [
        'organizations',
        'settings',
        'archived',
        'assets',
      ]
      if (!rootLevelRoutes.includes(pathSegments[0])) {
        return // Already on a project path like /org/projec
redirect function · typescript · L48-L73 (26 LOC)
components/layout/LegacyUrlRedirect.tsx
    async function redirect() {
      setIsRedirecting(true)

      try {
        const result = await resolveProjectPath(projectPath!)

        if (result) {
          const orgPart = result.orgSlug || UNGROUPED_ORG_MARKER

          // Extract the page from pathname (e.g., /issues -> issues)
          const page = pathname.split('/').filter(Boolean)[0] || 'issues'

          // Build new URL and redirect
          router.replace(
            route({
              pathname: '/[...path]',
              query: { path: [orgPart, result.projectName, page] },
            })
          )
        }
      } catch (error) {
        console.error('Failed to resolve legacy URL:', error)
      } finally {
        setIsRedirecting(false)
      }
    }
MobileNotSupportedIcon function · typescript · L5-L39 (35 LOC)
components/layout/MobileNotSupportedOverlay.tsx
function MobileNotSupportedIcon() {
  return (
    <svg
      className="mobile-not-supported-svg"
      width="48"
      height="48"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      strokeWidth="2"
      strokeLinecap="round"
      strokeLinejoin="round"
    >
      <rect
        className="svg-rect"
        x="5"
        y="2"
        width="14"
        height="20"
        rx="2"
        ry="2"
      />
      <line className="svg-line" x1="12" y1="18" x2="12.01" y2="18" />
      <line
        className="svg-line"
        x1="2"
        y1="2"
        x2="22"
        y2="22"
        stroke="#ef4444"
        strokeWidth="2.5"
      />
    </svg>
  )
}
‹ prevpage 2 / 10next ›