diff --git a/src/app/app/documentation/glossary/cell-type/e-type/[slug]/page.tsx b/src/app/app/documentation/glossary/cell-type/e-type/[slug]/page.tsx index c6695ddf7..451fe0f55 100644 --- a/src/app/app/documentation/glossary/cell-type/e-type/[slug]/page.tsx +++ b/src/app/app/documentation/glossary/cell-type/e-type/[slug]/page.tsx @@ -4,7 +4,7 @@ import { useParams } from 'next/navigation'; import { useCallback, useState } from 'react'; import { useFetchSingleType } from '@/components/documentation/hooks/use-entitycore-fetch-single-type'; -import { CopyIcon } from '@/components/explore-section/Circuit/icon/ArticlesIcons'; +import { CopyIcon } from '@/components/icons/ArticlesIcons'; import { unslugify } from '@/components/explore-section/utils'; export type CopyButtonProps = { diff --git a/src/app/app/documentation/glossary/cell-type/m-type/[slug]/page.tsx b/src/app/app/documentation/glossary/cell-type/m-type/[slug]/page.tsx index 655516939..b24ab544a 100644 --- a/src/app/app/documentation/glossary/cell-type/m-type/[slug]/page.tsx +++ b/src/app/app/documentation/glossary/cell-type/m-type/[slug]/page.tsx @@ -4,7 +4,7 @@ import { useParams } from 'next/navigation'; import { useCallback, useState } from 'react'; import { useFetchSingleType } from '@/components/documentation/hooks/use-entitycore-fetch-single-type'; -import { CopyIcon } from '@/components/explore-section/Circuit/icon/ArticlesIcons'; +import { CopyIcon } from '@/components/icons/ArticlesIcons'; import { unslugify } from '@/components/explore-section/utils'; export type CopyButtonProps = { diff --git a/src/app/app/virtual-lab/(free)/explore/(interactive)/interactive/(data)/model/circuit/[id]/page.tsx b/src/app/app/virtual-lab/(free)/explore/(interactive)/interactive/(data)/model/circuit/[id]/page.tsx deleted file mode 100644 index 25c366254..000000000 --- a/src/app/app/virtual-lab/(free)/explore/(interactive)/interactive/(data)/model/circuit/[id]/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import CircuitDetails from '@/components/explore-section/Circuit/DetailView/main-detail-view-core'; - -export default function CircuitDetailPage() { - return ; -} diff --git a/src/app/app/virtual-lab/(free)/explore/(interactive)/interactive/(data)/model/circuit/layout.tsx b/src/app/app/virtual-lab/(free)/explore/(interactive)/interactive/(data)/model/circuit/layout.tsx deleted file mode 100644 index 820d267b1..000000000 --- a/src/app/app/virtual-lab/(free)/explore/(interactive)/interactive/(data)/model/circuit/layout.tsx +++ /dev/null @@ -1,22 +0,0 @@ -'use client'; - -import { useParams } from 'next/navigation'; -import { ReactNode } from 'react'; -import { ErrorBoundary } from 'react-error-boundary'; - -import SimpleErrorComponent from '@/components/GenericErrorFallback'; - -export default function ExploreCircuitListingView({ children }: { children: ReactNode }) { - const params = useParams(); - - if (params?.id) - return {children}; - - return ( -
- -
{children}
-
-
- ); -} diff --git a/src/app/app/virtual-lab/(free)/explore/(interactive)/interactive/(data)/model/circuit/page.tsx b/src/app/app/virtual-lab/(free)/explore/(interactive)/interactive/(data)/model/circuit/page.tsx deleted file mode 100644 index f89724c80..000000000 --- a/src/app/app/virtual-lab/(free)/explore/(interactive)/interactive/(data)/model/circuit/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import CircuitsListingPageComponent from '@/components/explore-section/Circuit/global/circuits-listing-page-component'; - -export default function ExploreModelCircuitListingPage() { - return ; -} diff --git a/src/app/app/virtual-lab/lab/[virtualLabId]/project/[projectId]/explore/interactive/(data)/model/circuit/[id]/page.tsx b/src/app/app/virtual-lab/lab/[virtualLabId]/project/[projectId]/explore/interactive/(data)/model/circuit/[id]/page.tsx deleted file mode 100644 index 25c366254..000000000 --- a/src/app/app/virtual-lab/lab/[virtualLabId]/project/[projectId]/explore/interactive/(data)/model/circuit/[id]/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import CircuitDetails from '@/components/explore-section/Circuit/DetailView/main-detail-view-core'; - -export default function CircuitDetailPage() { - return ; -} diff --git a/src/app/app/virtual-lab/lab/[virtualLabId]/project/[projectId]/explore/interactive/(data)/model/circuit/layout.tsx b/src/app/app/virtual-lab/lab/[virtualLabId]/project/[projectId]/explore/interactive/(data)/model/circuit/layout.tsx deleted file mode 100644 index e7aaeda88..000000000 --- a/src/app/app/virtual-lab/lab/[virtualLabId]/project/[projectId]/explore/interactive/(data)/model/circuit/layout.tsx +++ /dev/null @@ -1,22 +0,0 @@ -'use client'; - -import { useParams } from 'next/navigation'; -import { ReactNode } from 'react'; -import { ErrorBoundary } from 'react-error-boundary'; - -import SimpleErrorComponent from '@/components/GenericErrorFallback'; - -export default function ExploreCircuitListingView({ children }: { children: ReactNode }) { - const params = useParams(); - - if (params?.id) - return {children}; - - return ( -
- -
{children}
-
-
- ); -} diff --git a/src/app/app/virtual-lab/lab/[virtualLabId]/project/[projectId]/explore/interactive/(data)/model/circuit/page.tsx b/src/app/app/virtual-lab/lab/[virtualLabId]/project/[projectId]/explore/interactive/(data)/model/circuit/page.tsx deleted file mode 100644 index f89724c80..000000000 --- a/src/app/app/virtual-lab/lab/[virtualLabId]/project/[projectId]/explore/interactive/(data)/model/circuit/page.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import CircuitsListingPageComponent from '@/components/explore-section/Circuit/global/circuits-listing-page-component'; - -export default function ExploreModelCircuitListingPage() { - return ; -} diff --git a/src/components/CentralLoadingWheel/index.tsx b/src/components/CentralLoadingWheel/index.tsx deleted file mode 100644 index 9a1c3fdf1..000000000 --- a/src/components/CentralLoadingWheel/index.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import { CSSProperties, ReactNode } from 'react'; -import LoadingWheel from '@/components/icons/LoadingWheel'; -import GreyRing from '@/components/icons/LoadingWheel/GreyRing'; - -interface Props { - style?: CSSProperties; - text?: string | ReactNode; - noResults?: boolean; -} - -function CentralLoadingWheel({ - style = { display: 'table', width: '100%', height: '100vh' }, - text = '', - noResults = false, -}: Props) { - const IconComponent = noResults ? GreyRing : LoadingWheel; - - return ( -
-
- - {text && ( -
- {text} -
- )} -
-
- ); -} - -export default CentralLoadingWheel; diff --git a/src/components/ListTable/index.tsx b/src/components/ListTable/index.tsx deleted file mode 100644 index ccdebd467..000000000 --- a/src/components/ListTable/index.tsx +++ /dev/null @@ -1,224 +0,0 @@ -'use client'; - -import { CSSProperties, HTMLProps, ReactNode, useState } from 'react'; -import { ConfigProvider, Table, TableProps, Tooltip } from 'antd'; - -import { isNumeric, to64 } from '@/util/common'; -import usePathname from '@/hooks/pathname'; -import { BrainIcon, InteractiveViewIcon, VirtualLabIcon } from '@/components/icons'; -import { classNames } from '@/util/utils'; -import Link from '@/components/Link'; -import useResizeObserver from '@/hooks/useResizeObserver'; - -import styles from '@/components/ListTable/list-table.module.css'; - -type Column = { - dataIndex: string | string[]; - label: string; - key: string; - render?: (text: string, record: any, index: number) => ReactNode; -}; - -function ColumnContent(text: string) { - return isNumeric(text) ? ( - text - ) : ( - {JSON.stringify(text)} - ); -} - -function formatColumn({ render, ...rest }: Column) { - return { - render: render || ColumnContent, - ...rest, - }; -} - -function CustomTable({ children, style, ...props }: { children: ReactNode; style: CSSProperties }) { - return ( - - {children} -
- ); -} - -function CustomTH({ - children, - handleResizing, // Removes unwanted prop from props - style, - ...props -}: { - children: ReactNode; - handleResizing: () => void; - style: CSSProperties; -}) { - return ( - - {children} - - ); -} - -function CustomTD({ - children, - className, - style, - ...props -}: { - className: string; - children: ReactNode; - style: CSSProperties; -}) { - return ( - - {children} - - ); -} - -function LinkWrapper({ children, href, title }: HTMLProps) { - return ( - - - - {children} - - - - ); -} - -export function IndexColContent({ - id, - project, - text, -}: { - id: string; - project: string; - text: string; -}) { - const pathname = usePathname(); - - return ( -
- - {text} - -
- Open in -
- {[ - { - children: , - href: `${pathname}/${to64(`${project}!/!${id}`)}/experiment-interactive`, - title: 'Interactive View', - }, - { - children: , - href: `/app/build/cell-composition/interactive?brainModelConfigId=${id}`, - title: 'View brain configuration', - }, - { - children: , - href: `/app/experiment-designer/experiment-setup?simulationCampaignUIConfigId=${id}`, - title: 'View experiment configuration', - }, - ].map( - ({ children, href, title }) => - href && ( - - {children} - - ) - )} -
-
-
- ); -} - -export function ValueArray({ value }: { value?: string[] }) { - return value ? ( -
- {value.map((x, i, arr) => ( - {i < arr.length - 1 ? `${x},` : x} - ))} -
- ) : null; -} - -export default function ListTable({ columns, dataSource, loading }: TableProps) { - const [containerDimension, setContainerDimension] = useState<{ height: number; width: number }>({ - height: 0, - width: 0, - }); - - useResizeObserver({ - element: document.getElementById('simulation-campaigns-layout'), - callback: (target) => setContainerDimension(target.getBoundingClientRect()), - }); - - return ( - - row._source._self} - tableLayout="fixed" - scroll={{ y: containerDimension.height - 120 }} - /> - - ); -} diff --git a/src/components/ListTable/list-table.module.css b/src/components/ListTable/list-table.module.css deleted file mode 100644 index 8b7e9a111..000000000 --- a/src/components/ListTable/list-table.module.css +++ /dev/null @@ -1,11 +0,0 @@ -.customTD { - &:first-child { - border-radius: 0.375rem 0 0 0.375rem; - border-style: solid none solid solid !important; - } - - &:last-child { - border-radius: 0 0.375rem 0.375rem 0; - border-style: solid solid solid none !important; - } -} diff --git a/src/components/documentation/glossary/cell-types/all-types-block.tsx b/src/components/documentation/glossary/cell-types/all-types-block.tsx index 613850623..edff1b296 100644 --- a/src/components/documentation/glossary/cell-types/all-types-block.tsx +++ b/src/components/documentation/glossary/cell-types/all-types-block.tsx @@ -4,14 +4,15 @@ import { useEffect, useState } from 'react'; import AlphabeticalFilter from '@/components/documentation/global/AlphabeticalFilter'; // Adjust path if needed based on your project structure import { useFetchEntityTypes } from '@/components/documentation/hooks/use-entitycore-cell_type-for-glossary'; -import { CellTypeProps } from '@/components/explore-section/Circuit/type'; import { slugifyForUrl } from '@/components/explore-section/utils'; import { classNames } from '@/util/utils'; +import type { IAnnotation } from '@/api/entitycore/types/shared/global'; + import styles from './all-types-block.module.css'; interface SectionItemProps { - item: CellTypeProps; + item: IAnnotation; index: number; highlightedCellType: string | null; } @@ -49,11 +50,11 @@ export default function AllTypesBlock({ const cellcontent = useFetchEntityTypes({ cellType }); - const data: CellTypeProps[] = (cellcontent.data?.data ?? []).map((item: any) => ({ + const data: IAnnotation[] = (cellcontent.data?.data ?? []).map((item: any) => ({ ...item, creation_date: item.creation_date ?? '', update_date: item.update_date ?? '', - })) as CellTypeProps[]; + })) as IAnnotation[]; const sortedData = data.sort((a, b) => a.pref_label.localeCompare(b.pref_label)); diff --git a/src/components/entities-type-stats/panel.tsx b/src/components/entities-type-stats/panel.tsx index f88142c11..fff0010dc 100644 --- a/src/components/entities-type-stats/panel.tsx +++ b/src/components/entities-type-stats/panel.tsx @@ -7,7 +7,6 @@ import { match } from 'ts-pattern'; import get from 'lodash/get'; import { dataTabAtom } from '@/components/explore-section/ExploreInteractive/interactive/entity-group-tab'; -import { useFilteredCircuits } from '@/components/explore-section/Circuit/ListView/ExploreCircuitTable'; import { useBrainRegionHierarchy } from '@/features/brain-region-hierarchy/context'; import { EntityTypeCount } from '@/components/entities-type-stats/stat-item'; import { entitiesCountAtom } from '@/services/entitycore/entities-count'; @@ -44,7 +43,6 @@ function isEntityTypeCountProps(p: StatsPanelProps): p is EntityTypeCountProps { function EntityTypeStats(props: StatsPanelProps) { const pathName = usePathname(); const selectedTab = useAtomValue(dataTabAtom); - const { error: circuitError, filteredCircuits } = useFilteredCircuits({ dataKey: props.dataKey }); let data: EntityCountResponse | null = null; let error: Error | null = null; @@ -114,15 +112,6 @@ function EntityTypeStats(props: StatsPanelProps) { /> ); })} - )) .otherwise(() => null); diff --git a/src/components/explore-section/Circuit/DetailView/global/ListParameterBox.tsx b/src/components/explore-section/Circuit/DetailView/global/ListParameterBox.tsx deleted file mode 100644 index 85e464d63..000000000 --- a/src/components/explore-section/Circuit/DetailView/global/ListParameterBox.tsx +++ /dev/null @@ -1,136 +0,0 @@ -import { useState } from 'react'; -import { ContributorsProps } from '../../type'; - -import { CloseIcon } from '@/components/icons'; - -function SingleContributorPill({ name, lastName }: { name: string; lastName: string }) { - return ( -
- - {name} {lastName} - -
- ); -} - -export default function ListParameterBox({ - name, - value, - slice = 5, -}: { - name: string; - value: ContributorsProps[] | string[] | string; - slice?: number; -}) { - const [viewMore, setViewMore] = useState(false); - - let normalizedValue: ContributorsProps[] | string[]; - if (typeof value === 'string') { - try { - normalizedValue = JSON.parse(value); - if (!Array.isArray(normalizedValue)) { - return ( -
-
{name}
-
Error: Invalid data format
-
- ); - } - } catch (error) { - return ( -
-
{name}
-
Error: Invalid data format
-
- ); - } - } else if (Array.isArray(value)) { - normalizedValue = value; - } else { - return ( -
-
{name}
-
Error: Invalid data provided
-
- ); - } - - const slicedContent = normalizedValue.slice(0, slice); - - return ( -
-
{name}
- -
- {slicedContent.map((item: ContributorsProps | string) => { - if (typeof item === 'string') { - return ( - - {item} - - ); - } - return ( - - ); - })} -
- - {normalizedValue.length > slice && ( - - )} - - {viewMore && ( -
-
-
-
{name}
- -
-
- {normalizedValue.map((item: ContributorsProps | string) => { - if (typeof item === 'string') { - return ( - - {item}. - - ); - } - return ( - - ); - })} -
-
-
- )} -
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/global/ParameterBox.tsx b/src/components/explore-section/Circuit/DetailView/global/ParameterBox.tsx deleted file mode 100644 index 41e332e49..000000000 --- a/src/components/explore-section/Circuit/DetailView/global/ParameterBox.tsx +++ /dev/null @@ -1,88 +0,0 @@ -'use client'; - -import Link from 'next/link'; -import type { DetailedHTMLProps, HTMLAttributes } from 'react'; -import { useState } from 'react'; -import ReactMarkdown from 'react-markdown'; - -import { CloseIcon } from '@/components/icons'; - -function MarkdownParagraph( - props: DetailedHTMLProps, HTMLParagraphElement> -) { - const { children, className } = props; - return

{children}

; -} - -export default function ParameterBox({ - name, - value, - link, - hasViewMore = false, -}: { - name: string; - value: string | number; - link?: string; - hasViewMore?: boolean; -}) { - const [viewMore, setViewMore] = useState(false); - - return ( -
-
{name}
- {link && ( - - {value} - - )} - {!link && hasViewMore && ( -
-

- {value} -

- -
- )} - {!link && !hasViewMore && ( -
- - {String(value)} - -
- )} - - {viewMore && ( -
-
-
-
{name}
- -
-

{value}

-
-
- )} -
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/header-detail-view.tsx b/src/components/explore-section/Circuit/DetailView/header-detail-view.tsx deleted file mode 100644 index ebcfb9d84..000000000 --- a/src/components/explore-section/Circuit/DetailView/header-detail-view.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { CircuitSchemaProps } from '../type'; -import CircuitData from './header/circuit-data'; -import Heading from './header/Heading'; - -export default function HeaderDetailView({ content }: { content: CircuitSchemaProps }) { - return ( -
- - -
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/header/Heading.tsx b/src/components/explore-section/Circuit/DetailView/header/Heading.tsx deleted file mode 100644 index 17c92c2ae..000000000 --- a/src/components/explore-section/Circuit/DetailView/header/Heading.tsx +++ /dev/null @@ -1,140 +0,0 @@ -'use client'; - -import { useCallback, useState } from 'react'; -import Confetti from 'react-confetti'; - -import DownloadContainer from '../../global/download/download-container'; -import { CircuitSchemaProps } from '../../type'; - -import ActionButton from './action-button'; - -import { DownloadIcon } from '@/components/icons'; -import CloneIcon from '@/components/icons/Clone'; -import { classNames } from '@/util/utils'; - -export default function Heading({ content }: { content: CircuitSchemaProps }) { - const [downloadModalOpen, SetDownloadModalOpen] = useState(false); - const [showConfetti, setShowConfetti] = useState(false); - const [showMessage, setShowMessage] = useState(false); - - // DOWNLOAD MODAL - const handleOpenDownloadModal = useCallback(() => { - SetDownloadModalOpen(true); - }, []); - - const handleCloseDownloadModal = useCallback(() => { - SetDownloadModalOpen(false); - }, []); - - const copyToClipboard = async () => { - try { - await navigator.clipboard.writeText(content.entityCoreID || content.key || ''); - setShowConfetti(true); - setShowMessage(true); - setTimeout(() => { - setShowConfetti(false); - setShowMessage(false); - }, 3500); - } catch (err) { - throw new Error('Failed to copy to clipboard'); - } - }; - - return ( - <> -
-
-
Name
-

{content.name}

-
- - {showMessage && ( -
-

Id copied to the clipboard

-
- )} - {showConfetti && ( -
- -
- )} - -
- {/* - - */} - {/* - - */} - {/* - - */} - - {content.key !== null && ( - - - - )} - - - -
-
- -
- -
-
- - ); -} diff --git a/src/components/explore-section/Circuit/DetailView/header/action-button.tsx b/src/components/explore-section/Circuit/DetailView/header/action-button.tsx deleted file mode 100644 index b09238665..000000000 --- a/src/components/explore-section/Circuit/DetailView/header/action-button.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import { InfoCircleOutlined } from '@ant-design/icons'; -import { Tooltip } from 'antd'; -import Link from 'next/link'; - -export default function ActionButton({ - type, - label, - action, - link, - disabled, - children, -}: { - type: 'button' | 'link' | 'download'; - label: string; - action?: () => void; - link?: string; - disabled?: boolean; - children: React.ReactNode; -}) { - if (type === 'button') { - return ( - - ); - } - - if (type === 'link') { - return ( - - {label} -
- {children} -
- - ); - } - - if (type === 'download' && link) { - return ( - - Download - e.stopPropagation()} - > - The connectome will be downloaded in Connectome Utilities format, see more here. - - } - > - - - - ); - } -} diff --git a/src/components/explore-section/Circuit/DetailView/header/circuit-data.tsx b/src/components/explore-section/Circuit/DetailView/header/circuit-data.tsx deleted file mode 100644 index 2063f164f..000000000 --- a/src/components/explore-section/Circuit/DetailView/header/circuit-data.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { CircuitSchemaProps } from '../../type'; -import CircuitMetadata from './circuit-metadata'; -import CircuitParameters from './circuit-parameter'; - -export default function CircuitData({ content }: { content: CircuitSchemaProps }) { - return ( -
- - -
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/header/circuit-metadata.tsx b/src/components/explore-section/Circuit/DetailView/header/circuit-metadata.tsx deleted file mode 100644 index ee09b9ae6..000000000 --- a/src/components/explore-section/Circuit/DetailView/header/circuit-metadata.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { CircuitSchemaProps } from '../../type'; -import ListParameterBox from '../global/ListParameterBox'; -import ParameterBox from '../global/ParameterBox'; - -export default function CircuitMetadata({ content }: { content: CircuitSchemaProps }) { - return ( -
-
- -
-
- -
-
- -
-
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/header/circuit-parameter.tsx b/src/components/explore-section/Circuit/DetailView/header/circuit-parameter.tsx deleted file mode 100644 index 111d429cf..000000000 --- a/src/components/explore-section/Circuit/DetailView/header/circuit-parameter.tsx +++ /dev/null @@ -1,51 +0,0 @@ -'use client'; - -import { CircuitSchemaProps } from '../../type'; -import formatNumberWithComma from '../../utils/format-number-with-comma'; -import ParameterBox from '../global/ParameterBox'; - -export default function CircuitParameters({ content }: { content: CircuitSchemaProps }) { - const parentCircuitLink = `./${content.parent}`; - const licenseLink = content.metadata.license?.url; - - return ( -
- {/* COLUMN 1 */} -
- - - - -
- {/* COLUMN 2 */} -
- - - -
- {/* COLUMN 3 */} -
- - - -
-
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/main-detail-view-core.tsx b/src/components/explore-section/Circuit/DetailView/main-detail-view-core.tsx deleted file mode 100644 index 6aeef8bbf..000000000 --- a/src/components/explore-section/Circuit/DetailView/main-detail-view-core.tsx +++ /dev/null @@ -1,139 +0,0 @@ -'use client'; - -import { useSetAtom } from 'jotai'; -import { useParams } from 'next/navigation'; -import { useEffect, useState } from 'react'; - -import { DetailsPageSideBackLink } from '../../Sidebar'; -import HeaderDetailView from './header-detail-view'; -import SectionMainContainer from './sections/section-main-container'; - -import { CircuitSchemaProps } from '@/components/explore-section/Circuit/type'; -import { buildCircuitMap } from '@/components/explore-section/Circuit/utils/circuits-map'; -import { brainRegionSidebarIsCollapsedAtom } from '@/state/explore-section/detail-view-atoms'; - -function MainDetailViewCore({ - content, - parentCircuit, - derivedCircuits, -}: { - content: CircuitSchemaProps; - parentCircuit: CircuitSchemaProps | null; - derivedCircuits: CircuitSchemaProps[] | null; -}) { - return ( -
- - -
- ); -} - -export default function CircuitDetailPage() { - const setBrainRegionSidebarIsCollapsed = useSetAtom(brainRegionSidebarIsCollapsedAtom); - const params = useParams(); - - const [circuitData, setCircuitData] = useState(null); - const [parentCircuitData, setParentCircuitData] = useState(null); - const [derivedCircuitsData, setDerivedCircuitsData] = useState(null); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - - const circuitKey = params.id as string | undefined; - - useEffect(() => { - const fetchCircuit = async () => { - if (!circuitKey) { - setError('No existing circuit'); - setLoading(false); - return; - } - - setBrainRegionSidebarIsCollapsed(true); - - try { - setLoading(true); - const response = await fetch('/api/explore-circuits/data', { - cache: 'no-store', - }); - - if (!response.ok) { - throw new Error(`Error: ${response.statusText}`); - } - - const data = await response.json(); - - if (data.error || !Array.isArray(data.circuits)) { - throw new Error(data.error || 'Invalid response from API'); - } - - const { circuits } = data; - const circuitMap = buildCircuitMap(circuits); - - // Current Circuit content - const matchingCircuit = circuitMap.get(circuitKey); - if (!matchingCircuit) { - throw new Error(`Circuit with key ${circuitKey} not found!`); - } - - // Parent Circuit content - let parentCircuit: CircuitSchemaProps | null = null; - if (matchingCircuit.parent) { - parentCircuit = circuitMap.get(matchingCircuit.parent) || null; - } - - // Derived Circuit content - const derivedCircuits: CircuitSchemaProps[] = matchingCircuit.derivedFrom - .map((key: string) => circuitMap.get(key)) - .filter( - (circuit: CircuitSchemaProps | undefined): circuit is CircuitSchemaProps => !!circuit - ); - - setCircuitData(matchingCircuit); - setParentCircuitData(parentCircuit); - setDerivedCircuitsData(derivedCircuits); - } catch (er) { - setError( - er instanceof Error ? er.message : 'An error occurred while fetching the circuit data' - ); - } finally { - setLoading(false); - } - }; - - fetchCircuit(); - }, [circuitKey, setBrainRegionSidebarIsCollapsed]); - - if (loading) { - return ( -
- Loading... -
- ); - } - - if (error) { - return ( -
- {error} -
- ); - } - - return ( -
- - {circuitData && ( - - )} -
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/sections/Overview/index.tsx b/src/components/explore-section/Circuit/DetailView/sections/Overview/index.tsx deleted file mode 100644 index 3f06477fb..000000000 --- a/src/components/explore-section/Circuit/DetailView/sections/Overview/index.tsx +++ /dev/null @@ -1,44 +0,0 @@ -'use client'; - -import Image from 'next/image'; -import { CircuitSchemaProps } from '../../../type'; -import SubtitleBar from '../global/SubtitleBar'; - -type ImageProps = { - name: string; - url: string; -}; - -export default function OverviewSection({ content }: { content: CircuitSchemaProps }) { - return ( -
- -
- {content.overview.cellStatistics.map((image: ImageProps) => ( - - ))} -
- - -
- {content.overview.networkStatistics.map((image: ImageProps) => ( - - ))} -
-
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/sections/Provenance/Literature.tsx b/src/components/explore-section/Circuit/DetailView/sections/Provenance/Literature.tsx deleted file mode 100644 index b123492c9..000000000 --- a/src/components/explore-section/Circuit/DetailView/sections/Provenance/Literature.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { useMemo } from 'react'; -import { CircuitSchemaProps, PaperLiteratureProps } from '../../../type'; -import PublicationCard from '../global/PublicationCard'; -import SubtitleBar from '../global/SubtitleBar'; - -export default function Literature({ content }: { content: CircuitSchemaProps }) { - const CIRCUIT_PROVENANCE_LITERATURE = useMemo( - () => - content.literature.filter( - (publication: PaperLiteratureProps) => publication.category === 'circuit_source' - ), - [content.literature] - ); - - const CIRCUIT_PROVENANCE_RELATED_ARTIFACTS = useMemo( - () => - content.literature.filter( - (publication: PaperLiteratureProps) => publication.category === 'component_source' - ), - [content.literature] - ); - - return ( -
- -
- {CIRCUIT_PROVENANCE_LITERATURE.map((publication: PaperLiteratureProps, index: number) => ( - - ))} -
- -
- {CIRCUIT_PROVENANCE_RELATED_ARTIFACTS.map( - (publication: PaperLiteratureProps, index: number) => ( - - ) - )} -
-
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/sections/Provenance/RelatedArtifacts.tsx b/src/components/explore-section/Circuit/DetailView/sections/Provenance/RelatedArtifacts.tsx deleted file mode 100644 index 9b4720334..000000000 --- a/src/components/explore-section/Circuit/DetailView/sections/Provenance/RelatedArtifacts.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export default function RelatedArtifacts() { - return ( -
- Coming soon -
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/sections/Provenance/index.tsx b/src/components/explore-section/Circuit/DetailView/sections/Provenance/index.tsx deleted file mode 100644 index 42e611d55..000000000 --- a/src/components/explore-section/Circuit/DetailView/sections/Provenance/index.tsx +++ /dev/null @@ -1,61 +0,0 @@ -'use client'; - -import { useState } from 'react'; -import { CircuitSchemaProps } from '../../../type'; -import Literature from './Literature'; -import RelatedArtifacts from './RelatedArtifacts'; - -type ProvenanceSubsectionProps = { - name: string; - id: 'literature' | 'related artifacts'; -}; - -export default function ProvenanceSection({ content }: { content: CircuitSchemaProps }) { - const subsections: ProvenanceSubsectionProps[] = [ - { name: 'Literature', id: 'literature' }, - { name: 'Related artifacts', id: 'related artifacts' }, - ]; - - const [currentSubsection, setCurrentSubsection] = useState<'literature' | 'related artifacts'>( - 'literature' - ); - - let displayedContent; - - switch (currentSubsection) { - case 'literature': - displayedContent = ; - break; - case 'related artifacts': - displayedContent = ; - break; - default: - displayedContent = ; - break; - } - - return ( -
-
- {subsections.map((subsection: ProvenanceSubsectionProps) => ( - - ))} -
- - {displayedContent} -
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/sections/RelatedCircuits/index.tsx b/src/components/explore-section/Circuit/DetailView/sections/RelatedCircuits/index.tsx deleted file mode 100644 index e604cfd21..000000000 --- a/src/components/explore-section/Circuit/DetailView/sections/RelatedCircuits/index.tsx +++ /dev/null @@ -1,39 +0,0 @@ -'use client'; - -import CircuitTable from '../../../global/circuit-table'; -import { CircuitSchemaProps } from '../../../type'; -import SubtitleBar from '../global/SubtitleBar'; - -export default function RelatedCircuitsSection({ - content, - parentCircuit, - derivedCircuits, -}: { - content: CircuitSchemaProps; - parentCircuit: CircuitSchemaProps | null; - derivedCircuits: CircuitSchemaProps[] | null; -}) { - return ( -
- {content.parent !== null && ( - <> - - - - )} - {content.subcircuits.length > 0 && ( - <> - 1 ? 'Subcircuits' : 'Subcircuit'} /> - - - )} - {(derivedCircuits && derivedCircuits.length > 0) || - (derivedCircuits === null && ( - <> - - - - ))} -
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/sections/RelatedPublications/index.tsx b/src/components/explore-section/Circuit/DetailView/sections/RelatedPublications/index.tsx deleted file mode 100644 index 00a989836..000000000 --- a/src/components/explore-section/Circuit/DetailView/sections/RelatedPublications/index.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { useMemo } from 'react'; -import { CircuitSchemaProps, PaperLiteratureProps } from '../../../type'; -import PublicationCard from '../global/PublicationCard'; -import SubtitleBar from '../global/SubtitleBar'; - -export default function RelatedPublicationssSection({ content }: { content: CircuitSchemaProps }) { - const CIRCUIT_PROVENANCE_LITERATURE = useMemo( - () => - content.literature.filter( - (publication: PaperLiteratureProps) => publication.category === 'circuit_source' - ), - [content.literature] - ); - - const CIRCUIT_APPLICATION_LITERATURE = useMemo( - () => - content.literature.filter( - (publication: PaperLiteratureProps) => publication.category === 'application' - ), - [content.literature] - ); - - return ( -
- -
- {CIRCUIT_PROVENANCE_LITERATURE.map((publication: PaperLiteratureProps, index: number) => ( - - ))} -
- -
- {CIRCUIT_APPLICATION_LITERATURE.map((publication: PaperLiteratureProps, index: number) => ( - - ))} -
-
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/sections/Visualisation/circuit_placeholder.jpg b/src/components/explore-section/Circuit/DetailView/sections/Visualisation/circuit_placeholder.jpg deleted file mode 100644 index aefb98da2..000000000 Binary files a/src/components/explore-section/Circuit/DetailView/sections/Visualisation/circuit_placeholder.jpg and /dev/null differ diff --git a/src/components/explore-section/Circuit/DetailView/sections/Visualisation/index.tsx b/src/components/explore-section/Circuit/DetailView/sections/Visualisation/index.tsx deleted file mode 100644 index c763068e4..000000000 --- a/src/components/explore-section/Circuit/DetailView/sections/Visualisation/index.tsx +++ /dev/null @@ -1,22 +0,0 @@ -'use client'; - -import Image from 'next/image'; -import { CircuitSchemaProps } from '../../../type'; -import placeholderImage from './circuit_placeholder.jpg'; - -export default function Visualisation({ content }: { content: CircuitSchemaProps }) { - const imageUrl = content.overview.mainDisplay[0].url || placeholderImage; - - return ( -
- -
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/sections/global/PublicationCard.tsx b/src/components/explore-section/Circuit/DetailView/sections/global/PublicationCard.tsx deleted file mode 100644 index d7ad67586..000000000 --- a/src/components/explore-section/Circuit/DetailView/sections/global/PublicationCard.tsx +++ /dev/null @@ -1,116 +0,0 @@ -'use client'; - -import Link from 'next/link'; -import { useState } from 'react'; - -import { PaperLiteratureProps } from '../../../type'; - -import { CheckIcon, LinkIcon, UserIcon } from '@/components/icons'; -import CalendarIcon from '@/components/icons/Calendar'; -import CopyIcon from '@/components/icons/CopyIcon'; -import { classNames } from '@/util/utils'; - -export default function PublicationCard({ - content, - index, -}: { - content: PaperLiteratureProps; - index: number; -}) { - const { abstract } = content; - - const [isExpanded, setIsExpanded] = useState(false); - const [showPopup, setShowPopup] = useState(false); - - const copyDOI = () => { - navigator.clipboard.writeText(content.doi); - setShowPopup(true); - setTimeout(() => setShowPopup(false), 2000); - }; - - return ( -
- {showPopup && ( -
-
- -
- DOI copied to clipboard -
- )} -
-
-
- {index + 1} -
-

- {content.title} -

-
-
- {content.link !== undefined && ( - - - Link - - )} - -
-
- -
-
-
- -
- -
- {content.authors} -
-
-
-
- -
-
{content.publicationDate}
-
-
- -
-
-

- {abstract} -

- -
-
-
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/sections/global/SubtitleBar.tsx b/src/components/explore-section/Circuit/DetailView/sections/global/SubtitleBar.tsx deleted file mode 100644 index 39611dccb..000000000 --- a/src/components/explore-section/Circuit/DetailView/sections/global/SubtitleBar.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export default function SubtitleBar({ title }: { title: string }) { - return ( -
- {title} -
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/sections/section-content-bloc.tsx b/src/components/explore-section/Circuit/DetailView/sections/section-content-bloc.tsx deleted file mode 100644 index f7da90499..000000000 --- a/src/components/explore-section/Circuit/DetailView/sections/section-content-bloc.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { CircuitSchemaProps } from '../../type'; -import OverviewSection from './Overview'; -import ProvenanceSection from './Provenance'; -import RelatedCircuitsSection from './RelatedCircuits'; -import RelatedPublicationssSection from './RelatedPublications'; -import Visualisation from './Visualisation'; - -export default function SectionContentBlock({ - content, - parentCircuit, - derivedCircuits, - activeSection, -}: { - content: CircuitSchemaProps; - parentCircuit: CircuitSchemaProps | null; - derivedCircuits: CircuitSchemaProps[] | null; - activeSection: - | 'visualization' - | 'overview' - | 'provenance' - | 'related-publications' - | 'related-circuits'; -}) { - let currentSection; - - switch (activeSection) { - case 'visualization': - currentSection = ; - break; - case 'overview': - currentSection = ; - break; - case 'provenance': - currentSection = ; - break; - case 'related-publications': - currentSection = ; - break; - case 'related-circuits': - currentSection = ( - - ); - break; - default: - currentSection = null; - } - - return ( -
{currentSection}
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/sections/section-main-container.tsx b/src/components/explore-section/Circuit/DetailView/sections/section-main-container.tsx deleted file mode 100644 index c0cf57c84..000000000 --- a/src/components/explore-section/Circuit/DetailView/sections/section-main-container.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { useState } from 'react'; -import { CircuitSchemaProps } from '../../type'; - -import SectionContentBlock from './section-content-bloc'; -import SectionTabs from './section-tabs'; - -export default function SectionMainContainer({ - content, - parentCircuit, - derivedCircuits, -}: { - content: CircuitSchemaProps; - parentCircuit: CircuitSchemaProps | null; - derivedCircuits: CircuitSchemaProps[] | null; -}) { - const [activeSection, setActiveSection] = useState< - 'visualization' | 'overview' | 'provenance' | 'related-publications' | 'related-circuits' - >('visualization'); - - return ( -
- - -
- ); -} diff --git a/src/components/explore-section/Circuit/DetailView/sections/section-tabs.tsx b/src/components/explore-section/Circuit/DetailView/sections/section-tabs.tsx deleted file mode 100644 index 676f16036..000000000 --- a/src/components/explore-section/Circuit/DetailView/sections/section-tabs.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import { - ActiveSection, - SECTION_OVERVIEW, - SECTION_PROVENANCE, - SECTION_RELATED_CIRCUITS, - SECTION_RELATED_PUBLICATIONS, - SECTION_VISUALIZATION, -} from '../../type/sectionTypes'; - -type SectionProps = { - name: string; - id: ActiveSection; -}; - -export default function SectionTabs({ - activeSection, - setActiveSection, -}: { - activeSection: ActiveSection; - setActiveSection: (section: ActiveSection) => void; -}) { - const sections: SectionProps[] = [ - { - name: 'Visualization', - id: SECTION_VISUALIZATION, - }, - { - name: 'Overview', - id: SECTION_OVERVIEW, - }, - { - name: 'Provenance', - id: SECTION_PROVENANCE, - }, - { - name: 'Related Publications', - id: SECTION_RELATED_PUBLICATIONS, - }, - { - name: 'Related Circuits', - id: SECTION_RELATED_CIRCUITS, - }, - ]; - - return ( -
- {sections.map((section: SectionProps) => { - return ( - - ); - })} -
- ); -} diff --git a/src/components/explore-section/Circuit/ListView/ExploreCircuitTable.tsx b/src/components/explore-section/Circuit/ListView/ExploreCircuitTable.tsx deleted file mode 100644 index 99514fa3c..000000000 --- a/src/components/explore-section/Circuit/ListView/ExploreCircuitTable.tsx +++ /dev/null @@ -1,113 +0,0 @@ -'use client'; - -import { useAtomValue } from 'jotai'; -import { useEffect, useMemo, useState } from 'react'; -import CircuitTable from '../global/circuit-table'; -import { CircuitSchemaProps } from '../type'; - -import { - brainRegionBasicCellGroupsRegionsHierarchyAtom, - useBrainRegionHierarchy, -} from '@/features/brain-region-hierarchy/context'; -import { - buildHierarchyMap, - getBrainRegionDescendantsAndAncestorsNodes, -} from '@/features/brain-region-hierarchy/helpers'; - -function brainRegionFilter({ - circuits, - regionSet, -}: { - circuits: CircuitSchemaProps[]; - region: string | undefined; - regionSet: Set; -}) { - let count = 0; - - function recurse(circuit: CircuitSchemaProps): CircuitSchemaProps | null { - const brainRegionMatches = circuit.brainRegion - ? regionSet.has(circuit.brainRegion.trim().toLowerCase()) - : false; - - const filteredSubs = (circuit.subcircuits?.map(recurse).filter(Boolean) ?? - []) as CircuitSchemaProps[]; - - if (brainRegionMatches || filteredSubs.length > 0) { - count += 1; - return { - ...circuit, - subcircuits: filteredSubs, - }; - } - - return null; - } - - const filteredTree = circuits.map(recurse).filter(Boolean) as CircuitSchemaProps[]; - - return { - filteredTree, - count, - }; -} - -export function useFilteredCircuits({ dataKey }: { dataKey: string }) { - const { node } = useBrainRegionHierarchy({ dataKey }); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - const [circuitsData, setCircuitsData] = useState([]); - - useEffect(() => { - const fetchCircuit = async () => { - try { - setLoading(true); - const response = await fetch('/circuits/ALL_CIRCUITS.json'); - - if (!response.ok) { - throw new Error('Error: ' + response.statusText); - } - - const data: CircuitSchemaProps[] = await response.json(); - - setCircuitsData(data); - } catch (er) { - setError(er instanceof Error ? er.message : 'Unknown error'); - } finally { - setLoading(false); - } - }; - - fetchCircuit(); - }, []); - - const brainRegions = useAtomValue(brainRegionBasicCellGroupsRegionsHierarchyAtom); - const selectedBrainRegions = getBrainRegionDescendantsAndAncestorsNodes( - [node.id], - brainRegions?.root! - ); - const brainRegionByIdMap = buildHierarchyMap(brainRegions?.root!); - - const brainRegionSet = useMemo(() => { - return new Set( - selectedBrainRegions.map( - (br) => brainRegionByIdMap.get(br.id)?.name.toLowerCase().trim() ?? '' - ) - ); - }, [selectedBrainRegions, brainRegionByIdMap]); - - const filteredCircuits = brainRegionFilter({ - region: node?.id, - regionSet: brainRegionSet, - circuits: circuitsData, - }); - - return { loading, error, filteredCircuits }; -} - -export default function ExploreCircuitTable({ data }: { data: CircuitSchemaProps[] }) { - return ( -
- -
- ); -} diff --git a/src/components/explore-section/Circuit/ListView/ExploreCircuiteTable.module.css b/src/components/explore-section/Circuit/ListView/ExploreCircuiteTable.module.css deleted file mode 100644 index d6b1a868f..000000000 --- a/src/components/explore-section/Circuit/ListView/ExploreCircuiteTable.module.css +++ /dev/null @@ -1,5 +0,0 @@ -.circuitTable { - & :global(.ant-table-cell) { - padding-left: 10px !important; - } -} diff --git a/src/components/explore-section/Circuit/ListView/ExploreCircuiteTable.module.scss b/src/components/explore-section/Circuit/ListView/ExploreCircuiteTable.module.scss deleted file mode 100644 index 034679f2d..000000000 --- a/src/components/explore-section/Circuit/ListView/ExploreCircuiteTable.module.scss +++ /dev/null @@ -1,5 +0,0 @@ -.circuitTable { - :global(.ant-table-cell) { - padding-left: 10px !important; - } -} diff --git a/src/components/explore-section/Circuit/global/Columns.tsx b/src/components/explore-section/Circuit/global/Columns.tsx deleted file mode 100644 index 3ac8d9dcc..000000000 --- a/src/components/explore-section/Circuit/global/Columns.tsx +++ /dev/null @@ -1,229 +0,0 @@ -import { Tooltip } from 'antd'; -import { ColumnType } from 'antd/es/table'; -import Link from 'next/link'; -import { Key, SyntheticEvent } from 'react'; -import { ResizeCallbackData } from 'react-resizable'; -import { CircuitSchemaProps } from '../type'; -import formatNumberWithComma from '../utils/format-number-with-comma'; -import { FilterConfig } from './state/columns'; - -import { ChevronRight, DownloadIcon } from '@/components/icons'; -import truncateText from '@/util/truncate'; -import { classNames } from '@/util/utils'; - -type ResizableColumnType = ColumnType & { - onHeaderCell?: (column: ColumnType) => React.HTMLAttributes & { - width: number; - onResize: (e: SyntheticEvent, data: ResizeCallbackData) => void; - }; -}; - -const columns = ( - expandedRowKeys: Key | Key[], - calculateSubcircuitsForParent: (row: CircuitSchemaProps) => number, - handleExpandRow: (row: CircuitSchemaProps, index: number) => void, - isCircuitDetailPage: boolean, - handleOpenDownloadModal: (record: CircuitSchemaProps) => void, - toggle: 'hierarchical' | 'flat', - filters: Record, - searchQuery: string -): ResizableColumnType[] => { - return [ - { - title: ( - - - - ), - key: 'download', - width: 80, - fixed: 'left', // Optional: fixes the column to the left for better visibility - render: (_value: any, record: CircuitSchemaProps, _index: number) => { - return ( - - ); - }, - }, - { - title: 'Name', - key: 'name', - width: 150, - render: (_value: any, record: CircuitSchemaProps, _index: number) => { - const isFilterActive = - Object.values(filters).some((f) => f !== null) || searchQuery.trim() !== ''; - const isMatching = - isFilterActive && - ((filters.name?.min && - typeof record.name === 'string' && - record.name.toLowerCase().includes((filters.name?.min as string)?.toLowerCase())) || - (searchQuery.trim() !== '' && - typeof record.name === 'string' && - record.name.toLowerCase().includes(searchQuery.toLowerCase()))); - const href = isCircuitDetailPage ? `./${record.key}` : `./circuit/${record.key}`; - return ( - - {record.name} - - ); - }, - }, - { - title: 'Subcircuits', - key: 'subcircuits', - width: 120, - render: (_value: any, record: CircuitSchemaProps, index: number) => { - const isExpanded = Array.isArray(expandedRowKeys) && expandedRowKeys.includes(record.key); - const totalSubcircuitsForParent = calculateSubcircuitsForParent(record); - const subcircuitCount = totalSubcircuitsForParent > 0 ? totalSubcircuitsForParent : '–'; - - return ( - - ); - }, - }, - { - title: 'Description', - key: 'description', - width: 150, - render: (_value: any, record: CircuitSchemaProps, _index: number) => ( - -
- {truncateText(record.description, 46)} -
-
- ), - }, - { - title: 'Brain region', - key: 'brainRegion', - width: 150, - render: (_value: any, record: CircuitSchemaProps, _index: number) => ( -
{record.brainRegion}
- ), - }, - { - title: 'Scale', - key: 'scale', - width: 150, - render: (_value: any, record: CircuitSchemaProps, _index: number) => { - const content = [ - { - label: 'Small microcircuit', - value: 'smallMicrocircuit', - description: - 'Circuit with 3-20 neurons together with synapses coming from inside and outside its volume (usually called intrinsic and extrinsic synapses respectively).', - }, - { - label: 'Microcircuit', - value: 'microcircuit', - description: - 'Any circuit larger than 20 neurons but not being a region, system, or whole-brain circuit.', - }, - ]; - const scaleInfo = content.find( - (item) => item.value === (record.scale?.toLowerCase() || '') - ); - return ( - -
- {record.scale || 'Unknown'} -
-
- ); - }, - }, - { - title: '# Neurons', - key: 'numberOfNeurons', - width: 150, - render: (_value: any, record: CircuitSchemaProps, _index: number) => ( -
- {formatNumberWithComma(record.numberOfNeurons)} -
- ), - }, - { - title: '# Connections', - key: 'numberOfConnections', - width: 150, - render: (_value: any, record: CircuitSchemaProps, _index: number) => ( -
- {formatNumberWithComma(record.numberOfConnections)} -
- ), - }, - { - title: '# Synapses', - key: 'numberOfSynapses', - width: 150, - render: (_value: any, record: CircuitSchemaProps, _index: number) => ( -
- {formatNumberWithComma(record.numberOfSynapses)} -
- ), - }, - { - title: 'Species', - key: 'specie', - width: 120, - render: (_value: any, record: CircuitSchemaProps, _index: number) => ( -
{record.species}
- ), - }, - { - title: 'Published In', - key: 'publishedIn', - width: 150, - render: (_value: any, record: CircuitSchemaProps, _index: number) => ( -
{record.metadata.publishedIn}
- ), - }, - { - title: 'Registration date', - key: 'registrationDate', - width: 150, - render: (_value: any, record: CircuitSchemaProps, _index: number) => ( -
{record.metadata.registrationDate}
- ), - }, - { - title: 'Build category', - key: 'buildCategory', - width: 120, - render: (_value: any, record: CircuitSchemaProps, _index: number) => ( -
{record.buildCategory}
- ), - }, - ]; -}; - -export default columns; diff --git a/src/components/explore-section/Circuit/global/ViewToggle.tsx b/src/components/explore-section/Circuit/global/ViewToggle.tsx deleted file mode 100644 index 163cd91cc..000000000 --- a/src/components/explore-section/Circuit/global/ViewToggle.tsx +++ /dev/null @@ -1,55 +0,0 @@ -import { Tooltip } from 'antd'; - -import { FlatListViewIcon, HierarchicalViewIcon } from '@/components/icons'; -import { classNames } from '@/util/utils'; - -export default function ViewToggle({ - toggle, - setToggle, -}: { - toggle: 'hierarchical' | 'flat'; - setToggle: (toggle: 'hierarchical' | 'flat') => void; -}) { - const handleViewChange = () => { - const newView = toggle === 'hierarchical' ? 'flat' : 'hierarchical'; - setToggle(newView); - }; - - return ( -
-
View:
-
- -
- -
-
- - -
- -
-
-
-
- ); -} diff --git a/src/components/explore-section/Circuit/global/circuit-table.tsx b/src/components/explore-section/Circuit/global/circuit-table.tsx deleted file mode 100644 index 250e61871..000000000 --- a/src/components/explore-section/Circuit/global/circuit-table.tsx +++ /dev/null @@ -1,434 +0,0 @@ -import { Table } from 'antd'; -import { useAtom, useAtomValue } from 'jotai'; -import moment from 'moment'; -import { usePathname } from 'next/navigation'; -import { Key, useCallback, useEffect, useMemo, useRef, useState } from 'react'; -import { CircuitSchemaProps, FilteredCircuit } from '../type'; -import calculateSubcircuitsForParent from '../utils/calculate-subcircuits-for-parent'; -import collectExpandableKeys from '../utils/collectExpandableKeys'; -import { flattenCircuits } from '../utils/flatten-circuits'; -import columns from './Columns'; -import DownloadContainer from './download/download-container'; -import CircuitsFilterPanel from './filters/circuits-filter-panel'; -import FilterButton from './filters/filter-button'; -import SearchBar from './search-bar'; -import { columnsAtom, filtersAtom, setFilterAtom } from './state/columns'; -import SubcircuitTable from './subcircuit-table'; -import TableScrollButton from './table-scroll-button'; -import ViewToggle from './ViewToggle'; - -import { classNames } from '@/util/utils'; -import styles from './exploreCircuitTable.module.scss'; - -export default function CircuitTable({ - data, - hasSearch = true, -}: { - data: CircuitSchemaProps[]; - hasSearch?: boolean; -}) { - const [circuitToDownload, setCircuitToDownload] = useState(null); - const [downloadModalOpen, setDownloadModalOpen] = useState(false); - const [expandedRowKeys, setExpandedRowKeys] = useState([]); - - // FILTERING - const [filterPanelActive, setFilterPanelActive] = useState(false); - const [searchQuery, setSearchQuery] = useState(''); - const [, setFilter] = useAtom(setFilterAtom); - - // VIEWS - const [toggle, setToggle] = useState<'hierarchical' | 'flat'>('hierarchical'); - - // SCROLL BEHAVIOR - const [isAtStart, setIsAtStart] = useState(true); - const [isAtEnd, setIsAtEnd] = useState(false); - const scrollContainerRef = useRef(null); - - const updateScrollPosition = useCallback(() => { - if (scrollContainerRef.current) { - const { scrollLeft, scrollWidth, clientWidth } = scrollContainerRef.current; - setIsAtStart(scrollLeft === 0); - setIsAtEnd(scrollLeft + clientWidth >= scrollWidth - 1); - } - }, []); - - useEffect(() => { - const container = scrollContainerRef.current; - if (container) { - container.addEventListener('scroll', updateScrollPosition); - updateScrollPosition(); // Initial check - return () => container.removeEventListener('scroll', updateScrollPosition); - } - }, [updateScrollPosition]); - - const scrollToStart = useCallback(() => { - if (scrollContainerRef.current) { - scrollContainerRef.current.scrollTo({ left: 0, behavior: 'smooth' }); - updateScrollPosition(); - } - }, [updateScrollPosition]); - - const scrollToEnd = useCallback(() => { - if (scrollContainerRef.current) { - const { scrollWidth, clientWidth } = scrollContainerRef.current; - scrollContainerRef.current.scrollTo({ - left: scrollWidth - clientWidth, - behavior: 'smooth', - }); - updateScrollPosition(); - } - }, [updateScrollPosition]); - - // COLUMN VISIBILITY AND FILTERS FROM JOTAI - const columnState = useAtomValue(columnsAtom); - const filters = useAtomValue(filtersAtom); - - // RESET FILTERS - const handleResetFilter = useCallback(() => { - Object.keys(filters).forEach((columnId) => { - setFilter({ columnId, filter: null }); - }); - setSearchQuery(''); - }, [filters, setFilter]); - - // DOWNLOAD MODAL - const handleOpenDownloadModal = useCallback((record: CircuitSchemaProps) => { - setCircuitToDownload(record); - setDownloadModalOpen(true); - }, []); - - const handleCloseDownloadModal = useCallback(() => { - setCircuitToDownload(null); - setDownloadModalOpen(false); - }, []); - - // PATHNAME - const pathname = usePathname(); - const isCircuitDetailPage = pathname.includes('/circuit/'); - - // ROW EXPANSION - const handleRowExpandClick = useCallback((row: CircuitSchemaProps) => { - const rowKey = row.key; - setExpandedRowKeys((prev) => - prev.includes(rowKey) ? prev.filter((key) => key !== rowKey) : [...prev, rowKey] - ); - }, []); - - // DATA CLEANING - const cleanedData = useMemo(() => { - const result = data.map((circuit: CircuitSchemaProps) => { - const { numberOfNeurons } = circuit; - if (typeof numberOfNeurons !== 'number' || Number.isNaN(numberOfNeurons)) { - throw new Error(`Invalid numberOfNeurons for circuit ${circuit.key}`); - } - - return { - ...circuit, - key: circuit.key || `circuit-${Math.random().toString(36).slice(2)}`, - numberOfNeurons, - name: circuit.name || 'Unknown', - brainRegion: circuit.brainRegion || 'Unknown', - scale: circuit.scale || 'Unknown', - subcircuits: Array.isArray(circuit.subcircuits) - ? circuit.subcircuits.map((sub) => ({ - ...sub, - key: sub.key || `subcircuit-${Math.random().toString(36).slice(2)}`, - numberOfNeurons: - typeof sub.numberOfNeurons === 'number' && !Number.isNaN(sub.numberOfNeurons) - ? sub.numberOfNeurons - : 0, - name: sub.name || 'Unknown', - brainRegion: sub.brainRegion || 'Unknown', - scale: sub.scale || 'Unknown', - subcircuits: Array.isArray(sub.subcircuits) ? sub.subcircuits : [], - })) - : [], - }; - }); - - const flattened = flattenCircuits(result); - - return { hierarchical: result, flattened }; - }, [data]); - - // HELPER FUNCTION TO CHECK IF A CIRCUIT MATCHES FILTERS - const matchesFilters = useCallback( - (circuit: CircuitSchemaProps) => { - let matches = true; - - // Apply column filters - Object.entries(filters).forEach(([columnId, filter]) => { - if (!filter) return; - - const column = columnState.find((col) => col.id === columnId); - const filterType = column?.filterType; - const value = circuit[columnId as keyof CircuitSchemaProps]; - - let currentMatch = false; - if (filterType === 'numeric' && typeof value === 'number' && filter.type) { - const min = filter.min as number | undefined; - const max = filter.max as number | undefined; - if (filter.type === 'greaterThan' && min !== undefined) { - currentMatch = value > min; - } else if (filter.type === 'lessThan' && max !== undefined) { - currentMatch = value < max; - } else if (filter.type === 'between' && min !== undefined && max !== undefined) { - currentMatch = value >= min && value <= max; - } - } else if (filterType === 'text' && typeof value === 'string' && filter.min) { - currentMatch = value.toLowerCase().includes((filter.min as string).toLowerCase()); - } else if (filterType === 'select' && filter.type) { - currentMatch = value === filter.type; - } else if (filterType === 'date' && typeof value === 'string' && filter.min) { - currentMatch = moment(value).isSame(moment(filter.min as string), 'day'); - } else if (filterType === 'boolean' && filter.min) { - currentMatch = value === (filter.min === 'true'); - } - - matches = matches && currentMatch; - }); - - // Apply search query - if (searchQuery) { - matches = - matches && - ['name', 'brainRegion', 'scale', 'specie', 'publishedIn', 'buildCategory'].some( - (field) => { - const value = circuit[field as keyof CircuitSchemaProps]; - return ( - typeof value === 'string' && value.toLowerCase().includes(searchQuery.toLowerCase()) - ); - } - ); - } - - return matches; - }, - [filters, searchQuery, columnState] - ); - - // HELPER FUNCTION TO CHECK IF A CIRCUIT OR ITS SUBCIRCUITS MATCH - const hasMatchingSubcircuit = useCallback( - (circuit: CircuitSchemaProps): boolean => { - if (matchesFilters(circuit)) return true; - if (!circuit.subcircuits || circuit.subcircuits.length === 0) return false; - return circuit.subcircuits.some((sub) => hasMatchingSubcircuit(sub)); - }, - [matchesFilters] - ); - - // FILTERED DATA - const filteredData = useMemo(() => { - let result: CircuitSchemaProps[] = - toggle === 'hierarchical' ? cleanedData.hierarchical : cleanedData.flattened; - - result = result.filter((circuit) => { - const circuitMatches = matchesFilters(circuit); - const hasMatchingSub = toggle === 'hierarchical' && hasMatchingSubcircuit(circuit); - return circuitMatches || hasMatchingSub; - }); - - if (toggle === 'hierarchical') { - result = result.map((circuit) => ({ - ...circuit, - isNonMatchingParent: !matchesFilters(circuit) && hasMatchingSubcircuit(circuit), - })); - } - - return result; - }, [cleanedData, toggle, matchesFilters, hasMatchingSubcircuit]); - - const flattenedData = useMemo(() => { - if (toggle === 'hierarchical') { - return filteredData; - } - const keyCounts = filteredData.reduce( - (acc, circuit) => { - acc[circuit.key] = (acc[circuit.key] || 0) + 1; - return acc; - }, - {} as Record - ); - const duplicates = Object.entries(keyCounts).filter(([_, count]) => count > 1); - if (duplicates.length > 0) { - throw new Error( - `Duplicate keys found in flattened data: ${duplicates - .map(([key, count]) => `${key} (${count})`) - .join(', ')}` - ); - } - return filteredData; - }, [filteredData, toggle]); - - const tableData = useMemo(() => { - return toggle === 'hierarchical' ? filteredData : flattenedData; - }, [toggle, filteredData, flattenedData]); - - // COLUMNS - const filteredColumns = useMemo(() => { - const allColumns = columns( - expandedRowKeys, - (row: CircuitSchemaProps) => - calculateSubcircuitsForParent(row, matchesFilters, hasMatchingSubcircuit), - handleRowExpandClick, - isCircuitDetailPage, - handleOpenDownloadModal, - toggle, - filters, - searchQuery - ); - const activeColumnIds = columnState.filter((col) => col.isActive).map((col) => col.id); - const result = allColumns.filter((col) => activeColumnIds.includes(col.key as string)); - return toggle === 'flat' ? result.filter((col) => col.key !== 'subcircuits') : result; - }, [ - toggle, - expandedRowKeys, - isCircuitDetailPage, - handleOpenDownloadModal, - handleRowExpandClick, - columnState, - filters, - searchQuery, - matchesFilters, - hasMatchingSubcircuit, - ]); - - // EXPAND ALL WHEN FILTERS OR SEARCH ARE ACTIVE - useEffect(() => { - const isFilterActive = - Object.values(filters).some((f) => f !== null) || searchQuery.trim() !== ''; - if (toggle === 'hierarchical' && isFilterActive) { - const expandableKeys = collectExpandableKeys(cleanedData.hierarchical); - setExpandedRowKeys(expandableKeys); - } else { - setExpandedRowKeys([]); - } - }, [filters, searchQuery, cleanedData, toggle]); - - // ROW EXPANSION - const handleExpandRow = useCallback((expanded: boolean, row: CircuitSchemaProps) => { - const rowKey = row.key; - setExpandedRowKeys((prev) => - expanded ? [...prev, rowKey] : prev.filter((key) => key !== rowKey) - ); - }, []); - - // RENDER SUBCIRCUITS - const renderSubcircuits = useCallback( - (circuit: CircuitSchemaProps) => - circuit.subcircuits && circuit.subcircuits.length > 0 ? ( - - ) : null, - [expandedRowKeys, handleExpandRow, filteredColumns, filters, searchQuery, columnState] - ); - - // FILTERS CHECKS - const isFilterActive = useMemo(() => { - return Object.values(filters).some((f) => f !== null); - }, [filters]); - - const numberOfActiveFilters = useMemo(() => { - return Object.values(filters).filter((f) => f !== null).length; - }, [filters]); - - return ( -
- {hasSearch && ( -
- -
- {isFilterActive && ( - - )} - setFilterPanelActive(true)} - numberOfFilters={Object.values(filters).filter((f) => f !== null).length} - numberOfActiveColumns={columnState.filter((col) => col.isActive).length} - /> - -
-
- )} -
-
- {tableData.length === 0 ? ( -
No matching circuits found
- ) : ( -
null, - rowExpandable: (record) => - !!record.subcircuits && record.subcircuits.length > 0, - } - : undefined - } - rowClassName={(record: FilteredCircuit) => - toggle === 'hierarchical' && record.isNonMatchingParent - ? styles.nonMatchingRow - : styles.matchingRow - } - /> - )} - - - - setFilterPanelActive(false)} - handleResetFilter={handleResetFilter} - isFilterActive={isFilterActive} - numberOfActiveFilters={numberOfActiveFilters} - /> -
- {circuitToDownload !== null && ( - - )} -
-
-
- ); -} diff --git a/src/components/explore-section/Circuit/global/circuits-listing-page-component.tsx b/src/components/explore-section/Circuit/global/circuits-listing-page-component.tsx deleted file mode 100644 index 844e44fea..000000000 --- a/src/components/explore-section/Circuit/global/circuits-listing-page-component.tsx +++ /dev/null @@ -1,34 +0,0 @@ -'use client'; - -import { useParams } from 'next/navigation'; - -import ExploreCircuitTable, { - useFilteredCircuits, -} from '@/components/explore-section/Circuit/ListView/ExploreCircuitTable'; -import { resolveDataKey } from '@/utils/key-builder'; - -import type { WorkspaceContext } from '@/types/common'; - -export default function CircuitsListingPageComponent() { - const { projectId } = useParams(); - const dataKey = resolveDataKey({ projectId, section: 'explore' }); - const { filteredCircuits, loading, error } = useFilteredCircuits({ dataKey }); - - if (loading) { - return ( -
- Loading... -
- ); - } - - if (error) { - return ( -
- An error occurred: {error} -
- ); - } - - return ; -} diff --git a/src/components/explore-section/Circuit/global/download/download-container.tsx b/src/components/explore-section/Circuit/global/download/download-container.tsx deleted file mode 100644 index d2a8e728a..000000000 --- a/src/components/explore-section/Circuit/global/download/download-container.tsx +++ /dev/null @@ -1,120 +0,0 @@ -'use client'; - -import { Tooltip } from 'antd'; -import Link from 'next/link'; -import { CircuitSchemaProps, DownloadItemProps, FileTypeHeaderProps } from '../../type'; -import DownloadItem from './download-item'; -import HeaderDownloadModal from './header-download-modal'; - -import fileTypeDescriptions from '@/components/explore-section/Constant/file-type-descriptions'; -import { DownloadIcon } from '@/components/icons'; - -const [ - CONNECTIVITY_DESCRIPTION, - MORPHOLOGY_DESCRIPTION, - NODE_DESCRIPTION, - EDGE_DESCRIPTION, -]: FileTypeHeaderProps[] = fileTypeDescriptions; - -function FullCircuitItem({ content }: { content: DownloadItemProps }) { - return ( -
-
-
- Download full circuit -
-

- The complete circuit compressed in SONATA format, - - {' '} - see more here - -

-
-
-
{content.children?.[0]?.size || 'N/A'}
-
h5
- - - -
-
- ); -} - -export default function DownloadContainer({ - content, - handleCloseDownloadModal, -}: { - content: CircuitSchemaProps; - handleCloseDownloadModal: () => void; -}) { - const fullCircuitData = content.files.find( - (item: DownloadItemProps) => item.fileType === 'fullCircuit' - ); - - return ( -
- - - {fullCircuitData ? ( - - ) : ( -
Full circuit data is not available.
- )} -
- Download components only -
-
- {content.files - .filter((item: DownloadItemProps) => item.fileType !== 'fullCircuit') - .map((item: DownloadItemProps) => { - let headerType: FileTypeHeaderProps | null = null; - - if (item.fileType === 'connectivityMatrix') { - headerType = CONNECTIVITY_DESCRIPTION; - } else if (item.fileType === 'morphology') { - headerType = MORPHOLOGY_DESCRIPTION; - } else if (item.fileType === 'nodes') { - headerType = NODE_DESCRIPTION; - } else if (item.fileType === 'edges') { - headerType = EDGE_DESCRIPTION; - } - - return item.fileType === 'morphology' ? ( - - - - ) : ( - - ); - })} -
-
- ); -} diff --git a/src/components/explore-section/Circuit/global/download/download-item.module.css b/src/components/explore-section/Circuit/global/download/download-item.module.css deleted file mode 100644 index bffb71a2f..000000000 --- a/src/components/explore-section/Circuit/global/download/download-item.module.css +++ /dev/null @@ -1,3 +0,0 @@ -div.comingSoon { - color: #fff9; -} diff --git a/src/components/explore-section/Circuit/global/download/download-item.tsx b/src/components/explore-section/Circuit/global/download/download-item.tsx deleted file mode 100644 index 390690642..000000000 --- a/src/components/explore-section/Circuit/global/download/download-item.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import Link from 'next/link'; -import { - DownloadItemProps, - FileTypeHeaderProps, - SingleSelectedDownloadableItemProps, -} from '../../type'; - -import { DownloadIcon } from '@/components/icons'; -import { classNames } from '@/util/utils'; - -import styles from './download-item.module.css'; - -function DownloadChildrenItem({ - childrenItem, -}: { - childrenItem: SingleSelectedDownloadableItemProps; -}) { - const disabled = childrenItem.extension === 'directory'; - - if (disabled) { - return
Coming soon...
; - } - - return ( -
-
-
{childrenItem.name}
-

- {childrenItem.description} -

-
-
-
{childrenItem.size}
-
{childrenItem.extension}
- - - -
-
- ); -} - -export default function DownloadItem({ - item, - header, - className, -}: { - item: DownloadItemProps; - header: FileTypeHeaderProps; - className?: string; -}) { - const itemNumber = item.children ? item.children.length : 0; - - return ( -
-
-
-
- {header.name} -
- {header.description} -
-
-
- {itemNumber} File{itemNumber > 1 ? 's' : ''} -
-
{header.extension}
-
-
-
- {item.children?.length !== 0 ? ( - item.children?.map((childrenItem: SingleSelectedDownloadableItemProps) => ( - - )) - ) : ( -
- No files available for this type. -
- )} -
-
- ); -} diff --git a/src/components/explore-section/Circuit/global/download/header-download-modal.tsx b/src/components/explore-section/Circuit/global/download/header-download-modal.tsx deleted file mode 100644 index d321cfeec..000000000 --- a/src/components/explore-section/Circuit/global/download/header-download-modal.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { DownloadItemProps } from '../../type'; -import { calculateTotalDownloadableItems } from '../../utils/calculate-total-downloadable-items'; - -import { CloseIcon } from '@/components/icons'; - -export default function HeaderDownloadModal({ - handleCloseDownloadModal, - content, -}: { - handleCloseDownloadModal: () => void; - content: DownloadItemProps[]; -}) { - return ( -
-
-
Download files
-
Total files: {calculateTotalDownloadableItems(content)}
-
- -
- ); -} diff --git a/src/components/explore-section/Circuit/global/exploreCircuitTable.module.scss b/src/components/explore-section/Circuit/global/exploreCircuitTable.module.scss deleted file mode 100644 index 59ffd2732..000000000 --- a/src/components/explore-section/Circuit/global/exploreCircuitTable.module.scss +++ /dev/null @@ -1,68 +0,0 @@ -.circuitTable { - /* Row and cell styles */ - & .ant-table-row { - display: table-row !important; - min-height: 40px !important; - background: white; - } - - /* Header styles */ - & .ant-table-thead { - background: white !important; - } - - & .ant-table-thead > tr > th { - background: white !important; - color: #8c8c8c !important; - font-size: 14px !important; - font-weight: normal !important; - text-transform: uppercase !important; - letter-spacing: 0.05em !important; - padding: 0 !important; - border-bottom: 0 !important; - text-align: left !important; - white-space: nowrap !important; - } - - & .ant-table-thead > tr > th:hover { - background: #f5f5f5 !important; - } - - /* Cell styles */ - & .ant-table-cell { - padding: 8px !important; - font-size: 16px !important; - font-weight: 400 !important; - text-transform: uppercase !important; - letter-spacing: 0.05em !important; - background: transparent !important; - } - - /* Table body */ - - & .ant-table-tbody { - background: white; - - & > tr:last-child > td { - border-bottom: 0; - } - } - - /* Expand icon column */ - & .ant-table-expand-icon-col { - width: 0 !important; - display: none !important; - } -} - -.nonMatchingRow { - opacity: 0.3; -} - -.matchingRow { - opacity: 1; -} - -.boldName { - font-weight: bold; -} diff --git a/src/components/explore-section/Circuit/global/filters/circuits-filter-panel.module.css b/src/components/explore-section/Circuit/global/filters/circuits-filter-panel.module.css deleted file mode 100644 index 10bdd13a8..000000000 --- a/src/components/explore-section/Circuit/global/filters/circuits-filter-panel.module.css +++ /dev/null @@ -1,40 +0,0 @@ -.filterPanel { - position: fixed; - top: 0; - left: 0; - box-sizing: border-box; - width: 100vw; - max-width: 100vw; - height: 100vh; - max-height: 100vh; - z-index: 50; - margin: 0; - padding: 0; - transition: background-color duration 500ms; - background: rgba(0, 0, 0, 0); -} - -.filterPanel > div { - @starting-style { - transform: translateX(100%); - } -} - -.filterBox { - position: absolute; - top: 0; - right: 0; - height: 100%; - width: 480px; - padding: 32px; - transition: transform duration 500ms ease-in-out; - background: var(--color-primary-9); -} - -.isFilterOpen { - transform: translateX(0); -} - -.ifFilterClosed { - transform: translateX(100%); -} diff --git a/src/components/explore-section/Circuit/global/filters/circuits-filter-panel.tsx b/src/components/explore-section/Circuit/global/filters/circuits-filter-panel.tsx deleted file mode 100644 index 5e1a16aaf..000000000 --- a/src/components/explore-section/Circuit/global/filters/circuits-filter-panel.tsx +++ /dev/null @@ -1,498 +0,0 @@ -'use client'; - -/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */ -/* eslint-disable jsx-a11y/click-events-have-key-events */ - -import { DatePicker, Switch, Tooltip } from 'antd'; -import { useAtom, useAtomValue } from 'jotai'; -import moment from 'moment'; -import { useEffect, useRef, useState } from 'react'; -import { useBuildCategoryData } from '../../hook/use-build-category-data'; -import { useCircuitSpecies } from '../../hook/use-circuit-species'; -import { useCircuitScales } from '../../hook/use-scale-type-data'; -import { - activeColumnsCountAtom, - columnsAtom, - filtersAtom, - setFilterAtom, - SingleColumnContent, - toggleColumnAtom, -} from '../state/columns'; - -import { ChevronRight, CloseIcon, EyeIcon } from '@/components/icons'; -import EyeSlashIcon from '@/components/icons/EyeSlashIcon'; -import { classNames } from '@/util/utils'; - -import styles from './circuits-filter-panel.module.css'; - -function ApplyButton({ isDisabled, onClick }: { isDisabled: boolean; onClick: () => void }) { - return isDisabled ? ( - - - - ) : ( - - ); -} - -function SingleFilterItem({ - title, - id, - index, - filterType, - columnCustomizable, -}: { - title: string; - id: string; - index: number; - filterType: SingleColumnContent['filterType']; - columnCustomizable: SingleColumnContent['columnCustomizable']; -}) { - const [columns] = useAtom(columnsAtom); - const [, toggleColumn] = useAtom(toggleColumnAtom); - const [filters] = useAtom(filtersAtom); - const [, setFilter] = useAtom(setFilterAtom); - const isColumnActive = columns.find((column) => column.id === id)?.isActive ?? false; - const [isOpen, setIsOpen] = useState(false); - const isFilterActive = filters[id] !== null && filters[id] !== undefined; - - const [localType, setLocalType] = useState(filters[id]?.type); - const [localMin, setLocalMin] = useState(filters[id]?.min); - const [localMax, setLocalMax] = useState(filters[id]?.max); - - const { - categories, - isLoading: categoriesLoading, - error: categoriesError, - } = useBuildCategoryData(); - const { scales, loading: scalesLoading, error: scalesError } = useCircuitScales(); - const { species, isLoading: speciesLoading, error: speciesError } = useCircuitSpecies(); - - const handleApplyFilter = () => { - if (filterType === 'numeric' && localType) { - const filter = { - property: id, - type: localType, - min: localType === 'greaterThan' || localType === 'between' ? localMin : undefined, - max: localType === 'lessThan' || localType === 'between' ? localMax : undefined, - }; - setFilter({ columnId: id, filter }); - } else if (filterType === 'text' || filterType === 'date' || filterType === 'boolean') { - setFilter({ columnId: id, filter: localMin ? { property: id, min: localMin } : null }); - } else if (filterType === 'select' && localType) { - setFilter({ columnId: id, filter: { property: id, type: localType } }); - } - }; - - const handleResetFilter = () => { - setLocalType(undefined); - setLocalMin(undefined); - setLocalMax(undefined); - setFilter({ columnId: id, filter: null }); - }; - - const renderFilterControls = () => { - if (!filterType) return null; - - if (filterType === 'text') { - const isApplyDisabled = !localMin; - return ( -
- setLocalMin(e.target.value || undefined)} - className="text-bas mb-2 w-full overflow-hidden rounded-full px-6 py-2 font-sans focus:outline-none" - /> -
- - -
-
- ); - } - - if (filterType === 'numeric') { - return ( -
- - {(localType === 'greaterThan' || localType === 'between') && ( - setLocalMin(e.target.value ? Number(e.target.value) : undefined)} - className="mb-2 w-full overflow-hidden rounded-full px-6 py-2 font-sans text-base focus:outline-none" - /> - )} - {(localType === 'lessThan' || localType === 'between') && ( - setLocalMax(e.target.value ? Number(e.target.value) : undefined)} - className="mb-2 w-full overflow-hidden rounded-full px-6 py-2 font-sans text-base focus:outline-none" - /> - )} -
- - -
-
- ); - } - - if (filterType === 'select') { - const isBuildCategory = id === 'buildCategory'; - const isSpecies = id === 'specie'; - - // OPTIONS - let options; - if (isBuildCategory) { - options = categories; - } else if (isSpecies) { - options = species; - } else { - options = scales; - } - // LOADING - let loading; - if (isBuildCategory) { - loading = categoriesLoading; - } else if (isSpecies) { - loading = speciesLoading; - } else { - loading = scalesLoading; - } - let error; - - // ERROR - if (isBuildCategory) { - error = categoriesError; - } else if (isSpecies) { - error = speciesError; - } else { - error = scalesError; - } - - let errorLabel = 'scales'; - if (isBuildCategory) { - errorLabel = 'categories'; - } else if (isSpecies) { - errorLabel = 'species'; - } - - let selectPlaceholder = 'Select scale'; - if (isBuildCategory) { - selectPlaceholder = 'Select category'; - } else if (isSpecies) { - selectPlaceholder = 'Select species'; - } - - return ( -
- -
- - -
-
- ); - } - - if (filterType === 'boolean') { - return ( -
- setLocalMin(checked ? 'true' : undefined)} - /> -
- - -
-
- ); - } - - if (filterType === 'date') { - return ( -
- setLocalMin(date ? date.format('YYYY-MM-DD') : undefined)} - className="w-full" - /> -
- - -
-
- ); - } - - return null; - }; - - return ( -
-
-
- - - - -
- -
-
- {filterType !== null && ( -
- {isFilterActive && ( -
- Filter active -
- )} - -
- )} -
- {isOpen && renderFilterControls()} -
- ); -} - -export default function CircuitsFilterPanel({ - isActive = true, - toggle, - handleResetFilter, - isFilterActive, - numberOfActiveFilters, -}: { - isActive?: boolean; - toggle?: () => void; - handleResetFilter?: () => void; - isFilterActive?: boolean; - numberOfActiveFilters?: number; -}) { - const ref = useRef(null); - const columns = useAtomValue(columnsAtom); - const totalColumns = useAtomValue(activeColumnsCountAtom); - - useEffect(() => { - const dialog = ref.current; - if (!dialog) return; - - if (isActive) { - dialog.showModal(); - dialog.style.transform = 'translateX(0)'; - } - }, [isActive]); - - const handleClose = () => { - const dialog = ref.current; - if (!dialog) return; - - dialog.style.transform = 'translateX(100%)'; - setTimeout(() => { - dialog.close(); - if (toggle) { - toggle(); - } - }, 500); - }; - - return ( - -
evt.stopPropagation()} - className={classNames( - styles.filterBox, - isActive ? styles.isFilterOpen : styles.isFilterClosed - )} - > -
-
-
-
-
Filters
-
- {totalColumns} active columns -
-
-
- -
-
- -
- {columns.map((column: SingleColumnContent, index: number) => { - return ( - !!column.columnCustomizable && ( - - ) - ); - })} -
-
- -
- - {!isFilterActive ? ( -
No filter active
- ) : ( -
- {numberOfActiveFilters} filter{numberOfActiveFilters !== 1 ? 's' : ''} active -
- )} -
-
-
-
- ); -} diff --git a/src/components/explore-section/Circuit/global/filters/filter-button.tsx b/src/components/explore-section/Circuit/global/filters/filter-button.tsx deleted file mode 100644 index c75d0a570..000000000 --- a/src/components/explore-section/Circuit/global/filters/filter-button.tsx +++ /dev/null @@ -1,34 +0,0 @@ -import { SettingsIcon } from '@/components/icons'; - -export default function FilterButton({ - setActive, - numberOfFilters, - numberOfActiveColumns, -}: { - setActive: (active: boolean) => void; - numberOfFilters: number; - numberOfActiveColumns: number; -}) { - return ( - - ); -} diff --git a/src/components/explore-section/Circuit/global/search-bar.tsx b/src/components/explore-section/Circuit/global/search-bar.tsx deleted file mode 100644 index 46da64813..000000000 --- a/src/components/explore-section/Circuit/global/search-bar.tsx +++ /dev/null @@ -1,94 +0,0 @@ -'use client'; - -import { ChangeEvent, useCallback, useEffect, useRef, useState } from 'react'; - -import { CloseOutlined, SearchOutlined } from '@ant-design/icons'; - -type SearchBarProps = { - searchQuery: string; - onSearchChange: (query: string) => void; -}; - -export default function SearchBar({ searchQuery, onSearchChange }: SearchBarProps) { - const [searchOpen, setSearchOpen] = useState(false); - const inputRef = useRef(null); - - const handleClose = useCallback(() => { - setSearchOpen(false); - onSearchChange(''); - }, [onSearchChange]); - - const handleOpen = () => { - setSearchOpen(true); - }; - - useEffect(() => { - if (searchOpen && inputRef.current) { - setTimeout(() => { - inputRef.current?.focus(); - }, 0); - } - }, [searchOpen]); - - useEffect(() => { - if (!searchOpen) return; - - const handleEscape = (event: KeyboardEvent) => { - if (event.key === 'Escape') { - handleClose(); - } - }; - - document.addEventListener('keydown', handleEscape); - return () => { - document.removeEventListener('keydown', handleEscape); - }; - }, [searchOpen, handleClose]); - - const handleChange = (e: ChangeEvent) => { - onSearchChange(e.target.value); - }; - - return ( -
- Search: -
- {searchOpen ? ( -
- - - -
- ) : ( - - )} -
-
- ); -} diff --git a/src/components/explore-section/Circuit/global/state/columns.ts b/src/components/explore-section/Circuit/global/state/columns.ts deleted file mode 100644 index 987dc0888..000000000 --- a/src/components/explore-section/Circuit/global/state/columns.ts +++ /dev/null @@ -1,134 +0,0 @@ -import { atom } from 'jotai'; - -export type SingleColumnContent = { - title: string; - id: string; - isActive: boolean; - columnCustomizable: boolean; - filterType: 'text' | 'numeric' | 'select' | 'boolean' | 'date' | null; -}; - -export type FilterConfig = { - property: string; - type?: string; - min?: number | string; - max?: number | string; -}; - -const CIRCUITS_COLUMNS: SingleColumnContent[] = [ - { - title: 'Download', - id: 'download', - isActive: true, - columnCustomizable: false, - filterType: null, - }, - { - title: 'Scale', - id: 'scale', - isActive: true, - columnCustomizable: true, - filterType: 'select', - }, - { - title: '# Neurons', - id: 'numberOfNeurons', - isActive: true, - columnCustomizable: true, - filterType: 'numeric', - }, - { - title: '# Connections', - id: 'numberOfConnections', - isActive: true, - columnCustomizable: true, - filterType: 'numeric', - }, - { - title: '# Synapses', - id: 'numberOfSynapses', - isActive: true, - columnCustomizable: true, - filterType: 'numeric', - }, - { - title: 'Build category', - id: 'buildCategory', - isActive: true, - columnCustomizable: true, - filterType: 'select', - }, - { - title: 'Species', - id: 'specie', - isActive: true, - columnCustomizable: true, - filterType: null, - }, - { - title: 'Name', - id: 'name', - isActive: true, - columnCustomizable: true, - filterType: null, - }, - { - title: 'Subcircuits', - id: 'subcircuits', - isActive: true, - columnCustomizable: false, - filterType: null, - }, - { - title: 'Description', - id: 'description', - isActive: true, - columnCustomizable: true, - filterType: null, - }, - { - title: 'Brain region', - id: 'brainRegion', - isActive: true, - columnCustomizable: true, - filterType: null, - }, - { - title: 'Published In', - id: 'publishedIn', - isActive: true, - columnCustomizable: true, - filterType: null, - }, - { - title: 'Registration date', - id: 'registrationDate', - isActive: true, - columnCustomizable: true, - filterType: null, - }, -]; - -export const columnsAtom = atom(CIRCUITS_COLUMNS); - -export const toggleColumnAtom = atom(null, (get, set, columnId: string) => { - const columns = get(columnsAtom); - const updatedColumns = columns.map((column) => - column.id === columnId ? { ...column, isActive: !column.isActive } : column - ); - set(columnsAtom, updatedColumns); -}); - -export const activeColumnsCountAtom = atom( - (get) => get(columnsAtom).filter((column) => column.isActive).length -); - -export const filtersAtom = atom>({}); - -export const setFilterAtom = atom( - null, - (get, set, update: { columnId: string; filter: FilterConfig | null }) => { - const currentFilters = get(filtersAtom); - set(filtersAtom, { ...currentFilters, [update.columnId]: update.filter }); - } -); diff --git a/src/components/explore-section/Circuit/global/subcircuit-table.tsx b/src/components/explore-section/Circuit/global/subcircuit-table.tsx deleted file mode 100644 index 3662deb99..000000000 --- a/src/components/explore-section/Circuit/global/subcircuit-table.tsx +++ /dev/null @@ -1,151 +0,0 @@ -'use client'; - -import { Table } from 'antd'; -import { ColumnsType } from 'antd/es/table/interface'; -import moment from 'moment'; -import { Key, useCallback, useMemo } from 'react'; -import { ArrowSmall } from '../icon/ArrowSubcircuitIcon'; -import { CircuitSchemaProps } from '../type'; -import { FilterConfig, SingleColumnContent } from './state/columns'; - -import styles from './exploreCircuitTable.module.scss'; - -type SubcircuitsTableProps = { - circuit: CircuitSchemaProps; - columns: ColumnsType; - expandedRowKeys: Key[]; - onExpand?: (expanded: boolean, row: CircuitSchemaProps) => void; - filters: Record; - searchQuery: string; - columnState: SingleColumnContent[]; -}; - -export default function SubcircuitTable({ - circuit, - columns, - expandedRowKeys, - onExpand, - filters, - searchQuery, - columnState, -}: SubcircuitsTableProps) { - // HELPER FUNCTION TO CHECK IF A SUBCIRCUIT MATCHES FILTERS - const matchesFilters = useCallback( - (subCircuit: CircuitSchemaProps) => { - let matches = true; - - // Apply column filters - Object.entries(filters).forEach(([columnId, filter]) => { - if (!filter) return; - - const filterType = columnState.find((col) => col.id === columnId)?.filterType; - const value = subCircuit[columnId as keyof CircuitSchemaProps]; - - let currentMatch = false; - if (filterType === 'numeric' && typeof value === 'number' && filter.type) { - const min = filter.min as number | undefined; - const max = filter.max as number | undefined; - if (filter.type === 'greaterThan' && min !== undefined) { - currentMatch = value > min; - } else if (filter.type === 'lessThan' && max !== undefined) { - currentMatch = value < max; - } else if (filter.type === 'between' && min !== undefined && max !== undefined) { - currentMatch = value >= min && value <= max; - } - } else if (filterType === 'text' && typeof value === 'string' && filter.min) { - currentMatch = value.toLowerCase().includes((filter.min as string).toLowerCase()); - } else if (filterType === 'select' && filter.type) { - currentMatch = value === filter.type; - } else if (filterType === 'date' && typeof value === 'string' && filter.min) { - currentMatch = moment(value).isSame(moment(filter.min as string), 'day'); - } else if (filterType === 'boolean' && filter.min) { - currentMatch = value === (filter.min === 'true'); - } - - matches = matches && currentMatch; - }); - - // Apply search query - if (searchQuery) { - matches = - matches && - ['name', 'brainRegion', 'scale', 'specie', 'publishedIn', 'buildCategory'].some( - (field) => { - const value = subCircuit[field as keyof CircuitSchemaProps]; - return ( - typeof value === 'string' && value.toLowerCase().includes(searchQuery.toLowerCase()) - ); - } - ); - } - - return matches; - }, - [filters, searchQuery, columnState] - ); - - // HELPER FUNCTION TO CHECK IF A SUBCIRCUIT OR ITS DESCENDANTS MATCH - const hasMatchingSubcircuit = useCallback( - (subCircuit: CircuitSchemaProps): boolean => { - if (matchesFilters(subCircuit)) return true; - if (!subCircuit.subcircuits || subCircuit.subcircuits.length === 0) return false; - return subCircuit.subcircuits.some((sub) => hasMatchingSubcircuit(sub)); - }, - [matchesFilters] - ); - - // FILTER SUBCIRCUITS - const filteredSubcircuits = useMemo(() => { - if (!circuit.subcircuits) return []; - return circuit.subcircuits - .filter((sub) => { - const subMatches = matchesFilters(sub); - const hasMatchingSub = hasMatchingSubcircuit(sub); - return subMatches || hasMatchingSub; - }) - .map((sub) => ({ - ...sub, - isNonMatchingParent: !matchesFilters(sub) && hasMatchingSubcircuit(sub), - })); - }, [circuit.subcircuits, matchesFilters, hasMatchingSubcircuit]); - - const renderSubcircuits = (subCircuit: CircuitSchemaProps) => - subCircuit.subcircuits && subCircuit.subcircuits.length > 0 ? ( - - ) : null; - - return ( -
-
- - - Subcircuits - -
-
null, - rowExpandable: (record) => !!record.subcircuits && record.subcircuits.length > 0, - }} - rowClassName={(record) => - record.isNonMatchingParent ? styles.nonMatchingRow : styles.matchingRow - } - /> - - ); -} diff --git a/src/components/explore-section/Circuit/global/table-scroll-button.tsx b/src/components/explore-section/Circuit/global/table-scroll-button.tsx deleted file mode 100644 index 4da0aeac9..000000000 --- a/src/components/explore-section/Circuit/global/table-scroll-button.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { ArrowLeftIcon, ArrowRightIcon } from '@/components/icons'; -import { classNames } from '@/util/utils'; - -export default function TableScrollButton({ - scrollToEnd, - isAtEnd, - scrollToStart, - isAtStart, -}: { - scrollToEnd: () => void; - isAtEnd: boolean; - scrollToStart: () => void; - isAtStart: boolean; -}) { - return ( -
- - -
- ); -} diff --git a/src/components/explore-section/Circuit/hook/use-build-category-data.tsx b/src/components/explore-section/Circuit/hook/use-build-category-data.tsx deleted file mode 100644 index 88750a88c..000000000 --- a/src/components/explore-section/Circuit/hook/use-build-category-data.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { useEffect, useState } from 'react'; -import { CircuitSchemaProps } from '../type'; - -export const useBuildCategoryData = () => { - const [categories, setCategories] = useState([]); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); - - useEffect(() => { - const fetchCategories = async () => { - try { - setIsLoading(true); - const response = await fetch('/circuits/ALL_CIRCUITS.json'); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const data: CircuitSchemaProps[] = await response.json(); - - const uniqueCategories = Array.from( - new Set(data.map((circuit) => circuit.buildCategory)) - ).filter((category): category is string => category !== undefined); - - setCategories(uniqueCategories); - } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to fetch circuit categories'); - } finally { - setIsLoading(false); - } - }; - - fetchCategories(); - }, []); - - return { categories, isLoading, error }; -}; diff --git a/src/components/explore-section/Circuit/hook/use-circuit-species.tsx b/src/components/explore-section/Circuit/hook/use-circuit-species.tsx deleted file mode 100644 index ccdc2b860..000000000 --- a/src/components/explore-section/Circuit/hook/use-circuit-species.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { useEffect, useState } from 'react'; -import { CircuitSchemaProps } from '../type'; - -export const useCircuitSpecies = () => { - const [species, setSpecies] = useState([]); - const [isLoading, setIsLoading] = useState(true); - const [error, setError] = useState(null); - - useEffect(() => { - const fetchSpecies = async () => { - try { - setIsLoading(true); - const response = await fetch('/circuits/ALL_CIRCUITS.json'); - - if (!response.ok) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - const data: CircuitSchemaProps[] = await response.json(); - - const uniqueSpecies = Array.from(new Set(data.map((circuit) => circuit.species))).filter( - (specie): specie is string => specie !== undefined - ); - - setSpecies(uniqueSpecies); - } catch (err) { - setError(err instanceof Error ? err.message : 'Failed to fetch circuit species'); - } finally { - setIsLoading(false); - } - }; - - fetchSpecies(); - }, []); - - return { species, isLoading, error }; -}; diff --git a/src/components/explore-section/Circuit/hook/use-scale-type-data.tsx b/src/components/explore-section/Circuit/hook/use-scale-type-data.tsx deleted file mode 100644 index 4c2bb2ebf..000000000 --- a/src/components/explore-section/Circuit/hook/use-scale-type-data.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { useEffect, useState } from 'react'; -import { CircuitSchemaProps } from '../type'; - -export function useCircuitScales() { - const [scales, setScales] = useState([]); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - - useEffect(() => { - const fetchCircuits = async () => { - function extractScales(circuit: CircuitSchemaProps, uniqueScales: Set) { - if (circuit.scale) { - uniqueScales.add(circuit.scale); - } - if (circuit.subcircuits && circuit.subcircuits.length > 0) { - circuit.subcircuits.forEach((subcircuit) => extractScales(subcircuit, uniqueScales)); - } - } - - try { - setLoading(true); - const response = await fetch('/circuits/ALL_CIRCUITS.json'); - - if (!response.ok) { - throw new Error(`Error: ${response.statusText}`); - } - - const data: CircuitSchemaProps[] = await response.json(); - - const uniqueScales = new Set(); - - data.forEach((circuit) => extractScales(circuit, uniqueScales)); - - setScales(Array.from(uniqueScales)); - } catch (er) { - setError(er instanceof Error ? er.message : 'Unknown error'); - } finally { - setLoading(false); - } - }; - - fetchCircuits(); - }, []); - - return { scales, loading, error }; -} diff --git a/src/components/explore-section/Circuit/icon/ArrowSubcircuitIcon.tsx b/src/components/explore-section/Circuit/icon/ArrowSubcircuitIcon.tsx deleted file mode 100644 index 24e3c2b46..000000000 --- a/src/components/explore-section/Circuit/icon/ArrowSubcircuitIcon.tsx +++ /dev/null @@ -1,19 +0,0 @@ -export function ArrowSmall({ iconColor, className }: { iconColor: string; className?: string }) { - return ( - - - - ); -} diff --git a/src/components/explore-section/Circuit/type/sectionTypes.ts b/src/components/explore-section/Circuit/type/sectionTypes.ts deleted file mode 100644 index e2ddcbd1b..000000000 --- a/src/components/explore-section/Circuit/type/sectionTypes.ts +++ /dev/null @@ -1,15 +0,0 @@ -export const SECTION_VISUALIZATION = 'visualization'; -export const SECTION_OVERVIEW = 'overview'; -export const SECTION_PROVENANCE = 'provenance'; -export const SECTION_RELATED_PUBLICATIONS = 'related-publications'; -export const SECTION_RELATED_CIRCUITS = 'related-circuits'; - -const ACTIVE_SECTIONS = [ - SECTION_OVERVIEW, - SECTION_PROVENANCE, - SECTION_RELATED_PUBLICATIONS, - SECTION_RELATED_CIRCUITS, - SECTION_VISUALIZATION, -] as const; - -export type ActiveSection = (typeof ACTIVE_SECTIONS)[number]; diff --git a/src/components/explore-section/Circuit/utils/calculate-subcircuits-for-parent.ts b/src/components/explore-section/Circuit/utils/calculate-subcircuits-for-parent.ts deleted file mode 100644 index c596ea456..000000000 --- a/src/components/explore-section/Circuit/utils/calculate-subcircuits-for-parent.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { CircuitSchemaProps } from '../type'; - -const calculateSubcircuitsForParent = ( - row: CircuitSchemaProps, - matchesFilters: (circuit: CircuitSchemaProps) => boolean, - hasMatchingSubcircuit: (circuit: CircuitSchemaProps) => boolean -): number => { - if (!row.subcircuits || row.subcircuits.length === 0) return 0; - - let count = 0; - for (const sub of row.subcircuits) { - if (matchesFilters(sub) || hasMatchingSubcircuit(sub)) { - count += 1; - count += calculateSubcircuitsForParent(sub, matchesFilters, hasMatchingSubcircuit); - } - } - return count; -}; - -export default calculateSubcircuitsForParent; diff --git a/src/components/explore-section/Circuit/utils/calculate-total-downloadable-items.ts b/src/components/explore-section/Circuit/utils/calculate-total-downloadable-items.ts deleted file mode 100644 index d18189cc7..000000000 --- a/src/components/explore-section/Circuit/utils/calculate-total-downloadable-items.ts +++ /dev/null @@ -1,5 +0,0 @@ -import { DownloadItemProps } from '../type'; - -export function calculateTotalDownloadableItems(files: DownloadItemProps[]): number { - return files.reduce((total, file) => total + (file.children?.length ?? 0), 0); -} diff --git a/src/components/explore-section/Circuit/utils/circuits-map.ts b/src/components/explore-section/Circuit/utils/circuits-map.ts deleted file mode 100644 index b666766c4..000000000 --- a/src/components/explore-section/Circuit/utils/circuits-map.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { CircuitSchemaProps } from '../type'; - -export const buildCircuitMap = ( - circuits: CircuitSchemaProps[], - map: Map = new Map() -): Map => { - for (const circuit of circuits) { - map.set(circuit.key, circuit); - if (circuit.subcircuits && circuit.subcircuits.length > 0) { - buildCircuitMap(circuit.subcircuits, map); - } - } - return map; -}; diff --git a/src/components/explore-section/Circuit/utils/collectExpandableKeys.ts b/src/components/explore-section/Circuit/utils/collectExpandableKeys.ts deleted file mode 100644 index 821cd0119..000000000 --- a/src/components/explore-section/Circuit/utils/collectExpandableKeys.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Key } from 'react'; -import { CircuitSchemaProps } from '../type'; - -function collectExpandableKeys(circuits: CircuitSchemaProps[]): Key[] { - const keys: Key[] = []; - - for (const circuit of circuits) { - if (circuit.subcircuits && circuit.subcircuits.length > 0) { - keys.push(circuit.key); - keys.push(...collectExpandableKeys(circuit.subcircuits)); - } - } - return keys; -} - -export default collectExpandableKeys; diff --git a/src/components/explore-section/Circuit/utils/flatten-circuits.ts b/src/components/explore-section/Circuit/utils/flatten-circuits.ts deleted file mode 100644 index 11c9d02e9..000000000 --- a/src/components/explore-section/Circuit/utils/flatten-circuits.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { CircuitSchemaProps } from '../type'; - -export function flattenCircuits(circuits: CircuitSchemaProps[]): CircuitSchemaProps[] { - const flat: CircuitSchemaProps[] = []; - - function flatten(circuit: CircuitSchemaProps, depth: number = 0) { - flat.push(circuit); - if (circuit.subcircuits && circuit.subcircuits.length > 0) { - circuit.subcircuits.forEach((subCircuit) => flatten(subCircuit, depth + 1)); - } - } - - circuits.forEach((circuit) => flatten(circuit)); - return flat; -} diff --git a/src/components/explore-section/Circuit/utils/format-number-with-comma.ts b/src/components/explore-section/Circuit/utils/format-number-with-comma.ts deleted file mode 100644 index fd7271f1c..000000000 --- a/src/components/explore-section/Circuit/utils/format-number-with-comma.ts +++ /dev/null @@ -1,7 +0,0 @@ -const formatNumberWithComma = (num: number) => { - const formattedValue = new Intl.NumberFormat('en-US').format(num); - - return formattedValue; -}; - -export default formatNumberWithComma; diff --git a/src/components/explore-section/Constant/file-type-descriptions.tsx b/src/components/explore-section/Constant/file-type-descriptions.tsx deleted file mode 100644 index 207cdf245..000000000 --- a/src/components/explore-section/Constant/file-type-descriptions.tsx +++ /dev/null @@ -1,83 +0,0 @@ -type FileTypeHeaderProps = { - name: string; - description: React.ReactNode; - extension: string; -}; - -const fileTypeDescriptions: FileTypeHeaderProps[] = [ - { - name: 'Connectivity Matrices', - description: ( -

- The connectome, sparse connectivity matrix and node properties in Connectome Utilities - format.{' '} - - See more here - - . -

- ), - extension: 'h5', - }, - { - name: 'Morphologies', - description: ( -

- The neuronal morphologies used in the circuit grouped in h5 containers.{' '} - - See more here - - . -

- ), - extension: 'h5', - }, - { - name: 'Node files', - description: ( -

- Files containing information on the population of neurons in the circuit.{' '} - - See more here - - . -

- ), - extension: 'h5', - }, - { - name: 'Edge files', - description: ( -

- Files containing information on the connections between neurons in the circuit.{' '} - - See more here - - . -

- ), - extension: 'h5', - }, -]; - -export default fileTypeDescriptions; diff --git a/src/components/explore-section/ExploreListingLayout/index.tsx b/src/components/explore-section/ExploreListingLayout/index.tsx index fe3118437..6a50b4590 100644 --- a/src/components/explore-section/ExploreListingLayout/index.tsx +++ b/src/components/explore-section/ExploreListingLayout/index.tsx @@ -10,9 +10,6 @@ import { useAtomValue } from 'jotai'; import { useQueryState } from 'nuqs'; import get from 'lodash/get'; -import { StatError } from '../ExploreInteractive/StatItem'; - -import { useFilteredCircuits } from '../Circuit/ListView/ExploreCircuitTable'; import BackToInteractiveExplorationBtn from '@/components/explore-section/BackToInteractiveExplorationBtn'; import NavigationMenu from '@/components/explore-section/ExploreListingLayout/navigation-menu'; import SimpleErrorComponent from '@/components/GenericErrorFallback'; @@ -29,7 +26,6 @@ import { EntityCoreExperimentalConfiguration, EntityCoreModelConfiguration, } from '@/entity-configuration/domain'; -import { resolveDataKey } from '@/utils/key-builder'; import { ensureString } from '@/util/type-guards'; import type { NavigationMenuItem } from '@/components/explore-section/ExploreListingLayout/navigation-menu'; @@ -41,7 +37,6 @@ export default function ExploreListingLayout({ children }: { children: ReactNode const router = useRouter(); const params = useParams(); const pathname = usePathname(); - const dataKey = resolveDataKey({ projectId: params.projectId, section: 'explore' }); const [brainRegionId] = useQueryState(DEFAULT_BRAIN_REGION_QUERY_ID); const brainRegionHierarchy = useAtomValue( useMemo(() => unwrap(brainRegionBasicCellGroupsRegionsHierarchyAtom), []) @@ -107,30 +102,6 @@ export default function ExploreListingLayout({ children }: { children: ReactNode }; }); - const { filteredCircuits, loading, error } = useFilteredCircuits({ dataKey }); - - if (error) { - return ; - } - - if (showCircuitMenu && !loading) { - const circuitActive = activePath === 'circuit'; - - items.push({ - key: 'circuit', - title: 'Circuit', - // @ts-expect-error - entitytype: 'Circuit', - label: `Circuit (${filteredCircuits.count})`, - className: 'text-center font-semibold', - style: { - backgroundColor: circuitActive ? 'white' : '#002766', - color: circuitActive ? '#002766' : 'white', - flexBasis: menuItemWidth, - }, - }); - } - // NOTE: this is legacy to handle details page, // TODO: (this should change to layout per page type (one for listing and one for details)) // ! The menu is not rendered for details pages (where the route contains `id` segment) diff --git a/src/components/explore-section/Circuit/icon/ArticlesIcons.tsx b/src/components/icons/ArticlesIcons.tsx similarity index 100% rename from src/components/explore-section/Circuit/icon/ArticlesIcons.tsx rename to src/components/icons/ArticlesIcons.tsx diff --git a/src/features/brain-atlas-viewer/loading-handler.tsx b/src/features/brain-atlas-viewer/loading-handler.tsx deleted file mode 100644 index 3f28388e2..000000000 --- a/src/features/brain-atlas-viewer/loading-handler.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { useAtomValue } from 'jotai'; -import { Spin } from 'antd'; -import { LoadingOutlined } from '@ant-design/icons'; -import { ApplicationSection } from '@/types/common'; -import { loadingAtom } from '@/features/brain-atlas-viewer/state'; - -type LoadingHandlerProps = { - section: ApplicationSection; -}; - -export default function LoadingHandler({ section }: LoadingHandlerProps) { - const loading = useAtomValue(loadingAtom); - return ( - loading[section].length > 0 && ( - } - className="text-neutral-3 absolute top-1/2 left-1/2" - /> - ) - ); -} diff --git a/src/features/thumbnail/image.tsx b/src/features/thumbnail/image.tsx deleted file mode 100644 index 57731263f..000000000 --- a/src/features/thumbnail/image.tsx +++ /dev/null @@ -1,29 +0,0 @@ -'use client'; - -import { useInView } from 'react-intersection-observer'; - -import { classNames } from '@/util/utils'; - -export default function PreviewImage({ - className, - size, -}: { - className?: string; - size?: { height: number | string; width: number | string }; -}) { - const { ref } = useInView({ threshold: 0.2 }); - - return ( -
- {/* TODO: remove this component if not needed */} - Not yet needed -
- ); -} diff --git a/src/state/explore-section/details-view-atom.ts b/src/state/explore-section/details-view-atom.ts deleted file mode 100644 index d97f6c000..000000000 --- a/src/state/explore-section/details-view-atom.ts +++ /dev/null @@ -1,32 +0,0 @@ -'use client'; - -import { Atom, atom } from 'jotai'; -import { atomFamily } from 'jotai/utils'; -import isEqual from 'lodash/isEqual'; - -import { DetailViewUrlParams } from '@/types/explore-section/application'; -import { DataType } from '@/constants/explore-section/list-views'; -import { getEntityByLegacyType } from '@/entity-configuration/domain/helpers'; - -export const detailFamily = atomFamily< - DetailViewUrlParams & { dataType: DataType }, - Atom> ->( - (viewParams) => - atom(async () => { - const entity = getEntityByLegacyType({ legacyType: viewParams.dataType }); - if (entity && entity.api.query.one) { - return await entity.api.query.one({ - id: viewParams.id, - context: - viewParams.virtualLabId && viewParams.projectId - ? { - virtualLabId: viewParams.virtualLabId, - projectId: viewParams.projectId, - } - : undefined, - }); - } - }), - isEqual -);