Skip to content

Implementing confirm option for action component #315

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

Merged
merged 6 commits into from
Jan 3, 2020
Merged
Show file tree
Hide file tree
Changes from all 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
93 changes: 49 additions & 44 deletions app/concepts/matestack/ui/core/action/action.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,50 +14,55 @@ const componentDef = {
methods: {
perform: function(){
const self = this
axios({
method: self.componentConfig["method"],
url: self.componentConfig["action_path"],
data: self.componentConfig["data"],
headers: {
'X-CSRF-Token': document.getElementsByName("csrf-token")[0].getAttribute('content')
}
})
.then(function(response){
if (self.componentConfig["success"] != undefined && self.componentConfig["success"]["emit"] != undefined) {
matestackEventHub.$emit(self.componentConfig["success"]["emit"], response.data);
}
if (self.componentConfig["success"] != undefined
&& self.componentConfig["success"]["transition"] != undefined
&& (
self.componentConfig["success"]["transition"]["follow_response"] == undefined
||
self.componentConfig["success"]["transition"]["follow_response"] === false
)
&& self.$store != undefined
) {
let path = self.componentConfig["success"]["transition"]["path"]
self.$store.dispatch('navigateTo', {url: path, backwards: false})
return;
}
if (self.componentConfig["success"] != undefined
&& self.componentConfig["success"]["transition"] != undefined
&& self.componentConfig["success"]["transition"]["follow_response"] === true
&& self.$store != undefined
) {
let path = response.data["transition_to"] || response.request.responseURL;
self.$store.dispatch('navigateTo', {url: path, backwards: false});
return;
}
})
.catch(function(error){
if (self.componentConfig["failure"] != undefined && self.componentConfig["failure"]["emit"] != undefined) {
matestackEventHub.$emit(self.componentConfig["failure"]["emit"], error.response.data);
}
if (self.componentConfig["failure"] != undefined && self.componentConfig["failure"]["transition"] != undefined && self.$store != undefined) {
let path = self.componentConfig["failure"]["transition"]["path"]
self.$store.dispatch('navigateTo', {url: path, backwards: false})
}
})
if (
(self.componentConfig["confirm"] == undefined) || confirm(self.componentConfig["confirm_text"])
)
{
axios({
method: self.componentConfig["method"],
url: self.componentConfig["action_path"],
data: self.componentConfig["data"],
headers: {
'X-CSRF-Token': document.getElementsByName("csrf-token")[0].getAttribute('content')
}
})
.then(function(response){
if (self.componentConfig["success"] != undefined && self.componentConfig["success"]["emit"] != undefined) {
matestackEventHub.$emit(self.componentConfig["success"]["emit"], response.data);
}
if (self.componentConfig["success"] != undefined
&& self.componentConfig["success"]["transition"] != undefined
&& (
self.componentConfig["success"]["transition"]["follow_response"] == undefined
||
self.componentConfig["success"]["transition"]["follow_response"] === false
)
&& self.$store != undefined
) {
let path = self.componentConfig["success"]["transition"]["path"]
self.$store.dispatch('navigateTo', {url: path, backwards: false})
return;
}
if (self.componentConfig["success"] != undefined
&& self.componentConfig["success"]["transition"] != undefined
&& self.componentConfig["success"]["transition"]["follow_response"] === true
&& self.$store != undefined
) {
let path = response.data["transition_to"] || response.request.responseURL;
self.$store.dispatch('navigateTo', {url: path, backwards: false});
return;
}
})
.catch(function(error){
if (self.componentConfig["failure"] != undefined && self.componentConfig["failure"]["emit"] != undefined) {
matestackEventHub.$emit(self.componentConfig["failure"]["emit"], error.response.data);
}
if (self.componentConfig["failure"] != undefined && self.componentConfig["failure"]["transition"] != undefined && self.$store != undefined) {
let path = self.componentConfig["failure"]["transition"]["path"]
self.$store.dispatch('navigateTo', {url: path, backwards: false})
}
})
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions app/concepts/matestack/ui/core/action/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ def setup
if options[:notify].nil?
@component_config[:notify] = true
end
if @component_config[:confirm] = options[:confirm]
@component_config[:confirm_text] = options[:confirm].try(:[], :text) || "Are you sure?"
end
end

def action_path
Expand Down
16 changes: 16 additions & 0 deletions docs/components/action.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,22 @@ data: {
}
```

### Confirm

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.

```ruby
confirm: {
text: "Do you really want to delete this item?"
}
```

If no `text` is given, the default text "Are you sure?" will be used.

```ruby
confirm: true
```

### Success

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.
Expand Down
119 changes: 119 additions & 0 deletions spec/usage/components/action_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -384,6 +384,125 @@ def page2

end

specify "Async delete request with confirm option" do

class ActionTestController < TestController
def destroy
render json: {}, status: 200
end
end

Rails.application.routes.append do
delete '/action_test', to: 'action_test#destroy', as: 'action_destroy_test'
end
Rails.application.reload_routes!

class ExamplePage < Matestack::Ui::Page

def response
components {
action action_config do
button text: "Click me!"
end
async show_on: "my_action_success", hide_after: 300 do
plain "Well done!"
end
}
end

def action_config
return {
method: :delete,
path: :action_destroy_test_path,
data: {
foo: "bar"
},
confirm: {
text: "Are you sure?"
},
success: {
emit: "my_action_success"
}
}
end

end

visit "/example"

# https://stackoverflow.com/a/34888404/2066546
# https://github.com/teamcapybara/capybara#modals
dismiss_confirm do
click_button "Click me!"
end

expect(page).to have_no_text "Well done!"

accept_confirm do
click_button "Click me!"
end

expect(page).to have_text "Well done!"
end

end

it 'does not require a confirm text option' do
# When no confirm text is given, the default "Are you sure?" will be used.

class ActionTestController < TestController
def destroy
render json: {}, status: 200
end
end

Rails.application.routes.append do
delete '/action_test', to: 'action_test#destroy', as: 'action_destroy_default_text_test'
end
Rails.application.reload_routes!

class ExamplePage < Matestack::Ui::Page

def response
components {
action action_config do
button text: "Click me!"
end
async show_on: "my_action_success", hide_after: 300 do
plain "Well done!"
end
}
end

def action_config
return {
method: :delete,
path: :action_destroy_default_text_test_path,
data: {
foo: "bar"
},
confirm: true,
success: {
emit: "my_action_success"
}
}
end

end

visit "/example"

dismiss_confirm do
click_button "Click me!"
end

expect(page).to have_no_text "Well done!"

accept_confirm do
click_button "Click me!"
end

expect(page).to have_text "Well done!"
end

it 'accepts class and id attributes and returns them as the corresponding HTML attributes' do
Expand Down
62 changes: 32 additions & 30 deletions vendor/assets/javascripts/matestack-ui-core.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion vendor/assets/javascripts/matestack-ui-core.js.map

Large diffs are not rendered by default.