From ae0eda4d334734f552aca082ff59d9e1f5cf321a Mon Sep 17 00:00:00 2001 From: "Dusan Mijatovic (PC2020)" Date: Mon, 31 Oct 2022 16:17:07 +0100 Subject: [PATCH 01/15] feat: additional explanation about each login options and close btn --- frontend/components/login/LoginButton.tsx | 41 ++-------- frontend/components/login/LoginDialog.tsx | 99 +++++++++++++++++++++++ frontend/pages/api/fe/auth/index.ts | 3 +- frontend/pages/api/fe/auth/local.ts | 6 +- frontend/pages/api/fe/auth/orcid.ts | 8 +- frontend/pages/api/fe/auth/surfconext.ts | 8 +- 6 files changed, 123 insertions(+), 42 deletions(-) create mode 100644 frontend/components/login/LoginDialog.tsx diff --git a/frontend/components/login/LoginButton.tsx b/frontend/components/login/LoginButton.tsx index e6b663be6..88401a516 100644 --- a/frontend/components/login/LoginButton.tsx +++ b/frontend/components/login/LoginButton.tsx @@ -10,17 +10,13 @@ import {useState} from 'react' import Link from 'next/link' -import Dialog from '@mui/material/Dialog' -import DialogContent from '@mui/material/DialogContent' -import DialogTitle from '@mui/material/DialogTitle' -import useMediaQuery from '@mui/material/useMediaQuery' import {useTheme} from '@mui/material/styles' import {useAuth} from '~/auth' import useLoginProviders from '~/auth/api/useLoginProviders' import {getUserMenuItems} from '~/config/userMenuItems' import UserMenu from '~/components/layout/UserMenu' -import CaretIcon from '~/components/icons/caret.svg' +import LoginDialog from './LoginDialog' export default function LoginButton() { const providers = useLoginProviders() @@ -28,9 +24,8 @@ export default function LoginButton() { const status = session?.status || 'loading' const [open, setOpen] = useState(false) const theme = useTheme() - const fullScreen = useMediaQuery(theme.breakpoints.down('md')) - /* Sign in dialog */ + /* LoginDialog */ const handleClickOpen = () => { setOpen(true) } const handleClose = () => { setOpen(false) } @@ -57,37 +52,11 @@ export default function LoginButton() { - - - Sign in with - - - - - Somewhere, something incredible is waiting to be known. -
Carl Sagan -
- {providers.map(provider => { - return ( - - - {provider.name} - - - ) - })} -
-
-
+ /> ) } diff --git a/frontend/components/login/LoginDialog.tsx b/frontend/components/login/LoginDialog.tsx new file mode 100644 index 000000000..32159627b --- /dev/null +++ b/frontend/components/login/LoginDialog.tsx @@ -0,0 +1,99 @@ +import Link from 'next/link' + +import Dialog from '@mui/material/Dialog' +import DialogContent from '@mui/material/DialogContent' +import DialogTitle from '@mui/material/DialogTitle' +import useMediaQuery from '@mui/material/useMediaQuery' +import {useTheme} from '@mui/material/styles' +import List from '@mui/material/List' +import ListItem from '@mui/material/ListItem' +import ListItemText from '@mui/material/ListItemText' +import CloseIcon from '@mui/icons-material/Close' +import IconButton from '@mui/material/IconButton' + +import {Provider} from 'pages/api/fe/auth' + +type LoginDialogProps = { + providers: Provider[] + open:boolean, + onClose:()=>void +} + +export default function LoginDialog({providers,open, onClose}: LoginDialogProps) { + const theme = useTheme() + const fullScreen = useMediaQuery(theme.breakpoints.down('md')) + + return ( + + + Sign in with + + + + + + <> + + {providers.map(provider => { + return ( + + + + + : null + } + sx={{ + '.MuiListItemText-primary': { + color:'primary.main', + fontSize: '1.5rem', + fontWeight: 700, + letterSpacing: '0.125rem' + } + }} + /> + + + + ) + })} + + + Somewhere, something incredible is waiting to be known. + - Carl Sagan + + + + ) +} diff --git a/frontend/pages/api/fe/auth/index.ts b/frontend/pages/api/fe/auth/index.ts index f876afb05..7047c9fc9 100644 --- a/frontend/pages/api/fe/auth/index.ts +++ b/frontend/pages/api/fe/auth/index.ts @@ -28,7 +28,8 @@ export type ApiError = { export type Provider = { name: string, - redirectUrl:string + redirectUrl: string, + html?: string } type Data = Provider[] | ApiError diff --git a/frontend/pages/api/fe/auth/local.ts b/frontend/pages/api/fe/auth/local.ts index 0c5f1c971..65f492e0e 100644 --- a/frontend/pages/api/fe/auth/local.ts +++ b/frontend/pages/api/fe/auth/local.ts @@ -6,6 +6,10 @@ export function localInfo() { return { name: 'Local account', - redirectUrl: '/login/local' + redirectUrl: '/login/local', + html: ` +

Signing in with local account is for testing purposes only. + This option should not be enabled in the production version.

+ ` } } diff --git a/frontend/pages/api/fe/auth/orcid.ts b/frontend/pages/api/fe/auth/orcid.ts index 5a37895a4..33457f369 100644 --- a/frontend/pages/api/fe/auth/orcid.ts +++ b/frontend/pages/api/fe/auth/orcid.ts @@ -57,8 +57,12 @@ export async function orcidInfo() { const redirectUrl = getRedirectUrl(redirectProps) // provide redirectUrl and name/label return { - name: 'ORCID', - redirectUrl + name: 'ORCID *', + redirectUrl, + html: ` + Signing in with ORCID is supported only for persons invited by RSD administrators. + Contact us if you wish to login with your ORCID. + ` } } return null diff --git a/frontend/pages/api/fe/auth/surfconext.ts b/frontend/pages/api/fe/auth/surfconext.ts index 69394e7b6..1f8bbef99 100644 --- a/frontend/pages/api/fe/auth/surfconext.ts +++ b/frontend/pages/api/fe/auth/surfconext.ts @@ -57,8 +57,12 @@ export async function surfconextInfo() { const redirectUrl = getRedirectUrl(redirectProps) // provide redirectUrl and name/label return { - name: 'SURFconext', - redirectUrl + name: 'SURFconext *', + redirectUrl, + html: `

Signing in with SURFconext is for Dutch Institutions who enabled + RSD service in the + SURFconext IdP dashboard. +

` } } return null From 50387cdfa50438f542942577a415acac1db238c5 Mon Sep 17 00:00:00 2001 From: "Dusan Mijatovic (PC2020)" Date: Mon, 31 Oct 2022 20:17:22 +0100 Subject: [PATCH 02/15] refactor: remove min-width for mobile as we changed viewport meta to scale to device width --- frontend/styles/global.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/styles/global.css b/frontend/styles/global.css index fb43ffe80..90e8e1912 100644 --- a/frontend/styles/global.css +++ b/frontend/styles/global.css @@ -16,7 +16,7 @@ body{ font-size: 1rem; /* minimal with to have logo, menu and profile */ - min-width: 29rem; + /* min-width: 29rem; */ } #__next { From 2e1cbc15899c110ad6909bb70537b6322f3907fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Mee=C3=9Fen?= <14222414+cmeessen@users.noreply.github.com> Date: Tue, 1 Nov 2022 10:34:52 +0100 Subject: [PATCH 03/15] minor: adds description for Helmholtz AAI button --- frontend/pages/api/fe/auth/helmholtzaai.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/frontend/pages/api/fe/auth/helmholtzaai.ts b/frontend/pages/api/fe/auth/helmholtzaai.ts index f9ae2f061..fee968822 100644 --- a/frontend/pages/api/fe/auth/helmholtzaai.ts +++ b/frontend/pages/api/fe/auth/helmholtzaai.ts @@ -1,3 +1,4 @@ +// SPDX-FileCopyrightText: 2022 Christian Meeßen (GFZ) // SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all) // SPDX-FileCopyrightText: 2022 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences // SPDX-FileCopyrightText: 2022 Matthias Rüster (GFZ) @@ -57,7 +58,10 @@ export async function helmholtzInfo() { // provide redirectUrl and name/label return { name: 'Helmholtz AAI', - redirectUrl + redirectUrl, + html: ` + Sign in with Helmholtz AAI is enabled for all members of the Helmholtz Research Foundation. + ` } } return null From 77f3e6fbe410172cce214f08d9bee6fe8270254c Mon Sep 17 00:00:00 2001 From: "Dusan Mijatovic (PC2020)" Date: Tue, 1 Nov 2022 13:23:30 +0100 Subject: [PATCH 04/15] chore: improve provider info texts. feat: add link to signing in documentation. --- frontend/components/feedback/FeedbackPanelButton.tsx | 2 +- frontend/components/login/LoginDialog.tsx | 10 +++++++--- frontend/config/rsdSettingsReducer.ts | 1 + frontend/pages/api/fe/auth/local.ts | 2 +- frontend/pages/api/fe/auth/orcid.ts | 6 +++--- frontend/pages/api/fe/auth/surfconext.ts | 4 ++-- frontend/public/data/settings.json | 3 ++- 7 files changed, 17 insertions(+), 11 deletions(-) diff --git a/frontend/components/feedback/FeedbackPanelButton.tsx b/frontend/components/feedback/FeedbackPanelButton.tsx index 4e834a25f..601e6bb09 100644 --- a/frontend/components/feedback/FeedbackPanelButton.tsx +++ b/frontend/components/feedback/FeedbackPanelButton.tsx @@ -11,7 +11,7 @@ import Divider from '@mui/material/Divider' import getBrowser from '~/utils/getBrowser' export default function FeedbackPanelButton( - {feedback_email, issues_page_url, closeFeedbackPanel}: { feedback_email: string, issues_page_url:string, closeFeedbackPanel?: () => void } + {feedback_email, issues_page_url, closeFeedbackPanel}: {feedback_email: string, issues_page_url:string, closeFeedbackPanel?: () => void } ) { const [text, setText] = useState('') diff --git a/frontend/components/login/LoginDialog.tsx b/frontend/components/login/LoginDialog.tsx index 32159627b..79a03b6d3 100644 --- a/frontend/components/login/LoginDialog.tsx +++ b/frontend/components/login/LoginDialog.tsx @@ -12,6 +12,7 @@ import CloseIcon from '@mui/icons-material/Close' import IconButton from '@mui/material/IconButton' import {Provider} from 'pages/api/fe/auth' +import useRsdSettings from '~/config/useRsdSettings' type LoginDialogProps = { providers: Provider[] @@ -20,6 +21,7 @@ type LoginDialogProps = { } export default function LoginDialog({providers,open, onClose}: LoginDialogProps) { + const {host} = useRsdSettings() const theme = useTheme() const fullScreen = useMediaQuery(theme.breakpoints.down('md')) @@ -89,9 +91,11 @@ export default function LoginDialog({providers,open, onClose}: LoginDialogProps) ) })} - - Somewhere, something incredible is waiting to be known. - - Carl Sagan + {host.login_info_url && +

+ You can find more information on signing in to the RSD in our documentation. +

+ } diff --git a/frontend/config/rsdSettingsReducer.ts b/frontend/config/rsdSettingsReducer.ts index bbffd14e8..9abb31e53 100644 --- a/frontend/config/rsdSettingsReducer.ts +++ b/frontend/config/rsdSettingsReducer.ts @@ -25,6 +25,7 @@ export type RsdHost = { url: string, issues_page_url: string }, + login_info_url?:string } export type CustomLink = { diff --git a/frontend/pages/api/fe/auth/local.ts b/frontend/pages/api/fe/auth/local.ts index 65f492e0e..b6e56dce0 100644 --- a/frontend/pages/api/fe/auth/local.ts +++ b/frontend/pages/api/fe/auth/local.ts @@ -8,7 +8,7 @@ export function localInfo() { name: 'Local account', redirectUrl: '/login/local', html: ` -

Signing in with local account is for testing purposes only. +

Sign in with local account is for testing purposes only. This option should not be enabled in the production version.

` } diff --git a/frontend/pages/api/fe/auth/orcid.ts b/frontend/pages/api/fe/auth/orcid.ts index 33457f369..82bf76136 100644 --- a/frontend/pages/api/fe/auth/orcid.ts +++ b/frontend/pages/api/fe/auth/orcid.ts @@ -57,11 +57,11 @@ export async function orcidInfo() { const redirectUrl = getRedirectUrl(redirectProps) // provide redirectUrl and name/label return { - name: 'ORCID *', + name: 'ORCID', redirectUrl, html: ` - Signing in with ORCID is supported only for persons invited by RSD administrators. - Contact us if you wish to login with your ORCID. + Sign in with ORCID is supported only for persons invited by the RSD administrators. + Contact us if you wish to login with your ORCID. ` } } diff --git a/frontend/pages/api/fe/auth/surfconext.ts b/frontend/pages/api/fe/auth/surfconext.ts index 1f8bbef99..84b9c00c5 100644 --- a/frontend/pages/api/fe/auth/surfconext.ts +++ b/frontend/pages/api/fe/auth/surfconext.ts @@ -57,9 +57,9 @@ export async function surfconextInfo() { const redirectUrl = getRedirectUrl(redirectProps) // provide redirectUrl and name/label return { - name: 'SURFconext *', + name: 'SURFconext', redirectUrl, - html: `

Signing in with SURFconext is for Dutch Institutions who enabled + html: `

Sign in with SURFconext is for Dutch Institutions who enabled the RSD service in the SURFconext IdP dashboard.

` diff --git a/frontend/public/data/settings.json b/frontend/public/data/settings.json index 3eb169f9b..8ef251b04 100644 --- a/frontend/public/data/settings.json +++ b/frontend/public/data/settings.json @@ -8,7 +8,8 @@ "enabled": true, "url": "rsd@esciencecenter.nl", "issues_page_url": "https://github.com/research-software-directory/RSD-as-a-service/issues" - } + }, + "login_info_url":"https://research-software-directory.github.io/documentation/getting-started.html#signing-in" }, "links": [ { From fd29818087cecde214f8552a5c6fa79546ced843 Mon Sep 17 00:00:00 2001 From: "Dusan Mijatovic (PC2020)" Date: Tue, 1 Nov 2022 13:24:31 +0100 Subject: [PATCH 05/15] chore: bump fe version --- docker-compose.yml | 4 ++-- frontend/package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index aa685efe7..bb26c3a4e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -91,7 +91,7 @@ services: # dockerfile to use for build dockerfile: Dockerfile # update version number to correspond to frontend/package.json - image: rsd/frontend:1.6.6 + image: rsd/frontend:1.9.1 environment: # it uses values from .env file - POSTGREST_URL @@ -203,7 +203,7 @@ services: - DUID - DGID # update version number to correspond to frontend/package.json - image: rsd/frontend-dev:1.6.4 + image: rsd/frontend-dev:1.9.1 ports: - "3000:3000" - "9229:9229" diff --git a/frontend/package.json b/frontend/package.json index 46e865151..9e9e5cb58 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,6 +1,6 @@ { "name": "rsd-frontend", - "version": "1.6.4", + "version": "1.9.1", "private": true, "scripts": { "dev": "next dev", From b2bdc5893c0cce6ebb15c5e3c64db0658c36bc95 Mon Sep 17 00:00:00 2001 From: "Dusan Mijatovic (PC2020)" Date: Tue, 1 Nov 2022 17:54:30 +0100 Subject: [PATCH 06/15] fix: show only specific links in the organisation info card chore: remove unused hook/file --- .../organisation/metadata/Links.tsx | 47 +++++ .../organisation/metadata/RorLocation.tsx | 44 +++++ .../organisation/metadata/RorType.tsx | 33 ++++ .../organisation/metadata/UnderlinedTitle.tsx | 8 + .../organisation/metadata/index.tsx | 186 ++++-------------- .../metadata/useOrganisationMetadata.ts | 23 --- 6 files changed, 165 insertions(+), 176 deletions(-) create mode 100644 frontend/components/organisation/metadata/Links.tsx create mode 100644 frontend/components/organisation/metadata/RorLocation.tsx create mode 100644 frontend/components/organisation/metadata/RorType.tsx create mode 100644 frontend/components/organisation/metadata/UnderlinedTitle.tsx delete mode 100644 frontend/components/organisation/metadata/useOrganisationMetadata.ts diff --git a/frontend/components/organisation/metadata/Links.tsx b/frontend/components/organisation/metadata/Links.tsx new file mode 100644 index 000000000..6bac70a22 --- /dev/null +++ b/frontend/components/organisation/metadata/Links.tsx @@ -0,0 +1,47 @@ +import Link from 'next/link' +import UnderlinedTitle from './UnderlinedTitle' + +export type LinksProps = { + title: string, + url: string + icon: JSX.Element, +} + +export default function Links({links=[]}:{links:LinksProps[]}) { + try { + if (links.length === 0) return null + + return ( + <> + + + + ) + } catch (e) { + return null + } +} diff --git a/frontend/components/organisation/metadata/RorLocation.tsx b/frontend/components/organisation/metadata/RorLocation.tsx new file mode 100644 index 000000000..c613bda15 --- /dev/null +++ b/frontend/components/organisation/metadata/RorLocation.tsx @@ -0,0 +1,44 @@ +import Link from 'next/link' +import PlaceIcon from '@mui/icons-material/Place' +import {RORItem} from '~/utils/getROR' +import UnderlinedTitle from './UnderlinedTitle' + +export default function RorLocation({meta}: { meta: RORItem | null }) { + try { + if (meta===null) return null + const location = meta.addresses[0] + if (location) { + const country = meta.country.country_name + const {lng,lat} = location + if (lng && lat) { + const query = encodeURIComponent(`${meta.name},${location.city},${country}`) + return ( + <> + + + +
+ +
+
{meta.name}
+
{location.city}, {country}
+
+
+
+ + + ) + } + return null + } + return null + } catch (e) { + return null + } +} diff --git a/frontend/components/organisation/metadata/RorType.tsx b/frontend/components/organisation/metadata/RorType.tsx new file mode 100644 index 000000000..9629c67e0 --- /dev/null +++ b/frontend/components/organisation/metadata/RorType.tsx @@ -0,0 +1,33 @@ +import Chip from '@mui/material/Chip' +import {RORItem} from '~/utils/getROR' +import UnderlinedTitle from './UnderlinedTitle' + +export default function RorType({meta}:{meta:RORItem|null}) { + try { + if (meta===null) return null + return ( + <> + +
+ {meta.types.map(item => ( + + ))} +
+ + ) + } catch (e) { + return null + } +} diff --git a/frontend/components/organisation/metadata/UnderlinedTitle.tsx b/frontend/components/organisation/metadata/UnderlinedTitle.tsx new file mode 100644 index 000000000..e4f13ddf4 --- /dev/null +++ b/frontend/components/organisation/metadata/UnderlinedTitle.tsx @@ -0,0 +1,8 @@ +export default function UnderlinedTitle({title}:{title: string}) { + return ( + <> +

{title}

+
+ + ) +} diff --git a/frontend/components/organisation/metadata/index.tsx b/frontend/components/organisation/metadata/index.tsx index 11aa38c16..df3191d45 100644 --- a/frontend/components/organisation/metadata/index.tsx +++ b/frontend/components/organisation/metadata/index.tsx @@ -1,9 +1,12 @@ -import Link from 'next/link' import {RORItem} from '~/utils/getROR' import OrganisationLogo from './OrganisationLogo' -import PlaceIcon from '@mui/icons-material/Place' -import Chip from '@mui/material/Chip' import {OrganisationForOverview} from '~/types/Organisation' +import RorType from './RorType' +import Links, {LinksProps} from './Links' +import RorLocation from './RorLocation' +import LanguageIcon from '@mui/icons-material/Language' +import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined' +import AutoStoriesIcon from '@mui/icons-material/AutoStories' type OrgnisationInfoProps = { organisation: OrganisationForOverview, @@ -11,167 +14,42 @@ type OrgnisationInfoProps = { isMaintainer: boolean } -export function UnderlinedTitle({title}:{title: string}) { - return ( - <> -

