Skip to content

Commit 8938cf6

Browse files
authored
Merge pull request #315 from basemate/sf/action-confirm-option-issue-257
Implementing confirm option for action component
2 parents b58de2e + b438fda commit 8938cf6

File tree

6 files changed

+220
-75
lines changed

6 files changed

+220
-75
lines changed

app/concepts/matestack/ui/core/action/action.js

Lines changed: 49 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -14,50 +14,55 @@ const componentDef = {
1414
methods: {
1515
perform: function(){
1616
const self = this
17-
axios({
18-
method: self.componentConfig["method"],
19-
url: self.componentConfig["action_path"],
20-
data: self.componentConfig["data"],
21-
headers: {
22-
'X-CSRF-Token': document.getElementsByName("csrf-token")[0].getAttribute('content')
23-
}
24-
})
25-
.then(function(response){
26-
if (self.componentConfig["success"] != undefined && self.componentConfig["success"]["emit"] != undefined) {
27-
matestackEventHub.$emit(self.componentConfig["success"]["emit"], response.data);
28-
}
29-
if (self.componentConfig["success"] != undefined
30-
&& self.componentConfig["success"]["transition"] != undefined
31-
&& (
32-
self.componentConfig["success"]["transition"]["follow_response"] == undefined
33-
||
34-
self.componentConfig["success"]["transition"]["follow_response"] === false
35-
)
36-
&& self.$store != undefined
37-
) {
38-
let path = self.componentConfig["success"]["transition"]["path"]
39-
self.$store.dispatch('navigateTo', {url: path, backwards: false})
40-
return;
41-
}
42-
if (self.componentConfig["success"] != undefined
43-
&& self.componentConfig["success"]["transition"] != undefined
44-
&& self.componentConfig["success"]["transition"]["follow_response"] === true
45-
&& self.$store != undefined
46-
) {
47-
let path = response.data["transition_to"] || response.request.responseURL;
48-
self.$store.dispatch('navigateTo', {url: path, backwards: false});
49-
return;
50-
}
51-
})
52-
.catch(function(error){
53-
if (self.componentConfig["failure"] != undefined && self.componentConfig["failure"]["emit"] != undefined) {
54-
matestackEventHub.$emit(self.componentConfig["failure"]["emit"], error.response.data);
55-
}
56-
if (self.componentConfig["failure"] != undefined && self.componentConfig["failure"]["transition"] != undefined && self.$store != undefined) {
57-
let path = self.componentConfig["failure"]["transition"]["path"]
58-
self.$store.dispatch('navigateTo', {url: path, backwards: false})
59-
}
60-
})
17+
if (
18+
(self.componentConfig["confirm"] == undefined) || confirm(self.componentConfig["confirm_text"])
19+
)
20+
{
21+
axios({
22+
method: self.componentConfig["method"],
23+
url: self.componentConfig["action_path"],
24+
data: self.componentConfig["data"],
25+
headers: {
26+
'X-CSRF-Token': document.getElementsByName("csrf-token")[0].getAttribute('content')
27+
}
28+
})
29+
.then(function(response){
30+
if (self.componentConfig["success"] != undefined && self.componentConfig["success"]["emit"] != undefined) {
31+
matestackEventHub.$emit(self.componentConfig["success"]["emit"], response.data);
32+
}
33+
if (self.componentConfig["success"] != undefined
34+
&& self.componentConfig["success"]["transition"] != undefined
35+
&& (
36+
self.componentConfig["success"]["transition"]["follow_response"] == undefined
37+
||
38+
self.componentConfig["success"]["transition"]["follow_response"] === false
39+
)
40+
&& self.$store != undefined
41+
) {
42+
let path = self.componentConfig["success"]["transition"]["path"]
43+
self.$store.dispatch('navigateTo', {url: path, backwards: false})
44+
return;
45+
}
46+
if (self.componentConfig["success"] != undefined
47+
&& self.componentConfig["success"]["transition"] != undefined
48+
&& self.componentConfig["success"]["transition"]["follow_response"] === true
49+
&& self.$store != undefined
50+
) {
51+
let path = response.data["transition_to"] || response.request.responseURL;
52+
self.$store.dispatch('navigateTo', {url: path, backwards: false});
53+
return;
54+
}
55+
})
56+
.catch(function(error){
57+
if (self.componentConfig["failure"] != undefined && self.componentConfig["failure"]["emit"] != undefined) {
58+
matestackEventHub.$emit(self.componentConfig["failure"]["emit"], error.response.data);
59+
}
60+
if (self.componentConfig["failure"] != undefined && self.componentConfig["failure"]["transition"] != undefined && self.$store != undefined) {
61+
let path = self.componentConfig["failure"]["transition"]["path"]
62+
self.$store.dispatch('navigateTo', {url: path, backwards: false})
63+
}
64+
})
65+
}
6166
}
6267
}
6368
}

