diff --git a/src/js/components/Provenance/DatasetProvenance.tsx b/src/js/components/Provenance/DatasetProvenance.tsx
index d1ed9f2a..65949796 100644
--- a/src/js/components/Provenance/DatasetProvenance.tsx
+++ b/src/js/components/Provenance/DatasetProvenance.tsx
@@ -30,7 +30,7 @@ const DatasetProvenance = ({ metadata, loading }: DatasetProvenanceProps) => {
{t(metadata.version)}
,
]}
- style={{ borderRadius: '11px', maxWidth: '1400px' }}
+ style={{ borderRadius: '11px' }}
loading={loading}
>
{/* --- DESCRIPTION ---*/}
@@ -44,7 +44,7 @@ const DatasetProvenance = ({ metadata, loading }: DatasetProvenanceProps) => {
{t(metadata.privacy)}
)}
- {metadata.licenses.length && (
+ {!!metadata.licenses?.length && (
}>
{metadata.licenses.map((l, i) => (
@@ -53,11 +53,11 @@ const DatasetProvenance = ({ metadata, loading }: DatasetProvenanceProps) => {
))}
)}
- {metadata.keywords.length && (
+ {!!metadata.keywords?.length && (
}>
{metadata.keywords.map((keyword, i) => (
- {t(keyword.value)}
+ {t(keyword.value.toString())}
))}
@@ -67,32 +67,60 @@ const DatasetProvenance = ({ metadata, loading }: DatasetProvenanceProps) => {
{/* TableTitle has translation in it*/}
{/* --- CREATED BY ---*/}
-
-
+ {!!metadata.creators?.length && (
+ <>
+
+
+ >
+ )}
{/* --- DISTRIBUTIONS ---*/}
-
-
+ {!!metadata.distributions?.length && (
+ <>
+
+
+ >
+ )}
{/* --- IS ABOUT ---*/}
-
-
+ {!!metadata.isAbout?.length && (
+ <>
+
+
+ >
+ )}
{/* --- PUBLICATIONS ---*/}
-
-
+ {!!metadata.primaryPublications?.length && (
+ <>
+
+
+ >
+ )}
{/* --- ACKNOWLEDGES ---*/}
-
-
+ {!!metadata.acknowledges?.length && (
+ <>
+
+
+ >
+ )}
{/* --- SPATIAL COVERAGE ---*/}
-
-
+ {!!metadata.spatialCoverage?.length && (
+ <>
+
+
+ >
+ )}
{/* --- EXTRA PROPERTIES ---*/}
-
-
+ {!!metadata.extraProperties?.length && (
+ <>
+
+
+ >
+ )}
{/* --- DOWNLOAD DATS --- */}
@@ -108,7 +136,7 @@ export type DatasetProvenanceProps = {
export default DatasetProvenance;
-const TableTitleWitTranslation = ({ title }: { title: string }) => {
+const TableTitleWithTranslation = ({ title }: { title: string }) => {
const { t } = useTranslation(DEFAULT_TRANSLATION);
return (
diff --git a/src/js/components/Provenance/Tables/AcknowledgesTable.tsx b/src/js/components/Provenance/Tables/AcknowledgesTable.tsx
index 165c3f65..92100add 100644
--- a/src/js/components/Provenance/Tables/AcknowledgesTable.tsx
+++ b/src/js/components/Provenance/Tables/AcknowledgesTable.tsx
@@ -1,5 +1,4 @@
import React from 'react';
-import { Tag } from 'antd';
import BaseProvenanceTable from './BaseProvenanceTable';
import LinkIfUrl from '../../Util/LinkIfUrl';
@@ -24,10 +23,11 @@ const AcknowledgesTable = ({ acknowledges }: AcknowledgesTableProps) => {
dataIndex: 'funders',
render: (_, { funders }) =>
funders.map((f, i) => (
-
+
- {f.abbreviation ? `(${t(f.abbreviation)})` : ''}
-
+ {f.abbreviation ? ` (${t(f.abbreviation)})` : ''}
+ {i < funders.length - 1 ? '; ' : ''}
+
)),
},
]}
diff --git a/src/js/components/Provenance/Tables/CreatedByTable.tsx b/src/js/components/Provenance/Tables/CreatedByTable.tsx
index 30ddb65e..7a837d55 100644
--- a/src/js/components/Provenance/Tables/CreatedByTable.tsx
+++ b/src/js/components/Provenance/Tables/CreatedByTable.tsx
@@ -33,7 +33,7 @@ const CreatedByTable = ({ creators }: CreatedByTableProps) => {
roles &&
roles.map((r, i) => (
- {t(r.value)}
+ {t(r.value.toString())}
)),
},
diff --git a/src/js/components/Provenance/Tables/DistributionsTable.tsx b/src/js/components/Provenance/Tables/DistributionsTable.tsx
index e87c0151..aff70350 100644
--- a/src/js/components/Provenance/Tables/DistributionsTable.tsx
+++ b/src/js/components/Provenance/Tables/DistributionsTable.tsx
@@ -1,19 +1,20 @@
-import React from 'react';
+import React, { useMemo } from 'react';
+
import { Tag, Typography } from 'antd';
+import { ColumnsType } from 'antd/es/table';
const { Link } = Typography;
import BaseProvenanceTable from './BaseProvenanceTable';
import { useTranslationDefault, useTranslationCustom } from '@/hooks';
-import { ProvenanceStoreDataset } from '@/types/provenance';
+import { Distribution, ProvenanceStoreDataset } from '@/types/provenance';
const DistributionsTable = ({ distributions }: DistributionsTableProps) => {
const t = useTranslationCustom();
const td = useTranslationDefault();
- return (
-
+ [
{
title: td('Formats'),
dataIndex: 'formats',
@@ -27,7 +28,7 @@ const DistributionsTable = ({ distributions }: DistributionsTableProps) => {
{
title: td('Unit'),
dataIndex: 'unit',
- render: (_, { unit }) => t(unit.value),
+ render: (_, { unit }) => t(unit.value.toString()),
},
{
title: td('Access'),
@@ -47,15 +48,17 @@ const DistributionsTable = ({ distributions }: DistributionsTableProps) => {
render: (_, { access }) =>
access.authorizations.map((a, i) => (
- {t(a.value)}
+ {t(a.value.toString())}
)),
},
],
},
- ]}
- />
+ ] as ColumnsType,
+ [td]
);
+
+ return ;
};
export interface DistributionsTableProps {
diff --git a/src/js/components/Provenance/Tables/ExtraPropertiesTable.tsx b/src/js/components/Provenance/Tables/ExtraPropertiesTable.tsx
index 2032193c..1cecb2ed 100644
--- a/src/js/components/Provenance/Tables/ExtraPropertiesTable.tsx
+++ b/src/js/components/Provenance/Tables/ExtraPropertiesTable.tsx
@@ -1,33 +1,36 @@
-import React from 'react';
-import { Tag } from 'antd';
+import React, { useMemo } from 'react';
+
+import { ColumnsType } from 'antd/es/table';
import BaseProvenanceTable from '@/components/Provenance/Tables/BaseProvenanceTable';
import LinkIfUrl from '../../Util/LinkIfUrl';
import { useTranslationCustom, useTranslationDefault } from '@/hooks';
-import { ProvenanceStoreDataset } from '@/types/provenance';
+import { ExtraProperty, ProvenanceStoreDataset } from '@/types/provenance';
const ExtraPropertiesTable = ({ extraProperties }: ExtraPropertiesTableProps) => {
const t = useTranslationCustom();
const td = useTranslationDefault();
- return (
-
+ [
{ title: td('Category'), dataIndex: 'category', render: (text) => t(text) },
{
title: td('Values'),
dataIndex: 'values',
render: (_, { values }) =>
values.map((v, i) => (
-
-
-
+ <>
+
+ {i < values.length - 1 ? '; ' : ''}
+ >
)),
},
- ]}
- />
+ ] as ColumnsType,
+ [td]
);
+
+ return ;
};
export interface ExtraPropertiesTableProps {
diff --git a/src/js/components/Provenance/Tables/PublicationsTable.tsx b/src/js/components/Provenance/Tables/PublicationsTable.tsx
index 59a071e7..772eba28 100644
--- a/src/js/components/Provenance/Tables/PublicationsTable.tsx
+++ b/src/js/components/Provenance/Tables/PublicationsTable.tsx
@@ -1,70 +1,124 @@
-import React from 'react';
-import { Tag, Typography } from 'antd';
+import React, { ReactNode, useMemo } from 'react';
+
+import { Typography } from 'antd';
+import { ColumnsType } from 'antd/es/table';
import BaseProvenanceTable from './BaseProvenanceTable';
import LinkIfUrl from '../../Util/LinkIfUrl';
import { useTranslationCustom, useTranslationDefault } from '@/hooks';
-import { ProvenanceStoreDataset } from '@/types/provenance';
+import { Person, PrimaryPublication, ProvenanceStoreDataset } from '@/types/provenance';
+
+import { stringIsDOI, stringIsURL } from '@/utils/strings';
+
+const URLLink = ({ url, children }: { url: string; children?: ReactNode }) => (
+
+ {children || url}
+
+);
+
+const DOILink = ({ doi, children }: { doi: string; children?: ReactNode }) => (
+ {children || doi}
+);
+
+const formatAuthorList = (authors: Person[]): string => {
+ const fullNames = authors.map((a) => a.fullName);
+ if (fullNames.length === 0) {
+ return '';
+ } else if (fullNames.length === 1) {
+ return `${fullNames[0]}.`;
+ } else if (fullNames.length === 2) {
+ return `${fullNames.join(' and ')}.`;
+ } else {
+ return `${fullNames.slice(0, -1).join(', ')}, and ${fullNames.at(-1)}.`;
+ }
+};
const PublicationsTable = ({ publications }: PublicationsTableProps) => {
const t = useTranslationCustom();
const td = useTranslationDefault();
- return (
-
+ [
{
- title: td('Title'),
- dataIndex: 'title',
+ title: td('Publication'),
+ key: 'publication',
+
+ render: (_, { title, identifier: { identifier }, authors }) => {
+ const formattedTitle = `${t(title)}${title.endsWith('.') ? '' : '.'}`;
+ return (
+ <>
+ {stringIsDOI(identifier) ? (
+ {formattedTitle}
+ ) : stringIsURL(identifier) ? (
+ {formattedTitle}
+ ) : (
+ formattedTitle
+ )}
+ {!!authors?.length && (
+ <>
+
+ {formatAuthorList(authors)}
+ >
+ )}
+ >
+ );
+ },
- render: (_, { title, identifier }) =>
- identifier.identifier === '' ? (
- t(title)
- ) : (
-
- {t(title)}
-
- ),
+ sorter: (a, b) => a.title.localeCompare(b.title),
},
{
title: td('Publication Venue'),
dataIndex: 'publicationVenue',
render: (text) => t(text),
+ sorter: (a, b) => a.publicationVenue.localeCompare(b.publicationVenue),
},
{
- title: td('Authors'),
- dataIndex: 'authors',
- render: (_, { authors }) =>
- authors.map((author, i) => (
-
- {author}
-
- )),
- },
- {
- title: td('Dates'),
+ title: td('Date'),
dataIndex: 'dates',
- render: (_, { dates }) =>
- dates.map((date, i) => (
-
- {date}
-
- )),
+ render: (_, { dates }) => {
+ const _dates = dates ?? [];
+ return _dates.map((date, i) => (
+ <>
+ {new Date(Date.parse(date.date)).toLocaleDateString()}
+ {i < _dates.length - 1 ? '; ' : ''}
+ >
+ ));
+ },
+ sorter: (a, b) => {
+ if (!a.dates?.length) {
+ if (!b.dates?.length) return 0;
+ return 1; // Sort blank entries after
+ } else if (!b.dates?.length) {
+ return -1; // Sort blank entries after
+ } else {
+ return Date.parse(a.dates[0].date) - Date.parse(b.dates[0].date);
+ }
+ },
+ defaultSortOrder: 'descend',
},
{
title: td('Identifier'),
dataIndex: 'identifier.identifier',
- render: (_, { identifier }) => ,
+ render: (_, { identifier: { identifier } }) =>
+ stringIsDOI(identifier) ? : ,
},
{
title: td('Identifier Source'),
dataIndex: 'identifier.identifierSource',
- render: (_, { identifier }) => t(identifier.identifierSource),
+ render: (_, { identifier: { identifierSource } }) => t(identifierSource),
+ sorter: (a, b) => a.identifier.identifierSource.localeCompare(b.identifier.identifierSource),
+ filters: Array.from(new Set(publications.map((p) => p.identifier.identifierSource))).map((v) => ({
+ text: v,
+ value: v,
+ })),
+ onFilter: (filterValue, p) => p.identifier.identifierSource === filterValue,
},
- ]}
- />
+ ] as ColumnsType,
+ [td, publications]
);
+
+ return ;
};
export interface PublicationsTableProps {
diff --git a/src/js/components/Util/LinkIfUrl.tsx b/src/js/components/Util/LinkIfUrl.tsx
new file mode 100644
index 00000000..9d1eb448
--- /dev/null
+++ b/src/js/components/Util/LinkIfUrl.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { Typography } from 'antd';
+
+import { stringIsURL } from '@/utils/strings';
+
+// Renders text as link if the text provided is a valid url.
+const LinkIfUrl = ({ text }: { text: string }) => {
+ if (stringIsURL(text)) {
+ return (
+
+ {text}
+
+ );
+ }
+ return <>{text}>;
+};
+
+export default LinkIfUrl;
diff --git a/src/js/components/Util/LinkIfUrl.js b/src/js/constants/patterns.ts
similarity index 51%
rename from src/js/components/Util/LinkIfUrl.js
rename to src/js/constants/patterns.ts
index a05bf25e..2fe9af6e 100644
--- a/src/js/components/Util/LinkIfUrl.js
+++ b/src/js/constants/patterns.ts
@@ -1,5 +1,4 @@
-import React from 'react';
-import { Typography } from 'antd';
+export const DOI_PATTERN = /^10.\d{4,9}\/[-._;()/:A-Z0-9]+$/i;
/*
^ starts with...
@@ -14,18 +13,4 @@ import { Typography } from 'antd';
+ repeated at least once
$ until the end of the string
*/
-const url_regex = /^(http|https):\/\/[^ "]+$/;
-
-// Renders text as link if the text provided is a valid url.
-const LinkIfUrl = ({ text }) => {
- if (text.match(url_regex)) {
- return (
-
- {text}
-
- );
- }
- return text;
-};
-
-export default LinkIfUrl;
+export const URL_PATTERN = /^(http|https):\/\/[^ "]+$/;
diff --git a/src/js/index.tsx b/src/js/index.tsx
index a346c0c6..f15ab5cf 100644
--- a/src/js/index.tsx
+++ b/src/js/index.tsx
@@ -37,7 +37,7 @@ const App = () => {
}, [lang, i18n.language, navigate]);
return (
-
+
diff --git a/src/js/types/provenance.ts b/src/js/types/provenance.ts
index c44bfef3..d3f7e52b 100644
--- a/src/js/types/provenance.ts
+++ b/src/js/types/provenance.ts
@@ -21,7 +21,7 @@ export interface DatsFile {
distributions: Distribution[];
extraProperties: ExtraProperty[];
isAbout: IsAbout[];
- keywords: Keyword[];
+ keywords: Annotation[];
licenses: License[];
primaryPublications: PrimaryPublication[];
privacy: string;
@@ -43,29 +43,30 @@ export interface Funder {
export interface Creator {
name: string;
- roles: Keyword[];
+ roles: Annotation[];
abbreviation?: string;
}
-export interface Keyword {
- value: string;
+export interface Annotation {
+ value: string | number;
+ valueIRI?: string;
}
export interface Distribution {
access: Access;
formats: string[];
size: number;
- unit: Keyword;
+ unit: Annotation;
}
export interface Access {
- authorizations: Keyword[];
+ authorizations: Annotation[];
landingPage: string;
}
export interface ExtraProperty {
category: string;
- values: Keyword[];
+ values: Annotation[];
}
export interface IsAbout {
@@ -82,9 +83,18 @@ export interface License {
name: string;
}
+export interface Person {
+ fullName: string;
+}
+
+export interface DateInfo {
+ date: string;
+ type?: Annotation;
+}
+
export interface PrimaryPublication {
- authors: string[];
- dates: string[];
+ authors?: Person[];
+ dates?: DateInfo[];
identifier: Identifier;
publicationVenue: string;
title: string;
@@ -96,5 +106,5 @@ export interface SpatialCoverage {
}
export interface Type {
- information: Keyword;
+ information: Annotation;
}
diff --git a/src/js/utils/strings.ts b/src/js/utils/strings.ts
new file mode 100644
index 00000000..a30bd27d
--- /dev/null
+++ b/src/js/utils/strings.ts
@@ -0,0 +1,4 @@
+import { DOI_PATTERN, URL_PATTERN } from '@/constants/patterns';
+
+export const stringIsDOI = (s: string) => !!s.match(DOI_PATTERN);
+export const stringIsURL = (s: string) => !!s.match(URL_PATTERN);
diff --git a/src/public/locales/en/default_translation_en.json b/src/public/locales/en/default_translation_en.json
index 290d1032..b3587487 100644
--- a/src/public/locales/en/default_translation_en.json
+++ b/src/public/locales/en/default_translation_en.json
@@ -18,7 +18,8 @@
"Distributions": "Distributions",
"Is About": "Is About",
"Primary Publications": "Primary Publications",
- "Acknowledges": "Acknowledges",
+ "Publication": "Publication",
+ "Acknowledgements": "Acknowledgements",
"Spatial Coverage": "Spatial Coverage",
"Extra Properties": "Extra Properties",
"Name": "Name",
@@ -38,6 +39,7 @@
"Title": "Title",
"Publication Venue": "Publication Venue",
"Authors": "Authors",
+ "Date": "Date",
"Dates": "Dates",
"Description": "Description",
"Manage Charts": "Manage Charts",
diff --git a/src/public/locales/fr/default_translation_fr.json b/src/public/locales/fr/default_translation_fr.json
index 9a55adc7..b5e11373 100644
--- a/src/public/locales/fr/default_translation_fr.json
+++ b/src/public/locales/fr/default_translation_fr.json
@@ -18,7 +18,8 @@
"Distributions": "Distributions",
"Is About": "Sujet",
"Primary Publications": "Publications primaires",
- "Acknowledges": "Reconnaît",
+ "Publication": "Publication",
+ "Acknowledgements": "Remerciements",
"Spatial Coverage": "Couverture spatiale",
"Extra Properties": "Propriétés supplémentaires",
"Name": "Nom",
@@ -38,6 +39,7 @@
"Title": "Titre",
"Publication Venue": "Lieu de publication",
"Authors": "Auteurs",
+ "Date": "Date",
"Dates": "Dates",
"Description": "Description",
"Manage Charts": "Gestion des tableaux",