@dejwcake/craftable 2.3.0 → 2.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +655 -497
- package/package.json +1 -1
- package/src/components/listing/BulkOperationsBar.vue +19 -4
- package/src/components/listing/ForceDeleteButton.vue +57 -0
- package/src/components/listing/RestoreButton.vue +62 -0
- package/src/components/listing/ShowDeleted.vue +28 -0
- package/src/composables/useBaseListing.js +46 -11
- package/src/index.js +3 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dejwcake/craftable",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.4.0",
|
|
4
4
|
"description": "This is a frontend dependency for Craftable. Craftable is a Laravel-based open-source toolkit for building administration interfaces.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.cjs",
|
|
@@ -13,9 +13,20 @@
|
|
|
13
13
|
|
|
14
14
|
<span class="float-end pe-2">
|
|
15
15
|
<slot>
|
|
16
|
-
<
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
<span class="d-inline-flex gap-2">
|
|
17
|
+
<button v-if="onBulkDelete" class="btn btn-sm btn-danger px-4" @click="onBulkDelete()">
|
|
18
|
+
<i class="fa fa-trash me-1"></i>
|
|
19
|
+
{{ translations.delete_btn }}
|
|
20
|
+
</button>
|
|
21
|
+
<button v-if="onBulkForceDelete" class="btn btn-sm btn-dark px-4" @click="onBulkForceDelete()">
|
|
22
|
+
<i class="fa fa-eraser me-1"></i>
|
|
23
|
+
{{ translations.force_delete_btn }}
|
|
24
|
+
</button>
|
|
25
|
+
<button v-if="onBulkRestore" class="btn btn-sm btn-success text-white px-4" @click="onBulkRestore()">
|
|
26
|
+
<i class="fa fa-trash-arrow-up me-1"></i>
|
|
27
|
+
{{ translations.restore_btn }}
|
|
28
|
+
</button>
|
|
29
|
+
</span>
|
|
19
30
|
</slot>
|
|
20
31
|
</span>
|
|
21
32
|
</template>
|
|
@@ -27,7 +38,9 @@ defineProps({
|
|
|
27
38
|
loading: { type: Boolean, default: false },
|
|
28
39
|
onCheckAll: { type: Function, required: true },
|
|
29
40
|
onUncheckAll: { type: Function, required: true },
|
|
30
|
-
onBulkDelete: { type: Function,
|
|
41
|
+
onBulkDelete: { type: Function, default: null },
|
|
42
|
+
onBulkForceDelete: { type: Function, default: null },
|
|
43
|
+
onBulkRestore: { type: Function, default: null },
|
|
31
44
|
translations: {
|
|
32
45
|
type: Object,
|
|
33
46
|
default: () => ({
|
|
@@ -35,6 +48,8 @@ defineProps({
|
|
|
35
48
|
check_all_items: 'Check all items',
|
|
36
49
|
uncheck_all_items: 'Uncheck all items',
|
|
37
50
|
delete_btn: 'Delete',
|
|
51
|
+
force_delete_btn: 'Delete permanently',
|
|
52
|
+
restore_btn: 'Restore',
|
|
38
53
|
}),
|
|
39
54
|
},
|
|
40
55
|
});
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<button
|
|
3
|
+
type="button"
|
|
4
|
+
class="btn btn-sm btn-dark"
|
|
5
|
+
:title="translations.force_delete_btn"
|
|
6
|
+
@click="showConfirm = true"
|
|
7
|
+
>
|
|
8
|
+
<i class="fa fa-eraser"></i>
|
|
9
|
+
</button>
|
|
10
|
+
|
|
11
|
+
<ConfirmModal
|
|
12
|
+
:show="showConfirm"
|
|
13
|
+
variant="danger"
|
|
14
|
+
:translations="translations"
|
|
15
|
+
@confirm="onConfirm"
|
|
16
|
+
@cancel="showConfirm = false"
|
|
17
|
+
/>
|
|
18
|
+
</template>
|
|
19
|
+
|
|
20
|
+
<script setup>
|
|
21
|
+
import { ref } from 'vue';
|
|
22
|
+
const axios = window.axios;
|
|
23
|
+
import { notifySuccess, notifyError } from '../../utils/notify.js';
|
|
24
|
+
import ConfirmModal from '../ConfirmModal.vue';
|
|
25
|
+
|
|
26
|
+
const props = defineProps({
|
|
27
|
+
url: { type: String, required: true },
|
|
28
|
+
translations: {
|
|
29
|
+
type: Object,
|
|
30
|
+
default: () => ({
|
|
31
|
+
force_delete_btn: 'Delete permanently',
|
|
32
|
+
confirm_title: 'Deletion',
|
|
33
|
+
confirm_text: 'Delete this item permanently? This cannot be undone.',
|
|
34
|
+
confirm_btn: 'Delete permanently',
|
|
35
|
+
cancel_btn: 'Cancel',
|
|
36
|
+
}),
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const emit = defineEmits(['deleted']);
|
|
41
|
+
|
|
42
|
+
const showConfirm = ref(false);
|
|
43
|
+
|
|
44
|
+
function onConfirm() {
|
|
45
|
+
showConfirm.value = false;
|
|
46
|
+
|
|
47
|
+
axios.delete(props.url).then(
|
|
48
|
+
(response) => {
|
|
49
|
+
notifySuccess(response.data.message);
|
|
50
|
+
emit('deleted');
|
|
51
|
+
},
|
|
52
|
+
(error) => {
|
|
53
|
+
notifyError(error.response?.data?.message);
|
|
54
|
+
},
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
</script>
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<span :title="disabled ? translations.not_restorable : translations.restore_btn">
|
|
3
|
+
<button
|
|
4
|
+
type="button"
|
|
5
|
+
class="btn btn-sm btn-success text-white"
|
|
6
|
+
:aria-label="disabled ? translations.not_restorable : translations.restore_btn"
|
|
7
|
+
:disabled="disabled"
|
|
8
|
+
@click="showConfirm = true"
|
|
9
|
+
>
|
|
10
|
+
<i class="fa fa-trash-arrow-up"></i>
|
|
11
|
+
</button>
|
|
12
|
+
</span>
|
|
13
|
+
|
|
14
|
+
<ConfirmModal
|
|
15
|
+
:show="showConfirm"
|
|
16
|
+
variant="success"
|
|
17
|
+
:translations="translations"
|
|
18
|
+
@confirm="onConfirm"
|
|
19
|
+
@cancel="showConfirm = false"
|
|
20
|
+
/>
|
|
21
|
+
</template>
|
|
22
|
+
|
|
23
|
+
<script setup>
|
|
24
|
+
import { ref } from 'vue';
|
|
25
|
+
const axios = window.axios;
|
|
26
|
+
import { notifySuccess, notifyError } from '../../utils/notify.js';
|
|
27
|
+
import ConfirmModal from '../ConfirmModal.vue';
|
|
28
|
+
|
|
29
|
+
const props = defineProps({
|
|
30
|
+
url: { type: String, required: true },
|
|
31
|
+
disabled: { type: Boolean, default: false },
|
|
32
|
+
translations: {
|
|
33
|
+
type: Object,
|
|
34
|
+
default: () => ({
|
|
35
|
+
restore_btn: 'Restore',
|
|
36
|
+
not_restorable: 'This item cannot be restored, an item it belongs to is deleted.',
|
|
37
|
+
confirm_title: 'Restore',
|
|
38
|
+
confirm_text: 'Do you really want to restore this item?',
|
|
39
|
+
confirm_btn: 'Restore',
|
|
40
|
+
cancel_btn: 'Cancel',
|
|
41
|
+
}),
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
const emit = defineEmits(['restored']);
|
|
46
|
+
|
|
47
|
+
const showConfirm = ref(false);
|
|
48
|
+
|
|
49
|
+
function onConfirm() {
|
|
50
|
+
showConfirm.value = false;
|
|
51
|
+
|
|
52
|
+
axios.post(props.url).then(
|
|
53
|
+
(response) => {
|
|
54
|
+
notifySuccess(response.data.message);
|
|
55
|
+
emit('restored');
|
|
56
|
+
},
|
|
57
|
+
(error) => {
|
|
58
|
+
notifyError(error.response?.data?.message);
|
|
59
|
+
},
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
</script>
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
<template>
|
|
2
|
+
<label class="d-inline-flex align-items-center gap-2 mb-0 text-nowrap text-reset">
|
|
3
|
+
<span class="form-check form-switch form-switch-inline mb-0">
|
|
4
|
+
<input
|
|
5
|
+
class="form-check-input"
|
|
6
|
+
type="checkbox"
|
|
7
|
+
role="switch"
|
|
8
|
+
:checked="modelValue"
|
|
9
|
+
@change="$emit('update:modelValue', $event.target.checked)"
|
|
10
|
+
/>
|
|
11
|
+
</span>
|
|
12
|
+
{{ translations.show_deleted }}
|
|
13
|
+
</label>
|
|
14
|
+
</template>
|
|
15
|
+
|
|
16
|
+
<script setup>
|
|
17
|
+
defineProps({
|
|
18
|
+
modelValue: { type: Boolean, default: false },
|
|
19
|
+
translations: {
|
|
20
|
+
type: Object,
|
|
21
|
+
default: () => ({
|
|
22
|
+
show_deleted: 'Show deleted',
|
|
23
|
+
}),
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
defineEmits(['update:modelValue']);
|
|
28
|
+
</script>
|
|
@@ -32,15 +32,18 @@ export function useBaseListing(props) {
|
|
|
32
32
|
const bulkItems = reactive({});
|
|
33
33
|
const bulkCheckingAllLoader = ref(false);
|
|
34
34
|
|
|
35
|
+
const defaultConfirmTranslations = {
|
|
36
|
+
confirm_title: 'Warning!',
|
|
37
|
+
confirm_text: 'Are you sure?',
|
|
38
|
+
confirm_btn: 'Yes, confirm',
|
|
39
|
+
cancel_btn: 'Cancel',
|
|
40
|
+
};
|
|
41
|
+
|
|
35
42
|
const confirmModal = reactive({
|
|
36
43
|
show: false,
|
|
37
44
|
onConfirm: null,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
confirm_text: 'Are you sure?',
|
|
41
|
-
confirm_btn: 'Yes, confirm',
|
|
42
|
-
cancel_btn: 'Cancel',
|
|
43
|
-
},
|
|
45
|
+
variant: 'danger',
|
|
46
|
+
translations: { ...defaultConfirmTranslations },
|
|
44
47
|
});
|
|
45
48
|
|
|
46
49
|
// Update "now" every second
|
|
@@ -152,13 +155,14 @@ export function useBaseListing(props) {
|
|
|
152
155
|
}
|
|
153
156
|
}
|
|
154
157
|
|
|
155
|
-
function
|
|
156
|
-
const
|
|
158
|
+
function bulkAction(url, trans = {}, variant = 'danger') {
|
|
159
|
+
const selectedItems = Object.keys(bulkItems).filter((key) => bulkItems[key]);
|
|
157
160
|
|
|
161
|
+
confirmModal.variant = variant;
|
|
158
162
|
confirmModal.translations = {
|
|
159
|
-
...
|
|
163
|
+
...defaultConfirmTranslations,
|
|
160
164
|
...trans,
|
|
161
|
-
confirm_text: (trans.confirm_text ||
|
|
165
|
+
confirm_text: (trans.confirm_text || defaultConfirmTranslations.confirm_text).replace(
|
|
162
166
|
':number',
|
|
163
167
|
clickedBulkItemsCount.value,
|
|
164
168
|
),
|
|
@@ -167,7 +171,7 @@ export function useBaseListing(props) {
|
|
|
167
171
|
confirmModal.show = false;
|
|
168
172
|
axios
|
|
169
173
|
.post(url, {
|
|
170
|
-
ids:
|
|
174
|
+
ids: selectedItems,
|
|
171
175
|
})
|
|
172
176
|
.then((response) => {
|
|
173
177
|
Object.keys(bulkItems).forEach((key) => delete bulkItems[key]);
|
|
@@ -181,6 +185,34 @@ export function useBaseListing(props) {
|
|
|
181
185
|
confirmModal.show = true;
|
|
182
186
|
}
|
|
183
187
|
|
|
188
|
+
function bulkDelete(url, trans = {}) {
|
|
189
|
+
bulkAction(url, {
|
|
190
|
+
...trans,
|
|
191
|
+
confirm_text: trans.confirm_text || 'Do you really want to delete :number selected items?',
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function bulkForceDelete(url, trans = {}) {
|
|
196
|
+
bulkAction(url, {
|
|
197
|
+
confirm_btn: 'Delete permanently',
|
|
198
|
+
...trans,
|
|
199
|
+
confirm_text: trans.confirm_text || 'Delete :number selected items permanently? This cannot be undone.',
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
function bulkRestore(url, trans = {}) {
|
|
204
|
+
bulkAction(
|
|
205
|
+
url,
|
|
206
|
+
{
|
|
207
|
+
confirm_title: 'Restore',
|
|
208
|
+
confirm_btn: 'Restore',
|
|
209
|
+
...trans,
|
|
210
|
+
confirm_text: trans.confirm_text || 'Do you really want to restore :number selected items?',
|
|
211
|
+
},
|
|
212
|
+
'success',
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
184
216
|
function loadData(resetCurrentPage) {
|
|
185
217
|
const options = {
|
|
186
218
|
params: {
|
|
@@ -298,7 +330,10 @@ export function useBaseListing(props) {
|
|
|
298
330
|
onBulkItemsClickedAll,
|
|
299
331
|
onBulkItemsClickedAllWithPagination,
|
|
300
332
|
onBulkItemsClickedAllUncheck,
|
|
333
|
+
bulkAction,
|
|
301
334
|
bulkDelete,
|
|
335
|
+
bulkForceDelete,
|
|
336
|
+
bulkRestore,
|
|
302
337
|
loadData,
|
|
303
338
|
filter,
|
|
304
339
|
resolveUrl,
|
package/src/index.js
CHANGED
|
@@ -25,6 +25,9 @@ export { default as ListingHeader } from './components/listing/ListingHeader.vue
|
|
|
25
25
|
export { default as ShowButton } from './components/listing/ShowButton.vue';
|
|
26
26
|
export { default as EditButton } from './components/listing/EditButton.vue';
|
|
27
27
|
export { default as DeleteButton } from './components/listing/DeleteButton.vue';
|
|
28
|
+
export { default as ForceDeleteButton } from './components/listing/ForceDeleteButton.vue';
|
|
29
|
+
export { default as RestoreButton } from './components/listing/RestoreButton.vue';
|
|
30
|
+
export { default as ShowDeleted } from './components/listing/ShowDeleted.vue';
|
|
28
31
|
export { default as BackButton } from './components/BackButton.vue';
|
|
29
32
|
export { default as ConfirmModal } from './components/ConfirmModal.vue';
|
|
30
33
|
export { default as ToggleSwitch } from './components/listing/ToggleSwitch.vue';
|