mirror of
https://github.com/datahub-project/datahub.git
synced 2025-11-13 17:59:48 +00:00
Misc. bug fixes related to search and person entity display attributes, and lost picture url for person entity
This commit is contained in:
parent
d8c594aeb9
commit
06d19d2958
@ -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 { IEntityRenderProps } from '@datahub/data-models/types/entity/rendering/entity-render-props';
|
||||||
import { DataModelEntity } from '@datahub/data-models/constants/entity';
|
import { DataModelEntity } from '@datahub/data-models/constants/entity';
|
||||||
import { IPersonEntityEditableProperties } from '@datahub/data-models/types/entity/person/props';
|
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 { readPerson, saveEditablePersonalInfo } from '@datahub/data-models/api/person/entity';
|
||||||
import { alias, not } from '@ember/object/computed';
|
import { alias, not } from '@ember/object/computed';
|
||||||
|
|
||||||
@ -164,6 +164,11 @@ export class PersonEntity extends BaseEntity<ICorpUserInfo> {
|
|||||||
@alias('entity.info.email')
|
@alias('entity.info.email')
|
||||||
email!: string;
|
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.
|
* 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, {
|
return saveEditablePersonalInfo(this.urn, {
|
||||||
teams: props.teamTags,
|
teams: props.teamTags,
|
||||||
aboutMe: props.focusArea,
|
aboutMe: props.focusArea,
|
||||||
skills: props.skills
|
skills: props.skills,
|
||||||
|
pictureLink: this.pictureLink
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,7 +58,7 @@ export const getRenderProps = (): IEntityRenderProps => {
|
|||||||
searchResultEntityFields: {
|
searchResultEntityFields: {
|
||||||
description: 'title',
|
description: 'title',
|
||||||
pictureUrl: 'editableInfo.pictureLink',
|
pictureUrl: 'editableInfo.pictureLink',
|
||||||
name: 'username'
|
name: 'info.fullName'
|
||||||
},
|
},
|
||||||
showFacets: false,
|
showFacets: false,
|
||||||
placeholder: 'Search for People...',
|
placeholder: 'Search for People...',
|
||||||
|
|||||||
@ -70,13 +70,6 @@ export default class EntityDeprecation extends Component {
|
|||||||
*/
|
*/
|
||||||
centeredDate: Date = this.selectedDate;
|
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,
|
* 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
|
* 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;
|
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
|
* The earliest date a user can select as a decommission date
|
||||||
* @type {Date}
|
* @type {Date}
|
||||||
@ -116,13 +101,6 @@ export default class EntityDeprecation extends Component {
|
|||||||
@reads('deprecationNote')
|
@reads('deprecationNote')
|
||||||
deprecationNoteAlias!: EntityDeprecation['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
|
* Invokes the save action with the updated values for deprecated status, decommission time, and
|
||||||
* deprecation note. The actual save functionality should be handled by
|
* deprecation note. The actual save functionality should be handled by
|
||||||
@ -155,13 +133,4 @@ export default class EntityDeprecation extends Component {
|
|||||||
onDecommissionDateChange(decommissionTime: Date): void {
|
onDecommissionDateChange(decommissionTime: Date): void {
|
||||||
set(this, 'decommissionTime', new Date(decommissionTime).getTime());
|
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');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -80,27 +80,13 @@
|
|||||||
{{if decommissionTime (concat 'Will be decommissioned on ' (moment-format decommissionTime 'MMMM DD YYYY')) ''}}
|
{{if decommissionTime (concat 'Will be decommissioned on ' (moment-format decommissionTime 'MMMM DD YYYY')) ''}}
|
||||||
</strong>
|
</strong>
|
||||||
</p>
|
</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}}
|
{{/if}}
|
||||||
|
|
||||||
<div class="entity-deprecation__actions">
|
<div class="entity-deprecation__actions">
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="nacho-button--large nacho-button--secondary"
|
class="nacho-button--large nacho-button--secondary"
|
||||||
disabled={{and isDeprecatedAlias (or (not decommissionTime) (not isDeprecationAcknowledged))}}>
|
disabled={{and isDeprecatedAlias (not decommissionTime)}}>
|
||||||
Update Deprecation Status
|
Update Deprecation Status
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { module, test } from 'qunit';
|
import { module, test } from 'qunit';
|
||||||
import { setupRenderingTest } from 'ember-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';
|
import hbs from 'htmlbars-inline-precompile';
|
||||||
|
|
||||||
const findInput = (selector: string): HTMLInputElement => {
|
const findInput = (selector: string): HTMLInputElement => {
|
||||||
@ -67,7 +67,6 @@ module('Integration | Component | entity-deprecation', function(hooks): void {
|
|||||||
|
|
||||||
test('decommissionTime', async function(assert): Promise<void> {
|
test('decommissionTime', async function(assert): Promise<void> {
|
||||||
let isDisabled;
|
let isDisabled;
|
||||||
assert.expect(3);
|
|
||||||
|
|
||||||
this.setProperties({
|
this.setProperties({
|
||||||
...defaultProperties,
|
...defaultProperties,
|
||||||
@ -83,58 +82,5 @@ module('Integration | Component | entity-deprecation', function(hooks): void {
|
|||||||
|
|
||||||
isDisabled = findInput('.entity-deprecation__actions [type=submit]').disabled;
|
isDisabled = findInput('.entity-deprecation__actions [type=submit]').disabled;
|
||||||
assert.ok(isDisabled, 'submit button is 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');
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -8,6 +8,8 @@ export interface ICorpUserEditableInfo {
|
|||||||
teams: Array<string>;
|
teams: Array<string>;
|
||||||
// A self-assigned list of skills that the person claims to own
|
// A self-assigned list of skills that the person claims to own
|
||||||
skills: Array<string>;
|
skills: Array<string>;
|
||||||
|
// Reference to the picture URL for the person
|
||||||
|
pictureLink: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import { NotificationEvent } from '@datahub/utils/constants/notifications';
|
|||||||
import { PersonEntity } from '@datahub/data-models/entity/person/person-entity';
|
import { PersonEntity } from '@datahub/data-models/entity/person/person-entity';
|
||||||
import { task } from 'ember-concurrency';
|
import { task } from 'ember-concurrency';
|
||||||
import { ETaskPromise } from '@datahub/utils/types/concurrency';
|
import { ETaskPromise } from '@datahub/utils/types/concurrency';
|
||||||
|
import DataModelsService from '@datahub/data-models/services/data-models';
|
||||||
|
|
||||||
type Comparator = -1 | 0 | 1;
|
type Comparator = -1 | 0 | 1;
|
||||||
|
|
||||||
@ -89,6 +90,12 @@ export default class DatasetAuthors extends Component {
|
|||||||
@service('user-lookup')
|
@service('user-lookup')
|
||||||
userLookup: UserLookup;
|
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
|
* 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
|
* 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}
|
* @returns {OwnerWithAvatarRecord}
|
||||||
*/
|
*/
|
||||||
datasetAuthorsOwnersAugmentedWithAvatars = (owner: IOwner): OwnerWithAvatarRecord => {
|
datasetAuthorsOwnersAugmentedWithAvatars = (owner: IOwner): OwnerWithAvatarRecord => {
|
||||||
const { avatarProperties } = this;
|
const { avatarProperties, dataModels } = this;
|
||||||
|
const PersonEntityClass = dataModels.getModel('people') as typeof PersonEntity;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
owner,
|
owner,
|
||||||
avatar: avatarProperties
|
avatar: avatarProperties
|
||||||
? makeAvatar(avatarProperties)(owner)
|
? makeAvatar(avatarProperties)(owner)
|
||||||
: { imageUrl: '', imageUrlFallback: '/assets/images/default_avatar.png' },
|
: { imageUrl: '', imageUrlFallback: '/assets/images/default_avatar.png' },
|
||||||
profile: PersonEntity.profileLinkFromUsername(owner.userName)
|
profile: PersonEntityClass.urnFromUsername(owner.userName)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import { facetToParamUrl } from 'wherehows-web/utils/api/search/search';
|
|||||||
import RouterService from '@ember/routing/router-service';
|
import RouterService from '@ember/routing/router-service';
|
||||||
import { task } from 'ember-concurrency';
|
import { task } from 'ember-concurrency';
|
||||||
import { ETaskPromise } from '@datahub/utils/types/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
|
* Search box container that handle all the data part for
|
||||||
@ -29,6 +30,9 @@ export default class SearchBoxContainer extends Component {
|
|||||||
@service
|
@service
|
||||||
search: SearchService;
|
search: SearchService;
|
||||||
|
|
||||||
|
@service('data-models')
|
||||||
|
dataModels!: DataModelsService;
|
||||||
|
|
||||||
@alias('search.entity')
|
@alias('search.entity')
|
||||||
entity?: DataModelName;
|
entity?: DataModelName;
|
||||||
|
|
||||||
@ -44,9 +48,9 @@ export default class SearchBoxContainer extends Component {
|
|||||||
*/
|
*/
|
||||||
@computed('entity')
|
@computed('entity')
|
||||||
get dataModelEntity(): DataModelEntity | undefined {
|
get dataModelEntity(): DataModelEntity | undefined {
|
||||||
const { entity } = this;
|
const { entity, dataModels } = this;
|
||||||
if (entity) {
|
if (entity && dataModels) {
|
||||||
return DataModelEntity[entity];
|
return dataModels.getModel(entity);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -58,8 +62,15 @@ export default class SearchBoxContainer extends Component {
|
|||||||
* @returns {(IterableIterator<Promise<Array<ISuggestionGroup>>>)}
|
* @returns {(IterableIterator<Promise<Array<ISuggestionGroup>>>)}
|
||||||
* @memberof SearchBoxContainer
|
* @memberof SearchBoxContainer
|
||||||
*/
|
*/
|
||||||
@task(function*(query: string = '', entity?: DataModelName): IterableIterator<Promise<Array<ISuggestionGroup>>> {
|
@task(function*(
|
||||||
return yield typeaheadQueryProcessor(query, entity, grammarProcessingSteps);
|
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>>;
|
onSearchInputTask: ETaskPromise<Array<ISuggestionGroup>>;
|
||||||
|
|
||||||
@ -71,17 +82,20 @@ export default class SearchBoxContainer extends Component {
|
|||||||
*/
|
*/
|
||||||
onSearch(text: string = '', entity: DataModelName = DatasetEntity.displayName): void {
|
onSearch(text: string = '', entity: DataModelName = DatasetEntity.displayName): void {
|
||||||
// entity (dropdown value) might be different than this.entity (Page that you are in)
|
// entity (dropdown value) might be different than this.entity (Page that you are in)
|
||||||
const dataModelEntity = DataModelEntity[entity];
|
const { dataModels } = this;
|
||||||
const { attributes } = dataModelEntity.renderProps.search;
|
if (entity) {
|
||||||
const defaultFacets = facetToParamUrl(transformDefaultsIntoSelections(getFacetDefaultValueForEntity(attributes)));
|
const dataModelEntity = dataModels.getModel(entity);
|
||||||
|
const { attributes } = dataModelEntity.renderProps.search;
|
||||||
|
const defaultFacets = facetToParamUrl(transformDefaultsIntoSelections(getFacetDefaultValueForEntity(attributes)));
|
||||||
|
|
||||||
this.router.transitionTo('search', {
|
this.router.transitionTo('search', {
|
||||||
queryParams: {
|
queryParams: {
|
||||||
entity,
|
entity,
|
||||||
keyword: text,
|
keyword: text,
|
||||||
page: 1,
|
page: 1,
|
||||||
facets: defaultFacets
|
facets: defaultFacets
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,26 +36,38 @@ export default class SearchResult extends Component {
|
|||||||
/**
|
/**
|
||||||
* Result used in template
|
* Result used in template
|
||||||
*/
|
*/
|
||||||
result?: DataModelEntityInstance;
|
result!: DataModelEntityInstance;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Config for search for this entity
|
* Config for search for this entity
|
||||||
*/
|
*/
|
||||||
searchConfig?: IEntityRenderCommonPropsSearch;
|
searchConfig!: IEntityRenderCommonPropsSearch;
|
||||||
/**
|
/**
|
||||||
* Will return the name of the entity. By default it will use
|
* Will return the name of the entity. By default it will use
|
||||||
* 'name' as field to fetch the name, otherwise it should be
|
* 'name' as field to fetch the name, otherwise it should be
|
||||||
* specified in 'entityNameField'
|
* specified in 'entityNameField'
|
||||||
*/
|
*/
|
||||||
@computed('searchConfig.entityNameField', 'entity')
|
@computed('searchConfig.entityNameField', 'entity')
|
||||||
get name(): string | void {
|
get name(): string | undefined {
|
||||||
const { result, searchConfig = { searchResultEntityFields: { name: 'name' } } } = this;
|
const { result, searchConfig } = this;
|
||||||
if (result) {
|
const { searchResultEntityFields = {} } = searchConfig;
|
||||||
const { searchResultEntityFields = { name: 'name' } } = searchConfig;
|
const { name = 'name' } = searchResultEntityFields || {};
|
||||||
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];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -4,9 +4,9 @@
|
|||||||
{{avatars/avatar-image avatar=@owner.avatar}}
|
{{avatars/avatar-image avatar=@owner.avatar}}
|
||||||
{{/unless}}
|
{{/unless}}
|
||||||
|
|
||||||
<a href={{@owner.profile}} rel="noopener" target="blank">
|
<LinkTo @route="user.profile" @model={{@owner.profile}}>
|
||||||
{{ownerRecord.userName}}
|
{{ownerRecord.userName}}
|
||||||
</a>
|
</LinkTo>
|
||||||
|
|
||||||
{{#if isOwnerInActive}}
|
{{#if isOwnerInActive}}
|
||||||
|
|
||||||
|
|||||||
15
datahub-web/packages/data-portal/app/typings/app/search/fields.d.ts
vendored
Normal file
15
datahub-web/packages/data-portal/app/typings/app/search/fields.d.ts
vendored
Normal 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>;
|
||||||
|
}
|
||||||
@ -13,7 +13,7 @@ import { generateGroups } from 'wherehows-web/utils/parsers/autocomplete/steps/g
|
|||||||
import { arrayReduce } from 'wherehows-web/utils/array';
|
import { arrayReduce } from 'wherehows-web/utils/array';
|
||||||
import { createSuggestionsFromError } from 'wherehows-web/utils/parsers/helpers';
|
import { createSuggestionsFromError } from 'wherehows-web/utils/parsers/helpers';
|
||||||
import { DatasetEntity } from '@datahub/data-models/entity/dataset/dataset-entity';
|
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
|
* Steps of the grammar process
|
||||||
@ -40,7 +40,7 @@ export const grammarProcessingSteps: Array<IGrammarProcessFn> = [
|
|||||||
*/
|
*/
|
||||||
export const typeaheadQueryProcessor = async (
|
export const typeaheadQueryProcessor = async (
|
||||||
query: string,
|
query: string,
|
||||||
entity: DataModelName = DatasetEntity.displayName,
|
entity: DataModelEntity = DatasetEntity,
|
||||||
steps: Array<IGrammarProcessFn>
|
steps: Array<IGrammarProcessFn>
|
||||||
): Promise<Array<ISuggestionGroup>> => {
|
): Promise<Array<ISuggestionGroup>> => {
|
||||||
const initArgs: Pick<ISuggestionBuilder, 'text' | 'entity'> = { text: query, entity };
|
const initArgs: Pick<ISuggestionBuilder, 'text' | 'entity'> = { text: query, entity };
|
||||||
|
|||||||
@ -1,7 +1,8 @@
|
|||||||
import {
|
import {
|
||||||
INodeProcessor,
|
INodeProcessor,
|
||||||
AutocompleteRuleNames,
|
AutocompleteRuleNames,
|
||||||
ISuggestionBuilder
|
ISuggestionBuilder,
|
||||||
|
ISuggestion
|
||||||
} from 'wherehows-web/utils/parsers/autocomplete/types';
|
} from 'wherehows-web/utils/parsers/autocomplete/types';
|
||||||
import { fetchFacetValue } from 'wherehows-web/utils/parsers/helpers';
|
import { fetchFacetValue } from 'wherehows-web/utils/parsers/helpers';
|
||||||
|
|
||||||
@ -12,17 +13,20 @@ import { fetchFacetValue } from 'wherehows-web/utils/parsers/helpers';
|
|||||||
export const entityProcessor: INodeProcessor = {
|
export const entityProcessor: INodeProcessor = {
|
||||||
[AutocompleteRuleNames.EntityName]: async (builder: ISuggestionBuilder): Promise<ISuggestionBuilder> => {
|
[AutocompleteRuleNames.EntityName]: async (builder: ISuggestionBuilder): Promise<ISuggestionBuilder> => {
|
||||||
const input = builder.textLastWord || '';
|
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 {
|
return {
|
||||||
...builder,
|
...builder,
|
||||||
datasets: [
|
datasets: [
|
||||||
...builder.datasets,
|
...builder.datasets,
|
||||||
...(suggestions || []).map(entityName => ({
|
...(suggestions || []).map(
|
||||||
title: entityName,
|
(entityName): ISuggestion => ({
|
||||||
text: `${builder.textPrevious}${entityName} `,
|
title: entityName,
|
||||||
description: ''
|
text: `${builder.textPrevious}${entityName} `,
|
||||||
}))
|
description: ''
|
||||||
|
})
|
||||||
|
)
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,6 @@ import {
|
|||||||
} from 'wherehows-web/utils/parsers/autocomplete/types';
|
} from 'wherehows-web/utils/parsers/autocomplete/types';
|
||||||
import { dataToString } from 'wherehows-web/utils/parsers/autocomplete/utils';
|
import { dataToString } from 'wherehows-web/utils/parsers/autocomplete/utils';
|
||||||
import { ISearchEntityRenderProps } from '@datahub/data-models/types/entity/rendering/search-entity-render-prop';
|
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';
|
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
|
* When 'name' is expected we just return 'name:' as suggestion
|
||||||
*/
|
*/
|
||||||
[AutocompleteRuleNames.FacetName]: (builder: ISuggestionBuilder, ruleState: IState): Promise<ISuggestionBuilder> => {
|
[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 facetName = getFacetNameFromStateRule(ruleState);
|
||||||
const fields = allFields.filter(
|
const fields = allFields.filter(
|
||||||
(field): boolean => field.fieldName.indexOf(facetName) >= 0 && field.showInAutoCompletion
|
(field): boolean => field.fieldName.indexOf(facetName) >= 0 && field.showInAutoCompletion
|
||||||
|
|||||||
@ -14,7 +14,8 @@ export const generateGroups = (builder: ISuggestionBuilder): ISuggestionBuilder
|
|||||||
const isEntityNamesEmpty = builder.datasets.length === 0;
|
const isEntityNamesEmpty = builder.datasets.length === 0;
|
||||||
const expectedEntityName = !!builder.wantedRulesMap[AutocompleteRuleNames.EntityName];
|
const expectedEntityName = !!builder.wantedRulesMap[AutocompleteRuleNames.EntityName];
|
||||||
const lastWordLength = typeof builder.textLastWord === 'string' ? builder.textLastWord.trim().length : -1;
|
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) {
|
if (isEntityNamesEmpty && expectedEntityName && lastWordLength < 3) {
|
||||||
groups.push({
|
groups.push({
|
||||||
|
|||||||
@ -43,7 +43,7 @@ export type INodeFacetProcessor = Record<
|
|||||||
* The structure is not intented to be mutated, redux like approach
|
* The structure is not intented to be mutated, redux like approach
|
||||||
*/
|
*/
|
||||||
export interface ISuggestionBuilder {
|
export interface ISuggestionBuilder {
|
||||||
entity: DataModelEntity['displayName'];
|
entity: DataModelEntity;
|
||||||
logicalOperators: Array<ISuggestion>;
|
logicalOperators: Array<ISuggestion>;
|
||||||
facetNames: Array<ISuggestion>;
|
facetNames: Array<ISuggestion>;
|
||||||
datasets: Array<ISuggestion>;
|
datasets: Array<ISuggestion>;
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { ISuggestionGroup } from 'wherehows-web/utils/parsers/autocomplete/types';
|
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 { IFieldValuesResponseV2, FieldValuesRequestV2 } from 'wherehows-web/typings/app/search/fields-v2';
|
||||||
import { facetValuesApiEntities } from 'wherehows-web/utils/parsers/autocomplete/utils';
|
import { facetValuesApiEntities } from 'wherehows-web/utils/parsers/autocomplete/utils';
|
||||||
|
|
||||||
@ -24,12 +24,13 @@ export const createSuggestionsFromError = (error: string): Array<ISuggestionGrou
|
|||||||
export const fetchFacetValue = async (
|
export const fetchFacetValue = async (
|
||||||
facetName: string,
|
facetName: string,
|
||||||
facetValue: string,
|
facetValue: string,
|
||||||
entity: DataModelName
|
entity: DataModelEntity
|
||||||
): Promise<Array<string>> => {
|
): Promise<Array<string>> => {
|
||||||
// otherwise lets invoke api to fetch values
|
// otherwise lets invoke api to fetch values
|
||||||
let suggestions: Array<string> = [];
|
let suggestions: Array<string> = [];
|
||||||
const { apiName, attributes } = DataModelEntity[entity].renderProps.search;
|
const searchRenderProps = entity.renderProps.search;
|
||||||
const fieldMeta = attributes.find((attr): boolean => attr.fieldName === facetName);
|
const searchAttributes = searchRenderProps.attributes;
|
||||||
|
const fieldMeta = searchAttributes.find((attr): boolean => attr.fieldName === facetName);
|
||||||
const { minAutocompleteFetchLength } = fieldMeta || { minAutocompleteFetchLength: undefined };
|
const { minAutocompleteFetchLength } = fieldMeta || { minAutocompleteFetchLength: undefined };
|
||||||
const cacheKey = `${facetName}:${facetValue}`;
|
const cacheKey = `${facetName}:${facetValue}`;
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ export const fetchFacetValue = async (
|
|||||||
const request: FieldValuesRequestV2<Record<string, string>> = {
|
const request: FieldValuesRequestV2<Record<string, string>> = {
|
||||||
field: facetName,
|
field: facetName,
|
||||||
input: facetValue,
|
input: facetValue,
|
||||||
type: apiName
|
type: searchRenderProps.apiName
|
||||||
};
|
};
|
||||||
const facetValueReturn: IFieldValuesResponseV2 | undefined = await facetValuesApiEntities({
|
const facetValueReturn: IFieldValuesResponseV2 | undefined = await facetValuesApiEntities({
|
||||||
query: facetValue,
|
query: facetValue,
|
||||||
|
|||||||
@ -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);
|
assert.expect(1);
|
||||||
|
|
||||||
const result = createEntity();
|
const result = createEntity();
|
||||||
|
|
||||||
this.setProperties({ fields: [], result });
|
this.setProperties({ searchConfig: { attributes: [] }, result });
|
||||||
await render(hbs`{{search/search-result
|
await render(hbs`<Search::SearchResult
|
||||||
result=result.data
|
@result={{this.result.data}}
|
||||||
meta=result.meta
|
@meta={{this.result.meta}}
|
||||||
resultFields=fields
|
@searchConfig={{this.searchConfig}}
|
||||||
}}`);
|
/>`);
|
||||||
|
|
||||||
assert.ok(find('.search-result'), 'expected component to have a class `search-result`');
|
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);
|
assert.expect(1);
|
||||||
|
|
||||||
const result = createEntity();
|
const result = createEntity();
|
||||||
|
|
||||||
this.setProperties({ fields: [], result });
|
this.setProperties({ searchConfig: { attributes: [] }, result });
|
||||||
await render(hbs`{{search/search-result
|
await render(hbs`<Search::SearchResult
|
||||||
result=result.data
|
@result={{this.result.data}}
|
||||||
meta=result.meta
|
@meta={{this.result.meta}}
|
||||||
resultFields=fields
|
@searchConfig={{this.searchConfig}}
|
||||||
}}`);
|
/>`);
|
||||||
|
|
||||||
const searchResultElement: Element | null = find('.search-result');
|
const searchResultElement: Element | null = find('.search-result');
|
||||||
const title = searchResultElement && searchResultElement.querySelector('.search-result__title');
|
const title = searchResultElement && searchResultElement.querySelector('.search-result__title');
|
||||||
|
|||||||
@ -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());
|
|
||||||
});
|
|
||||||
});
|
|
||||||
Loading…
x
Reference in New Issue
Block a user