Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dataset Catalog #225

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
9244020
Created a catalogue component
SanjeevLakhwani Nov 14, 2024
e95ddd7
Added demo data
SanjeevLakhwani Nov 14, 2024
0020bba
loaded demo data
SanjeevLakhwani Nov 14, 2024
fbb12c6
typed demo data
SanjeevLakhwani Nov 14, 2024
cdb4d94
created a card component
SanjeevLakhwani Nov 14, 2024
8996824
Added extra keyword logic
SanjeevLakhwani Nov 14, 2024
c0d92c8
Added descriptions
SanjeevLakhwani Nov 14, 2024
92743c0
Made basic dataset cards
SanjeevLakhwani Nov 14, 2024
b0956bc
Added dataset carousel
SanjeevLakhwani Nov 21, 2024
8a78b97
Added ellipses
SanjeevLakhwani Nov 21, 2024
245f838
Made the code compatible with existing data
SanjeevLakhwani Nov 21, 2024
fea86ba
Added tooltip to ellipses
SanjeevLakhwani Nov 21, 2024
ca679b1
Reorganized directory structure
SanjeevLakhwani Nov 21, 2024
e295d17
Removed redundant react import
SanjeevLakhwani Nov 21, 2024
16a034b
reformatted file
SanjeevLakhwani Nov 21, 2024
8129977
corrected keys
SanjeevLakhwani Nov 21, 2024
a2f567e
removed autoplay
SanjeevLakhwani Nov 21, 2024
39303dd
corrected import order
SanjeevLakhwani Nov 21, 2024
89057f3
renamed date string util
SanjeevLakhwani Nov 21, 2024
a13a864
Added translations
SanjeevLakhwani Nov 21, 2024
657c8fa
Improved catalogue render condition
SanjeevLakhwani Nov 21, 2024
8fbf828
Removed carousel arrows from <=1 datasets
SanjeevLakhwani Nov 21, 2024
ae0a94e
Merge remote-tracking branch 'origin/main' into feat/dataset-catalogue
davidlougheed Nov 25, 2024
8521f32
PR Changes
SanjeevLakhwani Nov 28, 2024
3380b3c
Used Already destructured values
SanjeevLakhwani Nov 28, 2024
0f67654
Destructured project
SanjeevLakhwani Dec 16, 2024
4f49046
Made catalogue card more responsive
SanjeevLakhwani Dec 16, 2024
a00cecc
improved the scopeToUrl function
SanjeevLakhwani Dec 16, 2024
341e8e1
Added buttons to navigate to project/dataset directly
SanjeevLakhwani Dec 16, 2024
1869850
Merge remote-tracking branch 'origin/main' into feat/dataset-catalogue
davidlougheed Dec 16, 2024
2be97db
Modified catalogue logo and title
SanjeevLakhwani Dec 19, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/js/components/Overview/PublicOverview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import ManageChartsDrawer from './Drawer/ManageChartsDrawer';
import Counts from './Counts';
import LastIngestionInfo from './LastIngestion';
import Loader from '@/components/Loader';
import Dataset from '@/components/Provenance/Dataset';
import Dataset from '@/components/Provenance/Catalogue/Dataset';
import Catalogue from '@/components/Provenance/Catalogue/Catalogue';

import { useAppSelector } from '@/hooks';
import { useSelectedProject, useSelectedScope } from '@/features/metadata/hooks';
import { useMetadata, useSelectedProject, useSelectedScope } from '@/features/metadata/hooks';
import { useTranslation } from 'react-i18next';
import { RequestStatus } from '@/types/requests';