app/concepts/matestack/ui/core/action/action.rb

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ def setup
1919
if options[:notify].nil?
2020
@component_config[:notify] = true
2121
end
22+
if @component_config[:confirm] = options[:confirm]
23+
@component_config[:confirm_text] = options[:confirm].try(:[], :text) || "Are you sure?"
24+
end
2225
end
2326

2427
def action_path

docs/components/action.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ data: {
3838
}
3939
```
4040

41+
### Confirm
42+
43+
When specified, a [browser-native confirm dialog](https://developer.mozilla.org/en-US/docs/Web/API/Window/confirm) is shown before the action is actually performed. The action only is performed after the user confirms. The action is not performed if the user declines to confirm dialog.
44+
45+
```ruby
46+
confirm: {
47+
text: "Do you really want to delete this item?"
48+
}
49+
```
50+
51+
If no `text` is given, the default text "Are you sure?" will be used.
52+
53+
```ruby
54+
confirm: true
55+
```
56+
4157
### Success
4258

4359
The success part of the action component gets triggered once the action we wanted to perform returns a success code, usually the `200` HTTP status code.

spec/usage/components/action_spec.rb

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,125 @@ def page2
384384

385385
end
386386

387+
specify "Async delete request with confirm option" do
388+
389+
class ActionTestController < TestController
390+
def destroy
391+
render json: {}, status: 200
392+
end
393+
end
394+
395+
Rails.application.routes.append do
396+
delete '/action_test', to: 'action_test#destroy', as: 'action_destroy_test'
397+
end
398+
Rails.application.reload_routes!
399+
400+
class ExamplePage < Matestack::Ui::Page
401+
402+
def response
403+
components {
404+
action action_config do
405+
button text: "Click me!"
406+
end
407+
async show_on: "my_action_success", hide_after: 300 do
408+
plain "Well done!"
409+
end
410+
}
411+
end
412+
413+
def action_config
414+
return {
415+
method: :delete,
416+
path: :action_destroy_test_path,
417+
data: {
418+
foo: "bar"
419+
},
420+
confirm: {
421+
text: "Are you sure?"
422+
},
423+
success: {
424+
emit: "my_action_success"
425+
}
426+
}
427+
end
428+
429+
end
430+
431+
visit "/example"
432+
433+
# https://stackoverflow.com/a/34888404/2066546
434+
# https://github.com/teamcapybara/capybara#modals
435+
dismiss_confirm do
436+
click_button "Click me!"
437+
end
438+
439+
expect(page).to have_no_text "Well done!"
440+
441+
accept_confirm do
442+
click_button "Click me!"
443+
end
444+
445+
expect(page).to have_text "Well done!"
446+
end
447+
448+
end
449+
450+
it 'does not require a confirm text option' do
451+
# When no confirm text is given, the default "Are you sure?" will be used.
452+
453+
class ActionTestController < TestController
454+
def destroy
455+
render json: {}, status: 200
456+
end
457+
end
458+
459+
Rails.application.routes.append do
460+
delete '/action_test', to: 'action_test#destroy', as: 'action_destroy_default_text_test'
461+
end
462+
Rails.application.reload_routes!
463+
464+
class ExamplePage < Matestack::Ui::Page
465+
466+
def response
467+
components {
468+
action action_config do
469+
button text: "Click me!"
470+
end
471+
async show_on: "my_action_success", hide_after: 300 do
472+
plain "Well done!"
473+
end
474+
}
475+
end
476+
477+
def action_config
478+
return {
479+
method: :delete,
480+
path: :action_destroy_default_text_test_path,
481+
data: {
482+
foo: "bar"
483+
},
484+
confirm: true,
485+
success: {
486+
emit: "my_action_success"
487+
}
488+
}
489+
end
490+
491+
end
492+
493+
visit "/example"
494+
495+
dismiss_confirm do
496+
click_button "Click me!"
497+
end
498+
499+
expect(page).to have_no_text "Well done!"
500+
501+
accept_confirm do
502+
click_button "Click me!"
503+
end
504+
505+
expect(page).to have_text "Well done!"
387506
end
388507

389508
it 'accepts class and id attributes and returns them as the corresponding HTML attributes' do

vendor/assets/javascripts/matestack-ui-core.js

Lines changed: 32 additions & 30 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vendor/assets/javascripts/matestack-ui-core.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)