← back to centy-io__centy-app

Function bodies 471 total

All specs Real LLM only Function bodies
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 buildPendingConte
ProjectProvider 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) => {
    setArchivedPathsS
ProvidersWithSuspense 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 proj
resolve 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, pathSegme
resolveSubRoute 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 (pageTyp
resolveRoute 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

  re
Provenance: 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"
          >
            &uarr;
          </button>
          <button
            type="button"
            onClick={onMoveDown}
            disabled={index === totalCount - 1}
            className="custom-field-move-btn"
            title="Move down"
          >
            &darr;
          </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) => {
    setEnumVa
CustomFieldsEditor 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 className
EnumValuesEditor 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)}
            >
              &times;
            </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 ac
DaemonHelpSection 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="form
AddDefaultRow 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={onAd
DefaultsEditor 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)
  )

  return
DefaultsTable 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...' : 'Res
Repobility · 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.shu
getPriorityLabel 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 = useCal
useProjectOrg 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.proj
TitlePreview 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 updateFromRespon
checkProjectInitialized 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()
                  : '-'}
   
‹ prevpage 5 / 10next ›