Skip to content

Commit

Permalink
feat: organisation categories are shown on project page
Browse files Browse the repository at this point in the history
  • Loading branch information
dmijatovic committed Oct 15, 2024
1 parent 8e5bdf7 commit 7b83564
Show file tree
Hide file tree
Showing 20 changed files with 307 additions and 94 deletions.
31 changes: 31 additions & 0 deletions database/014-create-keyword-and-category.sql
Original file line number Diff line number Diff line change
Expand Up @@ -258,3 +258,34 @@ CREATE TABLE category_for_project (
);

CREATE INDEX category_for_project_category_id_idx ON category_for_project(category_id);

-- RPC for project page to show all project categories
CREATE FUNCTION category_paths_by_project_expanded(project_id UUID)
RETURNS JSON
LANGUAGE SQL STABLE AS
$$
WITH
cat_ids AS
(SELECT
category_id
FROM
category_for_project
WHERE
category_for_project.project_id = category_paths_by_project_expanded.project_id
),
paths AS
(
SELECT
category_path_expanded(category_id) AS path
FROM cat_ids
)
SELECT
CASE
WHEN EXISTS(
SELECT 1 FROM cat_ids
) THEN (
SELECT json_agg(path) FROM paths
)
ELSE '[]'::json
END AS result
$$;
3 changes: 2 additions & 1 deletion frontend/components/category/CategoriesWithHeadlines.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
// SPDX-FileCopyrightText: 2023 Felix Mühlbauer (GFZ) <felix.muehlbauer@gfz-potsdam.de>
// SPDX-FileCopyrightText: 2023 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
// SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 Ewan Cahen (Netherlands eScience Center) <e.cahen@esciencecenter.nl>
// SPDX-FileCopyrightText: 2024 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

import React from 'react'
import {useCategoryTree} from '~/utils/categories'
import {SidebarHeadline} from '../typography/SidebarHeadline'
import {CategoryPath} from '~/types/Category'
import {SidebarHeadline} from '~/components/typography/SidebarHeadline'
import {CategoryTreeLevel} from '~/components/category/CategoryTree'