Expand All @@ -37,6 +38,7 @@ const PublicOverview = () => {

const selectedProject = useSelectedProject();
const { scope } = useSelectedScope();
const { projects } = useMetadata();

useEffect(() => {
// Save sections to localStorage when they change
Expand All @@ -59,6 +61,8 @@ const PublicOverview = () => {
saveToLocalStorage(sections);
}, [sections]);

if (!selectedProject && projects.length > 1) return <Catalogue />;

return !isContentPopulated || isFetchingOverviewData ? (
<Loader />
) : (
Expand Down
16 changes: 16 additions & 0 deletions src/js/components/Provenance/Catalogue/Catalogue.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Space } from 'antd';
import CatalogueCard from './CatalogueCard';
import { useMetadata } from '@/features/metadata/hooks';

const Catalogue = () => {
const { projects } = useMetadata();
return (
<Space align="center" direction="vertical" size="large" style={{ width: '100%' }}>
{projects.map((project) => (
<CatalogueCard project={project} key={project.identifier} />
))}
</Space>
);
};

export default Catalogue;
116 changes: 116 additions & 0 deletions src/js/components/Provenance/Catalogue/CatalogueCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
import { useMemo } from 'react';
import i18n from '@/i18n';
import { Card, Carousel, Descriptions, Flex, Space, Tag, Tooltip, Typography } from 'antd';
import type { Project } from '@/types/metadata';
import { isoDateToString } from '@/utils/strings';
import { useTranslationFn } from '@/hooks';
import { BOX_SHADOW } from '@/constants/overviewConstants';
import Dataset from '@/components/Provenance/Catalogue/Dataset';

const { Paragraph, Text, Title } = Typography;

const MAX_KEYWORD_CHARACTERS = 50;

const CatalogueCard = ({ project }: { project: Project }) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think for consistency this should be called Project. we can then later split it into multiple view modes, like with Dataset.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather change, Dataset to CatalogDataset as Dataset/Project by itself can mean multiple things in public context by conflicting with overview. I do understand that it is in a folder but the naming does reduce the readability.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

catalogdataset to me doesn't make sense, as the dataset isn't just used in the catalog

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean it in the form that a "Dataset" could mean multiple things while at least prefixing catalog tells the purpose. If you think otherwise still, lmk, I shall change it.

const lang = i18n.language;
const t = useTranslationFn();

const { selectedKeywords, extraKeywords, extraKeywordCount } = useMemo(() => {
const keywords = project.datasets.flatMap((d) => d.dats_file.keywords ?? []).map((k) => t(k.value as string));

let totalCharacters = 0;
const selectedKeywords: string[] = [];
const extraKeywords: string[] = [];

for (const keyword of keywords) {
if (totalCharacters + keyword.length > MAX_KEYWORD_CHARACTERS) {
extraKeywords.push(keyword);
} else {
selectedKeywords.push(keyword);
totalCharacters += keyword.length;
}
}

return {
selectedKeywords,
extraKeywords,
extraKeywordCount: extraKeywords.length,
};
}, [project.datasets, t]);

const projectCreated = isoDateToString(project.created, lang);
const projectUpdated = isoDateToString(project.updated, lang);

const projectInfo = [
{
key: '1',
label: t('Created'),
children: (
<Paragraph
ellipsis={{
rows: 1,
tooltip: { title: projectCreated },
}}
>
{projectCreated}
</Paragraph>
),
span: 1.5,
},
{
key: '2',
label: t('Updated'),
children: <Paragraph ellipsis={{ rows: 1, tooltip: { title: projectUpdated } }}>{projectUpdated}</Paragraph>,
span: 1.5,
},
];

return (
<Card key={project.identifier} style={{ height: '260px', maxWidth: '1300px', ...BOX_SHADOW }}>
SanjeevLakhwani marked this conversation as resolved.
Show resolved Hide resolved
<Flex justify="space-between">
<div style={{ flex: 1, paddingRight: '10px' }}>
<Space direction="vertical">
<Title level={4} style={{ marginTop: 0 }}>
{t(project.title)}
</Title>
<Paragraph
SanjeevLakhwani marked this conversation as resolved.
Show resolved Hide resolved
ellipsis={{
rows: 3,
tooltip: { title: t(project.description) },
}}
>
{t(project.description)}
</Paragraph>
<div>
{selectedKeywords.map((kw) => (
<Tag key={kw} color="blue">
{kw}
</Tag>
))}
{extraKeywordCount !== 0 && (
<Tooltip title={extraKeywords.join(', ')}>
<Text>+{extraKeywordCount} more</Text>
</Tooltip>
)}
</div>
<Descriptions items={projectInfo} />
</Space>
</div>
<div style={{ flex: 1, maxWidth: '600px' }}>
<Title level={5} style={{ marginTop: 0 }}>
{t('Datasets')}
</Title>
<Carousel
arrows={project.datasets.length > 1}
style={{ border: '1px solid lightgray', borderRadius: '7px', height: '170px', padding: '16px' }}
>
{project.datasets.map((d) => (
<Dataset parentProjectID={project.identifier} key={d.identifier} dataset={d} format="carousel" />
))}
</Carousel>
</div>
</Flex>
</Card>
);
};
export default CatalogueCard;
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { RightOutlined } from '@ant-design/icons';
import { useCallback } from 'react';
import SmallChartCardTitle from '@/components/Util/SmallChartCardTitle';

const { Paragraph } = Typography;
const { Paragraph, Title } = Typography;

const KEYWORDS_LIMIT = 2;

Expand All @@ -22,7 +22,7 @@ const Dataset = ({
}: {
parentProjectID: string;
dataset: Dataset;
format: 'list-item' | 'card';
format: 'list-item' | 'card' | 'carousel';
selected?: boolean;
}) => {
const location = useLocation();
Expand Down Expand Up @@ -81,6 +81,17 @@ const Dataset = ({
</Space>
</Card>
);
} else if (format === 'carousel') {
return (
<>
<Title level={5} style={{ marginTop: 0 }}>
{t(dataset.title)}
SanjeevLakhwani marked this conversation as resolved.
Show resolved Hide resolved
</Title>
<Paragraph ellipsis={{ rows: 4, tooltip: { title: t(dataset.description) } }}>
{t(dataset.description)}
SanjeevLakhwani marked this conversation as resolved.
Show resolved Hide resolved
</Paragraph>
</>
);
} else {
return <span style={{ color: 'red' }}>UNIMPLEMENTED</span>;
}
Expand Down
2 changes: 1 addition & 1 deletion src/js/components/Scope/DatasetScopePicker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { DiscoveryScope } from '@/features/metadata/metadata.store';
import { useTranslationFn } from '@/hooks';
import type { Project } from '@/types/metadata';
import { getCurrentPage, scopeToUrl } from '@/utils/router';
import Dataset from '@/components/Provenance/Dataset';
import Dataset from '@/components/Provenance/Catalogue/Dataset';
import { useSelectedScope } from '@/features/metadata/hooks';

type DatasetScopePickerProps = {
Expand Down
4 changes: 3 additions & 1 deletion src/js/types/metadata.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Layout as DiscoveryOverview, Fields as DiscoveryFields } from '@/types/overviewResponse';
import type { Fields as DiscoveryFields, Layout as DiscoveryOverview } from '@/types/overviewResponse';
import type { Section as DiscoverySearch } from '@/types/search';
import type { DiscoveryRules } from '@/types/configResponse';
import type { DatsFile } from '@/types/dats';
Expand All @@ -16,6 +16,8 @@ export interface Project {
description: string;
discovery: Discovery | null;
datasets: Dataset[];
created: string;
updated: string;
}

export interface Dataset {
Expand Down
10 changes: 10 additions & 0 deletions src/js/utils/strings.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
import { DOI_PATTERN, URL_PATTERN } from '@/constants/patterns';
// import i18n from '@/i18n';

export const stringToBoolean = (s: string | undefined) =>
['true', 't', '1', 'yes'].includes((s || '').toLocaleLowerCase());

export const stringIsDOI = (s: string) => !!s.match(DOI_PATTERN);
export const stringIsURL = (s: string) => !!s.match(URL_PATTERN);

export const isoDateToString = (d: string, lang?: string) => {
const dateLang = lang === 'fr' ? 'fr-CA' : 'en-US';
return new Date(d).toLocaleString(dateLang, {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not use i18n.language (or in this case the lang argument) directly here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I gets accessed before i18n is initialized causing issues.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but can it be passed into the function elsewhere, thus mitigating the "if french else assume english" extra logic?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can create a utility function for it to separate logic., but I think such logic also exists on the initial render of the website (except there is an extra log statement for saying unsupported language).

year: 'numeric',
month: 'long',
day: 'numeric',
});
};
4 changes: 3 additions & 1 deletion src/public/locales/en/default_translation_en.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,7 @@
"Coordinates are one-based.",
"Leave this form blank to search by metadata only."
]
}
},
"Created": "Created",
"Updated": "Updated"
}
4 changes: 3 additions & 1 deletion src/public/locales/fr/default_translation_fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -129,5 +129,7 @@
"Les coordonnées sont en base un.",
"Laissez ce formulaire vide pour effectuer une recherche sur les métadonnées seulement."
]
}
},
"Created": "Créé",
"Updated": "Mis à jour"
}
8 changes: 8 additions & 0 deletions src/styles.css
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,14 @@ body {
gap: 20px;
}

.slick-arrow {
color: black !important; /* override slick-next/slick-prev color */
SanjeevLakhwani marked this conversation as resolved.
Show resolved Hide resolved
}

.slick-dots li button {
background-color: black !important; /* override slick-dots color */
}

/* END search results pane */


Expand Down