-
Notifications
You must be signed in to change notification settings - Fork 917
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
[Feature Request] Implement a CanBeDeletedInterface #5210
Comments
Updated version of Note: simpler HTML, added a js function to handle cannot-delete buttons.
@if ($crud->hasAccess('delete'))
<a href="javascript:void(0)"
class="btn btn-sm btn-link"
@if($entry instanceof \App\Models\Interfaces\CanBeDeletedInterface && $entry->can_be_deleted === false)
onclick="cannotDeleteEntry(this)"
data-button-type="canont-delete"
data-toggle="tooltip" data-placement="top" title="{{ $entry->why_cannot_be_deleted }}"
@else
data-button-type="delete"
onclick="deleteEntry(this)"
data-route="{{ url($crud->route.'/'.$entry->getKey()) }}"
@endif
>
<span><i class="la la-trash"></i> {{ trans('backpack::crud.delete') }}</span>
</a>
@endif
{{-- Button Javascript --}}
{{-- - used right away in AJAX operations (ex: List) --}}
{{-- - pushed to the end of the page, after jQuery is loaded, for non-AJAX operations (ex: Show) --}}
@push('after_scripts') @if (request()->ajax()) @endpush @endif
@bassetBlock('backpack/crud/buttons/delete-button-'.app()->getLocale().'.js')
<script>
if (typeof deleteEntry != 'function') {
$("[data-button-type=delete]").unbind('click');
function deleteEntry(button) {
// ask for confirmation before deleting an item
// e.preventDefault();
var route = $(button).attr('data-route');
swal({
title: "{!! trans('backpack::base.warning') !!}",
text: "{!! trans('backpack::crud.delete_confirm') !!}",
icon: "warning",
buttons: ["{!! trans('backpack::crud.cancel') !!}", "{!! trans('backpack::crud.delete') !!}"],
dangerMode: true,
}).then((value) => {
if (value) {
$.ajax({
url: route,
type: 'DELETE',
success: function(result) {
if (result == 1) {
// Redraw the table
if (typeof crud != 'undefined' && typeof crud.table != 'undefined') {
// Move to previous page in case of deleting the only item in table
if(crud.table.rows().count() === 1) {
crud.table.page("previous");
}
crud.table.draw(false);
}
// Show a success notification bubble
new Noty({
type: "success",
text: "{!! '<strong>'.trans('backpack::crud.delete_confirmation_title').'</strong><br>'.trans('backpack::crud.delete_confirmation_message') !!}"
}).show();
// Hide the modal, if any
$('.modal').modal('hide');
} else {
// if the result is an array, it means
// we have notification bubbles to show
if (result instanceof Object) {
// trigger one or more bubble notifications
Object.entries(result).forEach(function(entry, index) {
var type = entry[0];
entry[1].forEach(function(message, i) {
new Noty({
type: type,
text: message
}).show();
});
});
} else {// Show an error alert
swal({
title: "{!! trans('backpack::crud.delete_confirmation_not_title') !!}",
text: "{!! trans('backpack::crud.delete_confirmation_not_message') !!}",
icon: "error",
timer: 4000,
buttons: false,
});
}
}
},
error: function(result) {
// Show an alert with the result
swal({
title: "{!! trans('backpack::crud.delete_confirmation_not_title') !!}",
text: "{!! trans('backpack::crud.delete_confirmation_not_message') !!}",
icon: "error",
timer: 4000,
buttons: false,
});
}
});
}
});
}
}
if (typeof cannotDeleteEntry != 'function') {
$("[data-button-type=cannot-delete]").unbind('click');
function cannotDeleteEntry(button) {
swal({
title: "{!! trans('backpack::base.warning') !!}",
text: $(button).attr('title') ,
icon: "warning",
})
}
}
// make it so that the function above is run after each DataTable draw event
// crud.addFunctionToDataTablesDrawEventQueue('deleteEntry');
</script>
@endBassetBlock
@if (!request()->ajax()) @endpush @endif |
Thanks for sharing your code @realtebo 🙏 I agree we don't have a good solution for this, at the moment. You can't easily allow/deny item-access right now in Backpack. And we should probably work on that. But I don't think we should go for this solution, but a more general one. One that could apply to ALL operations, not just to Delete. Because ok your use case is to hide the Delete button. But what if the need is to hide the Clone button? Or the Edit button? Then we'd need to do the same thing inside all our Operations, which is not ok - it'll end up pretty spaghetti. I'll tag this to think about in v6.x when we have more time. Right now we're swamped with the launch of 6.0. Until then I'm sure your code will help someone fix their problem. Thanks! |
I have great news @realtebo - we have a solution for this now. And it's beautiful! Check out Access Closures - https://backpackforlaravel.com/articles/tutorials/new-in-v6-granular-user-access-using-custom-closures - using them you can define that the Delete operation is forbidden for some entries. And this will not only hide the button, but also prevent the routes from working. Which is exactly what you needed, I think 🎉 |
Feature Request
What's the feature you think Backpack should have?
In a common list , we have usually the delete button.
But some entry cannot be deleted, if they are related from other records, to ensure data integrity.
Usually this check is done my the db, but we could think to add some 'live checks' to single entry to allow the delete button to be dinamically disabled
Have you already implemented a prototype solution, for your own project?
We created
app/Models/Interfaces/CanBeDeletedInterface.php
A model could implement this interface.
For example: if an Organization has at least one active member, the organization cannot be deleted.
We customized delete button in
resources/views/vendor/backpack/crud/buttons/delete.blade.php
This is the relevant part of our implementation
Do you see this as a core feature or an add-on?
I think it could be a core feature, because it's plug-n-play
The text was updated successfully, but these errors were encountered: