Misc. bug fixes related to search and person entity display attributes, and lost picture url for person entity

This commit is contained in:
Seyi Adebajo 2020-02-10 18:51:15 -08:00 committed by Seyi Adebajo
parent d8c594aeb9
commit 06d19d2958
19 changed files with 128 additions and 476 deletions

View File

@ -11,7 +11,7 @@ import { BaseEntity, statics, IBaseEntityStatics } from '@datahub/data-models/en
import { IEntityRenderProps } from '@datahub/data-models/types/entity/rendering/entity-render-props';
import { DataModelEntity } from '@datahub/data-models/constants/entity';
import { IPersonEntityEditableProperties } from '@datahub/data-models/types/entity/person/props';
import { ICorpUserInfo } from '@datahub/metadata-types/types/entity/person/person-entity';
import { ICorpUserEditableInfo, ICorpUserInfo } from '@datahub/metadata-types/types/entity/person/person-entity';
import { readPerson, saveEditablePersonalInfo } from '@datahub/data-models/api/person/entity';
import { alias, not } from '@ember/object/computed';
@ -164,6 +164,11 @@ export class PersonEntity extends BaseEntity<ICorpUserInfo> {
@alias('entity.info.email')
email!: string;
/**
* References the pictureLink on the editableInfo for the Person Entity
*/
@alias('entity.editableInfo.pictureLink')
pictureLink!: ICorpUserEditableInfo['pictureLink'];
/**
* A list of skills that this particular person entity has declared to own.
*/
@ -287,7 +292,8 @@ export class PersonEntity extends BaseEntity<ICorpUserInfo> {
return saveEditablePersonalInfo(this.urn, {
teams: props.teamTags,
aboutMe: props.focusArea,
skills: props.skills
skills: props.skills,
pictureLink: this.pictureLink
});
}
}

View File

