From d2c61b67ac58fff143787320491929a24fa6592d Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Tue, 16 Jul 2024 10:43:36 -0400 Subject: [PATCH 01/19] chore: started search filtering bug --- static/js/ElasticSearchQuerier.jsx | 5 ++++- static/js/ReaderApp.jsx | 19 ++++++++++++++++++- static/js/ReaderPanel.jsx | 2 ++ static/js/SearchPage.jsx | 3 ++- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/static/js/ElasticSearchQuerier.jsx b/static/js/ElasticSearchQuerier.jsx index 485bd5dc66..fd86ffc698 100644 --- a/static/js/ElasticSearchQuerier.jsx +++ b/static/js/ElasticSearchQuerier.jsx @@ -62,6 +62,8 @@ class ElasticSearchQuerier extends Component { moreToLoad: true, }); this._executeAllQueries(newProps); + // this.props.resetSearchFilters('sheet'); + // this.props.resetSearchFilters('text'); } else if (this._shouldUpdateQuery(this.props, newProps, this.props.type)) { let state = { hits: [], @@ -375,7 +377,8 @@ ElasticSearchQuerier.propTypes = { onQueryChange: PropTypes.func, updateAppliedFilter: PropTypes.func, updateAppliedOptionSort: PropTypes.func, - updateAppliedOptionField: PropTypes.func + updateAppliedOptionField: PropTypes.func, + resetSearchFilters: PropTypes.func }; export { ElasticSearchQuerier }; \ No newline at end of file diff --git a/static/js/ReaderApp.jsx b/static/js/ReaderApp.jsx index 6125fa317a..2bd6e90b33 100644 --- a/static/js/ReaderApp.jsx +++ b/static/js/ReaderApp.jsx @@ -1218,6 +1218,21 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { }) }); } + resetSearchFilters(n, type) { + // reset both availableFilters and appliedFilters + const state = this.state.panels[n]; + const searchState = this._getSearchState(state, type); + const searchStateName = this._getSearchStateName(type); + searchState.availableFilters.forEach(filterNode => { + if (!filterNode.isUnselected()) { + filterNode.setUnselected(true); + } + }) + this.setPanelState(n, { + [searchStateName]: searchState.update({appliedFilters: [], appliedFilterAggTypes: [], filterRegistry: {}, + filtersValid: false}), + }); + } updateSearchFilter(n, type, searchState, filterNode) { const searchStateName = this._getSearchStateName(type); if (filterNode.isUnselected()) { @@ -2139,8 +2154,9 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { var unsetTextHighlight = this.unsetTextHighlight.bind(null, i); var updateQuery = this.updateQuery.bind(null, i); var updateAvailableFilters = this.updateAvailableFilters.bind(null, i); - let updateSearchState = this.updateSearchState.bind(null, i); + const updateSearchState = this.updateSearchState.bind(null, i); var updateSearchFilter = this.updateSearchFilter.bind(null, i); + const resetSearchFilters = this.resetSearchFilters.bind(null, i); var updateSearchOptionField = this.updateSearchOptionField.bind(null, i); var updateSearchOptionSort = this.updateSearchOptionSort.bind(null, i); var openConnectionsPanel = this.openTextListAt.bind(null, i+1); @@ -2171,6 +2187,7 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { Date: Wed, 17 Jul 2024 14:11:06 -0400 Subject: [PATCH 02/19] chore: started removing distinction between textSearchState and sheetSearchState --- reader/views.py | 40 ++++++----- static/js/ReaderApp.jsx | 93 ++++++++++---------------- static/js/SearchPage.jsx | 6 +- static/js/Sheets/SheetsWithRefPage.jsx | 2 +- 4 files changed, 59 insertions(+), 82 deletions(-) diff --git a/reader/views.py b/reader/views.py index 2344369f06..e9d6afd00e 100644 --- a/reader/views.py +++ b/reader/views.py @@ -785,24 +785,25 @@ def get_filters(prefix, filter_type): return [urllib.parse.unquote(f) for f in get_dict.get(get_param(prefix+filter_type+"Filters", i)).split("|")] if get_dict.get(get_param(prefix+filter_type+"Filters", i), "") else [] sheet_filters_types = ("collections", "topics_en", "topics_he") - sheet_filters = [] - sheet_agg_types = [] - for filter_type in sheet_filters_types: - filters = get_filters("s", filter_type) - sheet_filters += filters - sheet_agg_types += [filter_type] * len(filters) - text_filters = get_filters("t", "path") + filters = [] + agg_types = [] + sort = None + if get_dict.get('tab') == 'text': + filters = get_filters("t", "path") + sort = get_dict.get(get_param("tsort", i), None) + else: + for filter_type in sheet_filters_types: + filters += get_filters("s", filter_type) + agg_types += [filter_type] * len(filters) + sort = get_dict.get(get_param("ssort", i), None) return { "query": urllib.parse.unquote(get_dict.get(get_param("q", i), "")), "tab": urllib.parse.unquote(get_dict.get(get_param("tab", i), "text")), - "textField": ("naive_lemmatizer" if get_dict.get(get_param("tvar", i)) == "1" else "exact") if get_dict.get(get_param("tvar", i)) else "", - "textSort": get_dict.get(get_param("tsort", i), None), - "textFilters": text_filters, - "textFilterAggTypes": [None for _ in text_filters], # currently unused. just needs to be equal len as text_filters - "sheetSort": get_dict.get(get_param("ssort", i), None), - "sheetFilters": sheet_filters, - "sheetFilterAggTypes": sheet_agg_types, + "field": ("naive_lemmatizer" if get_dict.get(get_param("tvar", i)) == "1" else "exact") if get_dict.get(get_param("tvar", i)) else "", + "sort": sort, + "filters": filters, + "filterAggTypes": [None for _ in filters], # currently unused. just needs to be equal len as text_filters } @@ -840,13 +841,10 @@ def search(request): "initialMenu": "search", "initialQuery": search_params["query"], "initialSearchType": search_params["tab"], - "initialTextSearchFilters": search_params["textFilters"], - "initialTextSearchFilterAggTypes": search_params["textFilterAggTypes"], - "initialTextSearchField": search_params["textField"], - "initialTextSearchSortType": search_params["textSort"], - "initialSheetSearchFilters": search_params["sheetFilters"], - "initialSheetSearchFilterAggTypes": search_params["sheetFilterAggTypes"], - "initialSheetSearchSortType": search_params["sheetSort"] + "initialSearchFilters": search_params["filters"], + "initialSearchFilterAggTypes": search_params["filterAggTypes"], + "initialSearchField": search_params["field"], + "initialSearchSortType": search_params["sort"], } return render_template(request,'base.html', props, { "title": (search_params["query"] + " | " if search_params["query"] else "") + _("Sefaria Search"), diff --git a/static/js/ReaderApp.jsx b/static/js/ReaderApp.jsx index 6125fa317a..085f5f7cc3 100644 --- a/static/js/ReaderApp.jsx +++ b/static/js/ReaderApp.jsx @@ -53,20 +53,14 @@ class ReaderApp extends Component { menuOpen: props.initialMenu, searchQuery: props.initialQuery, searchType: props.initialSearchType, - tab: props.initialTab, + tab: props.initialSearchType, topicSort: props.initialTopicSort, - textSearchState: new SearchState({ - type: 'text', - appliedFilters: props.initialTextSearchFilters, - field: props.initialTextSearchField, - appliedFilterAggTypes: props.initialTextSearchFilterAggTypes, - sortType: props.initialTextSearchSortType, - }), - sheetSearchState: new SearchState({ - type: 'sheet', - appliedFilters: props.initialSheetSearchFilters, - appliedFilterAggTypes: props.initialSheetSearchFilterAggTypes, - sortType: props.initialSheetSearchSortType, + searchState: new SearchState({ + type: props.initialSearchType, + appliedFilters: props.initialSearchFilters, + field: props.initialSearchField, + appliedFilterAggTypes: props.initialSearchFilterAggTypes, + sortType: props.initialSearchSortType, }), navigationCategories: props.initialNavigationCategories, navigationTopicCategory: props.initialNavigationTopicCategory, @@ -156,8 +150,7 @@ class ReaderApp extends Component { searchQuery: state.searchQuery || null, searchType: state.searchType || 'text', showHighlight: state.showHighlight || null, - textSearchState: state.textSearchState || new SearchState({ type: 'text' }), - sheetSearchState: state.sheetSearchState || new SearchState({ type: 'sheet' }), + searchState: state.searchState || new SearchState({ type: this.state.tab }), compare: state.compare || false, openSidebarAsConnect: state.openSidebarAsConnect || false, bookRef: state.bookRef || null, @@ -276,8 +269,7 @@ class ReaderApp extends Component { // history does not preserve custom objects if (state.panels) { for (let p of state.panels) { - p.textSearchState = p.textSearchState && new SearchState(p.textSearchState); - p.sheetSearchState = p.sheetSearchState && new SearchState(p.sheetSearchState); + p.searchState = p.searchState && new SearchState(p.searchState); } } else { state.panels = []; @@ -377,10 +369,8 @@ class ReaderApp extends Component { const next = nextPanels[i]; if (!prev || !next) { return true; } // history does not preserve custom objects - const prevTextSearchState = new SearchState(prev.textSearchState); - const prevSheetSearchState = new SearchState(prev.sheetSearchState); - const nextTextSearchState = new SearchState(next.textSearchState); - const nextSheetSearchState = new SearchState(next.sheetSearchState); + const prevSearchState = new SearchState(prev.searchState); + const nextSearchState = new SearchState(next.searchState); if ((prev.mode !== next.mode) || (prev.menuOpen !== next.menuOpen) || @@ -395,14 +385,13 @@ class ReaderApp extends Component { (next.connectionsMode !== prev.connectionsMode) || (prev.currVersions.en !== next.currVersions.en) || (prev.currVersions.he !== next.currVersions.he) || - (prev.searchQuery != next.searchQuery) || - (prev.searchType != next.searchType) || + (prev.searchQuery !== next.searchQuery) || + (prev.searchType !== next.searchType) || (prev.tab !== next.tab) || (prev.topicSort !== next.topicSort) || (prev.collectionName !== next.collectionName) || (prev.collectionTag !== next.collectionTag) || - (!prevTextSearchState.isEqual({ other: nextTextSearchState, fields: ["appliedFilters", "field", "sortType"]})) || - (!prevSheetSearchState.isEqual({ other: nextSheetSearchState, fields: ["appliedFilters", "field", "sortType"]})) || + (!prevSearchState.isEqual({ other: nextSearchState, fields: ["appliedFilters", "field", "sortType"]})) || (prev.settings.language != next.settings.language) || (prev.navigationTopicCategory !== next.navigationTopicCategory) || (prev.settings.aliyotTorah != next.settings.aliyotTorah) || @@ -490,9 +479,9 @@ class ReaderApp extends Component { const query = state.searchQuery ? encodeURIComponent(state.searchQuery) : ""; hist.title = state.searchQuery ? state.searchQuery.stripHtml() + " | " : ""; hist.title += Sefaria._(siteName + " Search"); + const prefix = this.props hist.url = "search" + (state.searchQuery ? (`&q=${query}&tab=${state.searchType}` + - state.textSearchState.makeURL({ prefix: 't', isStart: false }) + - state.sheetSearchState.makeURL({ prefix: 's', isStart: false })) : ""); + state.searchState.makeURL({ prefix: 't', isStart: false }) : ""); hist.mode = "search"; break; case "topics": @@ -1178,31 +1167,25 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { unsetTextHighlight(n) { this.setPanelState(n, { textHighlights: null }); } - _getSearchStateName(type) { - return `${type}SearchState`; - } - _getSearchState(state, type) { - return !!state && state[this._getSearchStateName(type)]; + _getSearchState(state) { + return !!state && state['searchState']; } updateQuery(n, query) { const state = this.state.panels[n]; const updates = { searchQuery: query, - textSearchState: state.textSearchState.update({ filtersValid: false }), - sheetSearchState: state.sheetSearchState.update({ filtersValid: false }), + searchState: state.searchState.update({ filtersValid: false }), }; this.setPanelState(n, updates); } - updateSearchState(n, searchState, type) { - const searchStateName = this._getSearchStateName(type); - this.setPanelState(n,{[searchStateName]: searchState}); + updateSearchState(n, searchState) { + this.setPanelState(n,{searchState: searchState}); } - updateAvailableFilters(n, type, availableFilters, filterRegistry, orphanFilters, aggregationsToUpdate) { + updateAvailableFilters(n, availableFilters, filterRegistry, orphanFilters, aggregationsToUpdate) { const state = this.state.panels[n]; const searchState = this._getSearchState(state, type); - const searchStateName = this._getSearchStateName(type); this.setPanelState(n, { - [searchStateName]: !!searchState ? + searchState: !!searchState ? searchState.update({ availableFilters, filterRegistry, @@ -1219,31 +1202,28 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { }); } updateSearchFilter(n, type, searchState, filterNode) { - const searchStateName = this._getSearchStateName(type); if (filterNode.isUnselected()) { filterNode.setSelected(true); } else { filterNode.setUnselected(true); } - const update = Sefaria.search.getAppliedSearchFilters(searchState.availableFilters) + const update = Sefaria.search.getAppliedSearchFilters(searchState.availableFilters); this.setPanelState(n, { - [searchStateName]: searchState.update(update) + searchState: searchState.update(update) }); } - updateSearchOptionField(n, type, field) { + updateSearchOptionField(n, field) { const state = this.state.panels[n]; - const searchState = this._getSearchState(state, type); - const searchStateName = this._getSearchStateName(type); + const searchState = this._getSearchState(state); this.setPanelState(n, { - [searchStateName]: searchState.update({ field, filtersValid: false }) + searchState: searchState.update({ field, filtersValid: false }) }); } - updateSearchOptionSort(n, type, sortType) { + updateSearchOptionSort(n, sortType) { const state = this.state.panels[n]; - const searchState = this._getSearchState(state, type); - const searchStateName = this._getSearchStateName(type); + const searchState = this._getSearchState(state); this.setPanelState(n, { - [searchStateName]: searchState.update({ sortType }) + searchState: searchState.update({ sortType }) }); } setPanelState(n, state, replaceHistory) { @@ -2284,12 +2264,11 @@ ReaderApp.propTypes = { initialMenu: PropTypes.string, initialCollection: PropTypes.string, initialQuery: PropTypes.string, - initialTextSearchFilters: PropTypes.array, - initialTextSearchField: PropTypes.string, - initialTextSearchSortType: PropTypes.string, - initialSheetSearchFilters: PropTypes.array, - initialSheetSearchField: PropTypes.string, - initialSheetSearchSortType: PropTypes.string, + initialSearchType: PropTypes.string, + initialSearchFilters: PropTypes.array, + initialSearchField: PropTypes.string, + initialSearchSortType: PropTypes.string, + initialSearchFilterAggTypes: PropTypes.array, initialTopic: PropTypes.string, initialProfile: PropTypes.object, initialNavigationCategories: PropTypes.array, diff --git a/static/js/SearchPage.jsx b/static/js/SearchPage.jsx index 4da78b85d1..41050916fb 100644 --- a/static/js/SearchPage.jsx +++ b/static/js/SearchPage.jsx @@ -81,9 +81,9 @@ class SearchPage extends Component { this.setState({mobileFiltersOpen: false})} compare={this.props.compare} type={this.props.type} /> diff --git a/static/js/Sheets/SheetsWithRefPage.jsx b/static/js/Sheets/SheetsWithRefPage.jsx index cfc7f72262..ee321daeb5 100644 --- a/static/js/Sheets/SheetsWithRefPage.jsx +++ b/static/js/Sheets/SheetsWithRefPage.jsx @@ -121,7 +121,7 @@ const SheetsWithRefPage = ({srefs, searchState, updateSearchState, updateApplied const handleSheetsLoad = (sheets) => { const searchState = Sefaria.sheets.sheetsWithRefSearchState(sheets); setSheets(prepSheetsForDisplay(sheets)); - updateSearchState(searchState, 'sheet'); + updateSearchState(searchState); setOrigAvailableFilters(searchState.availableFilters); setLoading(false); setTotalResults(new SearchTotal({value: sheets.length})); From 1c0803953e195dd76970ef5453a16f42d0219b88 Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Wed, 17 Jul 2024 14:27:09 -0400 Subject: [PATCH 03/19] chore: make searchType a ReaderApp state variable --- static/js/ReaderApp.jsx | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/static/js/ReaderApp.jsx b/static/js/ReaderApp.jsx index 085f5f7cc3..8d0b1394d4 100644 --- a/static/js/ReaderApp.jsx +++ b/static/js/ReaderApp.jsx @@ -52,8 +52,6 @@ class ReaderApp extends Component { mode: "Menu", menuOpen: props.initialMenu, searchQuery: props.initialQuery, - searchType: props.initialSearchType, - tab: props.initialSearchType, topicSort: props.initialTopicSort, searchState: new SearchState({ type: props.initialSearchType, @@ -105,6 +103,7 @@ class ReaderApp extends Component { const layoutOrientation = (props.interfaceLang == "hebrew") ? "rtl" : "ltr"; this.state = { + searchType: props.initialSearchType, panels: panels, headerMode: props.headerMode, defaultVersions: defaultVersions, @@ -148,9 +147,9 @@ class ReaderApp extends Component { collectionTag: state.collectionTag || null, translationsSlug: state.translationsSlug || null, searchQuery: state.searchQuery || null, - searchType: state.searchType || 'text', + searchType: this.state.searchType || 'text', showHighlight: state.showHighlight || null, - searchState: state.searchState || new SearchState({ type: this.state.tab }), + searchState: state.searchState || new SearchState({ type: this.state.searchType }), compare: state.compare || false, openSidebarAsConnect: state.openSidebarAsConnect || false, bookRef: state.bookRef || null, @@ -479,9 +478,9 @@ class ReaderApp extends Component { const query = state.searchQuery ? encodeURIComponent(state.searchQuery) : ""; hist.title = state.searchQuery ? state.searchQuery.stripHtml() + " | " : ""; hist.title += Sefaria._(siteName + " Search"); - const prefix = this.props + const prefix = this.state.searchType === 'text' ? 't' : 's'; hist.url = "search" + (state.searchQuery ? (`&q=${query}&tab=${state.searchType}` + - state.searchState.makeURL({ prefix: 't', isStart: false }) : ""); + state.searchState.makeURL({ prefix: prefix, isStart: false })) : ""); hist.mode = "search"; break; case "topics": @@ -1193,7 +1192,7 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { filtersValid: true, aggregationsToUpdate, }) : new SearchState({ - type, + type: this.state.searchType, availableFilters, filterRegistry, orphanFilters, @@ -1201,7 +1200,7 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { }) }); } - updateSearchFilter(n, type, searchState, filterNode) { + updateSearchFilter(n, searchState, filterNode) { if (filterNode.isUnselected()) { filterNode.setSelected(true); } else { @@ -1703,18 +1702,17 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { } showSearch(searchQuery) { let panel; - const textSearchState = (!!this.state.panels && this.state.panels.length && !!this.state.panels[0].textSearchState) ? this.state.panels[0].textSearchState.update({ filtersValid: false }) : new SearchState({ type: 'text' }); - const sheetSearchState = (!!this.state.panels && this.state.panels.length && !!this.state.panels[0].sheetSearchState) ? this.state.panels[0].sheetSearchState.update({ filtersValid: false }) : new SearchState({ type: 'sheet' }); + const searchState = (!!this.state.panels && this.state.panels.length && !!this.state.panels[0].searchState) ? this.state.panels[0].searchState.update({ filtersValid: false }) + : new SearchState({ type: this.state.searchType }); - const searchType = !!this.state.panels && this.state.panels.length ? this.state.panels[0].searchType : "text"; - this.setSinglePanelState({mode: "Menu", menuOpen: "search", searchQuery, searchType, textSearchState, sheetSearchState }); + const searchType = this.state.searchType; + this.setSinglePanelState({mode: "Menu", menuOpen: "search", searchQuery, searchType, searchState }); } searchInCollection(searchQuery, collection) { let panel; - const textSearchState = new SearchState({ type: 'text' }); - const sheetSearchState = new SearchState({ type: 'sheet', appliedFilters: [collection], appliedFilterAggTypes: ['collections']}); + const searchState = new SearchState({ type: this.state.searchType }); - this.setSinglePanelState({mode: "Menu", menuOpen: "search", "searchType": "sheet", searchQuery, textSearchState, sheetSearchState }); + this.setSinglePanelState({mode: "Menu", menuOpen: "search", "searchType": "sheet", searchQuery, searchState }); } showCommunity() { this.setSinglePanelState({menuOpen: "community"}); From 0a6b9a55c60b5dc99078369901f88df34f5420cc Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Wed, 17 Jul 2024 15:54:47 -0400 Subject: [PATCH 04/19] chore: use searchState.type instead of searchType --- static/js/ElasticSearchQuerier.jsx | 34 +++++++++++++++--------------- static/js/ReaderApp.jsx | 29 ++++++++++++------------- static/js/ReaderPanel.jsx | 5 ++--- static/js/sefaria/search.js | 1 + 4 files changed, 33 insertions(+), 36 deletions(-) diff --git a/static/js/ElasticSearchQuerier.jsx b/static/js/ElasticSearchQuerier.jsx index a07ee2e5f5..e65ed1d29a 100644 --- a/static/js/ElasticSearchQuerier.jsx +++ b/static/js/ElasticSearchQuerier.jsx @@ -40,8 +40,8 @@ class ElasticSearchQuerier extends Component { this.state.hits = this.state.hits.concat(cachedQuery.hits.hits); this.state.totals = cachedQuery.hits.total; this.state.pagesLoaded += 1; - args.start = this.state.pagesLoaded * this.querySize[this.props.type]; - if (this.props.type === "text") { + args.start = this.state.pagesLoaded * this.querySize[this.props.searchState.type]; + if (this.props.searchState.type === "text") { // Since texts only have one filter type, aggregations are only requested once on first page args.aggregationsToUpdate = []; } @@ -62,9 +62,9 @@ class ElasticSearchQuerier extends Component { }; if (this.props.query !== newProps.query) { this.setState(state, () => this._executeAllQueries(newProps)); - } else if (this._shouldUpdateQuery(this.props, newProps, this.props.type)) { + } else if (this._shouldUpdateQuery(this.props, newProps, this.props.searchState.type)) { this.setState(state, () => { - this._executeQuery(newProps, this.props.type); + this._executeQuery(newProps, this.props.searchState.type); }) } } @@ -189,7 +189,7 @@ class ElasticSearchQuerier extends Component { if (!this.props.searchInBook) { this._executeTopicQuery(); } - this._executeQuery(props, this.props.type); + this._executeQuery(props, this.props.searchState.type); } _getAggsToUpdate(filtersValid, aggregation_field_array, aggregation_field_lang_suffix_array, appliedFilterAggTypes, type) { // Returns a list of aggregations type which we should request from the server. @@ -218,7 +218,7 @@ class ElasticSearchQuerier extends Component { const request_applied = args.applied_filters; const searchState = this._getSearchState(props); const { appliedFilters, appliedFilterAggTypes } = searchState; - const { aggregation_field_array, build_and_apply_filters } = SearchState.metadataByType[this.props.type]; + const { aggregation_field_array, build_and_apply_filters } = SearchState.metadataByType[this.props.searchState.type]; args.success = data => { this.updateRunningQuery(null); @@ -228,12 +228,12 @@ class ElasticSearchQuerier extends Component { hits: data.hits.hits, totals: currTotal, pagesLoaded: 1, - moreToLoad: currTotal.getValue() > this.querySize[this.props.type] + moreToLoad: currTotal.getValue() > this.querySize[this.props.searchState.type] }; this.setState(state); const filter_label = (request_applied && request_applied.length > 0) ? (' - ' + request_applied.join('|')) : ''; const query_label = props.query + filter_label; - Sefaria.track.event("Search", `${this.props.searchInBook? "SidebarSearch ": ""}Query: ${this.props.type}`, query_label, data.hits.total.getValue()); + Sefaria.track.event("Search", `${this.props.searchInBook? "SidebarSearch ": ""}Query: ${this.props.searchState.type}`, query_label, data.hits.total.getValue()); } if (data.aggregations) { @@ -253,7 +253,7 @@ class ElasticSearchQuerier extends Component { orphans.push(...tempOrphans); } } - this.props.registerAvailableFilters(this.props.type, availableFilters, registry, orphans, args.aggregationsToUpdate); + this.props.registerAvailableFilters(this.props.searchState.type, availableFilters, registry, orphans, args.aggregationsToUpdate); } }; args.error = this._handleError; @@ -267,16 +267,16 @@ class ElasticSearchQuerier extends Component { const searchState = this._getSearchState(props); const { field, fieldExact, sortType, filtersValid, appliedFilters, appliedFilterAggTypes } = searchState; const request_applied = filtersValid && appliedFilters; - const { aggregation_field_array, aggregation_field_lang_suffix_array } = SearchState.metadataByType[this.props.type]; - const aggregationsToUpdate = this._getAggsToUpdate(filtersValid, aggregation_field_array, aggregation_field_lang_suffix_array, appliedFilterAggTypes, this.props.type); + const { aggregation_field_array, aggregation_field_lang_suffix_array } = SearchState.metadataByType[this.props.searchState.type]; + const aggregationsToUpdate = this._getAggsToUpdate(filtersValid, aggregation_field_array, aggregation_field_lang_suffix_array, appliedFilterAggTypes, this.props.searchState.type); return { query: props.query, - type: this.props.type, + type: this.props.searchState.type, applied_filters: request_applied, appliedFilterAggTypes, aggregationsToUpdate, - size: this.querySize[this.props.type], + size: this.querySize[this.props.searchState.type], field, sort_type: sortType, exact: fieldExact === field, @@ -285,14 +285,14 @@ class ElasticSearchQuerier extends Component { _loadNextPage() { console.log("load next page") const args = this._getQueryArgs(this.props); - args.start = this.state.pagesLoaded * this.querySize[this.props.type]; + args.start = this.state.pagesLoaded * this.querySize[this.props.searchState.type]; args.error = () => console.log("Failure in SearchResultList._loadNextPage"); args.success = data => { let nextHits = this.state.hits.concat(data.hits.hits); this.state.hits = nextHits; this.state.pagesLoaded += 1; - if (this.state.pagesLoaded * this.querySize[this.props.type] >= this.state.totals.getValue() ) { + if (this.state.pagesLoaded * this.querySize[this.props.searchState.type] >= this.state.totals.getValue() ) { this.state.moreToLoad = false; } @@ -313,7 +313,7 @@ class ElasticSearchQuerier extends Component { this.updateRunningQuery(null); } normalizeHitsMetaData() { - if (this.props.type === 'sheet') { + if (this.props.searchState.type === 'sheet') { let results = this.state.hits; return results.map(result => { let normalizedResult = result._source; @@ -334,7 +334,7 @@ class ElasticSearchQuerier extends Component { query={this.props.query} hits={this.normalizeHitsMetaData()} totalResults={this.state.totals} - type={this.props.type} + type={this.props.searchState.type} searchState={this.props.searchState} settings={this.props.settings} panelsOpen={this.props.panelsOpen} diff --git a/static/js/ReaderApp.jsx b/static/js/ReaderApp.jsx index 8d0b1394d4..fd1db88043 100644 --- a/static/js/ReaderApp.jsx +++ b/static/js/ReaderApp.jsx @@ -45,7 +45,7 @@ class ReaderApp extends Component { // Currently these get generated in reader/views.py then regenerated again in ReaderApp. this.MIN_PANEL_WIDTH = 360.0; let panels = []; - + const searchType = props.initialSearchType; if (props.initialMenu) { // If a menu is specified in `initialMenu`, make a panel for it panels[0] = { @@ -54,7 +54,7 @@ class ReaderApp extends Component { searchQuery: props.initialQuery, topicSort: props.initialTopicSort, searchState: new SearchState({ - type: props.initialSearchType, + type: searchType, appliedFilters: props.initialSearchFilters, field: props.initialSearchField, appliedFilterAggTypes: props.initialSearchFilterAggTypes, @@ -103,7 +103,6 @@ class ReaderApp extends Component { const layoutOrientation = (props.interfaceLang == "hebrew") ? "rtl" : "ltr"; this.state = { - searchType: props.initialSearchType, panels: panels, headerMode: props.headerMode, defaultVersions: defaultVersions, @@ -147,9 +146,8 @@ class ReaderApp extends Component { collectionTag: state.collectionTag || null, translationsSlug: state.translationsSlug || null, searchQuery: state.searchQuery || null, - searchType: this.state.searchType || 'text', showHighlight: state.showHighlight || null, - searchState: state.searchState || new SearchState({ type: this.state.searchType }), + searchState: state.searchState || new SearchState({ type: this.props.initialSearchType }), compare: state.compare || false, openSidebarAsConnect: state.openSidebarAsConnect || false, bookRef: state.bookRef || null, @@ -478,8 +476,8 @@ class ReaderApp extends Component { const query = state.searchQuery ? encodeURIComponent(state.searchQuery) : ""; hist.title = state.searchQuery ? state.searchQuery.stripHtml() + " | " : ""; hist.title += Sefaria._(siteName + " Search"); - const prefix = this.state.searchType === 'text' ? 't' : 's'; - hist.url = "search" + (state.searchQuery ? (`&q=${query}&tab=${state.searchType}` + + const prefix = state.searchState.type === 'text' ? 't' : 's'; + hist.url = "search" + (state.searchQuery ? (`&q=${query}&tab=${state.searchState.type}` + state.searchState.makeURL({ prefix: prefix, isStart: false })) : ""); hist.mode = "search"; break; @@ -1192,7 +1190,7 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { filtersValid: true, aggregationsToUpdate, }) : new SearchState({ - type: this.state.searchType, + type: this.props.initialSearchType, availableFilters, filterRegistry, orphanFilters, @@ -1701,17 +1699,16 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { this.setSinglePanelState(state); } showSearch(searchQuery) { - let panel; - const searchState = (!!this.state.panels && this.state.panels.length && !!this.state.panels[0].searchState) ? this.state.panels[0].searchState.update({ filtersValid: false }) - : new SearchState({ type: this.state.searchType }); - - const searchType = this.state.searchType; + const hasSearchState = !!this.state.panels && this.state.panels.length && !!this.state.panels[0].searchState + const searchState = hasSearchState ? this.state.panels[0].searchState.update({ filtersValid: false }) + : new SearchState({ type: this.props.initialSearchType }); + const searchType = !!this.state.panels && this.state.panels.length ? this.state.panels[0].searchType : this.props.initialSearchType; this.setSinglePanelState({mode: "Menu", menuOpen: "search", searchQuery, searchType, searchState }); } searchInCollection(searchQuery, collection) { - let panel; - const searchState = new SearchState({ type: this.state.searchType }); - + const appliedFilters = this.state.searchType === 'sheet' ? [collection] : []; + const appliedFilterAggTypes = this.state.searchType === 'sheet' ? ['collections'] : []; + const searchState = new SearchState({ type: this.state.searchType, appliedFilters, appliedFilterAggTypes}); this.setSinglePanelState({mode: "Menu", menuOpen: "search", "searchType": "sheet", searchQuery, searchState }); } showCommunity() { diff --git a/static/js/ReaderPanel.jsx b/static/js/ReaderPanel.jsx index 42a01d446c..5b77e66f95 100644 --- a/static/js/ReaderPanel.jsx +++ b/static/js/ReaderPanel.jsx @@ -803,7 +803,7 @@ class ReaderPanel extends Component { toggleSignUpModal={this.props.toggleSignUpModal}/>); } else if (this.state.menuOpen === "sheetsWithRef") { menu = ( x.type === sort_type ); return { type, From f9b6ccdbcd54e19a1534f7515fdf455c929bc883 Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Wed, 17 Jul 2024 16:20:39 -0400 Subject: [PATCH 05/19] feat(Search): removed distinction between textSearchState and sheetSearchState --- static/js/ElasticSearchQuerier.jsx | 2 +- static/js/ReaderApp.jsx | 2 +- static/js/ReaderPanel.jsx | 1 + static/js/SearchResultList.jsx | 2 +- static/js/sefaria/search.js | 1 - 5 files changed, 4 insertions(+), 4 deletions(-) diff --git a/static/js/ElasticSearchQuerier.jsx b/static/js/ElasticSearchQuerier.jsx index e65ed1d29a..78af369078 100644 --- a/static/js/ElasticSearchQuerier.jsx +++ b/static/js/ElasticSearchQuerier.jsx @@ -253,7 +253,7 @@ class ElasticSearchQuerier extends Component { orphans.push(...tempOrphans); } } - this.props.registerAvailableFilters(this.props.searchState.type, availableFilters, registry, orphans, args.aggregationsToUpdate); + this.props.registerAvailableFilters(availableFilters, registry, orphans, args.aggregationsToUpdate); } }; args.error = this._handleError; diff --git a/static/js/ReaderApp.jsx b/static/js/ReaderApp.jsx index fd1db88043..ae542480cb 100644 --- a/static/js/ReaderApp.jsx +++ b/static/js/ReaderApp.jsx @@ -1180,7 +1180,7 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { } updateAvailableFilters(n, availableFilters, filterRegistry, orphanFilters, aggregationsToUpdate) { const state = this.state.panels[n]; - const searchState = this._getSearchState(state, type); + const searchState = this._getSearchState(state); this.setPanelState(n, { searchState: !!searchState ? searchState.update({ diff --git a/static/js/ReaderPanel.jsx b/static/js/ReaderPanel.jsx index 5b77e66f95..c19559fc1f 100644 --- a/static/js/ReaderPanel.jsx +++ b/static/js/ReaderPanel.jsx @@ -897,6 +897,7 @@ class ReaderPanel extends Component { menu = ( { if (sortType === newSortType) { return; } - updateAppliedOptionSort(type, newSortType); + updateAppliedOptionSort(newSortType); setIsOpen(false); } const filterTextClasses = classNames({searchFilterToggle: 1, active: isOpen}); diff --git a/static/js/sefaria/search.js b/static/js/sefaria/search.js index fa6f0a428a..4000acea6d 100644 --- a/static/js/sefaria/search.js +++ b/static/js/sefaria/search.js @@ -394,7 +394,6 @@ class Search { exact }) { const { sortTypeArray, aggregation_field_array } = SearchState.metadataByType[type]; - console.log(sortTypeArray); const { sort_method, fieldArray, score_missing, direction } = sortTypeArray.find( x => x.type === sort_type ); return { type, From 2ae7fd3042c9b330c7090b05463571fa1064a17f Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Wed, 17 Jul 2024 16:27:33 -0400 Subject: [PATCH 06/19] chore: default initialSearchType to 'text' --- static/js/ReaderApp.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/static/js/ReaderApp.jsx b/static/js/ReaderApp.jsx index ae542480cb..59f1d00477 100644 --- a/static/js/ReaderApp.jsx +++ b/static/js/ReaderApp.jsx @@ -45,7 +45,7 @@ class ReaderApp extends Component { // Currently these get generated in reader/views.py then regenerated again in ReaderApp. this.MIN_PANEL_WIDTH = 360.0; let panels = []; - const searchType = props.initialSearchType; + const searchType = props.initialSearchType || 'text'; if (props.initialMenu) { // If a menu is specified in `initialMenu`, make a panel for it panels[0] = { @@ -147,7 +147,7 @@ class ReaderApp extends Component { translationsSlug: state.translationsSlug || null, searchQuery: state.searchQuery || null, showHighlight: state.showHighlight || null, - searchState: state.searchState || new SearchState({ type: this.props.initialSearchType }), + searchState: state.searchState || new SearchState({ type: this.props.initialSearchType || 'text' }), compare: state.compare || false, openSidebarAsConnect: state.openSidebarAsConnect || false, bookRef: state.bookRef || null, @@ -1190,7 +1190,7 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { filtersValid: true, aggregationsToUpdate, }) : new SearchState({ - type: this.props.initialSearchType, + type: this.props.initialSearchType || 'text', availableFilters, filterRegistry, orphanFilters, @@ -1701,7 +1701,7 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { showSearch(searchQuery) { const hasSearchState = !!this.state.panels && this.state.panels.length && !!this.state.panels[0].searchState const searchState = hasSearchState ? this.state.panels[0].searchState.update({ filtersValid: false }) - : new SearchState({ type: this.props.initialSearchType }); + : new SearchState({ type: this.props.initialSearchType || 'text'}); const searchType = !!this.state.panels && this.state.panels.length ? this.state.panels[0].searchType : this.props.initialSearchType; this.setSinglePanelState({mode: "Menu", menuOpen: "search", searchQuery, searchType, searchState }); } From 0e5f69b03cd09c14db21cdfb164205ef244bdf4e Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Sun, 21 Jul 2024 12:06:45 -0400 Subject: [PATCH 07/19] chore: filterAggTypes was set to work only for text not sheets --- reader/views.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/reader/views.py b/reader/views.py index e9d6afd00e..278cb505eb 100644 --- a/reader/views.py +++ b/reader/views.py @@ -791,6 +791,7 @@ def get_filters(prefix, filter_type): if get_dict.get('tab') == 'text': filters = get_filters("t", "path") sort = get_dict.get(get_param("tsort", i), None) + agg_types = [None for _ in filters] # currently unused. just needs to be equal len as filters else: for filter_type in sheet_filters_types: filters += get_filters("s", filter_type) @@ -803,7 +804,7 @@ def get_filters(prefix, filter_type): "field": ("naive_lemmatizer" if get_dict.get(get_param("tvar", i)) == "1" else "exact") if get_dict.get(get_param("tvar", i)) else "", "sort": sort, "filters": filters, - "filterAggTypes": [None for _ in filters], # currently unused. just needs to be equal len as text_filters + "filterAggTypes": agg_types, } From 8c26de414fc6b64c031f6e01a6ed3f7970a7bc87 Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Sun, 21 Jul 2024 12:20:10 -0400 Subject: [PATCH 08/19] chore: updateAvailableFilters should take type --- static/js/ElasticSearchQuerier.jsx | 2 +- static/js/ReaderApp.jsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/static/js/ElasticSearchQuerier.jsx b/static/js/ElasticSearchQuerier.jsx index 78af369078..c08fb40aea 100644 --- a/static/js/ElasticSearchQuerier.jsx +++ b/static/js/ElasticSearchQuerier.jsx @@ -253,7 +253,7 @@ class ElasticSearchQuerier extends Component { orphans.push(...tempOrphans); } } - this.props.registerAvailableFilters(availableFilters, registry, orphans, args.aggregationsToUpdate); + this.props.registerAvailableFilters(searchState.type, availableFilters, registry, orphans, args.aggregationsToUpdate); } }; args.error = this._handleError; diff --git a/static/js/ReaderApp.jsx b/static/js/ReaderApp.jsx index 59f1d00477..7615fb98c9 100644 --- a/static/js/ReaderApp.jsx +++ b/static/js/ReaderApp.jsx @@ -1178,12 +1178,13 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { updateSearchState(n, searchState) { this.setPanelState(n,{searchState: searchState}); } - updateAvailableFilters(n, availableFilters, filterRegistry, orphanFilters, aggregationsToUpdate) { + updateAvailableFilters(n, type, availableFilters, filterRegistry, orphanFilters, aggregationsToUpdate) { const state = this.state.panels[n]; const searchState = this._getSearchState(state); this.setPanelState(n, { searchState: !!searchState ? searchState.update({ + type, availableFilters, filterRegistry, orphanFilters, From 95496dfbb45f45e6d87242c4d49b49892e02b44a Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Sun, 21 Jul 2024 13:40:44 -0400 Subject: [PATCH 09/19] chore: searchInCollection should work only in sheets --- static/js/ElasticSearchQuerier.jsx | 2 +- static/js/ReaderApp.jsx | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/static/js/ElasticSearchQuerier.jsx b/static/js/ElasticSearchQuerier.jsx index c08fb40aea..78af369078 100644 --- a/static/js/ElasticSearchQuerier.jsx +++ b/static/js/ElasticSearchQuerier.jsx @@ -253,7 +253,7 @@ class ElasticSearchQuerier extends Component { orphans.push(...tempOrphans); } } - this.props.registerAvailableFilters(searchState.type, availableFilters, registry, orphans, args.aggregationsToUpdate); + this.props.registerAvailableFilters(availableFilters, registry, orphans, args.aggregationsToUpdate); } }; args.error = this._handleError; diff --git a/static/js/ReaderApp.jsx b/static/js/ReaderApp.jsx index 7615fb98c9..2a24b3ae66 100644 --- a/static/js/ReaderApp.jsx +++ b/static/js/ReaderApp.jsx @@ -1178,13 +1178,13 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { updateSearchState(n, searchState) { this.setPanelState(n,{searchState: searchState}); } - updateAvailableFilters(n, type, availableFilters, filterRegistry, orphanFilters, aggregationsToUpdate) { + updateAvailableFilters(n, availableFilters, filterRegistry, orphanFilters, aggregationsToUpdate) { const state = this.state.panels[n]; const searchState = this._getSearchState(state); this.setPanelState(n, { searchState: !!searchState ? searchState.update({ - type, + type: searchState.type, availableFilters, filterRegistry, orphanFilters, @@ -1703,13 +1703,13 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { const hasSearchState = !!this.state.panels && this.state.panels.length && !!this.state.panels[0].searchState const searchState = hasSearchState ? this.state.panels[0].searchState.update({ filtersValid: false }) : new SearchState({ type: this.props.initialSearchType || 'text'}); - const searchType = !!this.state.panels && this.state.panels.length ? this.state.panels[0].searchType : this.props.initialSearchType; + const searchType = this.props.initialSearchType; this.setSinglePanelState({mode: "Menu", menuOpen: "search", searchQuery, searchType, searchState }); } searchInCollection(searchQuery, collection) { - const appliedFilters = this.state.searchType === 'sheet' ? [collection] : []; - const appliedFilterAggTypes = this.state.searchType === 'sheet' ? ['collections'] : []; - const searchState = new SearchState({ type: this.state.searchType, appliedFilters, appliedFilterAggTypes}); + const appliedFilters = [collection]; + const appliedFilterAggTypes = ['collections']; + const searchState = new SearchState({ type: 'sheet', appliedFilters, appliedFilterAggTypes}); this.setSinglePanelState({mode: "Menu", menuOpen: "search", "searchType": "sheet", searchQuery, searchState }); } showCommunity() { From 04804359d7f722bd1ddf1eeb0f2ba4e3111f18f9 Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Sun, 21 Jul 2024 13:51:47 -0400 Subject: [PATCH 10/19] chore: remove searchType from panels --- static/js/ReaderApp.jsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/static/js/ReaderApp.jsx b/static/js/ReaderApp.jsx index 2a24b3ae66..f57f947401 100644 --- a/static/js/ReaderApp.jsx +++ b/static/js/ReaderApp.jsx @@ -45,7 +45,7 @@ class ReaderApp extends Component { // Currently these get generated in reader/views.py then regenerated again in ReaderApp. this.MIN_PANEL_WIDTH = 360.0; let panels = []; - const searchType = props.initialSearchType || 'text'; + const searchType = props.initialSearchType || 'text'; // should really be set by URL such as sheets.sefaria.org or www.sefaria.org if (props.initialMenu) { // If a menu is specified in `initialMenu`, make a panel for it panels[0] = { @@ -383,7 +383,6 @@ class ReaderApp extends Component { (prev.currVersions.en !== next.currVersions.en) || (prev.currVersions.he !== next.currVersions.he) || (prev.searchQuery !== next.searchQuery) || - (prev.searchType !== next.searchType) || (prev.tab !== next.tab) || (prev.topicSort !== next.topicSort) || (prev.collectionName !== next.collectionName) || @@ -1700,17 +1699,16 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { this.setSinglePanelState(state); } showSearch(searchQuery) { - const hasSearchState = !!this.state.panels && this.state.panels.length && !!this.state.panels[0].searchState + const hasSearchState = !!this.state.panels && this.state.panels.length && !!this.state.panels[0].searchState; const searchState = hasSearchState ? this.state.panels[0].searchState.update({ filtersValid: false }) : new SearchState({ type: this.props.initialSearchType || 'text'}); - const searchType = this.props.initialSearchType; - this.setSinglePanelState({mode: "Menu", menuOpen: "search", searchQuery, searchType, searchState }); + this.setSinglePanelState({mode: "Menu", menuOpen: "search", searchQuery, searchState }); } searchInCollection(searchQuery, collection) { const appliedFilters = [collection]; const appliedFilterAggTypes = ['collections']; const searchState = new SearchState({ type: 'sheet', appliedFilters, appliedFilterAggTypes}); - this.setSinglePanelState({mode: "Menu", menuOpen: "search", "searchType": "sheet", searchQuery, searchState }); + this.setSinglePanelState({mode: "Menu", menuOpen: "search", searchQuery, searchState }); } showCommunity() { this.setSinglePanelState({menuOpen: "community"}); From 2e8cbf9535247c2d2df5c334820e3d2896a26573 Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Tue, 23 Jul 2024 14:53:28 -0400 Subject: [PATCH 11/19] chore: URL params exist for sheetsWithRef but dont properly set searchState --- sourcesheets/views.py | 31 +++++++++++++------------- static/js/ReaderApp.jsx | 7 +++--- static/js/Sheets/SheetsWithRefPage.jsx | 19 ++++++++-------- static/js/sefaria/sefaria.js | 1 + 4 files changed, 30 insertions(+), 28 deletions(-) diff --git a/sourcesheets/views.py b/sourcesheets/views.py index d6373ede3f..dbee46e6c5 100644 --- a/sourcesheets/views.py +++ b/sourcesheets/views.py @@ -36,7 +36,7 @@ from sefaria.system.decorators import catch_error_as_json from sefaria.utils.util import strip_tags -from reader.views import render_template, catchall +from reader.views import render_template, catchall, get_search_params from sefaria.sheets import clean_source, bleach_text from bs4 import BeautifulSoup @@ -1026,24 +1026,22 @@ def sheets_by_ref_api(request, ref): include_first_comment = bool(int(request.GET.get("include_first_comment", 0))) return jsonResponse(get_sheets_for_ref(ref, include_collections=include_collections, include_first_comment=include_first_comment)) - -def sheets_with_ref(request, tref): - """ - Accepts tref as a string which is expected to be in the format of a ref or refs separated by commas, indicating a range. - """ - is_range = bool(int(request.GET.get('range', 0))) - if is_range: - refs = [Ref(r) for r in tref.split(",")] - tref = refs[0].to(refs[-1]).normal() - he_tref = Ref(tref).he_normal() - normal_ref = tref if request.interfaceLang == "english" else he_tref - title = _(f"Sheets with ")+normal_ref+_(" on Sefaria") - return menu_page(request, page="sheetsWithRef", title=title, props={"sheetsWithRef": {"en": tref, "he": he_tref}}) - def sheets_with_ref(request, tref): """ Accepts tref as a string which is expected to be in the format of a ref or refs separated by commas, indicating a range. """ + search_params = get_search_params(request.GET) + + props={ + "initialSearchType": "sheet", + "initialTextSearchFilters": search_params["textFilters"], + "initialTextSearchFilterAggTypes": search_params["textFilterAggTypes"], + "initialTextSearchField": search_params["textField"], + "initialTextSearchSortType": search_params["textSort"], + "initialSheetSearchFilters": search_params["sheetFilters"], + "initialSheetSearchFilterAggTypes": search_params["sheetFilterAggTypes"], + "initialSheetSearchSortType": search_params["sheetSort"] + } is_range = bool(int(request.GET.get('range', 0))) if is_range: refs = [Ref(r) for r in tref.split(",")] @@ -1051,7 +1049,8 @@ def sheets_with_ref(request, tref): he_tref = Ref(tref).he_normal() normal_ref = tref if request.interfaceLang == "english" else he_tref title = _(f"Sheets with ")+normal_ref+_(" on Sefaria") - return menu_page(request, page="sheetsWithRef", title=title, props={"sheetsWithRef": {"en": tref, "he": he_tref}}) + props["sheetsWithRef"] = {"en": tref, "he": he_tref} + return menu_page(request, page="sheetsWithRef", title=title, props=props) def get_aliyot_by_parasha_api(request, parasha): response = {"ref":[]}; diff --git a/static/js/ReaderApp.jsx b/static/js/ReaderApp.jsx index 2bd6e90b33..967ac2bac7 100644 --- a/static/js/ReaderApp.jsx +++ b/static/js/ReaderApp.jsx @@ -455,10 +455,11 @@ class ReaderApp extends Component { hist.mode = "navigation"; break; case "sheetsWithRef": - const lang = Sefaria.interfaceLang === "hebrew" ? "he" : "en"; - hist.title = Sefaria._("Sheets with ") + Sefaria.sheetsWithRef[lang] + Sefaria._(" on Sefaria"); + const encodedSheetsWithRef = Sefaria.sheetsWithRef[shortLang] ? encodeURIComponent(Sefaria.sheetsWithRef[shortLang]) : ""; + hist.title = Sefaria._("Sheets with ") + Sefaria.sheetsWithRef[shortLang] + Sefaria._(" on Sefaria"); + hist.url = "sheetsWithRef" + (Sefaria.sheetsWithRef[shortLang] ? (`/${encodedSheetsWithRef}` + + state.sheetSearchState.makeURL({ prefix: 's', isStart: false })) : ""); hist.mode = "sheetsWithRef"; - hist.url = `sheetsWithRef/${Sefaria.sheetsWithRef['en']}`; break; case "text toc": var ref = state.refs.slice(-1)[0]; diff --git a/static/js/Sheets/SheetsWithRefPage.jsx b/static/js/Sheets/SheetsWithRefPage.jsx index fcac50d457..456d866d0c 100644 --- a/static/js/Sheets/SheetsWithRefPage.jsx +++ b/static/js/Sheets/SheetsWithRefPage.jsx @@ -10,6 +10,7 @@ const SheetsWithRefPage = ({srefs, searchState, updateSearchState, updateApplied const [loading, setLoading] = useState(true); const [totalResults, setTotalResults] = useState(new SearchTotal()); const [origAvailableFilters, setOrigAvailableFilters] = useState([]); + const [refs, setRefs] = useState(srefs); const cloneFilters = (availableFilters, resetDocCounts = true) => { return availableFilters.map(availableFilter => { let newAvailableFilter = availableFilter.clone(); @@ -25,7 +26,7 @@ const SheetsWithRefPage = ({srefs, searchState, updateSearchState, updateApplied const currDocCounts = getDocCounts(searchState.availableFilters); if (!newDocCounts.compare(currDocCounts)) { availableFilters = availableFilters.sort((a, b) => b.docCount - a.docCount || a.title.localeCompare(b.title)); - registerAvailableFilters('sheet', availableFilters, {}, [], ['collections', 'topics']); + registerAvailableFilters('sheet', availableFilters, {}, [], ['collections', 'topics_en']); } } const updateDocCounts = (newAvailableFilters, slugs) => { @@ -36,7 +37,7 @@ const SheetsWithRefPage = ({srefs, searchState, updateSearchState, updateApplied }) } const getSheetSlugs = (type, sheet) => { - const items = sheet[[type]]; + const items = type === 'topics_en' ? sheet.topics : sheet.collections; return items.map(x => x.slug); } const applyFiltersToSheets = (sheets) => { @@ -63,7 +64,7 @@ const SheetsWithRefPage = ({srefs, searchState, updateSearchState, updateApplied return sheets; } const updateNewAvailableFilters = (newAvailableFilters, sheets) => { - ['collections', 'topics'].forEach(type => { + ['collections', 'topics_en'].forEach(type => { let allSlugs = {}; sheets.forEach(sheet => { let slugs = getSheetSlugs(type, sheet); @@ -178,18 +179,18 @@ const SheetsWithRefPage = ({srefs, searchState, updateSearchState, updateApplied // 'collections' won't be present if the related API set _sheetsByRef, // but 'collections' will be present if the sheets_by_ref_api has run // if the field is not present, we need to call the sheets_by_ref_api - const currentSheetsByRef = Sefaria.sheets._sheetsByRef[srefs]; + const currentSheetsByRef = Sefaria.sheets._sheetsByRef[refs]; const collectionsInCache = !!currentSheetsByRef && currentSheetsByRef.every(sheet => 'collections' in sheet); if (!collectionsInCache) { - delete Sefaria.sheets._sheetsByRef[srefs]; - Sefaria.sheets.getSheetsByRef(srefs, getSheetsByRefCallback).then(sheets => { + delete Sefaria.sheets._sheetsByRef[refs]; + Sefaria.sheets.getSheetsByRef(refs, getSheetsByRefCallback).then(sheets => { handleSheetsLoad(sheets); }) } else { - handleSheetsLoad(Sefaria.sheets._sheetsByRef[srefs]); + handleSheetsLoad(Sefaria.sheets._sheetsByRef[refs]); } - }, []); + }, [refs]); updateOrigAvailableFilters(); let sortedSheets = [...sheets]; @@ -201,7 +202,7 @@ const SheetsWithRefPage = ({srefs, searchState, updateSearchState, updateApplied isQueryRunning={loading} searchTopMsg="Sheets With" hits={sortedSheets} - query={srefs} + query={refs} type={'sheet'} totalResults={totalResults} compare={false} diff --git a/static/js/sefaria/sefaria.js b/static/js/sefaria/sefaria.js index e8eba67334..b84b1fcbee 100644 --- a/static/js/sefaria/sefaria.js +++ b/static/js/sefaria/sefaria.js @@ -2797,6 +2797,7 @@ _media: {}, let title, heTitle; if (type === 'topics') { [title, heTitle] = [item.en, item.he]; + type = 'topics_en'; } else if (type === 'collections') { [title, heTitle] = [item.name, item.name]; From 3e7837f801a5f0b2a99ce7edeb778b1e3e257b4c Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Sun, 28 Jul 2024 15:44:00 +0300 Subject: [PATCH 12/19] chore: remove sheetSearchState and replace with searchState --- sourcesheets/views.py | 11 ++++------- static/js/ElasticSearchQuerier.jsx | 6 +++--- static/js/ReaderApp.jsx | 10 ++++------ static/js/ReaderPanel.jsx | 1 - static/js/Sheets/SheetsWithRefPage.jsx | 2 +- 5 files changed, 12 insertions(+), 18 deletions(-) diff --git a/sourcesheets/views.py b/sourcesheets/views.py index dbee46e6c5..b2dd8ca773 100644 --- a/sourcesheets/views.py +++ b/sourcesheets/views.py @@ -1034,13 +1034,10 @@ def sheets_with_ref(request, tref): props={ "initialSearchType": "sheet", - "initialTextSearchFilters": search_params["textFilters"], - "initialTextSearchFilterAggTypes": search_params["textFilterAggTypes"], - "initialTextSearchField": search_params["textField"], - "initialTextSearchSortType": search_params["textSort"], - "initialSheetSearchFilters": search_params["sheetFilters"], - "initialSheetSearchFilterAggTypes": search_params["sheetFilterAggTypes"], - "initialSheetSearchSortType": search_params["sheetSort"] + "initialSearchField": search_params["field"], + "initialSearchFilters": search_params["filters"], + "initialSearchFilterAggTypes": search_params["filterAggTypes"], + "initialSearchSortType": search_params["sort"] } is_range = bool(int(request.GET.get('range', 0))) if is_range: diff --git a/static/js/ElasticSearchQuerier.jsx b/static/js/ElasticSearchQuerier.jsx index d038141e59..503a9deb9a 100644 --- a/static/js/ElasticSearchQuerier.jsx +++ b/static/js/ElasticSearchQuerier.jsx @@ -63,8 +63,9 @@ class ElasticSearchQuerier extends Component { if (this.props.query !== newProps.query) { this.setState(state, () => { this._executeAllQueries(newProps); - this.props.resetSearchFilters('sheet'); - this.props.resetSearchFilters('text'); + if (!this.props.searchInBook) { + this.props.resetSearchFilters(); + } }); } else if (this._shouldUpdateQuery(this.props, newProps, this.props.type)) { this.setState(state, () => { @@ -361,7 +362,6 @@ class ElasticSearchQuerier extends Component { ElasticSearchQuerier.propTypes = { query: PropTypes.string, - type: PropTypes.oneOf(["text", "sheet"]), searchState: PropTypes.object, onResultClick: PropTypes.func, registerAvailableFilters: PropTypes.func, diff --git a/static/js/ReaderApp.jsx b/static/js/ReaderApp.jsx index 9e8eea1991..96f9d344f8 100644 --- a/static/js/ReaderApp.jsx +++ b/static/js/ReaderApp.jsx @@ -443,7 +443,7 @@ class ReaderApp extends Component { const encodedSheetsWithRef = Sefaria.sheetsWithRef[shortLang] ? encodeURIComponent(Sefaria.sheetsWithRef[shortLang]) : ""; hist.title = Sefaria._("Sheets with ") + Sefaria.sheetsWithRef[shortLang] + Sefaria._(" on Sefaria"); hist.url = "sheetsWithRef" + (Sefaria.sheetsWithRef[shortLang] ? (`/${encodedSheetsWithRef}` + - state.sheetSearchState.makeURL({ prefix: 's', isStart: false })) : ""); + state.searchState.makeURL({ prefix: 's', isStart: false })) : ""); hist.mode = "sheetsWithRef"; break; case "text toc": @@ -1199,18 +1199,16 @@ toggleSignUpModal(modalContentKind = SignUpModalKind.Default) { }) }); } - resetSearchFilters(n, type) { - // reset both availableFilters and appliedFilters + resetSearchFilters(n) { const state = this.state.panels[n]; - const searchState = this._getSearchState(state, type); - const searchStateName = this._getSearchStateName(type); + const searchState = this._getSearchState(state); searchState.availableFilters.forEach(filterNode => { if (!filterNode.isUnselected()) { filterNode.setUnselected(true); } }) this.setPanelState(n, { - [searchStateName]: searchState.update({appliedFilters: [], appliedFilterAggTypes: [], filterRegistry: {}, + searchState: searchState.update({appliedFilters: [], appliedFilterAggTypes: [], filterRegistry: {}, filtersValid: false}), }); } diff --git a/static/js/ReaderPanel.jsx b/static/js/ReaderPanel.jsx index 8f3a829bf9..0e1f1c86a0 100644 --- a/static/js/ReaderPanel.jsx +++ b/static/js/ReaderPanel.jsx @@ -897,7 +897,6 @@ class ReaderPanel extends Component { menu = ( b.docCount - a.docCount || a.title.localeCompare(b.title)); - registerAvailableFilters('sheet', availableFilters, {}, [], ['collections', 'topics_en']); + registerAvailableFilters(availableFilters, {}, [], ['collections', 'topics_en']); } } const updateDocCounts = (newAvailableFilters, slugs) => { From 56d404fff4ab45ab335a29fc35868675f9f70e5a Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Wed, 7 Aug 2024 14:35:48 +0300 Subject: [PATCH 13/19] chore: fix bad merge --- static/js/ElasticSearchQuerier.jsx | 35 +++++++++++++++--------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/static/js/ElasticSearchQuerier.jsx b/static/js/ElasticSearchQuerier.jsx index fc2540c98d..79d7f126a1 100644 --- a/static/js/ElasticSearchQuerier.jsx +++ b/static/js/ElasticSearchQuerier.jsx @@ -130,23 +130,24 @@ class ElasticSearchQuerier extends Component { this._abortRunningQuery(); // todo: make this work w/ promises } componentWillReceiveProps(newProps) { - let state = { - hits: [], - pagesLoaded: 0, - moreToLoad: true - }; - if (this.props.query !== newProps.query) { - this.setState(state, () => { - this._executeAllQueries(newProps); - if (!this.props.searchInBook) { - this.props.resetSearchFilters(); - } - }); - } else if (this._shouldUpdateQuery(this.props, newProps, this.props.type)) { - this.setState(state, () => { - this._executeQuery(newProps, this.props.searchState.type); - }) - } + let state = { + hits: [], + pagesLoaded: 0, + moreToLoad: true + }; + if (this.props.query !== newProps.query) { + this.setState(state, () => { + this._executeAllQueries(newProps); + if (!this.props.searchInBook) { + this.props.resetSearchFilters(); + } + }); + } else if (this._shouldUpdateQuery(this.props, newProps, this.props.type)) { + this.setState(state, () => { + this._executeQuery(newProps, this.props.searchState.type); + }) + } + } async _executeTopicQuery() { const topicQuerier = new TopicQuerier(); const d = await Sefaria.getName(this.props.query) From febb11d36b3d11b68892fa600579c098bca0b80e Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Sun, 11 Aug 2024 11:35:04 +0300 Subject: [PATCH 14/19] chore: merge bugs in sheets with ref --- static/js/ElasticSearchQuerier.jsx | 4 ++-- static/js/SearchPage.jsx | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/static/js/ElasticSearchQuerier.jsx b/static/js/ElasticSearchQuerier.jsx index 4f180445ba..c974b4ef8f 100644 --- a/static/js/ElasticSearchQuerier.jsx +++ b/static/js/ElasticSearchQuerier.jsx @@ -142,7 +142,7 @@ class ElasticSearchQuerier extends Component { this.props.resetSearchFilters(); } }); - } else if (this._shouldUpdateQuery(this.props, newProps, this.props.type)) { + } else if (this._shouldUpdateQuery(this.props, newProps, this.props.searchState.type)) { this.setState(state, () => { this._executeQuery(newProps, this.props.searchState.type); }) @@ -340,7 +340,7 @@ class ElasticSearchQuerier extends Component { isQueryRunning={this.state.isQueryRunning} searchTopMsg="Results for" query={this.props.query} - sortTypeArray={SearchState.metadataByType[this.props.type].sortTypeArray} + sortTypeArray={SearchState.metadataByType[this.props.searchState.type].sortTypeArray} hits={this.normalizeHitsMetaData()} totalResults={this.state.totals} type={this.props.searchState.type} diff --git a/static/js/SearchPage.jsx b/static/js/SearchPage.jsx index 00e4dfcdd1..bbfb5afee6 100644 --- a/static/js/SearchPage.jsx +++ b/static/js/SearchPage.jsx @@ -94,9 +94,9 @@ class SearchPage extends Component { this.setState({mobileFiltersOpen: false})} compare={this.props.compare} type={this.props.type}/> From 2c4a60a06ce09a4c942426e0526c3968ffb645f3 Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Mon, 12 Aug 2024 10:35:26 +0300 Subject: [PATCH 15/19] fix(Sheets with Ref): reset search filters on unmount --- static/js/ReaderPanel.jsx | 1 + static/js/Sheets/SheetsWithRefPage.jsx | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/static/js/ReaderPanel.jsx b/static/js/ReaderPanel.jsx index 0ef1a6e588..2ed668b622 100644 --- a/static/js/ReaderPanel.jsx +++ b/static/js/ReaderPanel.jsx @@ -810,6 +810,7 @@ class ReaderPanel extends Component { updateAppliedOptionField={this.props.updateSearchOptionField} updateAppliedOptionSort={this.props.updateSearchOptionSort} registerAvailableFilters={this.props.registerAvailableFilters} + resetSearchFilters={this.props.resetSearchFilters} onResultClick={this.props.onSearchResultClick}/>); } else if (this.state.menuOpen === "sheet meta") { menu = ( { + registerAvailableFilters, resetSearchFilters}) => { const [sheets, setSheets] = useState([]); const [loading, setLoading] = useState(true); const [origAvailableFilters, setOrigAvailableFilters] = useState([]); @@ -169,6 +169,10 @@ const SheetsWithRefPage = ({srefs, searchState, updateSearchState, updateApplied } }, [refs]); + useEffect(() => { // when component unmounts, reset searchState + return () => resetSearchFilters(); + }, []); + updateOrigAvailableFilters(); let sortedSheets = [...sheets]; sortedSheets = applyFilters(sortedSheets); From 044cbf1e26a2ae86517d53caf4d1c2d39b68b4ad Mon Sep 17 00:00:00 2001 From: stevekaplan123 Date: Mon, 19 Aug 2024 14:56:40 +0300 Subject: [PATCH 16/19] chore: fix bad merge --- static/js/ReaderApp.jsx | 2 +- static/js/SearchPage.jsx | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/static/js/ReaderApp.jsx b/static/js/ReaderApp.jsx index 317d75fbf1..9c656c156a 100644 --- a/static/js/ReaderApp.jsx +++ b/static/js/ReaderApp.jsx @@ -59,8 +59,8 @@ class ReaderApp extends Component { field: props.initialSearchField, appliedFilterAggTypes: props.initialSearchFilterAggTypes, sortType: props.initialSearchSortType, - sheetsWithRef: props.sheetsWithRef, }), + sheetsWithRef: props.sheetsWithRef, navigationCategories: props.initialNavigationCategories, navigationTopicCategory: props.initialNavigationTopicCategory, navigationTopic: props.initialTopic, diff --git a/static/js/SearchPage.jsx b/static/js/SearchPage.jsx index 190c14f703..4ebbd46a13 100644 --- a/static/js/SearchPage.jsx +++ b/static/js/SearchPage.jsx @@ -104,22 +104,6 @@ class SearchPage extends Component { : null} - - {(Sefaria.multiPanel && !this.props.compare) || this.state.mobileFiltersOpen ? -
- {this.props.totalResults?.getValue() > 0 ? - this.setState({mobileFiltersOpen: false})} - compare={this.props.compare} - type={this.props.type} /> - : null } -
- : null } {this.props.panelsOpen === 1 ?