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

Add ability to pass a title and show the close button on a modal #10069

Merged

Conversation

stacey-gammon
Copy link
Contributor

Nothing is using this yet, but view/edit mode will need the concept of three separate actions - close (do nothing), use current filters, and load dashboard filters.

@@ -23,9 +27,15 @@ module.factory('confirmModal', function ($rootScope, $compile) {
return function confirmModal(message, customOptions) {
const defaultOptions = {
onCancel: noop,
cancelButtonText: 'Cancel'
cancelButtonText: 'Cancel',
onClose: noop,
Copy link
Contributor

Choose a reason for hiding this comment

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

I think that in every case, onCancel and onClose will reference the same handler (assuming onCancel is a handler they need in the first place).

This also introduces a gotcha where a user can forget to add an onCancel handler even in situations where they DID add an onCancel, but the dialog still works and now they have a silent error condition.

3 handlers on a dialog with 2 buttons seems strange. I think when a user clicks the close button, they mean to do the same thing as when they click the cancel button, so calling onCancel on close seems appropriate, and leaving this at 2 handlers seems right.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This also introduces a gotcha where a user can forget to add an onCancel handler even in situations where they DID add an onCancel,

I'm not sure what you mean by this.

View/edit mode needs this situation. It has two choices and I also want to give the ability for the user to "x" out of the dialog and "do nothing". I suppose I could not accept a custom onClose function and always make it a noop, which would be sufficient for my needs.

These are the two dialogs that I want to use this for:
Here 'x' will cancel out jumping into edit mode:
screen shot 2017-01-17 at 4 29 50 pm

Here 'x' will cancel out leaving edit mode:
screen shot 2017-01-17 at 4 30 55 pm

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually I have an idea. How about if the user passes a custom onCancel but not a custom onClose, and passes showClose, onClose defaults to onCancel instead of noop?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think Stacey's suggestion is the best option for now.

Longer term, I don't think ConfirmModal is the right tool for this use case. I think we should only use ConfirmModal for yes/no questions and create different modals for situations like this one.

Copy link
Contributor

Choose a reason for hiding this comment

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

That last example isn't a confirm dialog. There shouldn't be 3 choices on a confirmation. Confirm is a yes/no, not a yes/no/exit.

For this to be a confirmation dialog, the flow should just say something like "You will lose your changes, are you sure?" with a "Lose Changes" option and a "Go back to edit" option, and they can save manually.

Otherwise, I think this needs a new kind of modal which allows for 3 actions, Lose Changes, Save Changes, and Back to Edit.

@w33ble w33ble self-assigned this Jan 25, 2017
Copy link
Contributor

@cjcenizal cjcenizal left a comment

Choose a reason for hiding this comment

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

I love these tests! I had a few suggestions.

expect(true).to.be(false);
} catch (error) {
expect(error).to.not.be(undefined);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

According to the docs we can make assertions about errors like this:

expect(fn).to.throw(); // synonym of throwException
expect(fn).to.throwError(); // synonym of throwException
expect(fn).to.throwException(function (e) { // get the exception object
  expect(e).to.be.a(SyntaxError);
});
expect(fn).to.throwException(/matches the exception message/);
expect(fn2).to.not.throwException();

So we can rewrite this test to be:

expect(() => confirmModal('hi', { onConfirm: _.noop })).to.throw("Error message here");

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fancy! Now that looks much better.

expect(true).to.be(false);
} catch (error) {
expect(error).to.not.be(undefined);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here.

confirmModal('hi', { customConfirmButton: 'b', onConfirm: _.noop, showClose: true });
expect(true).to.be(false);
} catch (error) {
expect(error).to.not.be(undefined);
Copy link
Contributor

Choose a reason for hiding this comment

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

Same here.

it('shows custom text', function () {
const confirmModalOptions = {
confirmButtonText: 'Troodon',
cancelButtonText: 'Dilophosaurus',
Copy link
Contributor

Choose a reason for hiding this comment

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

More of an Allosaurus guy, myself.

expect(cancelButtonText).to.equal('Dilophosaurus');
const titleText = findByDataTestSubj('confirmModalTitleText')[0].innerText;
expect(titleText).to.equal('Dinosaurs');
});
Copy link
Contributor

Choose a reason for hiding this comment

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

This is a bit dogmatic, but I think it would be better to make this a describe block with individual tests per each individual customizable unit:

describe('shows custom text', () => {
  it('for confirm button', () => {
  });

  it('for cancel button', () => {
  });

  it('for title text', () => {
  });
});

I think this documents the interface a bit better, and it also makes it easier to zoom in on failing tests and know exactly what's failing based on the error messages in the terminal.

@@ -1,4 +1,16 @@
<div class="kuiModal" style="width: 450px" data-test-subj="confirmModal">
<div class="kuiModalHeader" ng-if="title">
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need this ng-if here? It seems unexpected to hide the close button if no title is provided. I think we can remove it entirely and just show an empty title element if no title is provided.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think it looks weird without a title and an empty header. It can't be that hard to come up with a title (Warning, Error, Info at the most basic), so I kinda like forcing people to add one, even if only for aesthetic reasons. If you disagree I can make it optional though.

Copy link
Contributor

@cjcenizal cjcenizal Jan 26, 2017

Choose a reason for hiding this comment

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

Yeah, you're right. You changed my mind. Still, there's a weird conflict if someone tries to set showClose to true, but doesn't specify a title. Since the component doesn't support that, we should let the engineer know they're misusing the interface. How about throwing an error?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

:) Already handled. Even have a test for it! 😸

    it('when showClose is on but title is not given', function () {
      const options = { customConfirmButton: 'b', onConfirm: _.noop, showClose: true };
      expect(confirmModal('hi', options)).to.throwError();
    });

Copy link
Contributor

Choose a reason for hiding this comment

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

Awesome!!

expect(xIcon.length).to.be(0);
});
});
});
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add tests verifying that the onClose, onConfirm, and onCancel callbacks are executed when buttons are pressed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