{title}

-
- - ) -} - -export function RorLocation({meta}: { meta: RORItem | null }) { - try { - if (meta===null) return null - const location = meta.addresses[0] - if (location) { - const country = meta.country.country_name - const {lng,lat} = location - if (lng && lat) { - const query = encodeURIComponent(`${meta.name},${location.city},${country}`) - return ( - <> - - - -
- -
-
{meta.name}
-
{location.city}, {country}
-
-
-
- - - ) - } - return null - } - return null - } catch (e) { - return null - } -} - -export function Links({links=[]}:{links:string[]}) { - try { - if (links.length===0) return null - return ( - <> - - {links.map(item => ( - - -
{item}
-
- - ))} - - ) - } catch (e) { - return null - } -} - -export function RorTypes({meta}:{meta:RORItem|null}) { - try { - if (meta===null) return null - return ( - <> - -
- {meta.types.map(item => ( - - ))} -
- - ) - } catch (e) { - return null - } -} - - export default function OrganisationMetadata({organisation, meta, isMaintainer}: OrgnisationInfoProps) { function getAllLinks() { - const links:string[] = [] + const rsdLinks:LinksProps[]=[] if (organisation.website) { // website as first link - links.push(organisation.website) - } - if (meta && meta.links) { - meta.links.forEach(item => { - // add only new items - if (links.indexOf(item) === -1) { - links.push(item) - } + rsdLinks.push({ + title: 'Website', + url: organisation.website, + icon: , + }) + } else if (meta && meta.links && meta.links.length > 0) { + rsdLinks.push({ + title: 'Website', + url: meta.links[0], + icon: , }) } // meta.id is ror_id url - if (meta && meta.id && links.indexOf(meta.id) === -1) { + if (meta && meta.id) { // add only new items - links.push(meta.id) + rsdLinks.push({ + title:'ROR info', + url: meta.id, + icon: , + }) } // some organisations provide wikipedia page - if (meta && meta?.wikipedia_url && links.indexOf(meta?.wikipedia_url) === -1) { - links.push(meta?.wikipedia_url) - } - return links - } - - function renderInfo() { - // if no metadata but website is provided - if (meta === null && organisation.website) { - // we return one link - return ( - - ) - } else if (meta) { - // if ror_id is valid (meta is present) we - // merge all links from meta and organisation.website - const links = getAllLinks() - return ( - <> - - - - - ) + if (meta && meta?.wikipedia_url) { + rsdLinks.push({ + title:'Wikipedia', + url: meta?.wikipedia_url, + icon: , + }) } - // if no meta and no website we return nothing - return null + return rsdLinks } return ( @@ -184,7 +62,9 @@ export default function OrganisationMetadata({organisation, meta, isMaintainer}: isMaintainer={isMaintainer} {...organisation} /> - {renderInfo()} + + + ) } diff --git a/frontend/components/organisation/metadata/useOrganisationMetadata.ts b/frontend/components/organisation/metadata/useOrganisationMetadata.ts deleted file mode 100644 index 3e7048680..000000000 --- a/frontend/components/organisation/metadata/useOrganisationMetadata.ts +++ /dev/null @@ -1,23 +0,0 @@ -import {useEffect, useState} from 'react' -import {getOrganisationMetadata, RORItem} from '~/utils/getROR' - -export function useOrganisationmMetadata(ror_id: string|null) { - const [meta, setMeta] = useState (null) - const [loading, setLoading] = useState(true) - - useEffect(() => { - async function getMeta() { - const resp = await getOrganisationMetadata(ror_id) - setMeta(resp) - setLoading(false) - } - if (ror_id) { - getMeta() - } - },[ror_id]) - - return { - meta, - loading - } -} From bea708f7097ec0a6ff247773e85e92f158dbd653 Mon Sep 17 00:00:00 2001 From: "Dusan Mijatovic (PC2020)" Date: Mon, 31 Oct 2022 19:39:34 +0100 Subject: [PATCH 07/15] feat: preload keywords filter with 30 most used keywords --- frontend/components/keyword/FindKeyword.tsx | 23 ++++++++++++++++++- frontend/components/keyword/KeywordFilter.tsx | 20 ++++++++++++---- .../edit/information/searchForKeyword.ts | 4 ++-- .../software/SoftwareKeywordFilter.tsx | 2 +- .../information/searchForSoftwareKeyword.ts | 7 +++--- frontend/pages/software/index.tsx | 1 + frontend/styles/global.css | 2 -- 7 files changed, 46 insertions(+), 13 deletions(-) diff --git a/frontend/components/keyword/FindKeyword.tsx b/frontend/components/keyword/FindKeyword.tsx index 63c43a77d..c01b55553 100644 --- a/frontend/components/keyword/FindKeyword.tsx +++ b/frontend/components/keyword/FindKeyword.tsx @@ -5,7 +5,7 @@ // // SPDX-License-Identifier: Apache-2.0 -import {HTMLAttributes, useState} from 'react' +import {HTMLAttributes, useEffect, useState} from 'react' import AsyncAutocompleteSC, {AsyncAutocompleteConfig, AutocompleteOption} from '~/components/form/AsyncAutocompleteSC' @@ -32,6 +32,27 @@ export default function FindKeyword({config, onAdd, searchForKeyword, onCreate}: foundFor: undefined }) + useEffect(() => { + async function getInitalList() { + const resp = await searchForKeyword({ + // we trim raw search value + searchFor: '' + }) + // convert keywords to autocomplete options + const options = resp.map(item => ({ + key: item.keyword, + label: item.keyword, + data: item + })) + // debugger + // set options + setOptions(options) + } + getInitalList() + // ignore linter for searchForKeyword fn + // eslint-disable-next-line react-hooks/exhaustive-deps + },[]) + async function searchKeyword(searchFor: string) { // console.log('searchKeyword...searchFor...', searchFor) // set loading status and clear foundFor diff --git a/frontend/components/keyword/KeywordFilter.tsx b/frontend/components/keyword/KeywordFilter.tsx index 794698fc3..1da82ac28 100644 --- a/frontend/components/keyword/KeywordFilter.tsx +++ b/frontend/components/keyword/KeywordFilter.tsx @@ -3,7 +3,7 @@ // // SPDX-License-Identifier: Apache-2.0 -import {useState, Fragment} from 'react' +import {useState, Fragment, useEffect} from 'react' import IconButton from '@mui/material/IconButton' import Tooltip from '@mui/material/Tooltip' import Badge from '@mui/material/Badge' @@ -17,6 +17,7 @@ import PlayArrowIcon from '@mui/icons-material/PlayArrow' import FindKeyword, {Keyword} from '~/components/keyword/FindKeyword' import Alert from '@mui/material/Alert' +import {height} from '@mui/system' type SeachApiProps = { searchFor: string @@ -41,7 +42,9 @@ export default function KeywordsFilter({items=[], searchApi, onApply}:KeywordFil // console.log('selectedItems...', selectedItems) // console.log('open...', open) // console.groupEnd() + useEffect(() => { + },[]) function handleOpen(event: React.MouseEvent){ setAnchorEl(event.currentTarget) @@ -92,8 +95,10 @@ export default function KeywordsFilter({items=[], searchApi, onApply}:KeywordFil + handleDelete(pos)} + sx={{ + borderRadius:'0.25rem' + }} /> ) @@ -102,8 +107,10 @@ export default function KeywordsFilter({items=[], searchApi, onApply}:KeywordFil handleDelete(pos)} + sx={{ + borderRadius:'0.25rem' + }} /> ) })} @@ -129,6 +136,8 @@ export default function KeywordsFilter({items=[], searchApi, onApply}:KeywordFil

diff --git a/frontend/components/projects/edit/information/searchForKeyword.ts b/frontend/components/projects/edit/information/searchForKeyword.ts index e87d2e304..e23a69853 100644 --- a/frontend/components/projects/edit/information/searchForKeyword.ts +++ b/frontend/components/projects/edit/information/searchForKeyword.ts @@ -20,8 +20,8 @@ export type NewKeyword = { export async function searchForProjectKeyword({searchFor}: { searchFor: string }) { try { - // GET top 50 matches - const url = `/api/v1/rpc/keyword_count_for_projects?keyword=ilike.*${searchFor}*&order=keyword.asc&limit=50` + // GET top 30 matches + const url = `/api/v1/rpc/keyword_count_for_projects?keyword=ilike.*${searchFor}*&order=cnt.desc.nullslast,keyword.asc&limit=30` const resp = await fetch(url, { method: 'GET' }) diff --git a/frontend/components/software/SoftwareKeywordFilter.tsx b/frontend/components/software/SoftwareKeywordFilter.tsx index 13b8ce516..3f959991a 100644 --- a/frontend/components/software/SoftwareKeywordFilter.tsx +++ b/frontend/components/software/SoftwareKeywordFilter.tsx @@ -15,7 +15,7 @@ type KeywordFilterProps = { * Keywords filter component. It receives array of keywords and returns * array of selected tags to use in filter using onSelect callback function */ -export default function SoftwareKeywordsFilter({items=[], onApply}:KeywordFilterProps) { +export default function SoftwareKeywordsFilter({items = [], onApply}: KeywordFilterProps) { return ( Date: Wed, 2 Nov 2022 12:55:03 +0100 Subject: [PATCH 08/15] tests: updated tests for new behaviour --- .../components/keyword/FindKeyword.test.tsx | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/frontend/components/keyword/FindKeyword.test.tsx b/frontend/components/keyword/FindKeyword.test.tsx index 99ec5fc11..f3a483a27 100644 --- a/frontend/components/keyword/FindKeyword.test.tsx +++ b/frontend/components/keyword/FindKeyword.test.tsx @@ -54,9 +54,9 @@ it('calls seach Fn and renders the loader', async () => { }) await waitFor(() => { - // validate that searchFn is called once - expect(mockSearch).toHaveBeenCalledTimes(1) - // is called with seachFor term + // validate that searchFn is called twice (first on load then on search) + expect(mockSearch).toHaveBeenCalledTimes(2) + // last called with seachFor term expect(mockSearch).toHaveBeenCalledWith({searchFor}) // check if loader is present const loader = screen.getByTestId('circular-loader') @@ -80,8 +80,10 @@ it('renders component with label, help and input with role comobox', () => { it('offer Add option when search has no results', async() => { // prepare jest.useFakeTimers() - // resolve with no options - mockSearch.mockResolvedValueOnce([]) + // resolve with no options twice (on load and on search) + mockSearch + .mockResolvedValueOnce([]) + .mockResolvedValueOnce([]) // render component render() @@ -113,11 +115,15 @@ it('DOES NOT offer Add option when search return result that match', async () => const searchFor = 'test' const searchCnt = 123 // resolve with no options - mockSearch.mockResolvedValueOnce([{ - id: '123123', - keyword: searchFor, - cnt: searchCnt - }]) + mockSearch + // intial call on load + .mockResolvedValueOnce([]) + // search call + .mockResolvedValueOnce([{ + id: '123123', + keyword: searchFor, + cnt: searchCnt + }]) // render component render() @@ -152,7 +158,10 @@ it('calls onCreate method with string value to add new option', async() => { // prepare jest.useFakeTimers() // resolve with no options - mockSearch.mockResolvedValueOnce([]) + mockSearch + // intial call on load + .mockResolvedValueOnce([]) + .mockResolvedValueOnce([]) // render component render() @@ -192,7 +201,11 @@ it('calls onAdd method to add option to selection', async() => { cnt: searchCnt } // resolve with no options - mockSearch.mockResolvedValueOnce([mockOption]) + mockSearch + // intial call on load + .mockResolvedValueOnce([]) + // search call + .mockResolvedValueOnce([mockOption]) // render component render() From f06fbad8be89155ab6605ad380650f8761f63968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20Mee=C3=9Fen?= <14222414+cmeessen@users.noreply.github.com> Date: Wed, 2 Nov 2022 13:39:02 +0100 Subject: [PATCH 09/15] minor: slightly more friendly message if repo url is missing --- frontend/components/software/CommitsChart.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/software/CommitsChart.tsx b/frontend/components/software/CommitsChart.tsx index 099825ff8..89b808ac4 100644 --- a/frontend/components/software/CommitsChart.tsx +++ b/frontend/components/software/CommitsChart.tsx @@ -38,7 +38,7 @@ export default function CommitsChart({repository_url, commit_history, commit_his // ELSE if no commit history we show graph placeholder with the message let noCommitMessage: string | undefined if (typeof repository_url === 'undefined' || repository_url === null) { - noCommitMessage = 'We cannot scrape the commit history because repository url is missing.' + noCommitMessage = 'We cannot display the activity graph, because we do not know the repository url.' } else if (typeof commit_history_scraped_at === 'undefined' || commit_history_scraped_at === null) { // not scraped yet noCommitMessage = 'We did not scrape the commit history of this repository yet.' From c2665967b2b86df9b2bad59a428a3fe488b64e07 Mon Sep 17 00:00:00 2001 From: "Dusan Mijatovic (PC2020)" Date: Wed, 2 Nov 2022 17:49:57 +0100 Subject: [PATCH 10/15] refactor: move filter icon before search input. Dynamicaly change tooltip label in the searchboxes. Include keyword field in search when the keyword filter is not applied. --- .../components/keyword/FindKeyword.test.tsx | 4 +++ frontend/components/keyword/KeywordFilter.tsx | 23 +++++++++------- .../components/mention/FindMention.test.tsx | 6 +++++ .../components/organisation/project/index.tsx | 2 +- .../organisation/software/index.tsx | 2 +- .../components/software/SoftwareKeywords.tsx | 4 +-- frontend/pages/organisations/index.tsx | 2 +- frontend/pages/projects/index.tsx | 11 ++++---- frontend/pages/software/index.tsx | 22 ++++++++------- frontend/utils/getOrganisations.ts | 4 +-- frontend/utils/postgrestUrl.ts | 27 ++++++++++++++----- 11 files changed, 68 insertions(+), 39 deletions(-) diff --git a/frontend/components/keyword/FindKeyword.test.tsx b/frontend/components/keyword/FindKeyword.test.tsx index f3a483a27..4c1848199 100644 --- a/frontend/components/keyword/FindKeyword.test.tsx +++ b/frontend/components/keyword/FindKeyword.test.tsx @@ -31,6 +31,10 @@ const props = { onCreate:mockCreate } +afterEach(() => { + jest.runOnlyPendingTimers() + // jest.useRealTimers() +}) // this test needs to be first to return mocked non-resolving promise it('calls seach Fn and renders the loader', async () => { diff --git a/frontend/components/keyword/KeywordFilter.tsx b/frontend/components/keyword/KeywordFilter.tsx index 1da82ac28..88f435329 100644 --- a/frontend/components/keyword/KeywordFilter.tsx +++ b/frontend/components/keyword/KeywordFilter.tsx @@ -11,13 +11,13 @@ import Divider from '@mui/material/Divider' import Button from '@mui/material/Button' import FilterAltIcon from '@mui/icons-material/FilterAlt' import CloseIcon from '@mui/icons-material/Close' +import CheckIcon from '@mui/icons-material/Check' import Popover from '@mui/material/Popover' import Chip from '@mui/material/Chip' -import PlayArrowIcon from '@mui/icons-material/PlayArrow' +import Alert from '@mui/material/Alert' +import AlertTitle from '@mui/material/AlertTitle' import FindKeyword, {Keyword} from '~/components/keyword/FindKeyword' -import Alert from '@mui/material/Alert' -import {height} from '@mui/system' type SeachApiProps = { searchFor: string @@ -119,9 +119,9 @@ export default function KeywordsFilter({items=[], searchApi, onApply}:KeywordFil } // debugger return ( - - {/* No keywords to filter. */} - Add keyword by typing in the Find keyword. + + Filter is not active + Select the keyword from the list of most often used terms or start typing to search for the specific term. ) } @@ -129,7 +129,10 @@ export default function KeywordsFilter({items=[], searchApi, onApply}:KeywordFil return ( <> 0 ? selectedItems.join(' + ') : 'None'}`}> - + @@ -142,8 +145,8 @@ export default function KeywordsFilter({items=[], searchApi, onApply}:KeywordFil open={open} onClose={handleClose} // align menu to the right from the menu button - transformOrigin={{horizontal: 'right', vertical: 'top'}} - anchorOrigin={{horizontal: 'right', vertical: 'bottom'}} + transformOrigin={{horizontal: 'center', vertical: 'top'}} + anchorOrigin={{horizontal: 'center', vertical: 'bottom'}} sx={{ display: 'flex', flexDirection: 'column', @@ -180,7 +183,7 @@ export default function KeywordsFilter({items=[], searchApi, onApply}:KeywordFil diff --git a/frontend/pages/software/index.tsx b/frontend/pages/software/index.tsx index ab5b4a620..54b5d6ab5 100644 --- a/frontend/pages/software/index.tsx +++ b/frontend/pages/software/index.tsx @@ -22,7 +22,6 @@ import {getSoftwareList} from '../../utils/getSoftware' import {ssrSoftwareParams} from '../../utils/extractQueryParam' import {softwareListUrl,ssrSoftwareUrl} from '../../utils/postgrestUrl' import SoftwareKeywordFilter from '~/components/software/SoftwareKeywordFilter' -import {searchForSoftwareKeyword} from '~/components/software/edit/information/searchForSoftwareKeyword' type SoftwareIndexPageProps = { count: number, From 5aa3813fb1c19af9ef84f7dd4d2fd526d760c956 Mon Sep 17 00:00:00 2001 From: "Dusan Mijatovic (PC2020)" Date: Fri, 4 Nov 2022 10:29:43 +0100 Subject: [PATCH 13/15] chore: improve no seleted keywords message --- frontend/components/keyword/KeywordFilter.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/frontend/components/keyword/KeywordFilter.tsx b/frontend/components/keyword/KeywordFilter.tsx index 3ae4a1cb5..56d74c218 100644 --- a/frontend/components/keyword/KeywordFilter.tsx +++ b/frontend/components/keyword/KeywordFilter.tsx @@ -114,10 +114,11 @@ export default function KeywordsFilter({items=[], searchApi, onApply}:KeywordFil ) } // debugger + // return null return ( Filter is not active - Select the keyword from the list of most often used terms or start typing to search for the specific term. + Select a keyword from the list or start typing. ) } @@ -159,7 +160,7 @@ export default function KeywordsFilter({items=[], searchApi, onApply}:KeywordFil config={{ freeSolo: false, minLength: 0, - label: 'Find keyword', + label: 'Select or type a keyword', help: '', reset: true }} From 8307e695a443aecc47df71641726577c62c8645e Mon Sep 17 00:00:00 2001 From: Ewan Cahen Date: Wed, 2 Nov 2022 16:56:26 +0100 Subject: [PATCH 14/15] fix: show a custom error message when logging in fails --- authentication/README.md | 30 +++-- .../rsd/authentication/Main.java | 126 ++++++++---------- ...PostgrestCheckOrcidWhitelistedAccount.java | 2 +- ...n.java => RsdAuthenticationException.java} | 4 +- frontend/auth/locationCookie.ts | 1 + frontend/pages/login/failed.tsx | 23 +++- 6 files changed, 100 insertions(+), 86 deletions(-) rename authentication/src/main/java/nl/esciencecenter/rsd/authentication/{AuthenticationException.java => RsdAuthenticationException.java} (69%) diff --git a/authentication/README.md b/authentication/README.md index ac5cb1ce0..b4b395d73 100644 --- a/authentication/README.md +++ b/authentication/README.md @@ -1,5 +1,7 @@