Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixeat(SFINT-3295): Improve UserActions interactivity #81

Merged
merged 5 commits into from
Jul 8, 2020
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 37 additions & 9 deletions src/components/UserActions/UserActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ export interface IUserActionsOptions {
* Default: `False`
*/
hidden: Boolean;
/**
* Whether or not the UserAction component should use the CoveoSearchUI ResponsiveManager
* Inoperant if `hidden` is true.
*
* Default: `True`
*/
useResponsiveManager: Boolean;
}

/**
Expand All @@ -80,6 +87,10 @@ export class UserActions extends Component {
* Identifier of the Search-UI component.
*/
static readonly ID = 'UserActions';
static readonly Events = {
Hide: 'userActionsPanelHide',
Show: 'userActionsPanelShow'
};

/**
* Default initialization options of the **UserActions** class.
Expand All @@ -100,6 +111,9 @@ export class UserActions extends Component {
}),
hidden: ComponentOptions.buildBooleanOption({
defaultValue: false
}),
useResponsiveManager: ComponentOptions.buildBooleanOption({
defaultValue: true
})
};

Expand Down Expand Up @@ -130,7 +144,9 @@ export class UserActions extends Component {
this.tagViewsOfUser();

if (!options.hidden) {
ResponsiveUserActions.init(this.root, this);
if (options.useResponsiveManager) {
ResponsiveUserActions.init(this.root, this);
}
this.bind.onRootElement(QueryEvents.newQuery, () => this.hide());
this.hide();
}
Expand All @@ -144,33 +160,45 @@ export class UserActions extends Component {
(get(this.root, UserProfileModel) as UserProfileModel).deleteActions(this.options.userId);
this.root.classList.remove(UserActions.USER_ACTION_OPENED);
this.isOpened = false;
this.element.dispatchEvent(new CustomEvent(UserActions.Events.Hide));
}
}

/**
* Open the panel.
*/
public show() {
public async show() {
if (!this.isOpened) {
(get(this.root, UserProfileModel) as UserProfileModel)
.getActions(this.options.userId)
.then(actions => (actions.length > 0 ? this.render() : this.renderNoActions()))
.catch(e => (e && e.statusCode === 404 ? this.renderEnablePrompt() : this.renderNoActions()));

this.element.dispatchEvent(new CustomEvent(UserActions.Events.Show));
this.bindings.usageAnalytics.logCustomEvent({ name: 'openUserActions', type: 'User Actions' }, {}, this.element);
this.root.classList.add(UserActions.USER_ACTION_OPENED);
this.isOpened = true;

try {
const userActions = await (get(this.root, UserProfileModel) as UserProfileModel).getActions(this.options.userId);
if (userActions.length > 0) {
this.render();
} else {
this.renderNoActions();
}
} catch (e) {
if (e && e.statusCode === 404) {
Copy link
Collaborator Author

@louis-bompart louis-bompart Jul 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wanted to use optional chaining, was not able because of prettier, so #80 should fix it and allow latest TypeScript features to be used.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we only checking for status code 404?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're still considering the others status code, but do not wish to take special action for them other than render no actions.

I'm guessing that if https://platformqa.cloud.coveo.com/docs/?api=Reveal#!/User32Profiles/rest_organizations_paramId_machinelearning_user_actions_post answer 404, it means the feature is not enabled on the client organization.

this.renderEnablePrompt();
} else {
this.renderNoActions();
}
}
}
}

/**
* Toggle the visibility of the panel.
*/
public toggle() {
public async toggle() {
if (this.isOpened) {
this.hide();
} else {
this.show();
await this.show();
}
}

Expand Down
50 changes: 50 additions & 0 deletions tests/components/UserActions/UserActions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ describe('UserActions', () => {

it('should not be displayed if hidden option is true', () => {
const responsiveComponentStub = sandbox.stub(ResponsiveUserActions, 'init');
const hideSpy = sandbox.spy(UserActions.prototype, 'hide');

Mock.advancedComponentSetup<UserActions>(
UserActions,
Expand All @@ -85,6 +86,39 @@ describe('UserActions', () => {
})
);

return delay(() => {
expect(hideSpy.called).toBe(false);
expect(responsiveComponentStub.called).toBe(false);
});
});

it('should register to the ResponsiveComponentManager by default', () => {
const responsiveComponentStub = sandbox.stub(ResponsiveUserActions, 'init');

Mock.advancedComponentSetup<UserActions>(
UserActions,
new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId' }, env => {
fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(ACTIONS));
return env;
})
);

return delay(() => {
expect(responsiveComponentStub.called).toBe(true);
});
});

it('should not register to the ResponsiveComponentManager when useResponsiveManager is false', () => {
const responsiveComponentStub = sandbox.stub(ResponsiveUserActions, 'init');

Mock.advancedComponentSetup<UserActions>(
UserActions,
new Mock.AdvancedComponentSetupOptions(null, { userId: 'testuserId', useResponsiveManager: false }, env => {
fakeUserProfileModel(env.root, sandbox).getActions.returns(Promise.resolve(ACTIONS));
return env;
})
);

return delay(() => {
expect(responsiveComponentStub.called).toBe(false);
});
Expand Down Expand Up @@ -452,6 +486,13 @@ describe('UserActions', () => {
expect(modelMock.getActions.calledWithExactly(someUserId)).toBe(true);
});
});

it('should trigger a userActionsShow event', () => {
const spyDispatchEvent = sandbox.spy(mock.cmp.element, 'dispatchEvent');
mock.cmp.show();

expect(spyDispatchEvent.calledOnceWith(new CustomEvent('userActionsPanelHide')));
});
});

describe('hide', () => {
Expand Down Expand Up @@ -510,6 +551,15 @@ describe('UserActions', () => {
expect(modelMock.deleteActions.calledWithExactly(someUserId)).toBe(true);
});
});

it('should trigger a userActionsHide event', () => {
mock.cmp.show();
const spyDispatchEvent = sandbox.spy(mock.cmp.element, 'dispatchEvent');

mock.cmp.hide();

expect(spyDispatchEvent.calledOnceWith(new CustomEvent('userActionsPanelHide')));
});
});

describe('tagViewsOfUser', () => {
Expand Down