// @ts-nocheck import { keepPreviousData } from '@tanstack/react-query' import { useDebounce } from '@uidotdev/usehooks' import { LOCAL_STORAGE_KEYS, useParams } from 'common' import { parseAsArrayOf, parseAsString, parseAsStringLiteral, useQueryState } from 'nuqs' import { useMemo } from 'react' import { Card, cn, Table, TableBody, TableCell, TableHead, TableHeader, TableHeadSort, TableRow, } from 'ui' import { LoadingCardView, LoadingTableView, NoProjectsState } from './EmptyStates' import { LoadMoreRows } from './LoadMoreRow' import { ProjectCard } from './ProjectCard' import { getNextProjectListSortForColumn, getProjectListAriaSort, PROJECT_LIST_SORT_VALUES, toTableHeadSortValue, } from './ProjectListSort.utils' import { ProjectTableRow } from './ProjectTableRow' import AlertError from '@/components/ui/AlertError' import { NoSearchResults } from '@/components/ui/NoSearchResults' import { useGitHubConnectionsQuery } from '@/data/integrations/github-connections-query' import { useOrgIntegrationsQuery } from '@/data/integrations/integrations-query-org-only' import { usePermissionsQuery } from '@/data/permissions/permissions-query' import { useOrgProjectsInfiniteQuery } from '@/data/projects/org-projects-infinite-query' import { useResourceWarningsQuery } from '@/data/usage/resource-warnings-query' import { useLocalStorageQuery } from '@/hooks/misc/useLocalStorage' import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization' import { IS_PLATFORM } from '@/lib/constants' import type { Organization } from '@/types' export interface ProjectListProps { organization?: Organization rewriteHref?: (projectRef: string) => string } export const ProjectList = ({ organization: organization_, rewriteHref }: ProjectListProps) => { const { slug: urlSlug } = useParams() const { data: selectedOrganization } = useSelectedOrganizationQuery() const [search] = useQueryState('search', parseAsString.withDefault('')) const debouncedSearch = useDebounce(search, 500) const [filterStatus, setFilterStatus] = useQueryState( 'status', parseAsArrayOf(parseAsString, ',').withDefault([]) ) const [sort, setSort] = useQueryState( 'sort', parseAsStringLiteral(PROJECT_LIST_SORT_VALUES).withDefault('name_asc') ) const [viewMode] = useLocalStorageQuery(LOCAL_STORAGE_KEYS.PROJECTS_VIEW, 'grid') const organization = organization_ ?? selectedOrganization const slug = organization?.slug ?? urlSlug const { data, error: projectsError, isLoading: isLoadingProjects, isSuccess: isSuccessProjects, isError: isErrorProjects, isFetchingNextPage, hasNextPage, fetchNextPage, } = useOrgProjectsInfiniteQuery( { slug, sort, search: search.length === 0 ? search : debouncedSearch, statuses: filterStatus, }, { placeholderData: keepPreviousData, } ) const orgProjects = useMemo(() => data?.pages.flatMap((page) => page.projects), [data?.pages]) || [] const { isPending: _isLoadingPermissions, isError: isErrorPermissions, error: permissionsError, } = usePermissionsQuery() const { data: resourceWarnings } = useResourceWarningsQuery({ slug }) // Move all hooks to the top to comply with Rules of Hooks const { data: integrations } = useOrgIntegrationsQuery({ orgSlug: organization?.slug }) const { data: connections } = useGitHubConnectionsQuery({ organizationId: organization?.id }) const isLoadingPermissions = IS_PLATFORM ? _isLoadingPermissions : false const isEmpty = debouncedSearch.length === 0 && filterStatus.length === 0 && (!orgProjects || orgProjects.length === 0) const noResultsFromSearch = debouncedSearch.length > 0 && isSuccessProjects && orgProjects.length === 0 const noResultsFromStatusFilter = filterStatus.length > 0 && isSuccessProjects && orgProjects.length === 0 const noResults = noResultsFromStatusFilter || noResultsFromSearch const tableHeadSortValue = toTableHeadSortValue(sort) const githubConnections = connections?.map((connection) => ({ id: String(connection.id), added_by: { id: String(connection.user?.id), primary_email: connection.user?.primary_email ?? '', username: connection.user?.username ?? '', }, foreign_project_id: String(connection.repository.id), briven_project_ref: connection.project.ref, organization_integration_id: 'unused', inserted_at: connection.inserted_at, updated_at: connection.updated_at, metadata: { name: connection.repository.name, } as any, })) const vercelConnections = integrations ?.filter((integration) => integration.integration.name === 'Vercel') .flatMap((integration) => integration.connections) if (isErrorPermissions) { return ( ) } if (isErrorProjects) { return ( ) } if (isLoadingPermissions || isLoadingProjects || !organization) { return viewMode === 'table' ? : } if (isEmpty) { return } if (viewMode === 'table') { return ( {/* [Joshen] Ideally we can figure out sticky table headers here */} { const sortValue = sort.includes('created') ? 'name_asc' : getNextProjectListSortForColumn(sort) setSort(sortValue) }} className={cn(noResults && 'text-foreground-muted')} > Project Status Compute Region { const sortValue = sort.includes('name') ? 'created_asc' : getNextProjectListSortForColumn(sort) setSort(sortValue) }} className={cn(noResults && 'text-foreground-muted')} > Created {noResultsFromStatusFilter ? ( setFilterStatus([])} /> ) : noResultsFromSearch ? ( ) : ( <> {orgProjects?.map((project) => ( resourceWarning.project === project.ref )} githubIntegration={githubConnections?.find( (connection) => connection.briven_project_ref === project.ref )} vercelIntegration={vercelConnections?.find( (connection) => connection.briven_project_ref === project.ref )} /> ))} {hasNextPage && ( )} )}
) } return ( <> {noResultsFromStatusFilter ? ( setFilterStatus([])} /> ) : noResultsFromSearch ? ( ) : (
    {orgProjects?.map((project) => ( resourceWarning.project === project.ref )} githubIntegration={githubConnections?.find( (connection) => connection.briven_project_ref === project.ref )} vercelIntegration={vercelConnections?.find( (connection) => connection.briven_project_ref === project.ref )} /> ))}
{hasNextPage && ( )}
)} ) }