Function bodies 471 total
PathContextProvider function · typescript · L25-L77 (53 LOC)components/providers/PathContextProvider.tsx
export function PathContextProvider({ children }: { children: ReactNode }) {
const router = useRouter()
const { urlOrg, urlProject, isAggregateView } = useUrlParams()
const { resolution, isLoading, error } = useProjectResolution(
urlOrg,
urlProject,
isAggregateView
)
const navigateToProject = useMemo(() => {
return (orgSlug: string | null, projectName: string, page?: string) => {
const resolvedPage = page !== undefined ? page : 'issues'
const o = orgSlug !== null ? orgSlug : UNGROUPED_ORG_MARKER
router.push(
route({
pathname: '/[...path]',
query: { path: [o, projectName, resolvedPage] },
})
)
}
}, [router])
const contextValue = useMemo(() => {
if (isAggregateView) return buildAggregateContext(navigateToProject)
if (resolution) {
return buildResolvedContext(
resolution,
isLoading,
error,
navigateToProject
)
}
return buildPendingConteProjectProvider function · typescript · L30-L45 (16 LOC)components/providers/ProjectProvider.tsx
export function ProjectProvider({ children }: { children: ReactNode }) {
const [projectPath, setProjectPathState] = useState('')
const [isInitialized, setIsInitialized] = useState<boolean | null>(null)
const setProjectPath = useCallback((path: string) => {
setProjectPathState(path)
}, [])
return (
<ProjectContext.Provider
value={{ projectPath, setProjectPath, isInitialized, setIsInitialized }}
>
{children}
</ProjectContext.Provider>
)
}useProject function · typescript · L47-L53 (7 LOC)components/providers/ProjectProvider.tsx
export function useProject() {
const context = useContext(ProjectContext)
if (!context) {
throw new ProjectProviderError()
}
return context
}useArchivedProjects function · typescript · L55-L106 (52 LOC)components/providers/ProjectProvider.tsx
export function useArchivedProjects() {
// Initialize to empty to avoid hydration mismatch - load from localStorage after mount
const [archivedPaths, setArchivedPathsState] = useState<string[]>([])
// Load from localStorage after mount to avoid hydration mismatch
useEffect(() => {
const stored = localStorage.getItem(ARCHIVED_STORAGE_KEY)
if (stored) {
setArchivedPathsState(JSON.parse(stored))
}
}, [])
const archiveProject = useCallback((path: string) => {
setArchivedPathsState(prev => {
if (prev.includes(path)) return prev
const updated = [...prev, path]
setArchivedProjectsStorage(updated)
return updated
})
}, [])
const unarchiveProject = useCallback((path: string) => {
setArchivedPathsState(prev => {
const updated = prev.filter(p => p !== path)
setArchivedProjectsStorage(updated)
return updated
})
}, [])
const removeArchivedProject = useCallback((path: string) => {
setArchivedPathsSProvidersWithSuspense function · typescript · L10-L18 (9 LOC)components/providers/Providers.tsx
function ProvidersWithSuspense({ children }: { children: ReactNode }) {
return (
<Suspense fallback={null}>
<OrganizationProvider>
<ProjectProvider>{children}</ProjectProvider>
</OrganizationProvider>
</Suspense>
)
}Providers function · typescript · L20-L31 (12 LOC)components/providers/Providers.tsx
export function Providers({ children }: { children: ReactNode }) {
return (
<ThemeProvider>
<DaemonStatusProvider>
<ProvidersWithSuspense>
<Toaster position="bottom-right" richColors theme="system" />
{children}
</ProvidersWithSuspense>
</DaemonStatusProvider>
</ThemeProvider>
)
}ThemeProvider function · typescript · L6-L16 (11 LOC)components/providers/ThemeProvider.tsx
export function ThemeProvider({ children }: { children: ReactNode }) {
return (
<NextThemesProvider
attribute="data-theme"
defaultTheme="system"
enableSystem
>
{children}
</NextThemesProvider>
)
}Repobility · code-quality intelligence platform · https://repobility.com
useLastProjectPath function · typescript · L9-L18 (10 LOC)components/providers/useLastProjectPath.ts
export function useLastProjectPath(): string | null {
const [lastPath] = useState<string | null>(() => {
if (typeof window !== 'undefined') {
return localStorage.getItem(LAST_PROJECT_STORAGE_KEY)
}
return null
})
return lastPath
}usePathContext function · typescript · L10-L16 (7 LOC)components/providers/usePathContext.ts
export function usePathContext() {
const context = useContext(PathContext)
if (!context) {
throw new PathContextProviderError()
}
return context
}useProjectPathToUrl function · typescript · L8-L17 (10 LOC)components/providers/useProjectPathToUrl.ts
export function useProjectPathToUrl() {
return async (projectPath: string) => {
const result = await resolveProjectPath(projectPath)
if (!result) return null
return {
orgSlug: result.orgSlug,
projectName: result.projectName,
}
}
}useProjectResolution function · typescript · L6-L52 (47 LOC)components/providers/useProjectResolution.ts
export function useProjectResolution(
urlOrg: string | undefined,
urlProject: string | undefined,
isAggregateView: boolean
) {
const [resolution, setResolution] = useState<ProjectResolution | null>(null)
const [isLoading, setIsLoading] = useState(!isAggregateView)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
if (isAggregateView) {
setResolution(null)
setIsLoading(false)
setError(null)
return
}
let cancelled = false
async function resolve() {
setIsLoading(true)
setError(null)
try {
const result = await resolveProject(urlOrg!, urlProject!)
if (cancelled) return
if (result) {
setResolution(result)
} else {
setError(`Project not found: ${urlOrg}/${urlProject}`)
setResolution(null)
}
} catch (err) {
if (cancelled) return
setError(
err instanceof Error ? err.message : 'Failed to resolve projresolve function · typescript · L23-L44 (22 LOC)components/providers/useProjectResolution.ts
async function resolve() {
setIsLoading(true)
setError(null)
try {
const result = await resolveProject(urlOrg!, urlProject!)
if (cancelled) return
if (result) {
setResolution(result)
} else {
setError(`Project not found: ${urlOrg}/${urlProject}`)
setResolution(null)
}
} catch (err) {
if (cancelled) return
setError(
err instanceof Error ? err.message : 'Failed to resolve project'
)
setResolution(null)
} finally {
if (!cancelled) setIsLoading(false)
}
}useUrlParams function · typescript · L7-L44 (38 LOC)components/providers/useUrlParams.ts
export function useUrlParams() {
const params = useParams()
const pathname = usePathname()
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)
.map(s => decodeURIComponent(s))
}, [pathname])
const urlOrg = useMemo(() => {
if (org) return org
if (pathSegments.length >= 2 && !ROOT_ROUTES.has(pathSegments[0])) {
return pathSegments[0]
}
return undefined
}, [org, pathSegments])
const urlProject = useMemo(() => {
if (project) return project
if (pathSegments.length >= 2 && !ROOT_ROUTES.has(pathSegments[0])) {
return pathSegments[1]
}
return undefined
}, [project, pathSegmeresolveSubRoute function · typescript · L29-L59 (31 LOC)components/routing/CatchAllRouter.routeConfig.tsx
function resolveSubRoute(pageType: string, rest: string[]): RouteResult | null {
if (pageType === 'issues') {
if (rest[0] === 'new') return { content: <CreateIssue />, ...NO_REDIRECT }
if (rest[0])
return {
content: <IssueDetail issueNumber={rest[0]} />,
...NO_REDIRECT,
}
return { content: <IssuesList />, ...NO_REDIRECT }
}
if (pageType === 'docs') {
if (rest[0] === 'new') return { content: <CreateDoc />, ...NO_REDIRECT }
if (rest[0])
return { content: <DocDetail slug={rest[0]} />, ...NO_REDIRECT }
return { content: <DocsList />, ...NO_REDIRECT }
}
if (pageType === 'users') {
if (rest[0] === 'new') return { content: <CreateUser />, ...NO_REDIRECT }
if (rest[0])
return {
content: <UserDetail userId={rest[0]} />,
...NO_REDIRECT,
}
return { content: <UsersList />, ...NO_REDIRECT }
}
if (pageType === 'assets')
return { content: <SharedAssets />, ...NO_REDIRECT }
if (pageTypresolveRoute function · typescript · L61-L103 (43 LOC)components/routing/CatchAllRouter.routeConfig.tsx
export function resolveRoute(pathname: string): RouteResult {
const segments = pathname.split('/').filter(Boolean)
// Check if this is a single-segment project-scoped route
if (segments.length === 1 && PROJECT_SCOPED_ROUTES.has(segments[0])) {
return {
content: null,
shouldRedirect: false,
redirectTo: null,
// This case is handled specially in CatchAllRouter
}
}
// Need at least org/project
if (segments.length < 2) {
return {
content: <div className="not-found">Page not found</div>,
...NO_REDIRECT,
}
}
const [org, project, pageType, ...rest] = segments
if (pageType === undefined) {
// Just org/project - redirect to issues
return {
content: null,
shouldRedirect: true,
redirectTo: route({
pathname: '/[organization]/[project]/issues',
query: { organization: org, project },
}),
}
}
const result = resolveSubRoute(pageType, rest)
if (result) return result
reProvenance: Repobility (https://repobility.com) — every score reproducible from /scan/
ProjectContextRequired function · typescript · L16-L41 (26 LOC)components/routing/CatchAllRouter.tsx
function ProjectContextRequired({ requestedPage }: { requestedPage: string }) {
const pageLabel =
requestedPage === 'issues'
? 'Issues'
: requestedPage === 'docs'
? 'Docs'
: requestedPage === 'users'
? 'Users'
: requestedPage
return (
<div className="project-context-required">
<h2 className="project-context-title">Project Required</h2>
<p className="project-context-description">
{pageLabel} are project-scoped. Please select a project to view its{' '}
{pageLabel.toLowerCase()}.
</p>
<Link
href={route({ pathname: '/organizations' })}
className="select-project-link"
>
Select a Project
</Link>
</div>
)
}CatchAllRouter function · typescript · L52-L82 (31 LOC)components/routing/CatchAllRouter.tsx
export function CatchAllRouter(): ReactNode {
const pathname = usePathname()
const router = useRouter()
const { content, shouldRedirect, redirectTo } = useMemo(() => {
const segments = pathname.split('/').filter(Boolean)
// Handle single-segment project-scoped routes specially
if (segments.length === 1 && PROJECT_SCOPED_ROUTES.has(segments[0])) {
return {
content: <ProjectContextRequired requestedPage={segments[0]} />,
shouldRedirect: false,
redirectTo: null,
}
}
return resolveRoute(pathname)
}, [pathname])
useEffect(() => {
if (shouldRedirect && redirectTo) {
router.replace(redirectTo)
}
}, [shouldRedirect, redirectTo, router])
if (shouldRedirect) {
return null
}
return <PathContextProvider>{content}</PathContextProvider>
}CustomFieldDisplay function · typescript · L15-L101 (87 LOC)components/settings/CustomFieldsEditor/CustomFieldDisplay.tsx
export function CustomFieldDisplay({
field,
index,
totalCount,
onEdit,
onRemove,
onMoveUp,
onMoveDown,
}: CustomFieldDisplayProps) {
const typeLabel =
(() => {
const found = FIELD_TYPES.find(t => t.value === field.fieldType)
return found ? found.label : ''
})() || field.fieldType
return (
<div className="custom-field-display">
<div className="custom-field-header">
<div className="custom-field-move-btns">
<button
type="button"
onClick={onMoveUp}
disabled={index === 0}
className="custom-field-move-btn"
title="Move up"
>
↑
</button>
<button
type="button"
onClick={onMoveDown}
disabled={index === totalCount - 1}
className="custom-field-move-btn"
title="Move down"
>
↓
</button>
</div>
<span className="custom-CustomFieldFormFields function · typescript · L12-L61 (50 LOC)components/settings/CustomFieldsEditor/CustomFieldFormFields.tsx
export function CustomFieldFormFields({
name,
fieldType,
required,
onNameChange,
onFieldTypeChange,
onRequiredChange,
}: CustomFieldFormFieldsProps) {
return (
<div className="custom-field-form-row">
<div className="custom-field-form-group">
<label className="form-label">Name</label>
<input
type="text"
value={name}
onChange={e => onNameChange(e.target.value)}
placeholder="field_name"
className="custom-field-form-input"
/>
</div>
<div className="custom-field-form-group">
<label className="form-label">Type</label>
<select
value={fieldType}
onChange={e => onFieldTypeChange(e.target.value)}
className="custom-field-form-select"
>
{FIELD_TYPES.map(t => (
<option className="form-option" key={t.value} value={t.value}>
{t.label}
</option>
))}
</select>
</div>
CustomFieldForm function · typescript · L15-L96 (82 LOC)components/settings/CustomFieldsEditor/CustomFieldForm.tsx
export function CustomFieldForm({
field,
existingNames,
onSave,
onCancel,
}: CustomFieldFormProps) {
const [name, setName] = useState(field ? field.name : '')
const [fieldType, setFieldType] = useState(field ? field.fieldType : 'string')
const [required, setRequired] = useState(field ? field.required : false)
const [defaultValue, setDefaultValue] = useState(
field ? field.defaultValue : ''
)
const [enumValues, setEnumValues] = useState<string[]>(
field ? field.enumValues : []
)
const isValid =
name.trim() &&
!existingNames.includes(name.trim()) &&
(fieldType !== 'enum' || enumValues.length > 0)
const handleSave = () => {
if (!isValid) return
onSave({
name: name.trim(),
fieldType,
required,
defaultValue: defaultValue || '',
enumValues: fieldType === 'enum' ? enumValues : [],
$typeName: 'centy.v1.CustomFieldDefinition',
})
}
const handleRemoveEnumValue = (value: string) => {
setEnumVaCustomFieldsEditor function · typescript · L14-L109 (96 LOC)components/settings/CustomFieldsEditor/CustomFieldsEditor.tsx
export function CustomFieldsEditor({
fields,
onChange,
}: CustomFieldsEditorProps) {
const [editingIndex, setEditingIndex] = useState<number | null>(null)
const [isAdding, setIsAdding] = useState(false)
const handleAdd = (field: CustomFieldDefinition) => {
onChange([...fields, field])
setIsAdding(false)
}
const handleUpdate = (index: number, field: CustomFieldDefinition) => {
const newFields = [...fields]
newFields.splice(index, 1, field)
onChange(newFields)
setEditingIndex(null)
}
const handleRemove = (index: number) => {
onChange(fields.filter((_, i) => i !== index))
}
const handleMoveUp = (index: number) => {
if (index === 0) return
const newFields = [...fields]
const curr = newFields.at(index)
if (curr === undefined) return
newFields.splice(index - 1, 2, curr, newFields[index - 1])
onChange(newFields)
}
const handleMoveDown = (index: number) => {
if (index === fields.length - 1) return
const DefaultValueField function · typescript · L8-L59 (52 LOC)components/settings/CustomFieldsEditor/DefaultValueField.tsx
export function DefaultValueField({
fieldType,
defaultValue,
enumValues,
onChange,
}: DefaultValueFieldProps) {
return (
<div className="custom-field-form-group">
<label className="form-label">Default Value</label>
{fieldType === 'enum' ? (
<select
value={defaultValue}
onChange={e => onChange(e.target.value)}
className="custom-field-form-select"
>
<option className="form-option" value="">
No default
</option>
{enumValues.map(v => (
<option className="form-option" key={v} value={v}>
{v}
</option>
))}
</select>
) : fieldType === 'boolean' ? (
<select
value={defaultValue}
onChange={e => onChange(e.target.value)}
className="custom-field-form-select"
>
<option className="form-option" value="">
No default
</option>
<option classNameEnumValuesEditor function · typescript · L9-L66 (58 LOC)components/settings/CustomFieldsEditor/EnumValuesEditor.tsx
export function EnumValuesEditor({
enumValues,
onAdd,
onRemove,
}: EnumValuesEditorProps) {
const [newEnumValue, setNewEnumValue] = useState('')
const handleAddEnumValue = () => {
const trimmed = newEnumValue.trim()
if (!trimmed || enumValues.includes(trimmed)) return
onAdd(trimmed)
setNewEnumValue('')
}
return (
<div className="custom-field-enum-section">
<label className="form-label">Options</label>
<div className="custom-field-enum-list">
{enumValues.map(value => (
<span key={value} className="custom-field-enum-tag">
{value}
<button
className="custom-field-enum-remove-btn"
type="button"
onClick={() => onRemove(value)}
>
×
</button>
</span>
))}
</div>
<div className="custom-field-enum-add">
<input
type="text"
value={newEnumValue}
onChange={e =>About: code-quality intelligence by Repobility · https://repobility.com
DaemonHelpConnectionSection function · typescript · L1-L41 (41 LOC)components/settings/DaemonSettings/DaemonHelpConnectionSection.tsx
export function DaemonHelpConnectionSection() {
return (
<>
<h4 className="daemon-help-title">
Using the Online App with Local Daemon
</h4>
<p className="daemon-help-text">
To use <code className="inline-code">app.centy.io</code> with a daemon
running on your local machine, you need to:
</p>
<ol className="daemon-help-list">
<li className="daemon-help-list-item">
<strong className="daemon-help-strong">
Start the daemon with CORS enabled:
</strong>
<pre className="daemon-help-pre">
<code className="inline-code">
CENTY_CORS_ORIGINS=https://app.centy.io centy start
</code>
</pre>
<p className="daemon-help-text">
The <code className="inline-code">centy start</code> command will
automatically install the daemon if it is not already installed. You
can also start the daemon directly:
DaemonHelpManagementSection function · typescript · L1-L64 (64 LOC)components/settings/DaemonSettings/DaemonHelpManagementSection.tsx
export function DaemonHelpManagementSection() {
return (
<>
<h4 className="daemon-help-title">Autostart on Boot</h4>
<p className="daemon-help-text">
To have the daemon start automatically when your machine boots:
</p>
<pre className="daemon-help-pre">
<code className="inline-code">centy daemon autostart --enable</code>
</pre>
<p className="daemon-help-text">
Add <code className="inline-code">CENTY_CORS_ORIGINS</code> to your
shell profile (e.g. <code className="inline-code">~/.zshrc</code> or{' '}
<code className="inline-code">~/.bashrc</code>) so that CORS is
configured on every startup:
</p>
<pre className="daemon-help-pre">
<code className="inline-code">
export CENTY_CORS_ORIGINS=https://app.centy.io
</code>
</pre>
<h4 className="daemon-help-title">Exposing Your Local Daemon</h4>
<p className="daemon-help-text">
If you want to acDaemonHelpSection function · typescript · L4-L11 (8 LOC)components/settings/DaemonSettings/DaemonHelpSection.tsx
export function DaemonHelpSection() {
return (
<div className="daemon-help">
<DaemonHelpConnectionSection />
<DaemonHelpManagementSection />
</div>
)
}DaemonSettings function · typescript · L13-L82 (70 LOC)components/settings/DaemonSettings/DaemonSettings.tsx
export function DaemonSettings() {
const initialUrl = useMemo(() => getCurrentDaemonUrl(), [])
const initialIsDefault = useMemo(() => isUsingDefaultDaemonUrl(), [])
const [url, setUrl] = useState(initialUrl)
const [isDefault] = useState(initialIsDefault)
const [showHelp, setShowHelp] = useState(false)
const handleSave = () => {
if (url.trim()) {
setDaemonUrl(url.trim())
}
}
const handleReset = () => {
resetDaemonUrl()
}
const isModified = url !== getCurrentDaemonUrl()
return (
<div className="daemon-settings">
<p className="settings-description">
Configure the URL of your Centy daemon. This allows the web app to
connect to a daemon running on your local machine or a remote server.
</p>
<div className="daemon-url-input">
<label className="form-label" htmlFor="daemon-url">
Daemon URL
</label>
<div className="input-with-button">
<input
className="formAddDefaultRow function · typescript · L24-L70 (47 LOC)components/settings/DefaultsEditor/DefaultsEditor.tsx
function AddDefaultRow({
newKey,
newValue,
availableKeys,
hasExistingKey,
onKeyChange,
onValueChange,
onKeyDown,
onAdd,
}: AddDefaultRowProps) {
return (
<div className="defaults-add-row">
<input
type="text"
value={newKey}
onChange={e => onKeyChange(e.target.value)}
onKeyDown={onKeyDown}
placeholder="Key"
className="defaults-key-input"
list="suggested-keys"
/>
{availableKeys.length > 0 && (
<datalist className="defaults-suggested-keys" id="suggested-keys">
{availableKeys.map(k => (
<option className="defaults-suggested-option" key={k} value={k} />
))}
</datalist>
)}
<input
type="text"
value={newValue}
onChange={e => onValueChange(e.target.value)}
onKeyDown={onKeyDown}
placeholder="Value"
className="defaults-value-input"
/>
<button
type="button"
onClick={onAdDefaultsEditor function · typescript · L72-L141 (70 LOC)components/settings/DefaultsEditor/DefaultsEditor.tsx
export function DefaultsEditor({
value,
onChange,
suggestedKeys,
}: DefaultsEditorProps) {
const resolvedSuggestedKeys = suggestedKeys !== undefined ? suggestedKeys : []
const [newKey, setNewKey] = useState('')
const [newValue, setNewValue] = useState('')
const entries: [string, string][] = Object.entries(value)
const handleAdd = () => {
if (!newKey.trim() || value[newKey.trim()]) return
onChange({
...value,
[newKey.trim()]: newValue,
})
setNewKey('')
setNewValue('')
}
const handleRemove = (key: string) => {
const { [key]: _removed, ...rest } = value
onChange(rest)
}
const handleValueChange = (key: string, newVal: string) => {
onChange({
...value,
[key]: newVal,
})
}
const handleKeyDown = (e: React.KeyboardEvent) => {
if (e.key !== 'Enter') return
e.preventDefault()
handleAdd()
}
const availableKeys = resolvedSuggestedKeys.filter(
k => !Object.hasOwn(value, k)
)
returnDefaultsTable function · typescript · L7-L48 (42 LOC)components/settings/DefaultsEditor/DefaultsTable.tsx
export function DefaultsTable({
entries,
onValueChange,
onRemove,
}: DefaultsTableProps) {
return (
<table className="defaults-table">
<thead className="defaults-thead">
<tr className="defaults-header-row">
<th className="defaults-header-cell">Key</th>
<th className="defaults-header-cell">Value</th>
<th className="defaults-header-cell"></th>
</tr>
</thead>
<tbody className="defaults-tbody">
{entries.map(([key, val]) => (
<tr className="defaults-row" key={key}>
<td className="defaults-key">{key}</td>
<td className="defaults-value-cell">
<input
type="text"
value={val}
onChange={e => onValueChange(key, e.target.value)}
className="defaults-value-input"
/>
</td>
<td className="defaults-action-cell">
<button
type="button"
DaemonInfoSection function · typescript · L16-L100 (85 LOC)components/settings/GeneralSettings/DaemonInfoSection.tsx
export function DaemonInfoSection({
daemonInfo,
restarting,
shuttingDown,
showRestartConfirm,
showShutdownConfirm,
onShowRestartConfirm,
onShowShutdownConfirm,
onRestart,
onShutdown,
}: DaemonInfoSectionProps) {
return (
<section className="settings-section">
<h3 className="settings-section-title">Daemon Information</h3>
<div className="settings-card">
{daemonInfo ? (
<div className="info-grid">
<div className="info-item">
<span className="info-label">Version</span>
<span className="info-value">{daemonInfo.version}</span>
</div>
</div>
) : (
<div className="loading-inline">Loading daemon info...</div>
)}
<div className="daemon-controls">
<button
onClick={() => onShowRestartConfirm(true)}
className="restart-btn"
disabled={restarting}
>
{restarting ? 'Restarting...' : 'ResRepobility · open methodology · https://repobility.com/research/
GeneralSettings function · typescript · L5-L30 (26 LOC)components/settings/GeneralSettings/GeneralSettings.tsx
export function GeneralSettings() {
return (
<div className="settings-page">
<div className="settings-header">
<h2 className="settings-title">General Settings</h2>
</div>
{NEXT_PUBLIC_COMMIT_SHA && (
<section className="settings-section">
<h3 className="settings-section-title">App Information</h3>
<div className="settings-card">
<div className="info-grid">
<div className="info-item">
<span className="info-label">Commit SHA</span>
<span className="info-value commit-sha">
{NEXT_PUBLIC_COMMIT_SHA.slice(0, 7)}
</span>
</div>
</div>
</div>
</section>
)}
</div>
)
}useDaemonActions function · typescript · L14-L92 (79 LOC)components/settings/GeneralSettings/useDaemonActions.ts
export function useDaemonActions() {
const [daemonInfo, setDaemonInfo] = useState<DaemonInfo | null>(null)
const [error, setError] = useState<string | null>(null)
const [success, setSuccess] = useState<string | null>(null)
const [shuttingDown, setShuttingDown] = useState(false)
const [restarting, setRestarting] = useState(false)
const [showShutdownConfirm, setShowShutdownConfirm] = useState(false)
const [showRestartConfirm, setShowRestartConfirm] = useState(false)
const fetchDaemonInfo = useCallback(async () => {
try {
const request = create(GetDaemonInfoRequestSchema, {})
const response = await centyClient.getDaemonInfo(request)
setDaemonInfo(response)
} catch (err) {
console.error('Failed to fetch daemon info:', err)
}
}, [])
const handleShutdown = useCallback(async () => {
setShuttingDown(true)
setError(null)
try {
const request = create(ShutdownRequestSchema, {})
const response = await centyClient.shugetPriorityLabel function · typescript · L21-L31 (11 LOC)components/settings/PriorityEditor.tsx
function getPriorityLabel(level: number, totalLevels: number): string {
if (totalLevels <= 3) {
const labels = ['High', 'Medium', 'Low']
return labels[level - 1] || `P${level}`
}
if (totalLevels === 4) {
const labels = ['Critical', 'High', 'Medium', 'Low']
return labels[level - 1] || `P${level}`
}
return `P${level}`
}cleanupColors function · typescript · L39-L50 (12 LOC)components/settings/PriorityEditor.tsx
function cleanupColors(
colors: Record<string, string>,
newLevels: number
): Record<string, string> {
const newColors: Record<string, string> = {}
for (let i = 1; i <= newLevels; i++) {
if (colors[String(i)]) {
newColors[String(i)] = colors[String(i)]
}
}
return newColors
}PriorityItem function · typescript · L59-L76 (18 LOC)components/settings/PriorityEditor.tsx
function PriorityItem({
level,
totalLevels,
color,
onColorChange,
}: PriorityItemProps) {
return (
<div className="priority-item">
<div className="priority-preview" style={{ backgroundColor: color }}>
{getPriorityLabel(level, totalLevels)}
</div>
<span className="priority-level-label">Priority {level}</span>
<ColorPicker value={color} onChange={onColorChange} />
</div>
)
}PriorityEditor function · typescript · L78-L136 (59 LOC)components/settings/PriorityEditor.tsx
export function PriorityEditor({
levels,
colors,
onLevelsChange,
onColorsChange,
}: PriorityEditorProps) {
const handleColorChange = (level: number, color: string) => {
onColorsChange({
...colors,
[String(level)]: color,
})
}
const handleLevelsChange = (newLevels: number) => {
onLevelsChange(newLevels)
onColorsChange(cleanupColors(colors, newLevels))
}
const priorityLevels = Array.from({ length: levels }, (_, i) => i + 1)
return (
<div className="priority-editor">
<div className="priority-levels-selector">
<label className="form-label" htmlFor="priority-levels">
Number of priority levels:
</label>
<select
id="priority-levels"
value={levels}
onChange={e => handleLevelsChange(Number(e.target.value))}
className="priority-levels-select"
>
{[1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(n => (
<option className="form-option" key={n} value=OrgSection function · typescript · L16-L59 (44 LOC)components/settings/ProjectConfig/OrgSection.tsx
export function OrgSection({
organizations,
projectOrgSlug,
savingOrg,
onOrgChange,
}: OrgSectionProps) {
return (
<section className="settings-section">
<h3 className="settings-section-title">Organization</h3>
<div className="settings-card">
<div className="form-group">
<label className="form-label" htmlFor="project-org">
Assign to Organization
</label>
<div className="org-select-row">
<select
id="project-org"
value={projectOrgSlug}
onChange={e => onOrgChange(e.target.value)}
disabled={savingOrg}
className="org-select"
>
<option className="form-option" value="">
No Organization (Ungrouped)
</option>
{organizations.map(org => (
<option className="form-option" key={org.slug} value={org.slug}>
{org.name}
</option>
ProjectConfig function · typescript · L17-L106 (90 LOC)components/settings/ProjectConfig/ProjectConfig.tsx
export function ProjectConfig() {
const { projectPath, isInitialized } = usePathContext()
const { organizations, refreshOrganizations } = useOrganization()
const data = useProjectConfigData(projectPath, isInitialized)
const org = useProjectOrg(
projectPath,
refreshOrganizations,
data.setError,
data.setSuccess
)
const { doFetchProjectData } = data
const { fetchProjectOrg } = org
useEffect(() => {
if (isInitialized !== true) return
doFetchProjectData()
fetchProjectOrg()
}, [isInitialized, doFetchProjectData, fetchProjectOrg])
return (
<div className="settings-page">
<div className="settings-header">
<h2 className="settings-title">Project Configuration</h2>
{data.isDirty && (
<span className="unsaved-indicator">Unsaved changes</span>
)}
</div>
{data.error && <DaemonErrorMessage error={data.error} />}
{data.success && <div className="success-message">{data.success}</div>}
Repobility · code-quality intelligence platform · https://repobility.com
useProjectConfigData function · typescript · L9-L84 (76 LOC)components/settings/ProjectConfig/useProjectConfigData.ts
export function useProjectConfigData(
projectPath: string,
isInitialized: boolean | null
) {
const [config, setConfig] = useState<Config | null>(null)
const [originalConfig, setOriginalConfig] = useState<Config | null>(null)
const [manifest, setManifest] = useState<Manifest | null>(null)
const [loading, setLoading] = useState(false)
const [saving, setSaving] = useState(false)
const [error, setError] = useState<string | null>(null)
const [success, setSuccess] = useState<string | null>(null)
const isDirty =
config && originalConfig
? JSON.stringify(config) !== JSON.stringify(originalConfig)
: false
useEffect(() => {
const handleBeforeUnload = (e: BeforeUnloadEvent) => {
if (!isDirty) return
e.preventDefault()
e.returnValue = ''
}
window.addEventListener('beforeunload', handleBeforeUnload)
return () => window.removeEventListener('beforeunload', handleBeforeUnload)
}, [isDirty])
const doFetchProjectData = useCaluseProjectOrg function · typescript · L11-L75 (65 LOC)components/settings/ProjectConfig/useProjectOrg.ts
export function useProjectOrg(
projectPath: string,
refreshOrganizations: () => void,
setError: (e: string | null) => void,
setSuccess: (s: string | null) => void
) {
const [projectOrgSlug, setProjectOrgSlug] = useState<string>('')
const [savingOrg, setSavingOrg] = useState(false)
const fetchProjectOrg = useCallback(async () => {
if (!projectPath.trim()) return
try {
const request = create(GetProjectInfoRequestSchema, {
projectPath: projectPath.trim(),
})
const response = await centyClient.getProjectInfo(request)
if (response.found && response.project) {
setProjectOrgSlug(response.project.organizationSlug || '')
}
} catch (err) {
console.error('Failed to fetch project organization:', err)
}
}, [projectPath])
const handleOrgChange = useCallback(
async (newOrgSlug: string) => {
if (!projectPath.trim()) return
setSavingOrg(true)
setError(null)
setSuccess(null)
try {
clearTitle function · typescript · L10-L49 (40 LOC)components/settings/ProjectTitleEditor/clearTitle.ts
export async function clearTitle(
projectPath: string,
scope: TitleScope
): Promise<TitleActionResult> {
if (scope === 'user') {
const request = create(SetProjectUserTitleRequestSchema, {
projectPath,
title: '',
})
const response = await centyClient.setProjectUserTitle(request)
if (!response.success) {
return {
success: false,
error: response.error || 'Failed to clear user title',
}
}
return {
success: true,
project: response.project || undefined,
message: 'User title cleared',
}
}
const request = create(SetProjectTitleRequestSchema, {
projectPath,
title: '',
})
const response = await centyClient.setProjectTitle(request)
if (!response.success) {
return {
success: false,
error: response.error || 'Failed to clear project title',
}
}
return {
success: true,
project: response.project || undefined,
message: 'Project title cleared',
}
}ProjectTitleEditor function · typescript · L13-L98 (86 LOC)components/settings/ProjectTitleEditor/ProjectTitleEditor.tsx
export function ProjectTitleEditor({ projectPath }: ProjectTitleEditorProps) {
const {
projectInfo,
scope,
setScope,
saving,
error,
success,
currentTitle,
setCurrentTitle,
hasChanges,
handleSave,
handleClear,
} = useProjectTitle(projectPath)
if (!projectInfo) {
return <div className="title-loading">Loading project info...</div>
}
return (
<div className="project-title-editor">
<div className="title-scope-selector">
<span className="title-scope-label">Title Scope:</span>
<div className="title-scope-buttons">
<button
type="button"
onClick={() => setScope('user')}
className={`title-scope-btn ${scope === 'user' ? 'active' : ''}`}
>
User (local)
</button>
<button
type="button"
onClick={() => setScope('project')}
className={`title-scope-btn ${scope === 'project' ? 'active' : ''}`}
saveTitle function · typescript · L10-L51 (42 LOC)components/settings/ProjectTitleEditor/saveTitle.ts
export async function saveTitle(
projectPath: string,
scope: TitleScope,
userTitle: string,
projectTitle: string
): Promise<TitleActionResult> {
if (scope === 'user') {
const request = create(SetProjectUserTitleRequestSchema, {
projectPath,
title: userTitle,
})
const response = await centyClient.setProjectUserTitle(request)
if (!response.success) {
return {
success: false,
error: response.error || 'Failed to save user title',
}
}
return {
success: true,
project: response.project || undefined,
message: 'User title saved successfully',
}
}
const request = create(SetProjectTitleRequestSchema, {
projectPath,
title: projectTitle,
})
const response = await centyClient.setProjectTitle(request)
if (!response.success) {
return {
success: false,
error: response.error || 'Failed to save project title',
}
}
return {
success: true,
project: response.projTitlePreview function · typescript · L7-L30 (24 LOC)components/settings/ProjectTitleEditor/TitlePreview.tsx
export function TitlePreview({ projectInfo }: TitlePreviewProps) {
return (
<div className="title-preview">
<h4 className="title-preview-label">Current Display Name</h4>
<p className="title-preview-value">
<strong className="title-preview-strong">
{projectInfo.userTitle ||
projectInfo.projectTitle ||
projectInfo.name ||
'Unnamed Project'}
</strong>
<span className="title-source">
(
{projectInfo.userTitle
? 'user title'
: projectInfo.projectTitle
? 'project title'
: 'directory name'}
)
</span>
</p>
</div>
)
}useProjectTitle function · typescript · L14-L101 (88 LOC)components/settings/ProjectTitleEditor/useProjectTitle.ts
export function useProjectTitle(projectPath: string) {
const [projectInfo, setProjectInfo] = useState<ProjectInfo | null>(null)
const [userTitle, setUserTitle] = useState('')
const [projectTitle, setProjectTitle] = useState('')
const [scope, setScope] = useState<TitleScope>('user')
const [saving, setSaving] = useState(false)
const [error, setError] = useState<string | null>(null)
const [success, setSuccess] = useState<string | null>(null)
useEffect(() => {
if (!projectPath) return
const fetchProjectInfo = async () => {
try {
const request = create(ListProjectsRequestSchema, {})
const response = await centyClient.listProjects(request)
const project = response.projects.find(p => p.path === projectPath)
if (project) {
updateFromResponse(project)
}
} catch (err) {
console.error('Failed to fetch project info:', err)
}
}
fetchProjectInfo()
}, [projectPath])
const updateFromResponcheckProjectInitialized function · typescript · L5-L18 (14 LOC)components/settings/Settings/checkProjectInitialized.ts
export async function checkProjectInitialized(
path: string
): Promise<boolean | null> {
if (!path.trim()) return null
try {
const request = create(IsInitializedRequestSchema, {
projectPath: path.trim(),
})
const response = await centyClient.isInitialized(request)
return response.initialized
} catch {
return false
}
}Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
ConfigSections function · typescript · L18-L65 (48 LOC)components/settings/Settings/ConfigSections.tsx
export function ConfigSections({
config,
saving,
isDirty,
updateConfig,
onSave,
onReset,
}: ConfigSectionsProps) {
const formValue: Record<string, unknown> = {}
Object.assign(formValue, config)
const handleChange = (updates: Record<string, unknown>) => {
const configUpdate: Partial<Config> = {}
Object.assign(configUpdate, updates)
updateConfig(configUpdate)
}
return (
<>
<ProtoFormRenderer
schema={ConfigSchema}
value={formValue}
onChange={handleChange}
fieldGroups={CONFIG_FIELD_GROUPS}
fieldOverrides={CONFIG_FIELD_OVERRIDES}
/>
<div className="settings-actions">
<button
type="button"
onClick={onReset}
disabled={!isDirty || saving}
className="reset-btn"
>
Reset Changes
</button>
<button
type="button"
onClick={onSave}
disabled={!isDirty || saving}
className="save-btn"
fetchProjectData function · typescript · L16-L41 (26 LOC)components/settings/Settings/fetchProjectData.ts
export async function fetchProjectData(
projectPath: string
): Promise<FetchResult> {
const result: FetchResult = {}
const configRequest = create(GetConfigRequestSchema, {
projectPath: projectPath.trim(),
})
const configResponse = await centyClient.getConfig(configRequest)
if (configResponse.config) {
result.config = configResponse.config
} else {
result.error = configResponse.error || 'Failed to load configuration'
return result
}
const manifestRequest = create(GetManifestRequestSchema, {
projectPath: projectPath.trim(),
})
const manifestResponse = await centyClient.getManifest(manifestRequest)
if (manifestResponse.manifest) {
result.manifest = manifestResponse.manifest
}
return result
}ManifestSection function · typescript · L7-L45 (39 LOC)components/settings/Settings/ManifestSection.tsx
export function ManifestSection({ manifest }: ManifestSectionProps) {
if (!manifest) return null
return (
<section className="settings-section">
<h3 className="settings-section-title">Manifest</h3>
<div className="settings-card">
<div className="manifest-details">
<div className="info-grid">
<div className="info-item">
<span className="info-label">Schema Version</span>
<span className="info-value">{manifest.schemaVersion}</span>
</div>
<div className="info-item">
<span className="info-label">Centy Version</span>
<span className="info-value">{manifest.centyVersion}</span>
</div>
<div className="info-item">
<span className="info-label">Created</span>
<span className="info-value">
{manifest.createdAt
? new Date(manifest.createdAt).toLocaleString()
: '-'}