Skip to content

Commit

Permalink
ability to use action on the detail view
Browse files Browse the repository at this point in the history
  • Loading branch information
João Santos committed Jun 7, 2020
1 parent 622ab5a commit 0bfa986
Show file tree
Hide file tree
Showing 4 changed files with 198 additions and 19 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@

## 0.3.0 - 2020-06-07

- ability to change button text 02b9408
- ability to change button text
- ability to use action button on detail view
2 changes: 1 addition & 1 deletion dist/js/field.js

Large diffs are not rendered by default.

182 changes: 180 additions & 2 deletions resources/js/components/DetailField.vue
Original file line number Diff line number Diff line change
@@ -1,9 +1,187 @@
<template>
<panel-item :field="field" />
<panel-item :field="field">
<template v-slot:value>
<button
class="btn btn-default btn-primary"
@click="confirmActionModalOpened = true"
:disabled="field.readonly"
>
{{ buttonText }}
</button>

<!-- Action Confirmation Modal -->
<portal to="modals" transition="fade-transition">
<component
v-if="confirmActionModalOpened"
class="text-left"
:is="field.action.component"
:working="working"
:selected-resources="selectedResources"
:resource-name="resourceName"
:action="selectedAction"
:errors="errors"
@confirm="executeAction"
@close="confirmActionModalOpened = false"
/>
</portal>
</template>
</panel-item>
</template>

<script>
import { Errors, FormField, HandlesValidationErrors, InteractsWithResourceInformation } from 'laravel-nova'
export default {
props: ['resource', 'resourceName', 'resourceId', 'field'],
mixins: [FormField, HandlesValidationErrors, InteractsWithResourceInformation],
props: {
resource: String,
resourceName: String,
resourceId: Number,
field: Object,
queryString: {
type: Object,
default: () => ({
currentSearch: '',
encodedFilters: '',
currentTrashed: '',
viaResource: '',
viaResourceId: '',
viaRelationship: '',
}),
},
},
data: () => ({
working: false,
confirmActionModalOpened: false,
}),
methods: {
/**
* Confirm with the user that they actually want to run the selected action.
*/
openConfirmationModal() {
this.confirmActionModalOpened = true
},
/**
* Close the action confirmation modal.
*/
closeConfirmationModal() {
this.confirmActionModalOpened = false
this.errors = new Errors()
},
/**
* Execute the selected action.
*/
executeAction() {
this.working = true
if (this.selectedResources.length == 0) {
alert(this.__('Please select a resource to perform this action on.'))
return
}
Nova.request({
method: 'post',
url: this.endpoint || `/nova-api/${this.resourceName}/action`,
params: this.actionRequestQueryString,
data: this.actionFormData(),
})
.then(response => {
this.confirmActionModalOpened = false
this.handleActionResponse(response.data)
this.working = false
})
.catch(error => {
this.working = false
if (error.response.status == 422) {
this.errors = new Errors(error.response.data.errors)
Nova.error(this.__('There was a problem executing the action.'))
}
})
},
/**
* Gather the action FormData for the given action.
*/
actionFormData() {
return _.tap(new FormData(), formData => {
formData.append('resources', this.selectedResources)
_.each(this.selectedAction.fields, field => {
field.fill(formData)
})
})
},
/**
* Handle the action response. Typically either a message, download or a redirect.
*/
handleActionResponse(data) {
this.$parent.$parent.$children[2].$emit('actionExecuted')
if (data.message) {
this.$parent.$parent.$children[2].$emit('actionExecuted')
Nova.$emit('action-executed')
Nova.success(data.message)
} else if (data.deleted) {
this.$parent.$parent.$children[2].$emit('actionExecuted')
Nova.$emit('action-executed')
} else if (data.danger) {
this.$parent.$parent.$children[2].$emit('actionExecuted')
Nova.$emit('action-executed')
Nova.error(data.danger)
} else if (data.download) {
let link = document.createElement('a')
link.href = data.download
link.download = data.name
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
} else if (data.redirect) {
window.location = data.redirect
} else if (data.push) {
this.$router.push(data.push)
} else if (data.openInNewTab) {
window.open(data.openInNewTab, '_blank')
} else {
this.$parent.$parent.$children[2].$emit('actionExecuted')
Nova.$emit('action-executed')
Nova.success(this.__('The action ran successfully!'))
}
},
},
computed: {
selectedResources() {
return this.field.resourceId;
},
selectedAction() {
return this.field.action;
},
/**
* Get the query string for an action request.
*/
actionRequestQueryString() {
return {
action: this.selectedAction.uriKey,
search: this.queryString.currentSearch,
filters: this.queryString.encodedFilters,
trashed: this.queryString.currentTrashed,
viaResource: this.queryString.viaResource,
viaResourceId: this.queryString.viaResourceId,
viaRelationship: this.queryString.viaRelationship,
}
},
buttonText() {
return this.field.text || this.__('Run');
}
}
}
</script>
30 changes: 15 additions & 15 deletions resources/js/components/IndexField.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,21 @@
{{ buttonText }}
</button>

<!-- Action Confirmation Modal -->
<portal to="modals" transition="fade-transition">
<component
v-if="confirmActionModalOpened"
class="text-left"
:is="field.action.component"
:working="working"
:selected-resources="selectedResources"
:resource-name="resourceName"
:action="selectedAction"
:errors="errors"
@confirm="executeAction"
@close="confirmActionModalOpened = false"
/>
</portal>
<!-- Action Confirmation Modal -->
<portal to="modals" transition="fade-transition">
<component
v-if="confirmActionModalOpened"
class="text-left"
:is="field.action.component"
:working="working"
:selected-resources="selectedResources"
:resource-name="resourceName"
:action="selectedAction"
:errors="errors"
@confirm="executeAction"
@close="confirmActionModalOpened = false"
/>
</portal>
</div>
</template>

Expand Down

0 comments on commit 0bfa986

Please sign in to comment.