From 56c34f768ece231e4c7e19262656ce1d630dae73 Mon Sep 17 00:00:00 2001 From: mrzengel <99219497+mrzengel@users.noreply.github.com> Date: Thu, 18 Jul 2024 14:00:28 +0200 Subject: [PATCH] Developed searchable community feature (and minor fixes listed below) (#38) * changed widget class * added searchable community feature * fixed column headers * switched date and software type --- src/API/API_functions.tsx | 15 +++- src/components/SearchPanel.tsx | 121 +++++++++++++++++++++------ src/index.tsx | 2 +- style/base.css | 2 +- zenodo_jupyterlab/server/handlers.py | 14 +++- zenodo_jupyterlab/server/search.py | 16 +++- 6 files changed, 134 insertions(+), 36 deletions(-) diff --git a/src/API/API_functions.tsx b/src/API/API_functions.tsx index 7326c80..7083d03 100644 --- a/src/API/API_functions.tsx +++ b/src/API/API_functions.tsx @@ -35,9 +35,9 @@ export async function testZenodoConnection() { } } -export async function searchRecords(search_field: string) { +export async function searchRecords(search_field: string, page: number) { try { - const data = await requestAPI(`zenodo-jupyterlab/search-records?search_field=${encodeURIComponent(search_field)}`, { + const data = await requestAPI(`zenodo-jupyterlab/search-records?search_field=${encodeURIComponent(search_field)}&page=${encodeURIComponent(page)}`, { method: 'GET' }); return data; @@ -46,6 +46,17 @@ export async function searchRecords(search_field: string) { } } +export async function searchCommunities(search_field: string) { + try{ + const data = await requestAPI(`zenodo-jupyterlab/search-communities?search_field=${encodeURIComponent(search_field)}`, { + method: 'GET' + }); + return data; + } catch (error) { + console.error('Error searching communities: ', error); + } +} + /* export async function runPythonCode(code: string) { try { const data = await requestAPI('zenodo-jupyterlab/code', { diff --git a/src/components/SearchPanel.tsx b/src/components/SearchPanel.tsx index b52dcdf..829dd15 100644 --- a/src/components/SearchPanel.tsx +++ b/src/components/SearchPanel.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import { searchRecords } from '../API/API_functions'; +import { searchRecords, searchCommunities } from '../API/API_functions'; import { createUseStyles } from 'react-jss'; // interface SearchResult { @@ -19,6 +19,7 @@ const useStyles = createUseStyles({ container: { display: 'flex', flexDirection: 'column', + justifyContent: 'center', alignItems: 'center', marginBottom: '20px', }, @@ -67,6 +68,20 @@ const useStyles = createUseStyles({ padding: '10px', textAlign: 'left', }, + checkboxContainer: { + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + marginBottom: '10px', + flexDirection: 'row', + }, + checkboxLabel: { + display: 'flex', + alignItems: 'center', + }, + checkboxInput: { + marginRight: '5px', + } }); const SearchWidget: React.FC = () => { @@ -74,20 +89,31 @@ const SearchWidget: React.FC = () => { const[results, setResults] = useState([]); const[searchTerm, setSearchTerm] = useState(''); const[isLoading, setIsLoading] = useState(false); + const [selectedType, setSelectedType] = useState('records'); + const [lastSearchType, setLastSearchType] = useState('records'); + const [hasSearched, setHasSearched] = useState(false); const handleSearch = async () => { setIsLoading(true); + setHasSearched(true); try { - const response = await searchRecords(searchTerm); + //const response = await searchRecords(searchTerm); + const response = selectedType === 'records' + ? await searchRecords(searchTerm, 1) + : await searchCommunities(searchTerm); //const data: SearchResult[] = await response; - setResults(response['records']); + setResults(response[selectedType]); //console.log(response['records']); } catch (error) { console.error('Error during search: ', error); } finally { + setLastSearchType(selectedType); setIsLoading(false); } } + const handleCheckboxChange = (type: string) => { + setSelectedType(type); + }; return (
@@ -98,35 +124,78 @@ const SearchWidget: React.FC = () => { placeholder="Search..." className={classes.input} /> +
+ + +
- {/* {results && ( -

{results}

- )} */} {isLoading &&

Loading Search Results...

} - {results.length > 0 && ( -
- - - - - - - - - - {results.map((result, index) => ( - - - - + {hasSearched && !isLoading && ( + results.length > 0 ? ( + lastSearchType === 'records' ? ( +
+
TitleResource TypeDate Published
{result.title}{result.date}{result.resource_type}
+ + + + + - ))} - -
TitleResource TypeDate Published
-
+ + + {results.map((result, index) => ( + + {result.title} + {result.resource_type} + {result.date} + + ))} + + +
+ ) : ( +
+ + + + + + + + + {results.map((result, index) => ( + + + + + ))} + +
TitleDate Published
{result.title}{result.date}
+
+ ) + ) : ( +

No results found.

+ ) )} + ); }; diff --git a/src/index.tsx b/src/index.tsx index 090ed92..5a4a865 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -56,7 +56,7 @@ class ZenodoWidget extends Widget { this.isTrue = true; this.showLogin = false; this.showSearch = true; - this.addClass('my-apodWidget'); + this.addClass('zenodo-widget'); this.id = 'zenodo-jupyterlab-extension'; this.title.closable = true; const icon = new LabIcon ({ diff --git a/style/base.css b/style/base.css index 4f54e33..c3fa892 100644 --- a/style/base.css +++ b/style/base.css @@ -4,7 +4,7 @@ https://jupyterlab.readthedocs.io/en/stable/developer/css.html */ -.my-apodWidget { +.zenodo-widget { display: flex; flex-direction: column; align-items: left; diff --git a/zenodo_jupyterlab/server/handlers.py b/zenodo_jupyterlab/server/handlers.py index 3a4907d..298b874 100644 --- a/zenodo_jupyterlab/server/handlers.py +++ b/zenodo_jupyterlab/server/handlers.py @@ -4,7 +4,7 @@ from jupyter_server.utils import url_path_join import os from .testConnection import testZenodoConnection -from .search import searchRecords +from .search import searchRecords, searchCommunities class EnvHandler(APIHandler): @@ -36,9 +36,16 @@ async def get(self): class SearchRecordHandler(APIHandler): async def get(self): search_field = self.get_query_argument('search_field', default="") - response = await searchRecords(search_field=search_field) + page = self.get_query_argument('page', default=1) + response = await searchRecords(search_field=search_field, page=page) self.finish({'records': response}) +class SearchCommunityHandler(APIHandler): + async def get(self): + search_field = self.get_query_argument('search_field', default="") + response = await searchCommunities(search_field=search_field) + self.finish({'communities': response}) + def setup_handlers(web_app): base_path = web_app.settings['base_url'] @@ -49,7 +56,8 @@ def setup_handlers(web_app): (url_path_join(base_path, 'code'), CodeHandler), (url_path_join(base_path, 'xsrf_token'), XSRFTokenHandler), (url_path_join(base_path, 'test-connection'), ZenodoTestHandler), - (url_path_join(base_path, 'search-records'), SearchRecordHandler) + (url_path_join(base_path, 'search-records'), SearchRecordHandler), + (url_path_join(base_path, 'search-communities'), SearchCommunityHandler) ] web_app.add_handlers(".*$", handlers) \ No newline at end of file diff --git a/zenodo_jupyterlab/server/search.py b/zenodo_jupyterlab/server/search.py index 55acefe..33df3be 100644 --- a/zenodo_jupyterlab/server/search.py +++ b/zenodo_jupyterlab/server/search.py @@ -1,11 +1,21 @@ -from eossr.api.zenodo import search_records +from eossr.api.zenodo import search_records, search_communities -async def searchRecords(search_field): +async def searchRecords(search_field, page): try: - records = search_records(search=search_field, size= 50) + records = search_records(search=search_field, size= 50, page = page) response = [] for record in records: response.append({'id': record.id, 'title': record.title, 'date': record.metadata['publication_date'], 'resource_type': record.metadata['resource_type']['title']}) return response + except: + return ["failed"] + +async def searchCommunities(search_field): + try: + communities = search_communities(search=search_field, size= 50) + response = [] + for community in communities: + response.append({'id': community['id'], 'title': community['metadata']['title'], 'date': community['created'].split('T')[0]}) + return response except: return ["failed"] \ No newline at end of file