vue-laravel-crud 1.8.5 → 2.0.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.
@@ -0,0 +1,65 @@
1
+ <template>
2
+ <div class="kanban-board">
3
+ <div v-for="(column, colIndex) in items" :key="colIndex" class="kanban-column">
4
+ <KanbanColumn
5
+ :column="column"
6
+ :colIndex="colIndex"
7
+ :groupedAttribute="groupedAttribute"
8
+ :columns="columns"
9
+ :itemValue="itemValue"
10
+ :getStateValue="getStateValue"
11
+ :getArrayValue="getArrayValue"
12
+ :showItem="showItem"
13
+ :updateItem="updateItem"
14
+ :removeItem="removeItem"
15
+ :cardClass="cardClass"
16
+ :cardHideFooter="cardHideFooter"
17
+ @draggableChange="onDraggableChange"
18
+ />
19
+ </div>
20
+ </div>
21
+ </template>
22
+
23
+ <script>
24
+ import KanbanColumn from './KanbanColumn.vue';
25
+
26
+ export default {
27
+ name: 'KanbanBoard',
28
+ components: {
29
+ KanbanColumn
30
+ },
31
+ inject: [
32
+ 'items',
33
+ 'groupedAttribute',
34
+ 'columns',
35
+ 'itemValue',
36
+ 'getStateValue',
37
+ 'getArrayValue',
38
+ 'showItem',
39
+ 'updateItem',
40
+ 'removeItem',
41
+ 'cardClass',
42
+ 'cardHideFooter',
43
+ 'onDraggableChange'
44
+ ]
45
+ };
46
+ </script>
47
+
48
+ <style scoped>
49
+ .kanban-board {
50
+ display: flex;
51
+ gap: 1rem;
52
+ overflow-x: auto;
53
+ padding: 1rem;
54
+ }
55
+
56
+ .kanban-column {
57
+ background: #f4f5f7;
58
+ border-radius: 8px;
59
+ width: 300px;
60
+ display: flex;
61
+ flex-direction: column;
62
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
63
+ min-width: 300px;
64
+ }
65
+ </style>
@@ -0,0 +1,103 @@
1
+ <template>
2
+ <div class="kanban-card">
3
+ <b-card
4
+ :title="item.title || item.name || `Item ${item.id}`"
5
+ tag="article"
6
+ class="mb-2 card-crud"
7
+ :class="cardClass"
8
+ :hide-footer="cardHideFooter"
9
+ >
10
+ <slot name="card" v-bind:item="item">
11
+ <div v-for="(column, indexc) in columns" :key="indexc">
12
+ <b-card-text v-if="column.type !== 'actions' && column.prop !== 'id'">
13
+ <small class="text-muted">{{ column.label }}:</small>
14
+ <div class="mb-1">
15
+ <slot :name="'cell-' + column.prop" v-bind:item="item" v-bind:index="index" v-bind:itemindex="index"
16
+ v-bind:columnindex="indexc">
17
+ <span v-if="column.type === 'boolean'">
18
+ <b-badge variant="success" v-if="itemValue(column, item)"><b-icon-check-circle></b-icon-check-circle></b-badge>
19
+ <b-badge variant="danger" v-else><b-icon-x-circle></b-icon-x-circle></b-badge>
20
+ </span>
21
+ <span v-else-if="column.type === 'date'">
22
+ {{ itemValue(column, item) }}
23
+ </span>
24
+ <span v-else-if="column.type === 'state'">
25
+ {{ getStateValue(itemValue(column, item), column.options) }}
26
+ </span>
27
+ <span v-else-if="column.type === 'array'">
28
+ {{ getArrayValue(itemValue(column, item), column.displayProp, column.options) }}
29
+ </span>
30
+ <span v-else>
31
+ {{ itemValue(column, item) }}
32
+ </span>
33
+ </slot>
34
+ </div>
35
+ </b-card-text>
36
+ </div>
37
+ </slot>
38
+
39
+ <template v-slot:footer>
40
+ <b-button-group size="sm">
41
+ <slot name="rowAction" v-bind:item="item" v-bind:index="index" v-bind:showItem="showItem"
42
+ v-bind:updateItem="updateItem" v-bind:removeItem="removeItem">
43
+ <b-button variant="primary" @click="showItem(item.id, index)"><b-icon-eye></b-icon-eye></b-button>
44
+ <b-button variant="secondary" @click="updateItem(item.id, index)"><b-icon-pencil></b-icon-pencil></b-button>
45
+ <b-button variant="danger" @click="removeItem(item.id, index)"><b-icon-trash></b-icon-trash></b-button>
46
+ </slot>
47
+ </b-button-group>
48
+ </template>
49
+ </b-card>
50
+ </div>
51
+ </template>
52
+
53
+ <script>
54
+ export default {
55
+ name: 'KanbanCard',
56
+ props: {
57
+ item: Object,
58
+ columns: Array,
59
+ index: Number,
60
+ cardClass: String,
61
+ cardHideFooter: Boolean,
62
+ itemValue: Function,
63
+ getStateValue: Function,
64
+ getArrayValue: Function,
65
+ showItem: Function,
66
+ updateItem: Function,
67
+ removeItem: Function,
68
+ }
69
+ };
70
+ </script>
71
+
72
+ <style scoped>
73
+ .kanban-card {
74
+ background: #ffffff;
75
+ border-radius: 4px;
76
+ padding: 0.5rem;
77
+ box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
78
+ cursor: grab;
79
+ transition: box-shadow 0.2s ease;
80
+ }
81
+
82
+ .kanban-card:hover {
83
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
84
+ }
85
+
86
+ .kanban-card:active {
87
+ cursor: grabbing;
88
+ }
89
+
90
+ .card-crud {
91
+ border: 1px solid #e1e5e9;
92
+ }
93
+
94
+ .card-crud .card-title {
95
+ font-size: 0.9rem;
96
+ margin-bottom: 0.5rem;
97
+ }
98
+
99
+ .card-crud .card-text {
100
+ font-size: 0.8rem;
101
+ margin-bottom: 0.25rem;
102
+ }
103
+ </style>
@@ -0,0 +1,110 @@
1
+ <template>
2
+ <div class="kanban-column">
3
+ <div class="kanban-column-header">
4
+ <div class="d-flex justify-content-between align-items-center">
5
+ <span>{{ column.groupLabel }}</span>
6
+ <b-badge variant="secondary">{{ column.items.length }}</b-badge>
7
+ </div>
8
+ </div>
9
+
10
+ <draggable
11
+ v-model="column.items"
12
+ group="kanban"
13
+ class="kanban-column-body"
14
+ @end="onDragEnd"
15
+ :data-column="column.groupKey"
16
+ >
17
+ <div v-for="(item, itemIndex) in column.items" v-bind:key="itemIndex" class="item">
18
+ <slot name="card" v-bind:item="item">
19
+ <KanbanCard
20
+ :key="itemIndex"
21
+ :item="item"
22
+ :columns="columns"
23
+ :index="itemIndex"
24
+ :cardClass="cardClass"
25
+ :cardHideFooter="cardHideFooter"
26
+ :itemValue="itemValue"
27
+ :getStateValue="getStateValue"
28
+ :getArrayValue="getArrayValue"
29
+ :showItem="showItem"
30
+ :updateItem="updateItem"
31
+ :removeItem="removeItem"
32
+ />
33
+ </slot>
34
+ </div>
35
+ </draggable>
36
+ </div>
37
+ </template>
38
+
39
+ <script>
40
+ import draggable from "vuedraggable";
41
+ import KanbanCard from './KanbanCard.vue';
42
+
43
+ export default {
44
+ name: 'KanbanColumn',
45
+ components: {
46
+ draggable,
47
+ KanbanCard
48
+ },
49
+ props: {
50
+ column: Object,
51
+ colIndex: Number,
52
+ groupedAttribute: String,
53
+ columns: Array,
54
+ itemValue: Function,
55
+ getStateValue: Function,
56
+ getArrayValue: Function,
57
+ showItem: Function,
58
+ updateItem: Function,
59
+ removeItem: Function,
60
+ cardClass: String,
61
+ cardHideFooter: Boolean
62
+ },
63
+ methods: {
64
+ onDragEnd(event) {
65
+ // Handle drag end for Kanban
66
+ if (event.added || event.moved) {
67
+ const item = event.item.__vue__.$parent.item || event.item.__vue__.item;
68
+ const newColumn = event.to.parentElement.getAttribute('data-column');
69
+
70
+ if (item && newColumn) {
71
+ // Update the item's grouped attribute
72
+ item[this.groupedAttribute] = newColumn;
73
+
74
+ // Emit the change event
75
+ this.$emit('draggableChange', event);
76
+ }
77
+ }
78
+ }
79
+ }
80
+ };
81
+ </script>
82
+
83
+ <style scoped>
84
+ .kanban-column {
85
+ background: #f4f5f7;
86
+ border-radius: 8px;
87
+ width: 300px;
88
+ display: flex;
89
+ flex-direction: column;
90
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
91
+ }
92
+
93
+ .kanban-column-header {
94
+ font-weight: bold;
95
+ padding: 0.5rem;
96
+ background: #dfe1e6;
97
+ border-radius: 8px 8px 0 0;
98
+ text-align: center;
99
+ }
100
+
101
+ .kanban-column-body {
102
+ padding: 0.5rem;
103
+ min-height: 100px;
104
+ background: #ffffff;
105
+ border-radius: 0 0 8px 8px;
106
+ display: flex;
107
+ flex-direction: column;
108
+ gap: 0.5rem;
109
+ }
110
+ </style>
@@ -0,0 +1,91 @@
1
+ <template>
2
+ <td :scope="column.prop == 'id' ? 'row' : ''">
3
+ <slot :name="'cell-' + column.prop" v-bind:item="item" v-bind:index="index" v-bind:itemindex="index"
4
+ v-bind:columnindex="columnIndex">
5
+ <span v-if="column.type == 'boolean'">
6
+ <b-badge variant="success" v-if="itemValue(column, item) == 'true' ||
7
+ itemValue(column, item) == 1 ||
8
+ itemValue(column, item) == '1'
9
+ "><b-icon-check-circle></b-icon-check-circle></b-badge>
10
+ <b-badge variant="danger" v-if="!itemValue(column, item) ||
11
+ itemValue(column, item) == '0' ||
12
+ itemValue(column, item) == 'false'
13
+ "><b-icon-x-circle></b-icon-x-circle></b-badge>
14
+ </span>
15
+ <span v-else-if="column.type == 'date'">
16
+ {{
17
+ itemValue(column, item)
18
+ ? moment(itemValue(column, item)).format(
19
+ column.format ? column.format : 'L LT'
20
+ )
21
+ : itemValue(column, item)
22
+ }}
23
+ </span>
24
+ <span v-else-if="column.type == 'select'">
25
+ <b-form-checkbox v-model="item.selected" @change="onCheckSelect($event, item)">
26
+ </b-form-checkbox>
27
+ </span>
28
+ <span v-else-if="column.type == 'state' && optionsLoaded">
29
+ {{
30
+ getStateValue(itemValue(column, item), column.options)
31
+ }}
32
+ </span>
33
+ <span v-else-if="column.type == 'array' && optionsLoaded">
34
+ {{
35
+ getArrayValue(
36
+ itemValue(column, item),
37
+ column.displayProp,
38
+ column.options
39
+ )
40
+ }}
41
+ </span>
42
+ <span v-else>
43
+ {{ itemValue(column, item) }}
44
+ </span>
45
+ </slot>
46
+
47
+ <b-button-group v-if="column.type == 'actions'">
48
+ <slot name="rowAction" v-bind:item="item" v-bind:index="index" v-bind:showItem="showItem"
49
+ v-bind:updateItem="updateItem" v-bind:removeItem="removeItem">
50
+ <b-button variant="primary" @click="showItem(item.id, index)">
51
+ <b-icon-eye></b-icon-eye>
52
+ </b-button>
53
+ <b-button variant="secondary" @click="updateItem(item.id, index)">
54
+ <b-icon-pencil></b-icon-pencil>
55
+ </b-button>
56
+ <b-button variant="danger" @click="removeItem(item.id, index)">
57
+ <b-icon-trash></b-icon-trash>
58
+ </b-button>
59
+ </slot>
60
+ </b-button-group>
61
+ </td>
62
+ </template>
63
+
64
+ <script>
65
+ import moment from "moment";
66
+
67
+ export default {
68
+ name: 'TableCell',
69
+ props: {
70
+ column: Object,
71
+ item: Object,
72
+ index: Number,
73
+ columnIndex: Number
74
+ },
75
+ inject: [
76
+ 'itemValue',
77
+ 'getStateValue',
78
+ 'getArrayValue',
79
+ 'onCheckSelect',
80
+ 'showItem',
81
+ 'updateItem',
82
+ 'removeItem',
83
+ 'optionsLoaded'
84
+ ],
85
+ data() {
86
+ return {
87
+ moment: moment
88
+ };
89
+ }
90
+ };
91
+ </script>
@@ -0,0 +1,113 @@
1
+ <template>
2
+ <thead class="thead-light">
3
+ <tr>
4
+ <slot name="rowHead">
5
+ <th v-for="(column, indexc) in columns" :key="indexc"
6
+ :style="{ width: column.width ? column.width : 'inherit' }" scope="col">
7
+ <slot :name="'filter-' + column.prop" v-bind:column="column" v-bind:filter="filter"
8
+ v-bind:internalFilterByProp="internalFilterByProp" v-if="enableFilters &&
9
+ filtersVisible &&
10
+ isColumnHasFilter(column) &&
11
+ internalFilterByProp(column.prop)
12
+ ">
13
+
14
+ <div class="form-group">
15
+ <select v-if="column.type == 'boolean'" class="form-control form-control-md p-2"
16
+ v-model="internalFilterByProp(column.prop).value" @change="onChangeFilter($event)">
17
+ <option value="">{{ column.label }}</option>
18
+ <option value="1">Sí</option>
19
+ <option value="0">No</option>
20
+ </select>
21
+
22
+ <div class="row" v-else-if="column.type == 'date'">
23
+ <div class="col-6">
24
+ <b-form-datepicker v-model="internalFilterByProp(column.prop + '_from').value
25
+ " today-button reset-button close-button locale="es"
26
+ class="form-control-md p-2"></b-form-datepicker>
27
+ </div>
28
+ <div class="col-6">
29
+ <b-form-datepicker v-model="internalFilterByProp(column.prop + '_to').value
30
+ " today-button reset-button close-button locale="es"
31
+ class="form-control-md p-2"></b-form-datepicker>
32
+ </div>
33
+ </div>
34
+
35
+ <select v-else-if="column.type == 'state' && optionsLoaded" class="form-control form-control-md p-2"
36
+ v-model="internalFilterByProp(column.prop).value" @change="onChangeFilter($event)"
37
+ :placeholder="column.label">
38
+ <option value="">{{ column.label }}</option>
39
+ <option :value="option.id" v-for="(option, indexo) in column.options" :key="indexo">
40
+ {{
41
+ option.text
42
+ ? option.text
43
+ : option.label
44
+ ? option.label
45
+ : ""
46
+ }}
47
+ </option>
48
+ </select>
49
+
50
+ <select v-else-if="column.type == 'array' && optionsLoaded" class="form-control form-control-md p-2"
51
+ v-model="internalFilterByProp(column.prop).value" @change="onChangeFilter($event)"
52
+ :placeholder="column.label">
53
+ <option value="">{{ column.label }}</option>
54
+ <option :value="option.id" v-for="(option, indexo) in column.options" :key="indexo">
55
+ {{
56
+ option.text
57
+ ? option.text
58
+ : option.label
59
+ ? option.label
60
+ : ""
61
+ }}
62
+ </option>
63
+ </select>
64
+
65
+ <b-form-checkbox v-else-if="column.type == 'checkbox'" name="select-all"
66
+ @change="toggleAll($event)">
67
+ </b-form-checkbox>
68
+
69
+ <b-form-checkbox v-else-if="column.type == 'select'" name="select-all" @change="toggleAll($event)">
70
+ </b-form-checkbox>
71
+
72
+ <input v-else class="form-control form-control-md p-2"
73
+ v-model="internalFilterByProp(column.prop).value" :placeholder="column.label"
74
+ @change="onChangeFilter($event)" />
75
+
76
+ </div>
77
+ </slot>
78
+ <span v-else-if="column.type == 'select'">
79
+ <b-form-checkbox name="select-all" @change="toggleAll($event)"></b-form-checkbox>
80
+ </span>
81
+ <span v-else>{{ column.label }}</span>
82
+
83
+ <span
84
+ v-if="sortable && column.type != 'select' && column.type != 'checkbox' && internalFilterByProp(column.prop + '_sort')"
85
+ class="sort-filter" @click="toggleSortFilter(column)"><b-icon-sort-down
86
+ v-if="!internalFilterByProp(column.prop + '_sort').value"></b-icon-sort-down><b-icon-sort-up
87
+ v-if="internalFilterByProp(column.prop + '_sort').value == 'ASC'"></b-icon-sort-up>
88
+ <b-icon-sort-down
89
+ v-if="internalFilterByProp(column.prop + '_sort').value == 'DESC'"></b-icon-sort-down>
90
+ </span>
91
+ </th>
92
+ </slot>
93
+ </tr>
94
+ </thead>
95
+ </template>
96
+
97
+ <script>
98
+ export default {
99
+ name: 'TableHeader',
100
+ inject: [
101
+ 'columns',
102
+ 'enableFilters',
103
+ 'filtersVisible',
104
+ 'isColumnHasFilter',
105
+ 'internalFilterByProp',
106
+ 'onChangeFilter',
107
+ 'toggleAll',
108
+ 'toggleSortFilter',
109
+ 'sortable',
110
+ 'optionsLoaded'
111
+ ]
112
+ };
113
+ </script>
@@ -0,0 +1,39 @@
1
+ <template>
2
+ <tr @mouseover="onRowHover(item, index)" @click="onRowClick(item, index)" class="item">
3
+ <th :colspan="columns.length" v-if="grouped && item.crudgroup">
4
+ <span>{{ item.crudgrouplabel }}</span>
5
+ </th>
6
+
7
+ <slot name="row" v-bind:item="item" v-else>
8
+ <TableCell
9
+ v-for="(column, indexc) in columns"
10
+ :key="indexc"
11
+ :column="column"
12
+ :item="item"
13
+ :index="index"
14
+ :columnIndex="indexc"
15
+ />
16
+ </slot>
17
+ </tr>
18
+ </template>
19
+
20
+ <script>
21
+ import TableCell from './TableCell.vue';
22
+
23
+ export default {
24
+ name: 'TableRow',
25
+ components: {
26
+ TableCell
27
+ },
28
+ props: {
29
+ item: Object,
30
+ index: Number,
31
+ grouped: Boolean
32
+ },
33
+ inject: [
34
+ 'columns',
35
+ 'onRowHover',
36
+ 'onRowClick'
37
+ ]
38
+ };
39
+ </script>