type CategoriesWithHeadlinesProps = {
Expand Down
23 changes: 23 additions & 0 deletions frontend/components/category/CategoryChipFilter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

import {Fragment} from 'react'
import {CategoryEntry, CategoryPath} from '~/types/Category'
import {TreeNode} from '~/types/TreeNode'
import TagChipFilter from '~/components/layout/TagChipFilter'

export function CategoryChipFilter({nodes}:{nodes:TreeNode<CategoryEntry>[]}){
return nodes.map(node=>{
const cat = node.getValue()
const children = node.children()
return (
<Fragment key={cat.id}>
<TagChipFilter key={cat.id} title={cat.name} label={cat.short_name} />
<CategoryChipFilter nodes={children} />
</Fragment>
)
})
}

12 changes: 12 additions & 0 deletions frontend/components/layout/SidebarPanel.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

export default function SidebarPanel({children,className}:{children:any,className?:string}) {
return (
<aside className={`flex flex-col gap-8 ${className ?? ''}`}>
{children}
</aside>
)
}
21 changes: 21 additions & 0 deletions frontend/components/layout/SidebarSection.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

export default function SidebarSection({children,className}:{children:any,className?:string}) {

if (className){
return (
<div className={`${className ?? ''}`}>
{children}
</div>
)
}

return (
<div>
{children}
</div>
)
}
12 changes: 12 additions & 0 deletions frontend/components/layout/SidebarTitle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

export default function SidebarTitle({children,className}:{children:any,className?:string}) {
return (
<div className={`text-primary pb-2 ${className ?? ''}`}>
{children}
</div>
)
}
26 changes: 24 additions & 2 deletions frontend/components/layout/TagChipFilter.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 dv4all
// SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

Expand All @@ -8,10 +10,30 @@ import SearchIcon from '@mui/icons-material/Search'
import Link from 'next/link'

export default function TagChipFilter({url, label, title}:
{ label: string, url:string ,title?: string }) {

{label: string, url?:string ,title?: string }
){
// if no label no chip
if (!label) return null

// simple chip without link
if (!url) return (
<Chip
title={title ? title : label}
label={label}
sx={{
maxWidth: '19rem',
borderRadius: '0.125rem',
textTransform: 'capitalize',
'& .MuiChip-icon': {
order: 1,
margin:'0rem 0.5rem 0rem 0rem',
height: '1.125rem',
width: '1.125rem'
}
}}
/>
)

return (
<Link
href={url}
Expand Down
29 changes: 29 additions & 0 deletions frontend/components/projects/ProjectCategories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

import {CategoryPath} from '~/types/Category'
import {useCategoryTree} from '~/utils/categories'
import SidebarSection from '../layout/SidebarSection'
import SidebarTitle from '../layout/SidebarTitle'
import {CategoryChipFilter} from '../category/CategoryChipFilter'

export default function ProjectCategories({categories}:{categories:CategoryPath[]}) {
const tree = useCategoryTree(categories)

// each root category is separate sidebar section
return tree.map(node => {
const category = node.getValue()
const children = node.children()

return (
<SidebarSection key={category.id}>
<SidebarTitle>{category.name}</SidebarTitle>
<div className="flex flex-wrap gap-2">
<CategoryChipFilter nodes={children} />
</div>
</SidebarSection>
)
})
}
85 changes: 40 additions & 45 deletions frontend/components/projects/ProjectFunding.tsx
Original file line number Diff line number Diff line change
@@ -1,57 +1,52 @@
// SPDX-FileCopyrightText: 2022 - 2023 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 - 2023 dv4all
// SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2024 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

import Link from 'next/link'
import {ProjectOrganisationProps} from '~/types/Organisation'
import ProjectSidebarTitle from '~/components/layout/SidebarTitle'
import ProjectSidebarSection from '../layout/SidebarSection'

export default function ProjectFunding({grant_id, fundingOrganisations=[]}:
{ grant_id: string | null, fundingOrganisations:ProjectOrganisationProps[] }) {

function renderFundedUnder() {
if (grant_id) {
return (
<>
<div className="text-primary py-4">Funded under</div>
<div className="text-sm">Grant ID: {grant_id}</div>
</>
)
}
return null
}

function renderFundedBy() {
if (fundingOrganisations && fundingOrganisations.length > 0) {
return (
<>
<div className="text-primary py-4">Funded by</div>
<ul>
{fundingOrganisations.map(item => {
const link = `/organisations/${item.rsd_path}`
return (
<li key={link} className="text-sm py-1">
<Link
href={link}
target="_self"
passHref
>
{item.name}
</Link>
</li>
)
})}
</ul>
</>
)
}
return null
}

export function FundedUnder({grant_id}:{grant_id:string|null}){

if (!grant_id) return null

return (
<div>
{renderFundedUnder()}
{renderFundedBy()}
</div>
<ProjectSidebarSection>
<ProjectSidebarTitle>Funded under</ProjectSidebarTitle>
<div className="text-sm">Grant ID: {grant_id}</div>
</ProjectSidebarSection>
)
}

export function FundedBy({fundingOrganisations}:{fundingOrganisations:ProjectOrganisationProps[]}){

if (!fundingOrganisations || fundingOrganisations.length===0) return null

return (
<ProjectSidebarSection>
<ProjectSidebarTitle>Funded by</ProjectSidebarTitle>
<ul>
{fundingOrganisations.map(item => {
const link = `/organisations/${item.rsd_path}`
return (
<li key={link} className="text-sm py-1">
<Link
href={link}
target="_self"
passHref
>
{item.name}
</Link>
</li>
)
})}
</ul>
</ProjectSidebarSection>
)
}

19 changes: 13 additions & 6 deletions frontend/components/projects/ProjectInfo.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 dv4all
// SPDX-FileCopyrightText: 2023 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 Netherlands eScience Center
// SPDX-FileCopyrightText: 2023 - 2024 Dusan Mijatovic (Netherlands eScience Center)
// SPDX-FileCopyrightText: 2023 - 2024 Netherlands eScience Center
//
// SPDX-License-Identifier: Apache-2.0

import {ProjectOrganisationProps} from '~/types/Organisation'
import {KeywordForProject, ProjectLink, ResearchDomain} from '~/types/Project'
import {CategoryPath} from '~/types/Category'
import ProjectDescription from './ProjectDescription'
import ProjectSidebar from './ProjectSidebar'

Expand All @@ -22,13 +23,18 @@ type ProjectInfoProps = {
researchDomains: ResearchDomain[],
keywords: KeywordForProject[],
fundingOrganisations: ProjectOrganisationProps[],
categories: CategoryPath[]
}


export default function ProjectInfo(
{image_id, image_caption, image_contain, description, date_start, date_end,
grant_id, links, researchDomains, keywords, fundingOrganisations}: ProjectInfoProps
) {
export default function ProjectInfo({
image_id, image_caption,
image_contain, description,
date_start, date_end,
grant_id, links, researchDomains,
keywords, fundingOrganisations,
categories
}: ProjectInfoProps) {
return (
<section className="px-4 sm:pb-8 sm:grid sm:gap-8 lg:grid-cols-[3fr,1fr] lg:gap-16">
<ProjectDescription
Expand All @@ -45,6 +51,7 @@ export default function ProjectInfo(
keywords={keywords}
links={links}
fundingOrganisations={fundingOrganisations}
categories={categories}
/>
</section>
)
Expand Down
13 changes: 7 additions & 6 deletions frontend/components/projects/ProjectKeywords.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
// SPDX-FileCopyrightText: 2022 - 2023 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 - 2023 dv4all
// SPDX-FileCopyrightText: 2022 - 2024 Netherlands eScience Center
// SPDX-FileCopyrightText: 2022 Ewan Cahen (Netherlands eScience Center) <e.cahen@esciencecenter.nl>
// SPDX-FileCopyrightText: 2022 Netherlands eScience Center
// SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center)
//
// SPDX-License-Identifier: Apache-2.0

import {KeywordForProject} from '~/types/Project'
import {ssrProjectsUrl} from '~/utils/postgrestUrl'
import TagChipFilter from '../layout/TagChipFilter'
import ProjectSidebarSection from '../layout/SidebarSection'
import ProjectSidebarTitle from '../layout/SidebarTitle'

export default function ProjectKeywords({keywords=[]}:{keywords:KeywordForProject[]}) {

Expand All @@ -28,11 +31,9 @@ export default function ProjectKeywords({keywords=[]}:{keywords:KeywordForProjec
}

return (
<div>
<div className="text-primary py-4">
Keywords
</div>
<ProjectSidebarSection>
<ProjectSidebarTitle>Keywords</ProjectSidebarTitle>
{renderTags()}
</div>
</ProjectSidebarSection>
)
}
Loading

0 comments on commit 7b83564

Please sign in to comment.