fix(ui) : owner dropdown for teams with search text is not working (#9921)

* fix(ui) : owner dropdown for teams with search text is not working

* chore : convert searchFormattedUsersAndTeams to async/await

* chore: use searchFormattedUsersAndTeams for owner search on add alerts page

* fix : search api call with query is not working

* fix : filter issue for team assets

* fix : cy test for alerts

* fix : cy tests

* fix: cy test

* chore: update the search query logic

* fix: cy tests

* Fix search teams with special chars

* fix localization missing for constant

---------

Co-authored-by: Sriharsha Chintalapani <harsha@getcollate.io>
Co-authored-by: Chirag Madlani <12962843+chirag-madlani@users.noreply.github.com>
This commit is contained in:
Sachin Chaurasiya 2023-01-30 14:30:18 +05:30 committed by GitHub
parent 4bef627fd7
commit aa294a6a36
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 96 additions and 73 deletions

View File

@ -85,7 +85,9 @@ public class SearchResource {
private static final Integer MAX_AGGREGATE_SIZE = 50; private static final Integer MAX_AGGREGATE_SIZE = 50;
private static final Integer MAX_RESULT_HITS = 10000; private static final Integer MAX_RESULT_HITS = 10000;
private static final String NAME = "name"; private static final String NAME = "name";
private static final String NAME_KEYWORD = "name.keyword";
private static final String DISPLAY_NAME = "displayName"; private static final String DISPLAY_NAME = "displayName";
private static final String DISPLAY_NAME_KEYWORD = "displayName.keyword";
private static final String DESCRIPTION = "description"; private static final String DESCRIPTION = "description";
private static final String UNIFIED = "unified"; private static final String UNIFIED = "unified";
@ -570,13 +572,23 @@ public class SearchResource {
private SearchSourceBuilder buildUserSearchBuilder(String query, int from, int size) { private SearchSourceBuilder buildUserSearchBuilder(String query, int from, int size) {
QueryStringQueryBuilder queryBuilder = QueryStringQueryBuilder queryBuilder =
QueryBuilders.queryStringQuery(query).field(DISPLAY_NAME, 5.0f).field(NAME, 3.0f).lenient(true); QueryBuilders.queryStringQuery(query)
.field(DISPLAY_NAME, 5.0f)
.field(DISPLAY_NAME_KEYWORD, 3.0f)
.field(NAME, 2.0f)
.field(NAME_KEYWORD, 3.0f)
.fuzziness(Fuzziness.AUTO);
return searchBuilder(queryBuilder, null, from, size); return searchBuilder(queryBuilder, null, from, size);
} }
private SearchSourceBuilder buildTeamSearchBuilder(String query, int from, int size) { private SearchSourceBuilder buildTeamSearchBuilder(String query, int from, int size) {
QueryStringQueryBuilder queryBuilder = QueryStringQueryBuilder queryBuilder =
QueryBuilders.queryStringQuery(query).field(DISPLAY_NAME, 5.0f).field(NAME, 3.0f).lenient(true); QueryBuilders.queryStringQuery(query)
.field(DISPLAY_NAME, 5.0f)
.field(DISPLAY_NAME_KEYWORD, 3.0f)
.field(NAME, 2.0f)
.field(NAME_KEYWORD, 3.0f)
.fuzziness(Fuzziness.AUTO);
return searchBuilder(queryBuilder, null, from, size); return searchBuilder(queryBuilder, null, from, size);
} }

View File

@ -60,8 +60,8 @@ describe('Alerts page should work properly', () => {
cy.get('[data-testid="matchAnyOwnerName-select"]') cy.get('[data-testid="matchAnyOwnerName-select"]')
.should('be.visible') .should('be.visible')
.click() .click()
.type('Engineering'); .type('Applications');
cy.get('[title="Engineering"]').should('be.visible').click(); cy.get('[title="Applications"]').should('be.visible').click();
cy.get('#description').should('be.visible').click(); cy.get('#description').should('be.visible').click();
// Select include/exclude // Select include/exclude
cy.get('[title="Include"]').should('be.visible').click(); cy.get('[title="Include"]').should('be.visible').click();
@ -141,16 +141,16 @@ describe('Alerts page should work properly', () => {
cy.get('[data-testid="matchAnyOwnerName-select"]') cy.get('[data-testid="matchAnyOwnerName-select"]')
.should('be.visible') .should('be.visible')
.click() .click()
.type('Engineering'); .type('Applications');
cy.get('[title="Engineering"]').should('be.visible').click(); cy.get('[title="Applications"]').should('be.visible').click();
cy.get('#name').should('be.visible').click(); cy.get('#name').should('be.visible').click();
// Select second owner // Select second owner
cy.get('[data-testid="matchAnyOwnerName-select"]') cy.get('[data-testid="matchAnyOwnerName-select"]')
.should('be.visible') .should('be.visible')
.click() .click()
.type('Applications'); .type('Marketplace');
cy.get('[title="Applications"]').should('be.visible').click(); cy.get('[title="Marketplace"]').should('be.visible').click();
cy.get('#name').should('be.visible').click(); cy.get('#name').should('be.visible').click();
// Select include/exclude // Select include/exclude
@ -305,8 +305,8 @@ describe('Alerts page should work properly', () => {
cy.get('[data-testid="matchAnyOwnerName-select"]') cy.get('[data-testid="matchAnyOwnerName-select"]')
.should('be.visible') .should('be.visible')
.click() .click()
.type('Engineering'); .type('Applications');
cy.get('[title="Engineering"]').should('be.visible').click(); cy.get('[title="Applications"]').should('be.visible').click();
cy.get('#description').should('be.visible').click(); cy.get('#description').should('be.visible').click();
// Select include/exclude // Select include/exclude
cy.get('[title="Include"]').should('be.visible').click(); cy.get('[title="Include"]').should('be.visible').click();

View File

@ -135,13 +135,13 @@ describe('MyData page should work', () => {
it('My data and following section, CTA should work properly', () => { it('My data and following section, CTA should work properly', () => {
cy.get('[data-testid="my-data-container"]') cy.get('[data-testid="my-data-container"]')
.find('[data-testid*="My data"]') .find('[data-testid*="My data"]')
.should('have.length', FOLLOWING_MYDATA_COUNT); .should('have.length', FOLLOWING_MYDATA_COUNT + 1);
cy.get('[data-testid="following-data-container"]') cy.get('[data-testid="following-data-container"]')
.find('[data-testid*="Following data"]') .find('[data-testid*="Following data"]')
.should('have.length', FOLLOWING_MYDATA_COUNT); .should('have.length', FOLLOWING_MYDATA_COUNT);
interceptURL( interceptURL(
'GET', 'GET',
'/api/v1/search/query?q=owner.id:*&from=0&size=10&index=*', '/api/v1/search/query?q=*owner.id:*&from=0&size=10&index=*',
'userDetailsmyDataTab' 'userDetailsmyDataTab'
); );
cy.get('[data-testid="my-data-total-count"]').should('be.visible').click(); cy.get('[data-testid="my-data-total-count"]').should('be.visible').click();
@ -150,7 +150,7 @@ describe('MyData page should work', () => {
cy.clickOnLogo(); cy.clickOnLogo();
interceptURL( interceptURL(
'GET', 'GET',
'api/v1/search/query?q=followers:*&from=0&size=10&index=*', 'api/v1/search/query?q=*followers:*&from=0&size=10&index=*',
'userDetailsFollowTab' 'userDetailsFollowTab'
); );
cy.get('[data-testid="following-data-total-count"]') cy.get('[data-testid="following-data-total-count"]')

View File

@ -11,8 +11,8 @@
* limitations under the License. * limitations under the License.
*/ */
import i18next from 'i18next';
import { ServiceTypes } from 'Models'; import { ServiceTypes } from 'Models';
import i18n from 'utils/i18next/LocalUtil';
import addPlaceHolder from '../assets/img/add-placeholder.svg'; import addPlaceHolder from '../assets/img/add-placeholder.svg';
import airbyte from '../assets/img/Airbyte.png'; import airbyte from '../assets/img/Airbyte.png';
import noDataFound from '../assets/img/no-data-placeholder.svg'; import noDataFound from '../assets/img/no-data-placeholder.svg';
@ -200,23 +200,23 @@ export const SERVICE_CATEGORY_TYPE = {
}; };
export const servicesDisplayName: { [key: string]: string } = { export const servicesDisplayName: { [key: string]: string } = {
databaseServices: i18next.t('label.entity-service', { databaseServices: i18n.t('label.entity-service', {
entity: i18next.t('label.database'), entity: i18n.t('label.database'),
}), }),
messagingServices: i18next.t('label.entity-service', { messagingServices: i18n.t('label.entity-service', {
entity: i18next.t('label.messaging'), entity: i18n.t('label.messaging'),
}), }),
dashboardServices: i18next.t('label.entity-service', { dashboardServices: i18n.t('label.entity-service', {
entity: i18next.t('label.dashboard'), entity: i18n.t('label.dashboard'),
}), }),
pipelineServices: i18next.t('label.entity-service', { pipelineServices: i18n.t('label.entity-service', {
entity: i18next.t('label.pipeline'), entity: i18n.t('label.pipeline'),
}), }),
mlmodelServices: i18next.t('label.entity-service', { mlmodelServices: i18n.t('label.entity-service', {
entity: i18next.t('label.ml-model'), entity: i18n.t('label.ml-model'),
}), }),
metadataServices: i18next.t('label.entity-service', { metadataServices: i18n.t('label.entity-service', {
entity: i18next.t('label.metadata'), entity: i18n.t('label.metadata'),
}), }),
}; };

View File

@ -43,7 +43,9 @@ import {
getFilterFunctions, getFilterFunctions,
updateAlert, updateAlert,
} from 'rest/alertsAPI'; } from 'rest/alertsAPI';
import { getSearchedUsersAndTeams, getSuggestions } from 'rest/miscAPI'; import { getSuggestions } from 'rest/miscAPI';
import { getEntityName } from 'utils/CommonUtils';
import { searchFormattedUsersAndTeams } from 'utils/UserDataUtils';
import { import {
GlobalSettingOptions, GlobalSettingOptions,
GlobalSettingsMenuCategory, GlobalSettingsMenuCategory,
@ -279,11 +281,11 @@ const AddAlertPage = () => {
const getUsersAndTeamsOptions = useCallback(async (search: string) => { const getUsersAndTeamsOptions = useCallback(async (search: string) => {
try { try {
const response = await getSearchedUsersAndTeams(search, 1); const { teams, users } = await searchFormattedUsersAndTeams(search, 1);
return response.hits.hits.map((d) => ({ return [...teams, ...users].map((d) => ({
label: d._source.displayName ?? d._source.name, label: getEntityName(d),
value: d._source.fullyQualifiedName, value: d.name,
})); }));
} catch (error) { } catch (error) {
return []; return [];

View File

@ -126,12 +126,12 @@ const UserPage = () => {
setIsUserEntitiesLoading(true); setIsUserEntitiesLoading(true);
try { try {
const response = await searchData( const response = await searchData(
'',
entity.currPage,
PAGE_SIZE,
fetchOwnedEntities fetchOwnedEntities
? `owner.id:${userData.id}` ? `owner.id:${userData.id}`
: `followers:${userData.id}`, : `followers:${userData.id}`,
entity.currPage,
PAGE_SIZE,
``,
'', '',
'', '',
myDataSearchIndex myDataSearchIndex

View File

@ -500,10 +500,10 @@ const TeamsPage = () => {
const fetchAssets = () => { const fetchAssets = () => {
searchData( searchData(
`owner.id:${selectedTeam.id}`, ``,
assets.currPage, assets.currPage,
LIST_SIZE, LIST_SIZE,
``, `owner.id:${selectedTeam.id}`,
'', '',
'', '',
myDataSearchIndex myDataSearchIndex

View File

@ -202,9 +202,18 @@ export const getSearchedUsers = (
export const getSearchedTeams = ( export const getSearchedTeams = (
queryString: string, queryString: string,
from: number, from: number,
filter?: string,
size = 10 size = 10
) => { ) => {
return searchData(queryString, from, size, '', '', '', SearchIndex.TEAM); return searchData(
queryString,
from,
size,
filter ?? '',
'',
'',
SearchIndex.TEAM
);
}; };
export const getSearchedUsersAndTeams = async ( export const getSearchedUsersAndTeams = async (

View File

@ -27,7 +27,10 @@ export const getSearchAPIQueryParams = (
trackTotalHits = false trackTotalHits = false
): Record<string, string | boolean | number | string[]> => { ): Record<string, string | boolean | number | string[]> => {
const start = (from - 1) * size; const start = (from - 1) * size;
const query = queryString ? queryString : WILD_CARD_CHAR; const query =
queryString && queryString === WILD_CARD_CHAR
? queryString
: `*${queryString}*`;
const params: Record<string, string | boolean | number | string[]> = { const params: Record<string, string | boolean | number | string[]> = {
q: query + (filters ? ` AND ${filters}` : ''), q: query + (filters ? ` AND ${filters}` : ''),

View File

@ -146,46 +146,43 @@ export const getUserProfilePic = (
return profile; return profile;
}; };
export const searchFormattedUsersAndTeams = ( export const searchFormattedUsersAndTeams = async (
searchQuery = WILD_CARD_CHAR, searchQuery = WILD_CARD_CHAR,
from = 1 from = 1
): Promise<SearchedUsersAndTeams> => { ) => {
return new Promise<SearchedUsersAndTeams>((resolve, reject) => { try {
const teamQuery = `${searchQuery} AND teamType:Group`;
const promises = [ const promises = [
getSearchedUsers(searchQuery, from), getSearchedUsers(searchQuery, from),
getSearchedTeams(teamQuery, from), getSearchedTeams(searchQuery, from, 'teamType:Group'),
]; ];
Promise.allSettled(promises)
.then(([resUsers, resTeams]) => { const [resUsers, resTeams] = await Promise.allSettled(promises);
const users =
resUsers.status === SettledStatus.FULFILLED const users =
? formatUsersResponse( resUsers.status === SettledStatus.FULFILLED
(resUsers.value.data as SearchResponse<SearchIndex.USER>).hits ? formatUsersResponse(
.hits (resUsers.value.data as SearchResponse<SearchIndex.USER>).hits.hits
) )
: []; : [];
const teams = const teams =
resTeams.status === SettledStatus.FULFILLED resTeams.status === SettledStatus.FULFILLED
? formatTeamsResponse( ? formatTeamsResponse(
(resTeams.value.data as SearchResponse<SearchIndex.TEAM>).hits (resTeams.value.data as SearchResponse<SearchIndex.TEAM>).hits.hits
.hits )
) : [];
: []; const usersTotal =
const usersTotal = resUsers.status === SettledStatus.FULFILLED
resUsers.status === SettledStatus.FULFILLED ? resUsers.value.data.hits.total.value
? resUsers.value.data.hits.total.value : 0;
: 0; const teamsTotal =
const teamsTotal = resTeams.status === SettledStatus.FULFILLED
resTeams.status === SettledStatus.FULFILLED ? resTeams.value.data.hits.total.value
? resTeams.value.data.hits.total.value : 0;
: 0;
resolve({ users, teams, usersTotal, teamsTotal }); return { users, teams, usersTotal, teamsTotal };
}) } catch (error) {
.catch((err: AxiosError) => { return { users: [], teams: [], usersTotal: 0, teamsTotal: 0 };
reject(err); }
});
});
}; };
export const suggestFormattedUsersAndTeams = ( export const suggestFormattedUsersAndTeams = (