Skip to content

Commit

Permalink
Merge pull request #486 from research-software-directory/433-team-mem…
Browse files Browse the repository at this point in the history
…bers

433 team members
  • Loading branch information
ewan-escience authored Aug 26, 2022
2 parents c325ab2 + 4b2f311 commit 2bb7d40
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 35 deletions.
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ services:
# dockerfile to use for build
dockerfile: Dockerfile
# update version number to corespond to frontend/package.json
image: rsd/frontend:1.2.2
image: rsd/frontend:1.2.3
environment:
# it uses values from .env file
- POSTGREST_URL
Expand Down
24 changes: 7 additions & 17 deletions frontend/components/form/AsyncAutocompleteSC.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 Ewan Cahen (Netherlands eScience Center) <e.cahen@esciencecenter.nl>
// SPDX-FileCopyrightText: 2022 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences
// SPDX-FileCopyrightText: 2022 Matthias Rüster (GFZ) <matthias.ruester@gfz-potsdam.de>
// SPDX-FileCopyrightText: 2022 Netherlands eScience Center
// SPDX-FileCopyrightText: 2022 dv4all
//
// SPDX-License-Identifier: Apache-2.0
Expand All @@ -22,6 +24,7 @@ export type AutocompleteOption<T> = {
export type AsyncAutocompleteConfig = {
// enables creation of new items
freeSolo: boolean
forceShowAdd?: boolean,
minLength: number,
label: string,
help: string,
Expand Down Expand Up @@ -81,23 +84,10 @@ export default function AsyncAutocompleteSC<T>({status, options, config,
// create request is allowed only
// if the length is sufficient
// and we are not loading api responses
// AND onCreate method is provided
if (value.length >= config.minLength &&
loading === false) {
// console.log('requestCreate...', value)
if (options.length > 0) {
// try to find item in the options
const foundItems = options.filter(item => item.label.toLocaleLowerCase() === value.toLocaleLowerCase())
if (foundItems.length > 0) {
// if we found item in available options
// we use it
onAdd(foundItems[0])
} else if (onCreate) {
// otherwise we create item
onCreate(value)
}
} else if (onCreate) {
onCreate(value)
}
loading === false && onCreate) {
onCreate(value)
if (config?.reset) {
// reset selected value to nothing
setSelected(null)
Expand Down Expand Up @@ -213,7 +203,7 @@ export default function AsyncAutocompleteSC<T>({status, options, config,
// console.groupEnd()
if (loading === false &&
inputValue === foundFor &&
inputInOptions === false &&
(inputInOptions === false || config.forceShowAdd === true) &&
config.freeSolo === true
) {
// if we are not loading from api,
Expand Down
10 changes: 7 additions & 3 deletions frontend/components/projects/edit/team/FindMember.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 Ewan Cahen (Netherlands eScience Center) <e.cahen@esciencecenter.nl>
// SPDX-FileCopyrightText: 2022 Netherlands eScience Center
// SPDX-FileCopyrightText: 2022 dv4all
//
// SPDX-License-Identifier: Apache-2.0
Expand All @@ -9,6 +11,7 @@ import AsyncAutocompleteSC, {AutocompleteOption} from '~/components/form/AsyncAu
import FindContributorItem from '~/components/software/edit/contributors/FindContributorItem'
import {SearchTeamMember, TeamMember} from '~/types/Project'
import {splitName} from '~/utils/getDisplayName'
import {isOrcid} from '~/utils/getORCID'
import {cfgTeamMembers} from './config'
import {searchForMember} from './searchForMember'

Expand Down Expand Up @@ -101,10 +104,10 @@ export default function FindMember({onAdd,project,token}:FindMemberProps) {
function renderOption(props: HTMLAttributes<HTMLLIElement>,
option: AutocompleteOption<SearchTeamMember>) {
// console.log('renderOption...', option)
// when value is not not found option returns input prop
// when value is not found option returns input prop
if (option?.input) {
// if input is over minLength
if (option?.input.length > cfgTeamMembers.find.validation.minLength) {
// add option is NOT available when searching by ORCID
if (isOrcid(option?.input)===false) {
// we offer an option to create this entry
return renderAddOption(props,option)
} else {
Expand All @@ -130,6 +133,7 @@ export default function FindMember({onAdd,project,token}:FindMemberProps) {
onRenderOption={renderOption}
config={{
freeSolo: true,
forceShowAdd: true,
minLength: cfgTeamMembers.find.validation.minLength,
label: cfgTeamMembers.find.label,
help: cfgTeamMembers.find.help,
Expand Down
4 changes: 2 additions & 2 deletions frontend/components/projects/edit/team/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ export const cfgTeamMembers = {
title: 'Team Members',
find: {
title: 'Add member',
subtitle: 'We search by name in RSD and ORCID databases',
subtitle: 'We search by name and ORCID in RSD and ORCID databases',
label: 'Find or add team memeber',
help: 'At least 2 letters, use pattern {First name} {Last name}',
help: 'At least 2 letters, use pattern {First name} {Last name} or 0000-0000-0000-0000',
validation: {
// custom validation rule, not in use by react-hook-form
minLength: 2,
Expand Down
17 changes: 14 additions & 3 deletions frontend/components/projects/edit/team/searchForMember.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 Ewan Cahen (Netherlands eScience Center) <e.cahen@esciencecenter.nl>
// SPDX-FileCopyrightText: 2022 Netherlands eScience Center
// SPDX-FileCopyrightText: 2022 dv4all
//
// SPDX-License-Identifier: Apache-2.0

import {AutocompleteOption} from '~/types/AutocompleteOptions'
import {SearchTeamMember} from '~/types/Project'
import {createJsonHeaders} from '~/utils/fetchHelpers'
import {getORCID} from '~/utils/getORCID'
import {getORCID, isOrcid} from '~/utils/getORCID'
import logger from '../../../../utils/logger'

export type Keyword = {
Expand Down Expand Up @@ -46,10 +48,19 @@ export async function searchForMember({searchFor,token,frontend=true}:
export async function findRSDMember({searchFor, token, frontend}:
{ searchFor: string, token?: string, frontend?: boolean }) {
try {
let url = `${process.env.POSTGREST_URL}/rpc/unique_team_members?display_name=ilike.*${searchFor}*&limit=20`
let url = '/rpc/unique_team_members?limit=20'
if (frontend) {
url = `/api/v1/rpc/unique_team_members?display_name=ilike.*${searchFor}*&limit=20`
url = '/api/v1' + url
} else {
url = `${process.env.POSTGREST_URL}` + url
}

if (isOrcid(searchFor)) {
url = url + `&orcid=eq.${searchFor}`
} else {
url = url + `&display_name=ilike.*${searchFor}*`
}

const resp = await fetch(url, {
method: 'GET',
headers: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 Ewan Cahen (Netherlands eScience Center) <e.cahen@esciencecenter.nl>
// SPDX-FileCopyrightText: 2022 Netherlands eScience Center
// SPDX-FileCopyrightText: 2022 dv4all
//
// SPDX-License-Identifier: Apache-2.0
Expand All @@ -11,6 +13,7 @@ import FindContributorItem from './FindContributorItem'
import {splitName} from '../../../../utils/getDisplayName'
import {contributorInformation as config} from '../editSoftwareConfig'
import AsyncAutocompleteSC,{AutocompleteOption} from '~/components/form/AsyncAutocompleteSC'
import {isOrcid} from '~/utils/getORCID'

export type Name = {
given_names: string
Expand Down Expand Up @@ -80,10 +83,10 @@ export default function FindContributor({onAdd, onCreate}:
function renderOption(props: HTMLAttributes<HTMLLIElement>,
option: AutocompleteOption<SearchContributor>) {
// console.log('renderOption...', option)
// when value is not not found option returns input prop
// when value is not found option returns input prop
if (option?.input) {
// if input is over minLength
if (option?.input.length > config.findContributor.validation.minLength) {
// add option is NOT available when searching by ORCID
if (isOrcid(option?.input)===false) {
// we offer an option to create this entry
return renderAddOption(props,option)
} else {
Expand All @@ -109,6 +112,7 @@ export default function FindContributor({onAdd, onCreate}:
onRenderOption={renderOption}
config={{
freeSolo: true,
forceShowAdd: true,
minLength: config.findContributor.validation.minLength,
label: config.findContributor.label,
help: config.findContributor.help,
Expand Down
4 changes: 2 additions & 2 deletions frontend/components/software/edit/editSoftwareConfig.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ export type SoftwareInformationConfig = typeof softwareInformation
export const contributorInformation = {
findContributor: {
title: 'Add contributor',
subtitle: 'We search by name in the RSD and the ORCID databases',
subtitle: 'We search by name and ORCID in the RSD and the ORCID databases',
label: 'Find or add contributor',
help: 'At least 2 letters, use pattern {First name} {Last name}',
help: 'At least 2 letters, use pattern {First name} {Last name} or 0000-0000-0000-0000',
validation: {
// custom validation rule, not in use by react-hook-form
minLength: 2,
Expand Down
16 changes: 12 additions & 4 deletions frontend/utils/editContributors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
import {AutocompleteOption} from '../types/AutocompleteOptions'
import {Contributor, ContributorProps, SearchContributor} from '../types/Contributor'
import {createJsonHeaders, extractReturnMessage} from './fetchHelpers'
import {getORCID} from './getORCID'
import {getORCID, isOrcid} from './getORCID'
import {getPropsFromObject} from './getPropsFromObject'
import logger from './logger'
import {sortOnStrProp} from './sortFn'
Expand Down Expand Up @@ -96,11 +96,19 @@ export async function searchForContributor({searchFor, token, frontend}:
async function findRSDContributor({searchFor, token, frontend}:
{ searchFor: string, token?: string, frontend?: boolean }) {
try {

let url = `${process.env.POSTGREST_URL}/rpc/unique_contributors?display_name=ilike.*${searchFor}*&limit=20`
let url = '/rpc/unique_contributors?limit=20'
if (frontend) {
url = `/api/v1/rpc/unique_contributors?display_name=ilike.*${searchFor}*&limit=20`
url = '/api/v1' + url
} else {
url = `${process.env.POSTGREST_URL}` + url
}

if (isOrcid(searchFor)) {
url = url + `&orcid=eq.${searchFor}`
} else {
url = url + `&display_name=ilike.*${searchFor}*`
}

const resp = await fetch(url, {
method: 'GET',
headers: {
Expand Down
10 changes: 10 additions & 0 deletions frontend/utils/getORCID.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
// SPDX-FileCopyrightText: 2022 Dusan Mijatovic (dv4all)
// SPDX-FileCopyrightText: 2022 Ewan Cahen (Netherlands eScience Center) <e.cahen@esciencecenter.nl>
// SPDX-FileCopyrightText: 2022 Netherlands eScience Center
// SPDX-FileCopyrightText: 2022 dv4all
//
// SPDX-License-Identifier: Apache-2.0
Expand Down Expand Up @@ -27,6 +29,11 @@ const exampleResponse = {
export type OrcidRecord = typeof exampleResponse

const baseUrl = 'https://pub.orcid.org/v3.0/expanded-search/'
const orcidRegex = /^\d{4}-\d{4}-\d{4}-\d{3}[0-9X]$/

export function isOrcid(stringToCheck: string): boolean {
return stringToCheck.match(orcidRegex) !== null
}

export async function getORCID({searchFor}: { searchFor: string }) {
try {
Expand Down Expand Up @@ -57,6 +64,9 @@ export async function getORCID({searchFor}: { searchFor: string }) {
}

function buildSearchQuery(searchFor: string) {
if (isOrcid(searchFor)) {
return `q=orcid:${searchFor}`
}
const names = searchFor.split(' ')
const given_names = names[0]
const family_names = names.length > 1 ? names.slice(1).join(' ') : null
Expand Down

0 comments on commit 2bb7d40

Please sign in to comment.