@ -58,7 +58,7 @@ export const getRenderProps = (): IEntityRenderProps => {
searchResultEntityFields: {
description: 'title',
pictureUrl: 'editableInfo.pictureLink',
name: 'username'
name: 'info.fullName'
},
showFacets: false,
placeholder: 'Search for People...',

View File

@ -70,13 +70,6 @@ export default class EntityDeprecation extends Component {
*/
centeredDate: Date = this.selectedDate;
/**
* Before a user can update the deprecation status to deprecated, they must acknowledge that even if the
* entity is deprecated they must still keep it compliant.
* @type {boolean}
*/
isDeprecationAcknowledged: boolean = false;
/**
* Expected to be passed in if we plan on using the default entity deprecation acknowledgement template,
* leads to a more info link for the user about deprecation of such entity
@ -84,14 +77,6 @@ export default class EntityDeprecation extends Component {
*/
entityDecommissionWikiLink?: string;
/**
* Optionally passed in if the entity should have an acknowledgement message/structure that differs from
* our default provided partial. If not passed in, constructor will automatically populate this with the
* default acknowledgement
* @type {string}
*/
deprecationAcknowledgementTemplate!: string;
/**
* The earliest date a user can select as a decommission date
* @type {Date}
@ -116,13 +101,6 @@ export default class EntityDeprecation extends Component {
@reads('deprecationNote')
deprecationNoteAlias!: EntityDeprecation['deprecationNote'];
didInsertElement(): void {
super.didInsertElement();
typeof this.deprecationAcknowledgementTemplate === 'string' ||
set(this, 'deprecationAcknowledgementTemplate', 'partials/entity-deprecation/default-acknowledgement');
}
/**
* Invokes the save action with the updated values for deprecated status, decommission time, and
* deprecation note. The actual save functionality should be handled by
@ -155,13 +133,4 @@ export default class EntityDeprecation extends Component {
onDecommissionDateChange(decommissionTime: Date): void {
set(this, 'decommissionTime', new Date(decommissionTime).getTime());
}
/**
* When a user clicks the checkbox to acknolwedge or cancel the acknolwedgement of the notice for
* deprecating an entity
*/
@action
onAcknowledgeDeprecationNotice(): void {
this.toggleProperty('isDeprecationAcknowledged');
}
}

View File

@ -80,27 +80,13 @@
{{if decommissionTime (concat 'Will be decommissioned on ' (moment-format decommissionTime 'MMMM DD YYYY')) ''}}
</strong>
</p>
<span>
{{input
type="checkbox"
name="deprecated.acknowledge"
id="acknowledge-deprecation"
checked=(readonly isDeprecationAcknowledged)
change=(action "onAcknowledgeDeprecationNotice")}}
<label for="acknowledge-deprecation">
{{partial deprecationAcknowledgementTemplate}}
</label>
</span>
{{/if}}
<div class="entity-deprecation__actions">
<button
type="submit"
class="nacho-button--large nacho-button--secondary"
disabled={{and isDeprecatedAlias (or (not decommissionTime) (not isDeprecationAcknowledged))}}>
disabled={{and isDeprecatedAlias (not decommissionTime)}}>
Update Deprecation Status
</button>
</div>

View File

@ -1,6 +1,6 @@
import { module, test } from 'qunit';
import { setupRenderingTest } from 'ember-qunit';
import { render, find, findAll, click, fillIn } from '@ember/test-helpers';
import { render, find, findAll } from '@ember/test-helpers';
import hbs from 'htmlbars-inline-precompile';
const findInput = (selector: string): HTMLInputElement => {
@ -67,7 +67,6 @@ module('Integration | Component | entity-deprecation', function(hooks): void {
test('decommissionTime', async function(assert): Promise<void> {
let isDisabled;
assert.expect(3);
this.setProperties({
...defaultProperties,
@ -83,58 +82,5 @@ module('Integration | Component | entity-deprecation', function(hooks): void {
isDisabled = findInput('.entity-deprecation__actions [type=submit]').disabled;
assert.ok(isDisabled, 'submit button is disabled');
this.setProperties({ decommissionTime: new Date(), isDirty: true });
await render(hbs`{{entity-deprecation
entityName=entityName
isDeprecated=deprecated
decommissionTime=decommissionTime
updateDeprecation=(action updateDeprecation)}}`);
await fillIn('.entity-deprecation__note-editor .medium-editor-element', 'text');
isDisabled = findInput('.entity-deprecation__actions [type=submit]').disabled;
assert.ok(isDisabled, 'submit button is disabled if we only fill in decomissionTime');
await click('#acknowledge-deprecation');
isDisabled = findInput('.entity-deprecation__actions [type=submit]').disabled;
assert.notOk(isDisabled, 'submit button is disabled if we only fill in decomissionTime');
});
test('triggers the onUpdateDeprecation action when submitted', async function(assert): Promise<void> {
let submitActionCallCount = 0;
this.setProperties({
...defaultProperties,
submit(deprecated: boolean, note: string): void {
submitActionCallCount++;
assert.equal(deprecated, true, 'action is called with deprecation value of true');
assert.equal(note, '', 'action is called with an empty deprecation note');
},
decommissionTime: new Date()
});
await render(hbs`{{entity-deprecation
entityName=entityName
isDeprecated=deprecated
decommissionTime=decommissionTime
updateDeprecation=(action submit)}}`);
assert.equal(submitActionCallCount, 0, 'action is not called on render');
assert.equal(
(find('#dataset-is-deprecated') as HTMLInputElement).checked,
false,
'deprecation checkbox is unchecked'
);
await click('#dataset-is-deprecated');
assert.equal((find('#dataset-is-deprecated') as HTMLInputElement).checked, true, 'deprecation checkbox is checked');
await click('#acknowledge-deprecation');
await click('.entity-deprecation__actions [type=submit]');
assert.equal(submitActionCallCount, 1, 'action is called once');
});
});

View File

@ -8,6 +8,8 @@ export interface ICorpUserEditableInfo {
teams: Array<string>;
// A self-assigned list of skills that the person claims to own
skills: Array<string>;
// Reference to the picture URL for the person
pictureLink: string;
}
/**

View File

@ -26,6 +26,7 @@ import { NotificationEvent } from '@datahub/utils/constants/notifications';
import { PersonEntity } from '@datahub/data-models/entity/person/person-entity';
import { task } from 'ember-concurrency';
import { ETaskPromise } from '@datahub/utils/types/concurrency';
import DataModelsService from '@datahub/data-models/services/data-models';
type Comparator = -1 | 0 | 1;
@ -89,6 +90,12 @@ export default class DatasetAuthors extends Component {
@service('user-lookup')
userLookup: UserLookup;
/**
* Injected service for our data models getter to access the PersonEntity class
*/
@service('data-models')
dataModels!: DataModelsService;
/**
* If there are no changes to the ownership tab, we want to keep the save button disabled. Rather than
* try to compare two sets of prev vs new data, we just have a flag here that short stops the validation
@ -187,14 +194,15 @@ export default class DatasetAuthors extends Component {
* @returns {OwnerWithAvatarRecord}
*/
datasetAuthorsOwnersAugmentedWithAvatars = (owner: IOwner): OwnerWithAvatarRecord => {
const { avatarProperties } = this;
const { avatarProperties, dataModels } = this;
const PersonEntityClass = dataModels.getModel('people') as typeof PersonEntity;
return {
owner,
avatar: avatarProperties
? makeAvatar(avatarProperties)(owner)
: { imageUrl: '', imageUrlFallback: '/assets/images/default_avatar.png' },
profile: PersonEntity.profileLinkFromUsername(owner.userName)
profile: PersonEntityClass.urnFromUsername(owner.userName)
};
};

View File

@ -16,6 +16,7 @@ import { facetToParamUrl } from 'wherehows-web/utils/api/search/search';
import RouterService from '@ember/routing/router-service';
import { task } from 'ember-concurrency';
import { ETaskPromise } from '@datahub/utils/types/concurrency';
import DataModelsService from '@datahub/data-models/services/data-models';
/**
* Search box container that handle all the data part for
@ -29,6 +30,9 @@ export default class SearchBoxContainer extends Component {
@service
search: SearchService;
@service('data-models')
dataModels!: DataModelsService;
@alias('search.entity')
entity?: DataModelName;
@ -44,9 +48,9 @@ export default class SearchBoxContainer extends Component {
*/
@computed('entity')
get dataModelEntity(): DataModelEntity | undefined {
const { entity } = this;
if (entity) {
return DataModelEntity[entity];
const { entity, dataModels } = this;
if (entity && dataModels) {
return dataModels.getModel(entity);
}
return;
}
@ -58,8 +62,15 @@ export default class SearchBoxContainer extends Component {
* @returns {(IterableIterator<Promise<Array<ISuggestionGroup>>>)}
* @memberof SearchBoxContainer
*/
@task(function*(query: string = '', entity?: DataModelName): IterableIterator<Promise<Array<ISuggestionGroup>>> {
return yield typeaheadQueryProcessor(query, entity, grammarProcessingSteps);
@task(function*(
this: SearchBoxContainer,
query: string = '',
entity?: DataModelName
): IterableIterator<Promise<Array<ISuggestionGroup>>> {
const { dataModels } = this;
if (entity) {
return yield typeaheadQueryProcessor(query, dataModels.getModel(entity), grammarProcessingSteps);
}
})
onSearchInputTask: ETaskPromise<Array<ISuggestionGroup>>;
@ -71,17 +82,20 @@ export default class SearchBoxContainer extends Component {
*/
onSearch(text: string = '', entity: DataModelName = DatasetEntity.displayName): void {
// entity (dropdown value) might be different than this.entity (Page that you are in)
const dataModelEntity = DataModelEntity[entity];
const { attributes } = dataModelEntity.renderProps.search;
const defaultFacets = facetToParamUrl(transformDefaultsIntoSelections(getFacetDefaultValueForEntity(attributes)));
const { dataModels } = this;
if (entity) {
const dataModelEntity = dataModels.getModel(entity);
const { attributes } = dataModelEntity.renderProps.search;
const defaultFacets = facetToParamUrl(transformDefaultsIntoSelections(getFacetDefaultValueForEntity(attributes)));
this.router.transitionTo('search', {
queryParams: {
entity,
keyword: text,
page: 1,
facets: defaultFacets
}
});
this.router.transitionTo('search', {
queryParams: {
entity,
keyword: text,
page: 1,
facets: defaultFacets
}
});
}
}
}

View File

@ -36,26 +36,38 @@ export default class SearchResult extends Component {
/**
* Result used in template
*/
result?: DataModelEntityInstance;
result!: DataModelEntityInstance;
/**
* Config for search for this entity
*/
searchConfig?: IEntityRenderCommonPropsSearch;
searchConfig!: IEntityRenderCommonPropsSearch;
/**
* Will return the name of the entity. By default it will use
* 'name' as field to fetch the name, otherwise it should be
* specified in 'entityNameField'
*/
@computed('searchConfig.entityNameField', 'entity')
get name(): string | void {
const { result, searchConfig = { searchResultEntityFields: { name: 'name' } } } = this;
if (result) {
const { searchResultEntityFields = { name: 'name' } } = searchConfig;
const { name = 'name' } = searchResultEntityFields;
get name(): string | undefined {
const { result, searchConfig } = this;
const { searchResultEntityFields = {} } = searchConfig;
const { name = 'name' } = searchResultEntityFields || {};
return result[name as CompatibleKeysThatReturnString];
}
return get(result, name as CompatibleKeysThatReturnString);
}
/**
* Will return the description of the entity. By default it will use
* 'description' as field to fetch the description, otherwise it should be
* specified in 'entityDescriptionField'
*/
@computed('searchConfig.descriptionField', 'entity')
get description(): string | undefined {
const { result, searchConfig } = this;
const { searchResultEntityFields = {} } = searchConfig;
const { description = 'description' } = searchResultEntityFields || {};
return result[description as CompatibleKeysThatReturnString];
}
/**

View File

@ -4,9 +4,9 @@
{{avatars/avatar-image avatar=@owner.avatar}}
{{/unless}}
<a href={{@owner.profile}} rel="noopener" target="blank">
<LinkTo @route="user.profile" @model={{@owner.profile}}>
{{ownerRecord.userName}}
</a>
</LinkTo>
{{#if isOwnerInActive}}

View File

@ -0,0 +1,15 @@
/**
* Api expected request params for suggestion values autocomplete
*/
export interface IFieldValuesRequest {
input: string;
facet?: string;
}
/**
* Api expected response for suggestion values autocomplete
*/
export interface IFieldValuesResponse {
input: string;
source: Array<string>;
}

View File

@ -13,7 +13,7 @@ import { generateGroups } from 'wherehows-web/utils/parsers/autocomplete/steps/g
import { arrayReduce } from 'wherehows-web/utils/array';
import { createSuggestionsFromError } from 'wherehows-web/utils/parsers/helpers';
import { DatasetEntity } from '@datahub/data-models/entity/dataset/dataset-entity';
import { DataModelName } from '@datahub/data-models/constants/entity';
import { DataModelEntity } from '@datahub/data-models/constants/entity';
/**
* Steps of the grammar process
@ -40,7 +40,7 @@ export const grammarProcessingSteps: Array<IGrammarProcessFn> = [
*/
export const typeaheadQueryProcessor = async (
query: string,
entity: DataModelName = DatasetEntity.displayName,
entity: DataModelEntity = DatasetEntity,
steps: Array<IGrammarProcessFn>
): Promise<Array<ISuggestionGroup>> => {
const initArgs: Pick<ISuggestionBuilder, 'text' | 'entity'> = { text: query, entity };

View File

@ -1,7 +1,8 @@
import {
INodeProcessor,
AutocompleteRuleNames,
ISuggestionBuilder
ISuggestionBuilder,
ISuggestion
} from 'wherehows-web/utils/parsers/autocomplete/types';
import { fetchFacetValue } from 'wherehows-web/utils/parsers/helpers';
@ -12,17 +13,20 @@ import { fetchFacetValue } from 'wherehows-web/utils/parsers/helpers';
export const entityProcessor: INodeProcessor = {
[AutocompleteRuleNames.EntityName]: async (builder: ISuggestionBuilder): Promise<ISuggestionBuilder> => {
const input = builder.textLastWord || '';
const suggestions = await fetchFacetValue('name', input, builder.entity);
const nameField = builder.entity.renderProps.search.autocompleteNameField || 'name';
const suggestions = await fetchFacetValue(nameField, input, builder.entity);
return {
...builder,
datasets: [
...builder.datasets,
...(suggestions || []).map(entityName => ({
title: entityName,
text: `${builder.textPrevious}${entityName} `,
description: ''
}))
...(suggestions || []).map(
(entityName): ISuggestion => ({
title: entityName,
text: `${builder.textPrevious}${entityName} `,
description: ''
})
)
]
};
}

View File

@ -7,7 +7,6 @@ import {
} from 'wherehows-web/utils/parsers/autocomplete/types';
import { dataToString } from 'wherehows-web/utils/parsers/autocomplete/utils';
import { ISearchEntityRenderProps } from '@datahub/data-models/types/entity/rendering/search-entity-render-prop';
import { DataModelEntity } from '@datahub/data-models/constants/entity';
import { fetchFacetValue } from 'wherehows-web/utils/parsers/helpers';
/**
@ -52,7 +51,7 @@ export const facetsProcessor: INodeProcessor = {
* When 'name' is expected we just return 'name:' as suggestion
*/
[AutocompleteRuleNames.FacetName]: (builder: ISuggestionBuilder, ruleState: IState): Promise<ISuggestionBuilder> => {
const allFields: Array<ISearchEntityRenderProps> = DataModelEntity[builder.entity].renderProps.search.attributes;
const allFields: Array<ISearchEntityRenderProps> = builder.entity.renderProps.search.attributes;
const facetName = getFacetNameFromStateRule(ruleState);
const fields = allFields.filter(
(field): boolean => field.fieldName.indexOf(facetName) >= 0 && field.showInAutoCompletion

View File

@ -14,7 +14,8 @@ export const generateGroups = (builder: ISuggestionBuilder): ISuggestionBuilder
const isEntityNamesEmpty = builder.datasets.length === 0;
const expectedEntityName = !!builder.wantedRulesMap[AutocompleteRuleNames.EntityName];
const lastWordLength = typeof builder.textLastWord === 'string' ? builder.textLastWord.trim().length : -1;
const entityDisplayName = capitalize(builder.entity);
const entityModel = builder.entity;
const entityDisplayName = capitalize(entityModel.displayName);
if (isEntityNamesEmpty && expectedEntityName && lastWordLength < 3) {
groups.push({

View File

@ -43,7 +43,7 @@ export type INodeFacetProcessor = Record<
* The structure is not intented to be mutated, redux like approach
*/
export interface ISuggestionBuilder {
entity: DataModelEntity['displayName'];
entity: DataModelEntity;
logicalOperators: Array<ISuggestion>;
facetNames: Array<ISuggestion>;
datasets: Array<ISuggestion>;

View File

@ -1,5 +1,5 @@
import { ISuggestionGroup } from 'wherehows-web/utils/parsers/autocomplete/types';
import { DataModelEntity, DataModelName } from '@datahub/data-models/constants/entity';
import { DataModelEntity } from '@datahub/data-models/constants/entity';
import { IFieldValuesResponseV2, FieldValuesRequestV2 } from 'wherehows-web/typings/app/search/fields-v2';
import { facetValuesApiEntities } from 'wherehows-web/utils/parsers/autocomplete/utils';
@ -24,12 +24,13 @@ export const createSuggestionsFromError = (error: string): Array<ISuggestionGrou
export const fetchFacetValue = async (
facetName: string,
facetValue: string,
entity: DataModelName
entity: DataModelEntity
): Promise<Array<string>> => {
// otherwise lets invoke api to fetch values
let suggestions: Array<string> = [];
const { apiName, attributes } = DataModelEntity[entity].renderProps.search;
const fieldMeta = attributes.find((attr): boolean => attr.fieldName === facetName);
const searchRenderProps = entity.renderProps.search;
const searchAttributes = searchRenderProps.attributes;
const fieldMeta = searchAttributes.find((attr): boolean => attr.fieldName === facetName);
const { minAutocompleteFetchLength } = fieldMeta || { minAutocompleteFetchLength: undefined };
const cacheKey = `${facetName}:${facetValue}`;
@ -38,7 +39,7 @@ export const fetchFacetValue = async (
const request: FieldValuesRequestV2<Record<string, string>> = {
field: facetName,
input: facetValue,
type: apiName
type: searchRenderProps.apiName
};
const facetValueReturn: IFieldValuesResponseV2 | undefined = await facetValuesApiEntities({
query: facetValue,

View File

@ -34,32 +34,32 @@ module('Integration | Component | search/search-result', function(hooks) {
}
});
test('it renders', async function(assert) {
test('it renders', async function(assert): Promise<void> {
assert.expect(1);
const result = createEntity();
this.setProperties({ fields: [], result });
await render(hbs`{{search/search-result
result=result.data
meta=result.meta
resultFields=fields
}}`);
this.setProperties({ searchConfig: { attributes: [] }, result });
await render(hbs`<Search::SearchResult
@result={{this.result.data}}
@meta={{this.result.meta}}
@searchConfig={{this.searchConfig}}
/>`);
assert.ok(find('.search-result'), 'expected component to have a class `search-result`');
});
test('search-result properties', async function(assert) {
test('search-result properties', async function(assert): Promise<void> {
assert.expect(1);
const result = createEntity();
this.setProperties({ fields: [], result });
await render(hbs`{{search/search-result
result=result.data
meta=result.meta
resultFields=fields
}}`);
this.setProperties({ searchConfig: { attributes: [] }, result });
await render(hbs`<Search::SearchResult
@result={{this.result.data}}
@meta={{this.result.meta}}
@searchConfig={{this.searchConfig}}
/>`);
const searchResultElement: Element | null = find('.search-result');
const title = searchResultElement && searchResultElement.querySelector('.search-result__title');

View File

@ -1,311 +0,0 @@
import { module, test } from 'qunit';
import { grammarProcessingSteps, typeaheadQueryProcessor } from 'wherehows-web/utils/parsers/autocomplete';
import { startMirage } from 'wherehows-web/initializers/ember-cli-mirage';
import { IMirageServer } from '@datahub/utils/types/vendor/ember-cli-mirage-deprecated';
import { IMirageWherehows } from 'wherehows-web/typings/ember-cli-mirage';
import { ISuggestionGroup } from 'wherehows-web/utils/parsers/autocomplete/types';
import { DatasetEntity } from '@datahub/data-models/entity/dataset/dataset-entity';
import { DataModelName } from '@datahub/data-models/constants/entity';
interface ITestSet {
entity: DataModelName;
description: string;
text: string;
results: Array<ISuggestionGroup>;
}
const createTests = (server: IMirageWherehows): Array<ITestSet> => {
server.create('datasetView', { name: 'platform' });
server.create('datasetView', { name: 'pageviewevent' });
server.create('platform', { name: 'hive' });
server.create('platform', { name: 'mysql' });
return [
{
entity: DatasetEntity.displayName,
description: 'Initial suggestions',
text: '',
results: [
{
groupName: 'Datasets',
options: [
{
disabled: true,
text: '',
title: 'type at least 3 more characters to see Datasets names'
}
]
},
{
groupName: 'Filter By',
options: [
{
description: 'The origin of the dataset, e.g.: origin:PROD',
text: 'origin:',
title: 'origin:'
},
{
description: 'The name of the dataset, e.g.: name:TRACKING.PageViewEvent',
text: 'name:',
title: 'name:'
},
{
description: 'The confirmed owners for the dataset, e.g.: owners:sweaver',
text: 'owners:',
title: 'owners:'
},
{
description: 'The platform of the dataset, e.g.: platform:kafka',
text: 'platform:',
title: 'platform:'
}
]
}
]
},
{
entity: DatasetEntity.displayName,
description: '1 Dataset',
text: 'pageview',
results: [
{
groupName: 'Datasets',
options: [
{
description: '',
text: 'pageviewevent ',
title: 'pageviewevent'
}
]
}
]
},
{
entity: DatasetEntity.displayName,
description: 'Dataset with filter 1',
text: 'pageview AND platfo',
results: [
{
groupName: 'Filter By',
options: [
{
description: 'The platform of the dataset, e.g.: platform:kafka',
text: 'pageview AND platform:',
title: 'platform:'
}
]
},
{
groupName: 'Datasets',
options: [
{
description: '',
text: 'pageview AND platform ',
title: 'platform'
}
]
}
]
},
{
entity: DatasetEntity.displayName,
description: 'Dataset with filter 2',
text: 'pageview AND platform',
results: [
{
groupName: 'Filter By',
options: [
{
description: 'The platform of the dataset, e.g.: platform:kafka',
text: 'pageview AND platform:',
title: 'platform:'
}
]
},
{
groupName: 'Datasets',
options: [
{
description: '',
text: 'pageview AND platform ',
title: 'platform'
}
]
}
]
},
{
entity: DatasetEntity.displayName,
description: 'Dataset with filter 3',
text: 'pageview AND name:pageview',
results: [
{
groupName: 'Filter By',
options: [
{
text: 'pageview AND name:pageviewevent ',
title: 'name:pageviewevent'
}
]
}
]
},
// TODO: update tests with sample api response data for "text: 'platform:'", "text: 'platform:my'", and "text: 'origin:co'"
{
entity: DatasetEntity.displayName,
description: 'Dataset with filter platform',
text: 'platform:',
results: []
},
{
entity: DatasetEntity.displayName,
description: 'Dataset with filter platform my',
text: 'platform:my',
results: []
},
{
entity: DatasetEntity.displayName,
description: 'Dataset with filter fabric',
text: 'origin:co',
results: []
},
{
entity: DatasetEntity.displayName,
description: 'Logical Operators',
text: 'something AN',
results: [
{
groupName: 'Datasets',
options: [
{
disabled: true,
text: '',
title: 'type at least 1 more characters to see Datasets names'
}
]
},
{
groupName: 'Operators',
options: [
{
text: 'something AND ',
title: 'AND'
}
]
}
]
},
{
entity: DatasetEntity.displayName,
description: 'Logical Operators',
text: 'something O',
results: [
{
groupName: 'Datasets',
options: [
{
disabled: true,
text: '',
title: 'type at least 2 more characters to see Datasets names'
}
]
},
{
groupName: 'Operators',
options: [
{
text: 'something OR ',
title: 'OR'
}
]
}
]
},
{
entity: DatasetEntity.displayName,
description: 'Invalid Syntax',
text: 'notreallyafacet:',
results: []
},
{
entity: DatasetEntity.displayName,
description: 'Next things',
text: 'something ',
results: [
{
groupName: 'Datasets',
options: [
{
disabled: true,
text: '',
title: 'type at least 3 more characters to see Datasets names'
}
]
},
{
groupName: 'Operators',
options: [
{
text: 'something AND ',
title: 'AND'
},
{
text: 'something OR ',
title: 'OR'
}
]
},
{
groupName: 'Filter By',
options: [
{
description: 'The origin of the dataset, e.g.: origin:PROD',
text: 'something origin:',
title: 'origin:'
},
{
description: 'The name of the dataset, e.g.: name:TRACKING.PageViewEvent',
text: 'something name:',
title: 'name:'
},
{
description: 'The confirmed owners for the dataset, e.g.: owners:sweaver',
text: 'something owners:',
title: 'owners:'
},
{
description: 'The platform of the dataset, e.g.: platform:kafka',
text: 'something platform:',
title: 'platform:'
}
]
}
]
}
];
};
module('Unit | Utility | Autocomplete Suggestions', function(hooks) {
let server: IMirageServer;
hooks.beforeEach(function() {
server = startMirage();
});
hooks.afterEach(function() {
server.shutdown();
});
test('Suggestions returns as expected', async function(assert) {
const tests = createTests(server);
assert.expect(tests.length);
// tests must be resolved in sequence since processing includes some debouncing
await tests.reduce(async (previousResolution: Promise<void>, myTest: ITestSet): Promise<void> => {
await previousResolution;
const result = await typeaheadQueryProcessor(myTest.text, myTest.entity, grammarProcessingSteps);
assert.deepEqual(result, myTest.results, myTest.description);
}, Promise.resolve());
});
});