diff --git a/database/025-rsd-info.sql b/database/025-rsd-info.sql index 035c20043..f24ed457b 100644 --- a/database/025-rsd-info.sql +++ b/database/025-rsd-info.sql @@ -41,7 +41,7 @@ CREATE TRIGGER sanitise_update_rsd_info BEFORE UPDATE ON -- EXAMPLE OF PUBLIC PROPERTIES TO INSERT IN THE rsd_info table -- REMOTE NAME IS used to identify your instance to other RSD instances -INSERT INTO rsd_info VALUES ('remote_name','Not defined',TRUE); +INSERT INTO rsd_info VALUES ('remote_name','My RSD instance',TRUE); -- RLS -- rsd info table diff --git a/database/124-aggregated-software-views.sql b/database/124-aggregated-software-views.sql index 279e19838..c9e763bbf 100644 --- a/database/124-aggregated-software-views.sql +++ b/database/124-aggregated-software-views.sql @@ -1,6 +1,6 @@ --- SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center) +-- SPDX-FileCopyrightText: 2024 - 2025 Dusan Mijatovic (Netherlands eScience Center) +-- SPDX-FileCopyrightText: 2024 - 2025 Netherlands eScience Center -- SPDX-FileCopyrightText: 2024 Ewan Cahen (Netherlands eScience Center) --- SPDX-FileCopyrightText: 2024 Netherlands eScience Center -- -- SPDX-License-Identifier: Apache-2.0 @@ -26,8 +26,8 @@ CREATE FUNCTION aggregated_software_overview() RETURNS TABLE ( $$ SELECT software_overview.id, - -- use remote_name information for local name - (SELECT value FROM rsd_info WHERE KEY='remote_name') AS source, + -- use remote_name information for local name or DEFAULT value My RSD instance + COALESCE((SELECT value FROM rsd_info WHERE KEY='remote_name'),'My RSD instance') AS source, NULL AS domain, software_overview.slug, software_overview.brand_name, diff --git a/documentation/docs/03-rsd-instance/01-getting-started.md b/documentation/docs/03-rsd-instance/01-getting-started.md index 3e41f5230..1d573e007 100644 --- a/documentation/docs/03-rsd-instance/01-getting-started.md +++ b/documentation/docs/03-rsd-instance/01-getting-started.md @@ -22,15 +22,6 @@ POSTGRES_AUTHENTICATOR_PASSWORD=reallyreallyreallyreallyverysafe PGRST_JWT_SECRET=reallyreallyreallyreallyverysafe ``` -- Define remote name of your instance in the .env file. Other RSD instances can pull software information from your instance. How to link the remote RSD instances is described in the [remotes chapter](/rsd-instance/administration/#remotes) of the administration section. - -```env -# RSD REMOTE NAME -# identify this instance as remote by this name -# it is used as source label in RPC aggregated_software_overview -RSD_REMOTE_NAME=Local RSD -``` - - Start RSD using docker compose ```bash @@ -123,7 +114,7 @@ cp .env.example .env and change, as described above, the values for `POSTGRES_PASSWORD`, `PGRST_JWT_SECRET` (with at least 32 characters) and `POSTGRES_AUTHENTICATOR_PASSWORD` to arbitrary values. Additionally set -``` +```env POSTGREST_URL_EXTERNAL=http://fqdn.yourdomain.com/api/v1 RSD_AUTH_URL=http://fqdn.yourdomain.com:7000 ``` diff --git a/documentation/docs/03-rsd-instance/01-getting-started.md.license b/documentation/docs/03-rsd-instance/01-getting-started.md.license index 035cdadc3..0c4564c98 100644 --- a/documentation/docs/03-rsd-instance/01-getting-started.md.license +++ b/documentation/docs/03-rsd-instance/01-getting-started.md.license @@ -1,5 +1,5 @@ -SPDX-FileCopyrightText: 2023 - 2024 Dusan Mijatovic (Netherlands eScience Center) SPDX-FileCopyrightText: 2023 - 2024 Ewan Cahen (Netherlands eScience Center) -SPDX-FileCopyrightText: 2023 - 2024 Netherlands eScience Center +SPDX-FileCopyrightText: 2023 - 2025 Dusan Mijatovic (Netherlands eScience Center) +SPDX-FileCopyrightText: 2023 - 2025 Netherlands eScience Center SPDX-License-Identifier: CC-BY-4.0 diff --git a/documentation/docs/03-rsd-instance/03-administration.md b/documentation/docs/03-rsd-instance/03-administration.md index e7ff04376..c34bc9b83 100644 --- a/documentation/docs/03-rsd-instance/03-administration.md +++ b/documentation/docs/03-rsd-instance/03-administration.md @@ -194,12 +194,20 @@ In this section, admins can search for mentions and edit them. If you enter a DO Edit mentions with care: they might be referenced to in multiple places. If you want to fully change a mention attached to e.g. a software page, you should delete it there and create a new one instead of editing it. ::: +## RSD info + +Here you can define information about your RSD instance that you want to communicate to other RSD instances or some "third party services" developed by you or someone else. + +The core RSD services use the following information defined at this section: + +- `remote_name`: This is the name of your RSD instance. It used by other RSD instances to identify your RSD. It is also used by your RSD instance to identify your software entries when you make use of [Remotes](#remotes). + ## Remotes -Here you can connect your RSD to remote RSD instances. These connections will be used to "enrich" your RSD instance with additional (remote) software entries. +Here you can connect your RSD to remote RSD instances. These connections will be used to "enrich" your RSD instance with additional (remote) software entries. -:::info -When connecting to remote RSD instances, each software card in the software overview shows the source RSD. The software from the "local" RSD uses `remote_name` from the rsd_info table. This value is inserted in rsd_info table during the initialization of RSD instance using docker-compose.yml that uses `RSD_REMOTE_NAME` environment variable (see docker-compose.yml and .env.example). +:::tip +When connecting to remote RSD instances, each software card in the software overview shows the source RSD. The software from the your "local" RSD uses `remote_name` defined in [RSD Info section](#rsd-info). ::: For each remote RSD you wish to connect to, you need to provide the URL to the homepage of that RSD instance. If the RSD remote is of version 3 or higher the instance will return an RSD instance name suggested by the instance owner. For the earlier RSD versions you need to provide remote name/label manually. diff --git a/documentation/docs/03-rsd-instance/03-administration.md.license b/documentation/docs/03-rsd-instance/03-administration.md.license index e7e93a639..bd56cae28 100644 --- a/documentation/docs/03-rsd-instance/03-administration.md.license +++ b/documentation/docs/03-rsd-instance/03-administration.md.license @@ -1,8 +1,8 @@ -SPDX-FileCopyrightText: 2023 - 2024 Dusan Mijatovic (Netherlands eScience Center) SPDX-FileCopyrightText: 2023 - 2024 Dusan Mijatovic (dv4all) (dv4all) SPDX-FileCopyrightText: 2023 - 2024 Ewan Cahen (Netherlands eScience Center) -SPDX-FileCopyrightText: 2023 - 2024 Netherlands eScience Center SPDX-FileCopyrightText: 2023 - 2024 dv4all +SPDX-FileCopyrightText: 2023 - 2025 Dusan Mijatovic (Netherlands eScience Center) +SPDX-FileCopyrightText: 2023 - 2025 Netherlands eScience Center SPDX-FileCopyrightText: 2024 Christian Meeßen (GFZ) SPDX-FileCopyrightText: 2024 Helmholtz Centre Potsdam - GFZ German Research Centre for Geosciences diff --git a/frontend/components/admin/AdminNav.tsx b/frontend/components/admin/AdminNav.tsx index 1dee303e2..39d8bf8cd 100644 --- a/frontend/components/admin/AdminNav.tsx +++ b/frontend/components/admin/AdminNav.tsx @@ -109,7 +109,7 @@ export const adminPages = { path: '/admin/mentions', }, rsd_info:{ - title: 'Rsd info', + title: 'RSD info', subtitle: '', icon: , path: '/admin/rsd-info', diff --git a/frontend/components/admin/remote-rsd/apiRemoteRsd.ts b/frontend/components/admin/remote-rsd/apiRemoteRsd.ts index 3ce7666d3..a69e922d6 100644 --- a/frontend/components/admin/remote-rsd/apiRemoteRsd.ts +++ b/frontend/components/admin/remote-rsd/apiRemoteRsd.ts @@ -1,5 +1,5 @@ -// SPDX-FileCopyrightText: 2024 Dusan Mijatovic (Netherlands eScience Center) -// SPDX-FileCopyrightText: 2024 Netherlands eScience Center +// SPDX-FileCopyrightText: 2024 - 2025 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2024 - 2025 Netherlands eScience Center // // SPDX-License-Identifier: Apache-2.0 @@ -198,8 +198,10 @@ export async function getRemoteName(domain:string){ }) if (resp.ok){ const data = await resp.json() - const name = data[0]?.['value'] - return name + if (data[0]?.['value']){ + return data[0]?.['value'] + } + return null } return null }catch(e:any){ diff --git a/frontend/components/admin/rsd-info/RsdInfoTable.tsx b/frontend/components/admin/rsd-info/RsdInfoTable.tsx index db07fe257..5b79e4241 100644 --- a/frontend/components/admin/rsd-info/RsdInfoTable.tsx +++ b/frontend/components/admin/rsd-info/RsdInfoTable.tsx @@ -13,6 +13,7 @@ import EditableTable, {OrderByProps} from '~/components/table/EditableTable' import ContentLoader from '~/components/layout/ContentLoader' import {RsdInfo} from './apiRsdInfo' import useRsdInfo from './useRsdInfo' +import AddRsdInfo from './AddRsdInfo' const styles = { flex: 1, @@ -30,7 +31,7 @@ const initialOrder:OrderByProps = { export default function RsdInfoTable() { const {token} = useSession() const [orderBy, setOrderBy] = useState>(initialOrder) - const {loading, columns, rsdInfo} = useRsdInfo({token,orderBy}) + const {loading, columns, rsdInfo, addRsdInfo} = useRsdInfo({token,orderBy}) // console.group('RsdInfoTable') // console.log('loading...', loading) @@ -42,14 +43,16 @@ export default function RsdInfoTable() { if (rsdInfo.length === 0) { return ( -
+
- Rsd info not found + RSD info not found + Use Add button to create new entry. At least you should add remote_name to communicate name of your instance to other RSD instances. +
) } diff --git a/frontend/components/admin/rsd-info/config.tsx b/frontend/components/admin/rsd-info/config.tsx index 6f414ed7d..59c76a849 100644 --- a/frontend/components/admin/rsd-info/config.tsx +++ b/frontend/components/admin/rsd-info/config.tsx @@ -18,14 +18,16 @@ export function createColumns(token: string, addRsdInfo:(data:RsdInfo)=>void, de key: 'value', label: 'Value*', type: 'string', - validFn: ({value})=>{ - if (value && value.toString().trim()!=='') return true - return false + patchFn: async (props) => { + // change "" to null + if (props.value===''){ + props.value = null + } + return patchRsdInfo({ + ...props, + token + }) }, - patchFn: async (props) => patchRsdInfo({ - ...props, - token - }) }, { key: 'public', label: 'Public', @@ -33,12 +35,7 @@ export function createColumns(token: string, addRsdInfo:(data:RsdInfo)=>void, de patchFn: async (props) => patchRsdInfo({ ...props, token - }), - disabledFn:(data)=>{ - // remote_name public value cannot be changed - if (data.id==='remote_name') return true - return false - }, + }) },{ key: 'created_at', label: 'Created At', @@ -63,7 +60,7 @@ export function createColumns(token: string, addRsdInfo:(data:RsdInfo)=>void, de return ( { @@ -87,6 +84,7 @@ export const rsdInfoForm = { help: 'Unique single word without spaces is required.', validation: { required: 'Unique key value is required.', + minLength: {value: 3, message: 'Minimum length is 3'}, // we do not show error message for this one, we use only maxLength value maxLength: {value: 100, message: 'Maximum length is 100'}, pattern: { diff --git a/frontend/components/admin/rsd-info/useRsdInfo.tsx b/frontend/components/admin/rsd-info/useRsdInfo.tsx index 746815251..3987b24f7 100644 --- a/frontend/components/admin/rsd-info/useRsdInfo.tsx +++ b/frontend/components/admin/rsd-info/useRsdInfo.tsx @@ -8,7 +8,7 @@ import usePaginationWithSearch from '~/utils/usePaginationWithSearch' import {OrderByProps} from '~/components/table/EditableTable' import useSnackbar from '~/components/snackbar/useSnackbar' -import {createInfo, deleteInfoByKey, getRsdInfo, RsdInfoTable,RsdInfo} from './apiRsdInfo' +import {createInfo, deleteInfoByKey, getRsdInfo, RsdInfoTable, RsdInfo} from './apiRsdInfo' import {createColumns} from './config' type useContributorsProps = { @@ -92,6 +92,7 @@ export default function useRsdInfo({token, orderBy}:useContributorsProps) { return { loading, columns, - rsdInfo + rsdInfo, + addRsdInfo } } diff --git a/frontend/components/software/overview/filters/index.tsx b/frontend/components/software/overview/filters/index.tsx index 8fe60813d..d9573e457 100644 --- a/frontend/components/software/overview/filters/index.tsx +++ b/frontend/components/software/overview/filters/index.tsx @@ -1,5 +1,5 @@ -// SPDX-FileCopyrightText: 2023 - 2024 Dusan Mijatovic (Netherlands eScience Center) -// SPDX-FileCopyrightText: 2023 - 2024 Netherlands eScience Center +// SPDX-FileCopyrightText: 2023 - 2025 Dusan Mijatovic (Netherlands eScience Center) +// SPDX-FileCopyrightText: 2023 - 2025 Netherlands eScience Center // SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all) // SPDX-FileCopyrightText: 2023 Dusan Mijatovic (dv4all) (dv4all) // SPDX-FileCopyrightText: 2023 dv4all diff --git a/frontend/components/table/EditableCell.tsx b/frontend/components/table/EditableCell.tsx index 936e9f31b..c76c32dcb 100644 --- a/frontend/components/table/EditableCell.tsx +++ b/frontend/components/table/EditableCell.tsx @@ -6,9 +6,9 @@ // SPDX-License-Identifier: Apache-2.0 import {useEffect, useState} from 'react' +import Switch from '@mui/material/Switch' import useSnackbar from '~/components/snackbar/useSnackbar' import {ColType} from './EditableTable' -import Switch from '@mui/material/Switch' export type UpdateProps = { id: string, @@ -25,16 +25,14 @@ type EditableCellProps = Readonly<{ disabledFn?: (props:UpdateProps)=>boolean }> -export default function EditableCell({params,patchFn,validFn,disabledFn}: EditableCellProps) { +export default function EditableCell({params,patchFn,disabledFn}: EditableCellProps) { const {showErrorMessage} = useSnackbar() const {value} = params const [localValue, setValue] = useState(value) - const [valid, setValid] = useState(true) // console.group('EditableCell') // console.log('params...', params) // console.log('localValue...', localValue) - // console.log('valid...', valid) // console.log('value...', value) // console.groupEnd() @@ -44,31 +42,16 @@ export default function EditableCell({params,patchFn,validFn,disabledFn}: Editab async function patchValue(newValue:any) { if (patchFn) { - let validValue = true - if (validFn){ - validValue = validFn({ - ...params, - value: newValue - }) - } - // only if valid - if (validValue){ - const resp = await patchFn({ - ...params, - value: newValue - }) - if (resp.status !== 200) { - // show error message - showErrorMessage(`Failed to update value. ${resp.message}`) - // reverse back to original value - setValue(value) - } - }else{ + const resp = await patchFn({ + ...params, + value: newValue + }) + if (resp.status !== 200) { + // show error message + showErrorMessage(`Failed to update value. ${resp.message}`) // reverse back to original value setValue(value) } - // update valid if not in sync - if (validValue!==valid) setValid(validValue) } } @@ -89,7 +72,7 @@ export default function EditableCell({params,patchFn,validFn,disabledFn}: Editab return ( { diff --git a/frontend/components/table/EditableTable.tsx b/frontend/components/table/EditableTable.tsx index d2d77666e..adc21d1bc 100644 --- a/frontend/components/table/EditableTable.tsx +++ b/frontend/components/table/EditableTable.tsx @@ -33,7 +33,6 @@ export type Column = { order?: OrderProps patchFn?: (props: UpdateProps) => Promise<{ status: number, message: string }> disabledFn?: (props: UpdateProps) => boolean - validFn?: (props: UpdateProps) => boolean renderFn?: (data:T) => JSX.Element headerFn?: () => JSX.Element } diff --git a/frontend/components/table/TableBody.tsx b/frontend/components/table/TableBody.tsx index e544799fb..149be98bb 100644 --- a/frontend/components/table/TableBody.tsx +++ b/frontend/components/table/TableBody.tsx @@ -57,7 +57,6 @@ function TableRow({data }} patchFn={col?.patchFn} disabledFn={col?.disabledFn} - validFn={col?.validFn} /> )