Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
Pagination,
BucketAggregation,
SearchBar,
withState,
} from "react-searchkit";
import { OverridableContext } from "react-overridable";
import { apiConfig } from "./api/config";
Expand All @@ -39,6 +40,43 @@ const overriddenComponents = {
[`${linkedRecordsSearchAppID}.ResultsLoader.element`]: RelatedRecordsResultsLoader,
};

const SearchControls = withState(({ currentResultsState }) => {
const hasResults = currentResultsState?.data.total > 0;
if (!hasResults) {
return null;
}

return (
<Grid>
<Grid.Row>
<Grid.Column mobile={16} tablet={7} computer={8}>
<SearchBar
className="mb-10"
placeholder="Search within linked records..."
uiProps={{
name: "linked-records-search",
id: "linked-records-search-bar",
icon: "search",
}}
actionProps={{
"icon": "search",
"content": null,
"aria-label": "Search",
}}
/>
</Grid.Column>
<Grid.Column mobile={16} tablet={9} computer={8}>
<div className="flex align-items-center justify-end rel-mobile-pt-1">
<BucketAggregation
agg={{ field: "resource_type", aggName: "resource_type" }}
/>
</div>
</Grid.Column>
</Grid.Row>
</Grid>
);
});

export const LinkedRecordsSearch = ({ endpoint, searchQuery }) => {
// Pass the base query to apiConfig so it can be handled by the request interceptor
const searchApi = new InvenioSearchApi(apiConfig(endpoint, searchQuery));
Expand All @@ -62,33 +100,7 @@ export const LinkedRecordsSearch = ({ endpoint, searchQuery }) => {
>
<>
{/* Search Bar and Controls */}
<Grid>
<Grid.Row>
<Grid.Column mobile={16} tablet={7} computer={8}>
<SearchBar
className="mb-10"
placeholder="Search within linked records..."
uiProps={{
name: "linked-records-search",
id: "linked-records-search-bar",
icon: "search",
}}
actionProps={{
icon: "search",
content: null,
"aria-label": "Search",
}}
/>
</Grid.Column>
<Grid.Column mobile={16} tablet={9} computer={8}>
<div className="flex align-items-center justify-end rel-mobile-pt-1">
<BucketAggregation
agg={{ field: "resource_type", aggName: "resource_type" }}
/>
</div>
</Grid.Column>
</Grid.Row>
</Grid>
<SearchControls />

{/* Results */}
<Segment>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,23 +50,48 @@ Filter.propTypes = {
};

export const FilterValues = ({ bucket, isSelected, onFilterClicked, label }) => {
return (
<Dropdown.Item
key={bucket.key}
id={`${bucket.key}-agg-value`}
selected={isSelected}
onClick={() => onFilterClicked(bucket.key)}
value={bucket.key}
className="flex align-items-center justify-space-between"
>
{isSelected && <Icon name="check" className="positive" />}
const innerBuckets = bucket?.inner?.buckets || [];

<span>{label}</span>
<Label size="small" className="rel-ml-1 mr-0">
{bucket.doc_count.toLocaleString("en-US")}
</Label>
</Dropdown.Item>
);
if (innerBuckets.length === 0) {
return (
<Dropdown.Item
key={bucket.key}
id={`${bucket.key}-agg-value`}
selected={isSelected}
onClick={() => onFilterClicked(bucket.key)}
value={bucket.key}
className="flex align-items-center justify-space-between"
>
{isSelected && <Icon name="check" className="positive" />}
<span>{label}</span>
<Label size="small" className="rel-ml-1 mr-0">
{bucket.doc_count.toLocaleString("en-US")}
</Label>
</Dropdown.Item>
);
}

return innerBuckets.map((innerBucket) => {
const innerIsSelected = innerBucket.is_selected || false;
const innerLabel = `${label} / ${innerBucket.label}`;

return (
<Dropdown.Item
key={`${bucket.key}-${innerBucket.key}`}
id={`${bucket.key}-${innerBucket.key}-agg-value`}
selected={innerIsSelected}
onClick={() => onFilterClicked(`${bucket.key}::${innerBucket.key}`)}
value={innerBucket.key}
className="flex align-items-center justify-space-between"
>
{innerIsSelected && <Icon name="check" className="positive" />}
<span>{innerLabel}</span>
<Label size="small" className="rel-ml-1 mr-0">
{innerBucket.doc_count.toLocaleString("en-US")}
</Label>
</Dropdown.Item>
);
});
};

FilterValues.propTypes = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,14 @@ import ReactDOM from "react-dom";
import { LinkedRecordsSearch } from "./LinkedRecordsSearch";

const linkedRecordsContainer = document.getElementById("cds-linked-records");
console.log(linkedRecordsContainer);

if (linkedRecordsContainer) {
const endpoint = linkedRecordsContainer.dataset.apiEndpoint;
const searchQuery = linkedRecordsContainer.dataset.searchQuery;

ReactDOM.render(
<LinkedRecordsSearch
endpoint={endpoint}
searchQuery={searchQuery}
/>,
<LinkedRecordsSearch endpoint={endpoint} searchQuery={searchQuery} />,
linkedRecordsContainer
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,7 @@

{%- block record_details -%}
{{super()}}
{# Linked Records Section - Only evaluate if record has related_identifiers #}
{% if record.metadata.related_identifiers %}
{# Linked Records Section - Always evaluate to get other records linked to this one #}
{%- set linkedRecordsQuery = record | get_linked_records_search_query %}
{% if linkedRecordsQuery %}
<h2>Linked records</h2>
Expand All @@ -64,16 +63,13 @@ <h2>Linked records</h2>
</div>
</section>
{% endif %}
{% endif %}
{%- endblock record_details -%}

{%- block javascript -%}
{{ super() }}
{# Only load JS if we actually rendered the linked records section #}
{% if record.metadata.related_identifiers %}
{%- set linkedRecordsQuery = record | get_linked_records_search_query %}
{% if linkedRecordsQuery %}
{{ webpack['cds-rdm-linked-records.js'] }}
{% endif %}
{% endif %}
{%- endblock javascript -%}
6 changes: 4 additions & 2 deletions site/cds_rdm/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,9 +115,11 @@ def get_linked_records_search_query(record):
return None

# Combine all query parts with OR
combined_query = " OR ".join(query_parts)
combined_query = (
" OR ".join(query_parts) if len(query_parts) > 1 else query_parts[0]
)

# Exclude the current record and only show published records
final_query = f'({combined_query}) AND is_published:true NOT id:"{record_id}"'
final_query = f'({combined_query}) AND is_published:true AND NOT id:"{record_id}"'

return final_query
Loading