Skip to content

Commit

Permalink
Developed searchable community feature (and minor fixes listed below) (
Browse files Browse the repository at this point in the history
…#38)

* changed widget class

* added searchable community feature

* fixed column headers

* switched date and software type
  • Loading branch information
mrzengel authored Jul 18, 2024
1 parent 8d2b592 commit 56c34f7
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 36 deletions.
15 changes: 13 additions & 2 deletions src/API/API_functions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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', {
Expand Down
121 changes: 95 additions & 26 deletions src/components/SearchPanel.tsx
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -19,6 +19,7 @@ const useStyles = createUseStyles({
container: {
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
marginBottom: '20px',
},
Expand Down Expand Up @@ -67,27 +68,52 @@ 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 = () => {
const classes = useStyles();
const[results, setResults] = useState<any[]>([]);
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 (
<div className={classes.searchWidget}>
<div className={classes.container}>
Expand All @@ -98,35 +124,78 @@ const SearchWidget: React.FC = () => {
placeholder="Search..."
className={classes.input}
/>
<div className={classes.checkboxContainer}>
<label className={classes.checkboxLabel} style={{'marginRight': '20px'}}>
<input
type="checkbox"
checked={selectedType === 'records'}
onChange={() => handleCheckboxChange('records')}
className={classes.checkboxInput}
/>
Records
</label>
<label className={classes.checkboxLabel}>
<input
type="checkbox"
checked={selectedType === 'communities'}
onChange={() => handleCheckboxChange('communities')}
className={classes.checkboxInput}
/>
Communities
</label>
</div>
<button onClick={handleSearch} className={classes.button}>Search</button>
</div>
{/* {results && (
<p>{results}</p>
)} */}
{isLoading && <p>Loading Search Results...</p>}
{results.length > 0 && (
<div className={classes.tableContainer}>
<table className={classes.table}>
<thead>
<tr className={classes.headerRow}>
<th className={classes.headerCell}>Title</th>
<th className={classes.headerCell}>Resource Type</th>
<th className={classes.headerCell}>Date Published</th>
</tr>
</thead>
<tbody>
{results.map((result, index) => (
<tr key={result.id} className={classes.row} style={{ backgroundColor: index % 2 === 0 ? '#e6f7ff' : '#cceeff' }}>
<td className={classes.cell}>{result.title}</td>
<td className={classes.cell}>{result.date}</td>
<td className={classes.cell}>{result.resource_type}</td>
{hasSearched && !isLoading && (
results.length > 0 ? (
lastSearchType === 'records' ? (
<div className={classes.tableContainer}>
<table className={classes.table}>
<thead>
<tr className={classes.headerRow}>
<th className={classes.headerCell}>Title</th>
<th className={classes.headerCell}>Resource Type</th>
<th className={classes.headerCell}>Date Published</th>
</tr>
))}
</tbody>
</table>
</div>
</thead>
<tbody>
{results.map((result, index) => (
<tr key={result.id} className={classes.row} style={{ backgroundColor: index % 2 === 0 ? '#e6f7ff' : '#cceeff' }}>
<td className={classes.cell}>{result.title}</td>
<td className={classes.cell}>{result.resource_type}</td>
<td className={classes.cell}>{result.date}</td>
</tr>
))}
</tbody>
</table>
</div>
) : (
<div className={classes.tableContainer}>
<table className={classes.table}>
<thead>
<tr className={classes.headerRow}>
<th className={classes.headerCell}>Title</th>
<th className={classes.headerCell}>Date Published</th>
</tr>
</thead>
<tbody>
{results.map((result, index) => (
<tr key={result.id} className={classes.row} style={{ backgroundColor: index % 2 === 0 ? '#e6f7ff' : '#cceeff' }}>
<td className={classes.cell}>{result.title}</td>
<td className={classes.cell}>{result.date}</td>
</tr>
))}
</tbody>
</table>
</div>
)
) : (
<p>No results found.</p>
)
)}


</div>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 ({
Expand Down
2 changes: 1 addition & 1 deletion style/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
14 changes: 11 additions & 3 deletions zenodo_jupyterlab/server/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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']
Expand All @@ -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)
16 changes: 13 additions & 3 deletions zenodo_jupyterlab/server/search.py
Original file line number Diff line number Diff line change
@@ -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"]

0 comments on commit 56c34f7

Please sign in to comment.