Function bodies 471 total
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(
prouseIssueDetail 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(
createProjectLiuseStatusChange 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.editPriorityIssueDetailContent 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={sMetadata 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.cModals 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">
▼
</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, targuseIssueMoveActions 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-deuseIssuesTable 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="empIssuesHeader 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}
contexIssuesModals 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={seleRepobility · 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't installed the daemon yet, ruDemoModeIndicator 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're exploring with sample data. Changes won'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(effectiveOfetchItemTypes 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/projecredirect 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>
)
}