@5minds/node-red-dashboard-2-processcube-dynamic-table 2.0.1-feature-a2a44b-mbtbbouc → 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.
@@ -1,40 +1,49 @@
1
1
  <template>
2
- <v-data-table :headers="headers" :items="tasks" :search="search" :sort-by="sortBy" :items-per-page="itemsPerPage"
3
- :items-per-page-options="itemsPerPageOptions" @update:sort-by="updateSortBy"
4
- @update:items-per-page="updateItemsPerPage" class="full-width-table">
5
- <template v-slot:top>
6
- <v-toolbar flat class="py-2">
7
- <v-text-field class="mx-3 search-input" v-model="search" label="Search" prepend-inner-icon="mdi-magnify"
8
- variant="outlined" hide-details single-line></v-text-field>
9
- </v-toolbar>
10
- </template>
11
- <template v-slot:item.actions="{ item }">
12
- <v-container class="action-button-container">
13
- <v-container v-for="(action, index) in actions"
14
- style="padding: 0px; display: inline; width: fit-content; margin: 0px">
15
- <v-btn style="margin: 0px 2px" class="action-button" v-if="conditionCheck(action.condition, item)"
16
- :key="index" size="small" @click="actionFn(action, item)">
17
- {{ action.label }}
18
- </v-btn>
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
- </v-container>
21
- </template>
22
- <template v-slot:no-data>
23
- <v-alert text="No Data" style="margin: 12px"></v-alert>
24
- </template>
25
- </v-data-table>
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 { debounce } from 'lodash';
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,
@@ -128,7 +115,6 @@ export default {
128
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
- margin-bottom: 10px
2
+ margin-bottom: 10px;
3
3
  }
4
4
 
5
5
  h2 {
6
- margin-top: 1.5rem;
7
- margin-bottom: 0.75rem;
6
+ margin-top: 1.5rem;
7
+ margin-bottom: 0.75rem;
8
8
  }
9
9
 
10
10
  h3 {
11
- margin-top: 1rem;
11
+ margin-top: 1rem;
12
12
  }
13
13
 
14
14
  p {
15
- margin-bottom: 5px;
15
+ margin-bottom: 5px;
16
16
  }
17
17
 
18
18
  ul li {
19
- list-style-type: circle;
20
- list-style-position: inside;
21
- margin-left: 15px;
19
+ list-style-type: circle;
20
+ list-style-position: inside;
21
+ margin-left: 15px;
22
22
  }
23
23
 
24
24
  pre {
25
- padding: 12px;
26
- margin: 12px;
27
- background-color: #eee;
25
+ padding: 12px;
26
+ margin: 12px;
27
+ background-color: #eee;
28
28
  }
29
29
 
30
30
  code {
31
- font-size: 0.825rem;
32
- color: #ae0000;
31
+ font-size: 0.825rem;
32
+ color: #ae0000;
33
33
  }
34
34
 
35
35
  input {
36
- padding: 12px;
37
- margin: 12px;
38
- background-color: #eee;
36
+ padding: 12px;
37
+ margin: 12px;
38
+ background-color: #eee;
39
39
  }
40
40
 
41
41
  .task-div {
42
- padding: 8px;
43
- margin: 16px;
44
- border: solid;
45
- border-radius: 4px;
46
- border-color: #303030;
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
- width: 100%;
51
- display: flex;
52
- justify-content: center;
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
- background: unset !important;
61
- color: unset !important;
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
- background: unset !important;
66
- color: unset !important;
67
+ background: unset !important;
68
+ color: unset !important;
67
69
  }
68
70
 
69
- .full-width-table >>> thead th {
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 >>> tbody {
76
- background-color: #F6F5FA !important;
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 >>> .v-field__outline__end {
82
- border-right: none;
83
- border-top: none;
84
- border-radius: 0px;
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 >>> .v-label {
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 >>> .v-field__outline__start {
99
+ .search-input :deep(.v-field) {
92
100
  border-radius: 0px 0px 0px 8px;
93
- border-top: none;
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
+ }