diff --git a/notes-service/src/main/java/org/exoplatform/wiki/jpa/JPADataStorage.java b/notes-service/src/main/java/org/exoplatform/wiki/jpa/JPADataStorage.java index dce8081b7a..76c3b19411 100644 --- a/notes-service/src/main/java/org/exoplatform/wiki/jpa/JPADataStorage.java +++ b/notes-service/src/main/java/org/exoplatform/wiki/jpa/JPADataStorage.java @@ -149,6 +149,7 @@ public PageList search(WikiSearchData wikiSearchData) { wikiSearchData.getUserId(), wikiSearchData.getTagNames(), wikiSearchData.isFavorites(), + wikiSearchData.isNotesTreeFilter(), (int) wikiSearchData.getOffset(), wikiSearchData.getLimit()); diff --git a/notes-service/src/main/java/org/exoplatform/wiki/jpa/search/WikiElasticSearchServiceConnector.java b/notes-service/src/main/java/org/exoplatform/wiki/jpa/search/WikiElasticSearchServiceConnector.java index 526bf6d9e3..76dc41f69e 100644 --- a/notes-service/src/main/java/org/exoplatform/wiki/jpa/search/WikiElasticSearchServiceConnector.java +++ b/notes-service/src/main/java/org/exoplatform/wiki/jpa/search/WikiElasticSearchServiceConnector.java @@ -78,6 +78,21 @@ public class WikiElasticSearchServiceConnector extends ElasticSearchServiceConne } """; + public static final String SEARCH_QUERY_TERM_FOR_NOTES_APPLICATION = """ + ,"must": [ + @wildcard_query@ + ] + """; + + public static final String WILDCARD_QUERY = """ + { + "wildcard": { + "name": "*@term@*" + } + } + """; + + public WikiElasticSearchServiceConnector(ConfigurationManager configurationManager, InitParams initParams, @@ -120,13 +135,13 @@ protected String getSourceFields() { return StringUtils.join(sourceFields, ","); } - public List searchWiki(String searchedText, String userId, List tagNames, boolean isFavorites, int offset, int limit) { - return filteredWikiSearch(searchedText, userId, tagNames, isFavorites, offset, limit); + public List searchWiki(String searchedText, String userId, List tagNames, boolean isFavorites, boolean isNotesTreeFilter, int offset, int limit) { + return filteredWikiSearch(searchedText, userId, tagNames, isFavorites, isNotesTreeFilter, offset, limit); } - protected List filteredWikiSearch(String query, String userId, List tagNames, boolean isFavorites, int offset, int limit) { + protected List filteredWikiSearch(String query, String userId, List tagNames, boolean isFavorites,boolean isNotesTreeFilter , int offset, int limit) { Set ids = getUserSpaceIds(userId); - String esQuery = buildQueryStatement(ids, userId, tagNames, query, isFavorites, offset, limit); + String esQuery = buildQueryStatement(ids, userId, tagNames, query, isFavorites, isNotesTreeFilter,offset, limit); String jsonResponse = getClient().sendRequest(esQuery, getIndex()); return buildWikiResult(jsonResponse); } @@ -153,11 +168,33 @@ private String buildTagsQueryStatement(List values) { .toString(); } - private String buildTermQuery(String termQuery) { + private String buildTermQuery(String termQuery, boolean isNotesTreeFilter) { if (StringUtils.isBlank(termQuery)) { return ""; } + termQuery = removeSpecialCharacters(termQuery); + if (isNotesTreeFilter) { + termQuery = termQuery.trim().replaceAll("\\s+", " "); + List listTermQuery = List.of(termQuery.split(" ")); + if (listTermQuery.size() == 0) { + return ""; + } + String allWildcardQuery = ""; + String termWildcardQuery = WILDCARD_QUERY.replace("@term@",listTermQuery.get(0)); + allWildcardQuery = allWildcardQuery.concat(termWildcardQuery); + if (listTermQuery.size() > 1) { + int index = 0; + for(String term : listTermQuery) { + if (index > 0){ + termWildcardQuery = WILDCARD_QUERY.replace("@term@", term); + allWildcardQuery = allWildcardQuery.concat(",").concat(termWildcardQuery); + } + index++; + }; + } + return SEARCH_QUERY_TERM_FOR_NOTES_APPLICATION.replace("@wildcard_query@", allWildcardQuery); + } else { List termsQuery = Arrays.stream(termQuery.split(" ")).filter(StringUtils::isNotBlank).map(word -> { word = word.trim(); if (word.length() > 5) { @@ -165,7 +202,8 @@ private String buildTermQuery(String termQuery) { } return word; }).toList(); - return SEARCH_QUERY_TERM.replace("@term@", StringUtils.join(termsQuery, " ")); + return SEARCH_QUERY_TERM.replace("@term@", StringUtils.join(termsQuery, " ")); + } } private String buildQueryStatement(Set calendarOwnersOfUser, @@ -173,13 +211,14 @@ private String buildQueryStatement(Set calendarOwnersOfUser, List tagNames, String term, boolean isFavorites, + boolean isNotesTreeFilter, long offset, long limit) { term = removeSpecialCharacters(term); Map> metadataFilters = buildMetadataFilter(isFavorites, userId); String metadataQuery = buildMetadataQueryStatement(metadataFilters); String tagsQuery = buildTagsQueryStatement(tagNames); - String termsQuery = buildTermQuery(term); + String termsQuery = buildTermQuery(term, isNotesTreeFilter); return retrieveSearchQuery().replace("@term_query@", termsQuery) .replace("@metadatas_query@", metadataQuery) .replace("@tags_query@", tagsQuery) diff --git a/notes-service/src/main/java/org/exoplatform/wiki/service/rest/NotesRestService.java b/notes-service/src/main/java/org/exoplatform/wiki/service/rest/NotesRestService.java index 027989d0d9..131be8d319 100644 --- a/notes-service/src/main/java/org/exoplatform/wiki/service/rest/NotesRestService.java +++ b/notes-service/src/main/java/org/exoplatform/wiki/service/rest/NotesRestService.java @@ -1270,7 +1270,9 @@ public Response searchData(@Context int limit, @QueryParam("wikiType") String wikiType, @QueryParam("wikiOwner") String wikiOwner, @QueryParam("favorites") - boolean favorites, @QueryParam("tags") List tagNames) throws Exception { + boolean favorites, @QueryParam("tags") + List tagNames, @QueryParam("isNotesTreeFilter") + boolean isNotesTreeFilter) throws Exception { limit = limit > 0 ? limit : RestUtils.getLimit(uriInfo); try { @@ -1278,6 +1280,7 @@ public Response searchData(@Context Identity currentIdentity = ConversationState.getCurrent().getIdentity(); WikiSearchData data = new WikiSearchData(keyword, currentIdentity.getUserId()); data.setLimit(limit); + data.setNotesTreeFilter(isNotesTreeFilter); data.setFavorites(favorites); data.setTagNames(tagNames); List results = noteService.search(data).getAll(); @@ -1296,6 +1299,7 @@ public Response searchData(@Context TitleSearchResult titleSearchResult = new TitleSearchResult(); titleSearchResult.setTitle(attachment.getName()); titleSearchResult.setId(page.getId()); + titleSearchResult.setPageName(page.getName()); titleSearchResult.setActivityId(page.getActivityId()); titleSearchResult.setType(searchResult.getType()); titleSearchResult.setUrl(attachment.getDownloadURL()); @@ -1319,6 +1323,8 @@ public Response searchData(@Context TitleSearchResult titleSearchResult = new TitleSearchResult(); titleSearchResult.setTitle(searchResult.getTitle()); titleSearchResult.setId(page.getId()); + titleSearchResult.setPageName(page.getName()); + titleSearchResult.setPageName(page.getName()); titleSearchResult.setActivityId(page.getActivityId()); if (posterIdentity != null) { titleSearchResult.setPoster(posterIdentity); diff --git a/notes-service/src/main/java/org/exoplatform/wiki/service/search/SearchData.java b/notes-service/src/main/java/org/exoplatform/wiki/service/search/SearchData.java index dff6eafc05..943310f577 100644 --- a/notes-service/src/main/java/org/exoplatform/wiki/service/search/SearchData.java +++ b/notes-service/src/main/java/org/exoplatform/wiki/service/search/SearchData.java @@ -47,6 +47,8 @@ public class SearchData { private List tagNames; + private boolean isNotesTreeFilter; + public SearchData(String title, String content, String wikiType, String wikiOwner, String pageId, String userId) { this.title = org.exoplatform.wiki.utils.Utils.escapeIllegalCharacterInQuery(title); this.content = org.exoplatform.wiki.utils.Utils.escapeIllegalCharacterInQuery(content); diff --git a/notes-service/src/main/java/org/exoplatform/wiki/service/search/TitleSearchResult.java b/notes-service/src/main/java/org/exoplatform/wiki/service/search/TitleSearchResult.java index b940bf4b3b..89fd3f72dd 100644 --- a/notes-service/src/main/java/org/exoplatform/wiki/service/search/TitleSearchResult.java +++ b/notes-service/src/main/java/org/exoplatform/wiki/service/search/TitleSearchResult.java @@ -49,4 +49,6 @@ public class TitleSearchResult { private String lang; + private String pageName; + } diff --git a/notes-service/src/test/java/org/exoplatform/wiki/jpa/search/WikiElasticSearchServiceConnectorTest.java b/notes-service/src/test/java/org/exoplatform/wiki/jpa/search/WikiElasticSearchServiceConnectorTest.java index 3261027833..00a2c580f5 100644 --- a/notes-service/src/test/java/org/exoplatform/wiki/jpa/search/WikiElasticSearchServiceConnectorTest.java +++ b/notes-service/src/test/java/org/exoplatform/wiki/jpa/search/WikiElasticSearchServiceConnectorTest.java @@ -144,7 +144,7 @@ protected String getPermissionFilter() { // when List tagNames = new ArrayList<>(); tagNames.add("testNoteTag"); - List searchResults = searchServiceConnector.searchWiki("*","__system", tagNames, false, 0, 20); + List searchResults = searchServiceConnector.searchWiki("*","__system", tagNames, false, false, 0, 20); // Then assertNotNull(searchResults); diff --git a/notes-service/src/test/java/org/exoplatform/wiki/service/TestWikiRestService.java b/notes-service/src/test/java/org/exoplatform/wiki/service/TestWikiRestService.java index 9637eaf2c0..06fe396eb6 100644 --- a/notes-service/src/test/java/org/exoplatform/wiki/service/TestWikiRestService.java +++ b/notes-service/src/test/java/org/exoplatform/wiki/service/TestWikiRestService.java @@ -126,7 +126,7 @@ public void testSearchData() throws Exception { // When List tagNames = new ArrayList<>(); tagNames.add("testTag"); - Response response = wikiRestService.searchData(uriInfo, "wiki", 10, "page", "alioua", false, tagNames); + Response response = wikiRestService.searchData(uriInfo, "wiki", 10, "page", "alioua", false, tagNames, false); // Then assertEquals(200, response.getStatus()); diff --git a/notes-service/src/test/java/org/exoplatform/wiki/service/rest/NotesRestServiceTest.java b/notes-service/src/test/java/org/exoplatform/wiki/service/rest/NotesRestServiceTest.java index ff30a3f5c4..15f50c717a 100644 --- a/notes-service/src/test/java/org/exoplatform/wiki/service/rest/NotesRestServiceTest.java +++ b/notes-service/src/test/java/org/exoplatform/wiki/service/rest/NotesRestServiceTest.java @@ -445,7 +445,7 @@ public void testSearchData() throws Exception { anyString())) .thenReturn(identityEntity); - Response response = notesRestService.searchData(uriInfo, "test", 10, "wikiType", "wikiOwner", true, new ArrayList<>()); + Response response = notesRestService.searchData(uriInfo, "test", 10, "wikiType", "wikiOwner", true, new ArrayList<>(), false); assertEquals(Response.Status.OK.getStatusCode(), response.getStatus()); } diff --git a/notes-webapp/src/main/webapp/javascript/eXo/wiki/notesService.js b/notes-webapp/src/main/webapp/javascript/eXo/wiki/notesService.js index 1b039df146..8afd10067a 100644 --- a/notes-webapp/src/main/webapp/javascript/eXo/wiki/notesService.js +++ b/notes-webapp/src/main/webapp/javascript/eXo/wiki/notesService.js @@ -1,7 +1,7 @@ import { notesConstants } from './notesConstants.js'; export function getNote(noteBookType, noteBookOwner, noteId,source,lang) { - let url = `${notesConstants.PORTAL}/${notesConstants.PORTAL_REST}/notes/note/${noteBookType}/${noteBookOwner}/${noteId}`; +let url = `${notesConstants.PORTAL}/${notesConstants.PORTAL_REST}/notes/note/${noteBookType}/${noteBookOwner}/${noteId}`; if (source){ url=`${url}?source=${source}`; } @@ -429,3 +429,17 @@ export function removeNoteFeaturedImage(noteId, isDraft, lang) { } }); } + +export function searchNotes(keyword, limit) { + document.dispatchEvent(new CustomEvent('displayTopBarLoading')); + return fetch(`${notesConstants.PORTAL}/${notesConstants.PORTAL_REST}/notes/contextsearch?keyword=${keyword}&isNotesTreeFilter=true&limit=${limit}`, { + method: 'GET', + credentials: 'include', + }).then(resp => { + if (!resp || !resp.ok) { + throw new Error('Response code indicates a server error', resp); + } else { + return resp.json(); + } + }).finally(() => document.dispatchEvent(new CustomEvent('hideTopBarLoading'))); +} \ No newline at end of file diff --git a/notes-webapp/src/main/webapp/vue-app/notes/components/NoteTreeviewDrawer.vue b/notes-webapp/src/main/webapp/vue-app/notes/components/NoteTreeviewDrawer.vue index 0eb7579c36..09345e608e 100644 --- a/notes-webapp/src/main/webapp/vue-app/notes/components/NoteTreeviewDrawer.vue +++ b/notes-webapp/src/main/webapp/vue-app/notes/components/NoteTreeviewDrawer.vue @@ -470,7 +470,12 @@ export default { dataCreated: false, isLoading: false, selectionType: 'independent', - inProgressTreeFetches: [] + inProgressTreeFetches: [], + filterItems: [], + filterItemsDraft: [], + limit: 20, + timeout: 1000, + searchTimer: null, }), props: { selectedTranslation: { @@ -498,7 +503,7 @@ export default { }, active() { return this.search - && this.allItems + && this.allItems && this.allItems.filter(item => item.name.toLowerCase().match(this.search.toLowerCase())) || this.activeItem; }, @@ -533,24 +538,26 @@ export default { this.isLoading = this.inProgressTreeFetches?.length; }, search() { + clearTimeout(this.searchTimer); this.showTree = true; if (this.search) { - this.items = this.active; - this.items.forEach(item => { - item.children = null; - }); - this.showTree = !!this.active.length; + this.searchTerm(); } else { this.retrieveNoteTree(this.note.wikiType, this.note.wikiOwner, this.note.name); } }, filter() { - if (this.note && this.note.id) { - if (this.note.draftPage) { - this.getDraftNote(this.note.id); - } else { - this.getNoteById(this.note.id); + if (!this.search) { + this.items = []; + if (this.note && this.note.id) { + if (this.note.draftPage) { + this.getDraftNote(this.note.id); + } else { + this.getNoteById(this.note.id); + } } + } else { + this.searchTerm(); } }, }, @@ -822,6 +829,9 @@ export default { } if (this.isDraftFilter) { this.naturalSort(this.items); + this.filterItems = this.items; + this.filterItemsDraft = []; + this.filterItemsForSearch(this.filterItems); } this.allItems = data.treeNodeData; this.allItemsHome = data.jsonList[0].children; @@ -892,6 +902,49 @@ export default { this.exporting = false; this.$nextTick().then(() => this.close()); } + }, + searchTerm() { + this.items = []; + this.isLoading = true; + this.searchTimer = setTimeout(() => { + if (this.isDraftFilter) { + this.items = this.filterItemsDraft.filter(item => item.name.includes(this.search)); + } else { + this.$notesService.searchNotes(this.search, this.limit).then(data => { + this.items = data?.jsonList.length ? this.toListNotes(data?.jsonList) : []; + this.showTree = !!this.items.length; + }); + } + this.isLoading = false; + }, this.timeout); + }, + filterItemsForSearch(filterItems){ + filterItems.forEach(filterItem => { + if (filterItem.draftPage) { + this.filterItemsDraft.push(filterItem); + } + if (filterItem.hasChild) { + this.filterItemsForSearch(filterItem.children); + } + }); + }, + toListNotes(items) { + const itemsNotes = []; + items.forEach(item => itemsNotes.push(this.toNote(item))); + return itemsNotes; + }, + toNote(note) { + return { + children: [], + disabled: false, + draftPage: false, + name: note.title, + nodeType: note.type, + noteId: note.id, + url: note.url, + path: note.pageName, + parentPageId: '' + }; } } };