++ Good idea

@@ -23,9 +27,15 @@ module.factory('confirmModal', function ($rootScope, $compile) {
return function confirmModal(message, customOptions) {
const defaultOptions = {
onCancel: noop,
cancelButtonText: 'Cancel'
cancelButtonText: 'Cancel',
onClose: noop,
Copy link
Contributor

Choose a reason for hiding this comment

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

I think Stacey's suggestion is the best option for now.

Longer term, I don't think ConfirmModal is the right tool for this use case. I think we should only use ConfirmModal for yes/no questions and create different modals for situations like this one.

- Clean up tests and add some new ones
- Default onClose to onCancel if nothing is supplied.
confirmButtonText: 'bye',
onConfirm: confirmCallback,
onCancel: cancelCallback,
onClose: closeCallback,
Copy link
Contributor

@w33ble w33ble Jan 26, 2017

Choose a reason for hiding this comment

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

I still feel very strongly that there should not be an onClose action on a confirmation dialog. Confirmation is yes/no, and closing the modal should do the same thing as clicking on cancel/no. If you need a third action, I think there should be a new type of modal.

Since my other comment got collapsed, see: #10069 (comment)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm giving the user the option to not answer the confirmation. It's like, Yes/No/Prefer not to answer right now.

Copy link
Contributor

Choose a reason for hiding this comment

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

I understand that's what you are doing, but that's not how confirm dialogs work. Look to the thing you are replacing, window.confirm(), as an example.

Adding a third option is confusing, both to the user and to the person implementing the confirm dialog. Personally when I see a confirmation dialog with a close button, I expect that closing the box is the same as answering no.

Now, if you would like to add a new kind of dialog/modal, where you can defer your answer until later and close the prompt for now, that's fine. But I don't think that confirmModel should work this way.

Copy link
Contributor Author

@stacey-gammon stacey-gammon Jan 27, 2017

Choose a reason for hiding this comment

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

What would you propose instead? I can rename confirm => custom and rename all the buttons from cancel => secondary action and confirm => primary action?

I don't want to introduce a slew of extremely similar code just so I can can pass a different onClose than onCancel action, and that is the only difference between the modal that I need and the confirmModal that you would prefer.

Would you be content if I opened an issue for to explore this later? It feels like diminishing returns at this point. IMO it is not far fetched to allow a confirmation modal a custom onClose as a specialized option (not the default). Just because the native confirmation window works like that doesn't mean this has to. We allow them to set the cancel button text, so the user might not be answering 'no' or 'cancel', but something else.

Other "Confirmation" dialogs offer more than just yes/no as well:
customconfirm1

Bootstrap custom confirm:
screen shot 2017-01-27 at 1 59 36 pm

And jquery-confirm also doesn't make the close function match the onCancel function (at least I think that's how it works by reading the functions - looks like close just closes without calling onCancel) http://craftpip.github.io/jquery-confirm/v1.7.8/

I'm fine with improving this at some point, but I don't think it's the highest priority. Seems like something we could tackle when we address how to handle even more customized modals (e.g. passing in templates, etc). So unless there is a quick-ish solution that doesn't cause a bunch of duplicate code, I'd prefer to punt.

Copy link
Contributor

@cjcenizal cjcenizal Jan 27, 2017

Choose a reason for hiding this comment

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

I think we can punt on this for now as Stacey suggests. Can we merge this PR and have an in-depth discussion about this later?

I personally don't think we should look to window.confirm as a reference. I think of what we're building as a modal system first and foremost. Beyond that, we're creating customized modals to support different UXes, of which confirmation modals are one instance. So while I agree that this is a hacky use of the confirmation modal, I think that the onClose functionality should be kept, and we can build a more appropriate, custom modal for this use-case later.

@w33ble Can you walk me through the thought-process and pain points for an engineer who has the ability to customize onClose? It seems ergonomic to me, since it defaults to the onCancel callback, which sounds like the behavior you're asking for. Maybe I'm overlooking something, though, so if this is a 10 on a pain scale of 1-10, then I want to be able to empathize.

Copy link
Contributor

@w33ble w33ble Jan 27, 2017

Choose a reason for hiding this comment

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

Yeah, we can punt on it for now. I think it's enough that onClose defaults to onCancel, since it doesn't change the way this dialog works, and it should no longer trip up a developer trying to use it.

@stacey-gammon can you open a new issue and link back to this conversation?

Copy link
Contributor

Choose a reason for hiding this comment

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

Related: how do we handle keyboard input, like the escape key? #10099

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Filed #10104. ++ on the issue you filed above, no handling of esc key right now.

Copy link
Contributor

@w33ble w33ble left a comment

Choose a reason for hiding this comment

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

LGTM. Please open a new issue about the onClose handler so we can discuss our options somewhere else, then this is good to go.

@stacey-gammon stacey-gammon merged commit 58b5cbd into elastic:master Jan 28, 2017
elastic-jasper added a commit that referenced this pull request Jan 28, 2017
Backports PR #10069

**Commit 1:**
Add ability to pass a title and show the close button on a modal

* Original sha: b66a900
* Authored by Stacey Gammon <[email protected]> on 2017-01-25T18:50:06Z

**Commit 2:**
address code review comments

- Clean up tests and add some new ones
- Default onClose to onCancel if nothing is supplied.

* Original sha: 63e90f7
* Authored by Stacey Gammon <[email protected]> on 2017-01-26T18:01:58Z
stacey-gammon pushed a commit that referenced this pull request Jan 30, 2017
)

Backports PR #10069

**Commit 1:**
Add ability to pass a title and show the close button on a modal

* Original sha: b66a900
* Authored by Stacey Gammon <[email protected]> on 2017-01-25T18:50:06Z

**Commit 2:**
address code review comments

- Clean up tests and add some new ones
- Default onClose to onCancel if nothing is supplied.

* Original sha: 63e90f7
* Authored by Stacey Gammon <[email protected]> on 2017-01-26T18:01:58Z
@stacey-gammon stacey-gammon deleted the add-title-and-close-confirm branch January 30, 2017 15:39
stacey-gammon added a commit to stacey-gammon/kibana that referenced this pull request Apr 18, 2017
The reason they were added is no longer necessary (something for view
edit mode which didn’t pan out).  It was a point of contention:

See elastic#10104
and
elastic#10069 (review)
for background.

Since it’s no longer needed anyway, and this is going to get moved to
react anyhow, I’m removing the unused functionality.
stacey-gammon added a commit that referenced this pull request Apr 19, 2017
The reason they were added is no longer necessary (something for view
edit mode which didn’t pan out).  It was a point of contention:

See #10104
and
#10069 (review)
for background.

Since it’s no longer needed anyway, and this is going to get moved to
react anyhow, I’m removing the unused functionality.
stacey-gammon added a commit to stacey-gammon/kibana that referenced this pull request Apr 19, 2017
The reason they were added is no longer necessary (something for view
edit mode which didn’t pan out).  It was a point of contention:

See elastic#10104
and
elastic#10069 (review)
for background.

Since it’s no longer needed anyway, and this is going to get moved to
react anyhow, I’m removing the unused functionality.
stacey-gammon added a commit that referenced this pull request Apr 19, 2017
The reason they were added is no longer necessary (something for view
edit mode which didn’t pan out).  It was a point of contention:

See #10104
and
#10069 (review)
for background.

Since it’s no longer needed anyway, and this is going to get moved to
react anyhow, I’m removing the unused functionality.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants