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_RESULT_HITS = 10000;
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_KEYWORD = "displayName.keyword";
private static final String DESCRIPTION = "description";
private static final String UNIFIED = "unified";
@ -570,13 +572,23 @@ public class SearchResource {
private SearchSourceBuilder buildUserSearchBuilder(String query, int from, int size) {
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);
}
private SearchSourceBuilder buildTeamSearchBuilder(String query, int from, int size) {
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);
}

View File

@ -60,8 +60,8 @@ describe('Alerts page should work properly', () => {
cy.get('[data-testid="matchAnyOwnerName-select"]')
.should('be.visible')
.click()
.type('Engineering');
cy.get('[title="Engineering"]').should('be.visible').click();
.type('Applications');
cy.get('[title="Applications"]').should('be.visible').click();
cy.get('#description').should('be.visible').click();
// Select include/exclude
cy.get('[title="Include"]').should('be.visible').click();
@ -141,16 +141,16 @@ describe('Alerts page should work properly', () => {
cy.get('[data-testid="matchAnyOwnerName-select"]')
.should('be.visible')
.click()
.type('Engineering');
cy.get('[title="Engineering"]').should('be.visible').click();
.type('Applications');
cy.get('[title="Applications"]').should('be.visible').click();
cy.get('#name').should('be.visible').click();
// Select second owner
cy.get('[data-testid="matchAnyOwnerName-select"]')
.should('be.visible')
.click()
.type('Applications');
cy.get('[title="Applications"]').should('be.visible').click();
.type('Marketplace');
cy.get('[title="Marketplace"]').should('be.visible').click();
cy.get('#name').should('be.visible').click();
// Select include/exclude
@ -305,8 +305,8 @@ describe('Alerts page should work properly', () => {
cy.get('[data-testid="matchAnyOwnerName-select"]')
.should('be.visible')
.click()
.type('Engineering');
cy.get('[title="Engineering"]').should('be.visible').click();
.type('Applications');
cy.get('[title="Applications"]').should('be.visible').click();
cy.get('#description').should('be.visible').click();
// Select include/exclude
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', () => {
cy.get('[data-testid="my-data-container"]')
.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"]')
.find('[data-testid*="Following data"]')
.should('have.length', FOLLOWING_MYDATA_COUNT);
interceptURL(
'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'
);
cy.get('[data-testid="my-data-total-count"]').should('be.visible').click();
@ -150,7 +150,7 @@ describe('MyData page should work', () => {
cy.clickOnLogo();
interceptURL(
'GET',
'api/v1/search/query?q=followers:*&from=0&size=10&index=*',
'api/v1/search/query?q=*followers:*&from=0&size=10&index=*',
'userDetailsFollowTab'
);
cy.get('[data-testid="following-data-total-count"]')

View File

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

View File

@ -43,7 +43,9 @@ import {
getFilterFunctions,
updateAlert,
} 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 {
GlobalSettingOptions,
GlobalSettingsMenuCategory,
@ -279,11 +281,11 @@ const AddAlertPage = () => {
const getUsersAndTeamsOptions = useCallback(async (search: string) => {
try {
const response = await getSearchedUsersAndTeams(search, 1);
const { teams, users } = await searchFormattedUsersAndTeams(search, 1);
return response.hits.hits.map((d) => ({
label: d._source.displayName ?? d._source.name,
value: d._source.fullyQualifiedName,
return [...teams, ...users].map((d) => ({
label: getEntityName(d),
value: d.name,
}));
} catch (error) {
return [];

View File

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

View File

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

View File

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

View File

@ -27,7 +27,10 @@ export const getSearchAPIQueryParams = (
trackTotalHits = false
): Record<string, string | boolean | number | string[]> => {
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[]> = {
q: query + (filters ? ` AND ${filters}` : ''),

View File

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