|
63 | 63 | success: function (data) { |
64 | 64 | let devices = data.results; |
65 | 65 | let nextUrl = data.next; |
66 | | - const uniqueStatus = Array.from( |
67 | | - new Set(devices.map((d) => d.monitoring.status_label)), |
68 | | - ); |
| 66 | + const uniqueStatus = devices.reduce((acc, device) => { |
| 67 | + const { status_label, status } = device.monitoring; |
| 68 | + acc[status_label] = status; |
| 69 | + return acc; |
| 70 | + }, {}); |
69 | 71 | let statusFiltersBtn = ""; |
70 | | - uniqueStatus.forEach((status) => { |
71 | | - const label = gettext(status); |
| 72 | + Object.entries(uniqueStatus).forEach(([status_label, status]) => { |
| 73 | + const label = gettext(status_label); |
72 | 74 | statusFiltersBtn += ` |
73 | | - <span |
74 | | - class="health-status health-${status} status-filter" |
75 | | - data-status="${status}" |
76 | | - > |
77 | | - ${label} |
78 | | - </span> |
79 | | - `; |
| 75 | + <span |
| 76 | + class="health-status health-${status} status-filter" |
| 77 | + data-status="${status}" |
| 78 | + > |
| 79 | + ${label} |
| 80 | + </span> |
| 81 | + `; |
80 | 82 | }); |
81 | 83 | const has_floorplan = data.has_floorplan; |
82 | 84 | const floorplan_btn = has_floorplan |
|
110 | 112 | |
111 | 113 | </tbody> |
112 | 114 | </table> |
| 115 | + // Todo: Fix css |
113 | 116 | <div class="ow-loading-spinner" style="display: none; position: absolute; bottom: 10px; left: 50%; transform: translateX(-50%);"></div> |
114 | 117 | </div> |
115 | 118 | ${floorplan_btn} |
|
145 | 148 | el.find("tbody").html(rows); |
146 | 149 | } |
147 | 150 | let fetchDevicesTimeout; |
| 151 | + let loading = false; |
148 | 152 | function fetchDevices(url, ms = 0) { |
149 | | - if (!url) return; |
| 153 | + if (!url || loading) return; |
150 | 154 | clearTimeout(fetchDevicesTimeout); |
151 | 155 | fetchDevicesTimeout = setTimeout(() => { |
| 156 | + loading = true; |
| 157 | + const spinner = el.find(".table-container .ow-loading-spinner"); |
| 158 | + spinner.show(); |
152 | 159 | let params = new URLSearchParams(); |
153 | 160 | const searchParam = el |
154 | 161 | .find("#device-search") |
|
170 | 177 | // if nextUrl is the same as url, that means we are fetching for infinite scroll |
171 | 178 | if (url === nextUrl) fetchUrl = url; |
172 | 179 | else fetchUrl = queryString ? `${url}?${queryString}` : url; |
| 180 | + |
173 | 181 | $.ajax( |
174 | 182 | { |
175 | 183 | dataType: "json", |
|
188 | 196 | error() { |
189 | 197 | console.error("Could not load more devices from", url); |
190 | 198 | }, |
| 199 | + complete() { |
| 200 | + loading = false; |
| 201 | + spinner.hide(); |
| 202 | + }, |
191 | 203 | }, |
192 | | - ms, |
193 | 204 | ); |
194 | | - }); |
| 205 | + }, ms); |
195 | 206 | } |
196 | 207 | renderRows(); |
197 | 208 | el.find("#device-search").on("input", function () { |
198 | | - fetchDevices(url); |
| 209 | + fetchDevices(url, 300); |
199 | 210 | }); |
200 | 211 | let activeStatuses = []; |
201 | 212 | el.find(".status-filter").on("click", function (e) { |
|
218 | 229 | }); |
219 | 230 | el.find(".table-container").on("scroll", function () { |
220 | 231 | if (this.scrollTop + this.clientHeight >= this.scrollHeight - 10) { |
221 | | - fetchDevices(nextUrl, 300); |
| 232 | + fetchDevices(nextUrl, 100); |
222 | 233 | } |
223 | 234 | }); |
224 | 235 | loadingOverlay.hide(); |
|
0 commit comments