@5minds/node-red-dashboard-2-processcube-dynamic-table 2.0.1-develop-ac58f3-mccdrc9q → 2.0.1-feature-3da6b8-mcevyn1q
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/nodes/dynamic-table.html +312 -272
- package/package.json +76 -76
- package/resources/ui-dynamic-table.umd.js +2 -28
- package/ui/components/TitleText.vue +35 -0
- package/ui/components/UIDynamicTable.vue +37 -122
- package/ui/stylesheets/ui-dynamic-table.css +106 -38
|
@@ -1,40 +1,49 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
<v-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
2
|
+
<div class="ui-dynamic-table-container">
|
|
3
|
+
<UIDynamicTableTitleText v-if="props.title_text && props.title_text.length > 0" :title="props.title_text"
|
|
4
|
+
:style="props.title_style || 'default'" :customStyles="props.title_custom_text_styling || ''"
|
|
5
|
+
:titleIcon="props.title_icon || ''" />
|
|
6
|
+
<v-data-table :headers="headers" :items="tasks" :search="search" class="full-width-table">
|
|
7
|
+
<template v-slot:top>
|
|
8
|
+
<v-toolbar flat class="pb-2 pt-8">
|
|
9
|
+
<v-text-field class="mx-3 search-input" v-model="search" label="Search"
|
|
10
|
+
prepend-inner-icon="mdi-magnify" variant="outlined" hide-details single-line></v-text-field>
|
|
11
|
+
</v-toolbar>
|
|
12
|
+
</template>
|
|
13
|
+
<template v-slot:item.actions="{ item }">
|
|
14
|
+
<v-container class="action-button-container">
|
|
15
|
+
<v-container v-for="(action, index) in actions"
|
|
16
|
+
style="padding: 0px; display: inline; width: fit-content; margin: 0px">
|
|
17
|
+
<v-btn style="margin: 0px 2px" class="action-button"
|
|
18
|
+
v-if="conditionCheck(action.condition, item)" :key="index" size="small"
|
|
19
|
+
@click="actionFn(action, item)">
|
|
20
|
+
{{ action.label }}
|
|
21
|
+
</v-btn>
|
|
22
|
+
</v-container>
|
|
19
23
|
</v-container>
|
|
20
|
-
</
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
</
|
|
25
|
-
</
|
|
24
|
+
</template>
|
|
25
|
+
<template v-slot:no-data>
|
|
26
|
+
<v-alert text="No Data" style="margin: 12px"></v-alert>
|
|
27
|
+
</template>
|
|
28
|
+
</v-data-table>
|
|
29
|
+
</div>
|
|
26
30
|
</template>
|
|
27
31
|
|
|
28
32
|
<script>
|
|
29
33
|
import { mapState } from 'vuex';
|
|
30
|
-
import
|
|
34
|
+
import UIDynamicTableTitleText from './TitleText.vue'
|
|
31
35
|
|
|
32
36
|
export default {
|
|
33
37
|
name: 'UIDynamicTable',
|
|
38
|
+
components: {
|
|
39
|
+
UIDynamicTableTitleText
|
|
40
|
+
},
|
|
34
41
|
inject: ['$socket'],
|
|
35
42
|
props: {
|
|
43
|
+
/* do not remove entries from this - Dashboard's Layout Manager's will pass this data to your component */
|
|
36
44
|
id: { type: String, required: true },
|
|
37
45
|
props: { type: Object, default: () => ({}) },
|
|
46
|
+
/* state: { type: Object, default: () => ({ enabled: false, visible: false }) } // DEFAULT */
|
|
38
47
|
state: {
|
|
39
48
|
type: Object,
|
|
40
49
|
default: () => ({ enabled: true, visible: true }),
|
|
@@ -42,15 +51,6 @@ export default {
|
|
|
42
51
|
},
|
|
43
52
|
computed: {
|
|
44
53
|
...mapState('data', ['messages']),
|
|
45
|
-
searchParamKey() {
|
|
46
|
-
return `search_${this.id}`;
|
|
47
|
-
},
|
|
48
|
-
sortByStorageKey() {
|
|
49
|
-
return `table_sort_${this.id}`;
|
|
50
|
-
},
|
|
51
|
-
itemsPerPageStorageKey() {
|
|
52
|
-
return `table_items_per_page_${this.id}`;
|
|
53
|
-
},
|
|
54
54
|
},
|
|
55
55
|
data() {
|
|
56
56
|
return {
|
|
@@ -58,24 +58,9 @@ export default {
|
|
|
58
58
|
actions: [],
|
|
59
59
|
tasks: [],
|
|
60
60
|
headers: [],
|
|
61
|
-
isInitialized: false,
|
|
62
|
-
sortBy: [],
|
|
63
|
-
itemsPerPage: 10,
|
|
64
|
-
itemsPerPageOptions: [
|
|
65
|
-
{ value: 5, title: '5' },
|
|
66
|
-
{ value: 10, title: '10' },
|
|
67
|
-
{ value: 25, title: '25' },
|
|
68
|
-
{ value: 50, title: '50' },
|
|
69
|
-
{ value: 100, title: '100' },
|
|
70
|
-
{ value: -1, title: 'All' }
|
|
71
|
-
],
|
|
72
61
|
};
|
|
73
62
|
},
|
|
74
63
|
mounted() {
|
|
75
|
-
this.loadFromLocalStorage();
|
|
76
|
-
this.loadSearchFromUrl();
|
|
77
|
-
this.isInitialized = true;
|
|
78
|
-
|
|
79
64
|
this.$socket.on('widget-load:' + this.id, (msg) => {
|
|
80
65
|
this.initialize(msg);
|
|
81
66
|
this.$store.commit('data/bind', {
|
|
@@ -89,7 +74,9 @@ export default {
|
|
|
89
74
|
}
|
|
90
75
|
|
|
91
76
|
this.initialize(msg);
|
|
77
|
+
|
|
92
78
|
this.messages[this.id] = msg;
|
|
79
|
+
|
|
93
80
|
this.$store.commit('data/bind', {
|
|
94
81
|
widgetId: this.id,
|
|
95
82
|
msg,
|
|
@@ -125,10 +112,9 @@ export default {
|
|
|
125
112
|
}));
|
|
126
113
|
|
|
127
114
|
this.headers.push({
|
|
128
|
-
title: '
|
|
115
|
+
title: 'Actions',
|
|
129
116
|
align: 'center',
|
|
130
117
|
key: 'actions',
|
|
131
|
-
sortable: false
|
|
132
118
|
});
|
|
133
119
|
},
|
|
134
120
|
conditionCheck(condition, row) {
|
|
@@ -141,82 +127,11 @@ export default {
|
|
|
141
127
|
return false;
|
|
142
128
|
}
|
|
143
129
|
},
|
|
144
|
-
updateSearchParam: debounce(function (searchValue) {
|
|
145
|
-
const currentQuery = { ...this.$route.query };
|
|
146
|
-
|
|
147
|
-
if (searchValue && searchValue.trim() !== '') {
|
|
148
|
-
currentQuery[this.searchParamKey] = searchValue;
|
|
149
|
-
} else {
|
|
150
|
-
delete currentQuery[this.searchParamKey];
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
this.$router.replace({
|
|
154
|
-
path: this.$route.path,
|
|
155
|
-
query: currentQuery
|
|
156
|
-
}).catch(err => {
|
|
157
|
-
if (err.name !== 'NavigationDuplicated') {
|
|
158
|
-
console.error('Router navigation error:', err);
|
|
159
|
-
}
|
|
160
|
-
});
|
|
161
|
-
}, 500),
|
|
162
|
-
loadSearchFromUrl() {
|
|
163
|
-
const searchValue = this.$route.query[this.searchParamKey];
|
|
164
|
-
if (searchValue && typeof searchValue === 'string') {
|
|
165
|
-
this.search = searchValue;
|
|
166
|
-
} else {
|
|
167
|
-
this.search = '';
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
loadFromLocalStorage() {
|
|
171
|
-
try {
|
|
172
|
-
const savedSortBy = localStorage.getItem(this.sortByStorageKey);
|
|
173
|
-
if (savedSortBy) {
|
|
174
|
-
this.sortBy = JSON.parse(savedSortBy);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
const savedItemsPerPage = localStorage.getItem(this.itemsPerPageStorageKey);
|
|
178
|
-
if (savedItemsPerPage) {
|
|
179
|
-
this.itemsPerPage = parseInt(savedItemsPerPage, 10);
|
|
180
|
-
}
|
|
181
|
-
} catch (error) {
|
|
182
|
-
console.error('Error loading table settings from localStorage:', error);
|
|
183
|
-
}
|
|
184
|
-
},
|
|
185
|
-
saveToLocalStorage() {
|
|
186
|
-
try {
|
|
187
|
-
localStorage.setItem(this.sortByStorageKey, JSON.stringify(this.sortBy));
|
|
188
|
-
localStorage.setItem(this.itemsPerPageStorageKey, this.itemsPerPage.toString());
|
|
189
|
-
} catch (error) {
|
|
190
|
-
console.error('Error saving table settings to localStorage:', error);
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
updateSortBy(newSortBy) {
|
|
194
|
-
this.sortBy = newSortBy;
|
|
195
|
-
this.saveToLocalStorage();
|
|
196
|
-
},
|
|
197
|
-
updateItemsPerPage(newItemsPerPage) {
|
|
198
|
-
this.itemsPerPage = newItemsPerPage;
|
|
199
|
-
this.saveToLocalStorage();
|
|
200
|
-
},
|
|
201
|
-
},
|
|
202
|
-
watch: {
|
|
203
|
-
search(newValue, oldValue) {
|
|
204
|
-
if (this.isInitialized) {
|
|
205
|
-
this.updateSearchParam(newValue);
|
|
206
|
-
}
|
|
207
|
-
},
|
|
208
|
-
'$route.query': {
|
|
209
|
-
handler(newQuery) {
|
|
210
|
-
if (this.isInitialized) {
|
|
211
|
-
this.loadSearchFromUrl();
|
|
212
|
-
}
|
|
213
|
-
},
|
|
214
|
-
deep: true
|
|
215
|
-
}
|
|
216
130
|
},
|
|
217
131
|
};
|
|
218
132
|
</script>
|
|
219
133
|
|
|
220
134
|
<style scoped>
|
|
135
|
+
/* CSS is auto scoped, but using named classes is still recommended */
|
|
221
136
|
@import '../stylesheets/ui-dynamic-table.css';
|
|
222
137
|
</style>
|
|
@@ -1,96 +1,126 @@
|
|
|
1
1
|
h1 {
|
|
2
|
-
|
|
2
|
+
margin-bottom: 10px;
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
h2 {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
margin-top: 1.5rem;
|
|
7
|
+
margin-bottom: 0.75rem;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
h3 {
|
|
11
|
-
|
|
11
|
+
margin-top: 1rem;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
p {
|
|
15
|
-
|
|
15
|
+
margin-bottom: 5px;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
ul li {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
list-style-type: circle;
|
|
20
|
+
list-style-position: inside;
|
|
21
|
+
margin-left: 15px;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
pre {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
padding: 12px;
|
|
26
|
+
margin: 12px;
|
|
27
|
+
background-color: #eee;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
code {
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
font-size: 0.825rem;
|
|
32
|
+
color: #ae0000;
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
input {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
36
|
+
padding: 12px;
|
|
37
|
+
margin: 12px;
|
|
38
|
+
background-color: #eee;
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
.task-div {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
42
|
+
padding: 8px;
|
|
43
|
+
margin: 16px;
|
|
44
|
+
border: solid;
|
|
45
|
+
border-radius: 4px;
|
|
46
|
+
border-color: #303030;
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
.action-button-container {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
width: 100%;
|
|
51
|
+
display: flex;
|
|
52
|
+
justify-content: center;
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
.full-width-table {
|
|
56
56
|
--v-table-header-height: 40px !important;
|
|
57
|
+
background-color: #fff;
|
|
58
|
+
border-radius: 0px 0px 8px 8px;
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
.full-width-table .v-toolbar {
|
|
60
|
-
|
|
61
|
-
|
|
62
|
+
background: unset !important;
|
|
63
|
+
color: unset !important;
|
|
62
64
|
}
|
|
63
65
|
|
|
64
66
|
.full-width-table .v-table__wrapper .v-alert--variant-flat {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
background: unset !important;
|
|
68
|
+
color: unset !important;
|
|
67
69
|
}
|
|
68
70
|
|
|
69
|
-
.full-width-table
|
|
71
|
+
.full-width-table :deep(thead th) {
|
|
70
72
|
border-bottom: 4px solid rgb(var(--v-theme-primary)) !important;
|
|
71
73
|
font-weight: 700 !important;
|
|
72
74
|
font-size: 16px !important;
|
|
73
75
|
}
|
|
74
76
|
|
|
75
|
-
.full-width-table
|
|
76
|
-
background-color:
|
|
77
|
+
.full-width-table :deep(tbody) {
|
|
78
|
+
background-color: unset !important;
|
|
77
79
|
--widget-row-height: 40px !important;
|
|
78
80
|
font-size: 16px;
|
|
79
81
|
}
|
|
80
82
|
|
|
81
|
-
.search-input
|
|
82
|
-
border
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
.search-input :deep(.v-field__outline__end) {
|
|
84
|
+
border: none !important;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.search-input :deep(.v-field__outline__start) {
|
|
88
|
+
border: none !important;
|
|
85
89
|
}
|
|
86
90
|
|
|
87
|
-
.search-input
|
|
91
|
+
.search-input :deep(.v-field__outline) {
|
|
92
|
+
display: none !important;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.search-input :deep(.v-label) {
|
|
88
96
|
font-size: 14px !important;
|
|
89
97
|
}
|
|
90
98
|
|
|
91
|
-
.search-input
|
|
99
|
+
.search-input :deep(.v-field) {
|
|
92
100
|
border-radius: 0px 0px 0px 8px;
|
|
93
|
-
border-
|
|
101
|
+
border-bottom: 2px solid rgb(var(--v-theme-primary)) !important;
|
|
102
|
+
border-left: 2px solid rgb(var(--v-theme-primary)) !important;
|
|
103
|
+
border-right: none !important;
|
|
104
|
+
border-top: none !important;
|
|
105
|
+
transition: border-width 0.1s ease-in-out;
|
|
106
|
+
margin-bottom: 8px;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.search-input :deep(.v-field__input) {
|
|
110
|
+
font-size: 18px;
|
|
111
|
+
font-weight: 400;
|
|
112
|
+
font-style: normal;
|
|
113
|
+
padding: 4px 8px;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.search-input:focus-within :deep(.v-field) {
|
|
117
|
+
border-bottom: 4px solid rgb(var(--v-theme-primary)) !important;
|
|
118
|
+
border-left: 4px solid rgb(var(--v-theme-primary)) !important;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.search-input:focus-within :deep(.v-field__input) {
|
|
122
|
+
background-color: #f6f5fa;
|
|
123
|
+
border-radius: 0 8px 0px 5px;
|
|
94
124
|
}
|
|
95
125
|
|
|
96
126
|
.action-button {
|
|
@@ -101,3 +131,41 @@ input {
|
|
|
101
131
|
color: rgb(var(--v-theme-primary));
|
|
102
132
|
padding: 8px;
|
|
103
133
|
}
|
|
134
|
+
|
|
135
|
+
.ui-dynamic-table-container {
|
|
136
|
+
border-radius: 8px;
|
|
137
|
+
border-bottom: 4px solid rgb(var(--v-theme-primary));
|
|
138
|
+
box-shadow: 0 4px 16px -3px rgba(0, 0, 0, 0.5);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.ui-dynamic-table-title-default {
|
|
142
|
+
background: linear-gradient(131deg, #18181a 26.76%, #242326 100.16%);
|
|
143
|
+
padding: 32px;
|
|
144
|
+
color: #ffffff;
|
|
145
|
+
font-size: 36px;
|
|
146
|
+
font-weight: 700;
|
|
147
|
+
border-radius: 8px 8px 0px 0px;
|
|
148
|
+
margin-top: 0px;
|
|
149
|
+
border: 2px solid #f6f5fa;
|
|
150
|
+
border-bottom: none;
|
|
151
|
+
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.3);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
.ui-dynamic-table-title-default hr {
|
|
155
|
+
border: 4px solid rgb(var(--v-theme-primary));
|
|
156
|
+
border-radius: 2px;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
.ui-dynamic-table-title-minimal {
|
|
160
|
+
padding: 16px;
|
|
161
|
+
margin-top: 0px;
|
|
162
|
+
border: 2px solid #f6f5fa;
|
|
163
|
+
border-bottom: none;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.ui-dynamic-table-title-outside {
|
|
167
|
+
padding-bottom: 24px;
|
|
168
|
+
padding-top: 24px;
|
|
169
|
+
font-size: 24px;
|
|
170
|
+
font-weight: 700;
|
|
171
|
+
}
|